WyvernMods Configurable Phase 2

This commit is contained in:
Sindusk
2019-05-06 09:25:48 -04:00
parent 9eb8d1a2b5
commit acf5d74a9c
11 changed files with 854 additions and 1409 deletions

View File

@@ -12,7 +12,7 @@ repositories {
dependencies {
compile 'org.gotti.wurmunlimited:server-modlauncher:0.43'
compile 'com.github.Sindusk:sindusklibrary:v2.2'
compile 'com.github.Sindusk:sindusklibrary:v2.3'
compile 'com.github.bdew-wurm:bdew_server_mod_tools:v1.0.0'
compile 'com.github.Sindusk:DiscordRelay:v1.2'
compile 'com.github.Sindusk:DUSKombat:v1.0'

View File

@@ -515,6 +515,254 @@ regenerateStaminaOnVehicleAnySlope=true
## >> END QUALITY OF LIFE MODULE << ##
## >> COMBAT MODULE << ##
## The Combat Module offers options that affect the combat aspects of the game.
## This isn't restricted to simply the actual combat itself. It also includes some options to change combat-oriented spells and other mechanics.
enableCombatModule=true
# > COMBAT RATING ADJUSTMENTS < #
# Combat Rating Adjustments involve some tweaks to how combat rating is calculated.
# There are two components: additive and multiplicative combat rating adjustments.
# Additive modifiers are always applied first. This creates a "base" combat rating that is then modified.
# Multiplicative modifiers apply after all additive combat rating adjustments, including vanilla ones.
enableCombatRatingAdjustments=true
#royalExecutionerBonus: Additive - Adds +2 CR against PvE targets while holding Royal Executioner kingdom title.
# The vanilla royal executioner bonus only applies to PvP combat. This option is meant to give it a PvE bonus as well.
royalExecutionerBonus=true
#TODO: Make this option a value instead and allow configuration of how much CR to grant.
#petSoulDepthScaling: Multiplicative - Scales the CR of pets with the Soul Depth of the owner/dominator.
# Applies a multiplier of Soul Depth * 0.02 to the pet's CR. This grants 40% CR at 20 Soul Depth and 200% CR at 100 Soul Depth.
# At 50 Soul Depth this modifier equates to 100%, resulting in no change to the pet's CR.
petSoulDepthScaling=true
#TODO: Make this option a value instead and allow configuration of the CR multiplier per soul depth.
#vehicleCombatRatingPenalty: Multiplicative - Reduces the CR of players on a vehicle by 25%.
# There is no significant offensive penalty for being the commander of a vehicle while in combat.
# This option is meant to encourage players to avoid fighting while on a vehicle.
vehicleCombatRatingPenalty=true
#TODO: Make this option a value instead and allow configuration of the CR multiplier while on a vehicle.
# > END COMBAT RATING ADJUSTMENTS < #
#fixMagranonDamageStacking: In vanilla combat, Magranon/warrior damage bonus (+15% damage from deity) does not stack correctly.
# This applies only in aggressive stance, where the aggressive fighting skill calculations will adjust if the player has warrior bonus.
# When this occurs, it results in a loss of damage from the bonus, making the warrior passive effectively ~10-12% instead of the full 15%.
# This option adjusts the fight skill calculations and forces it to accurately apply the 15% damage bonus regardless of other factors.
fixMagranonDamageStacking=true
#adjustCombatRatingSpellPower: Adjusts the combat rating bonus from Truehit and Excel to 50% of their vanilla values.
adjustCombatRatingSpellPower=true
#TODO: Make this option a multiplier instead of a boolean.
#disableLegendaryRegeneration: Disables the natural healing/regeneration of legendary creatures (uniques).
disableLegendaryRegeneration=true
#useStaticLegendaryRegeneration: Applies a static healing over time to legendary creatures (uniques).
# This option is meant to be used in conjunction with the previous one to make legendaries able to be taken slowly.
# Instead of requiring their defeat in 10 minutes (where they would outheal their attackers), it now regenerates at a set rate.
# This allows players to take their time with uniques and use strategy, so long as the damage inflicted outpaces the natural static regeneration.
# The regeneration is set to 75 health per second (~0.1% maximim health per second). Requires ~874 seconds (14.5 minutes) to heal a full health bar.
useStaticLegendaryRegeneration=true
#TODO: Allow configuration of health regeneration per second.
## >> END COMBAT MODULE << ##
## >> MASTERCRAFT MODULE << ##
## The Mastercraft Module is a new series of systems designed to encourage players to explore end-game crafting further.
## Vanilla settings generally don't encourage players to skill past 90 or improve items past 90.
## The goals of this system, and the settings involved here, are to encourage players to strive for perfection instead of settling at "good enough."
enableMastercraftModule=true
# > DIFFICULTY ADJUSTMENTS < #
# Difficulty Adjustments modify the difficulty when a skill check occurs based on the factors set here.
# This affects almost all systems in the game, from combat to improvement to creation chance to spell power.
# These configurations are aimed at increasing the ways a player can improve their results for any given action.
# By putting time and effort into one's craft, they can more easily improve items to higher levels or be more successful in their activities.
enableDifficultyAdjustments=true
#affinityDifficultyBonus: Reduces the difficulty of actions by 1 per affinity in the skill.
affinityDifficultyBonus=true
#TODO: Make this configuration able to be set to any amount of difficulty reduction.
#legendDifficultyBonus: Grants a reduction to difficulty for all skill over 99.
# Begins at 99.00 skill with no difficulty change, then maxes out at 100.00 skill granting -2 difficulty.
legendDifficultyBonus=true
#masterDifficultyBonus: Grants a reduction to difficulty for all skill over 90.
# Begins at 90.00 skill with no difficulty change, then maxes out at 100.00 skill granting -2 difficulty.
masterDifficultyBonus=true
#TODO: Make the skill scaling a multi-configuration where multiple thresholds can be set for a variety of scaling difficulty changes.
#itemRarityDifficultyBonus: Reduces the difficulty of an action depending on the rarity of the tool being used.
# Normal: No bonus, Rare: -1 difficulty, Supreme: -2 difficulty, Fantastic: -3 difficulty
itemRarityDifficultyBonus=true
#legendItemDifficultyBonus: Reduces the difficulty of an action for all quality over 99 of the tool being used.
# Begins at 99.00 QL with no difficulty change, then maxes out at 100.00 QL granting -1 difficulty.
legendItemDifficultyBonus=true
#masterItemDifficultyBonus: Reduces the difficulty of an action for all quality over 90 of the tool being used.
# Begins at 90.00 QL with no difficulty change, then maxes out at 100.00 QL granting -1 difficulty.
masterItemDifficultyBonus=true
#TODO: Allow further customization of the configurations for difficulty adjustments regarding items.
# > END DIFFICULTY ADJUSTMENTS < #
#empoweredChannelers: Empowers players with up to double the power on their casts based on their channeling skill and affinities.
# This grants +2 power to casts per affinity in channeling.
# Furthermore, it also rolls 4 times up to the value of their channeling skill. It then takes the lowest value and adds it to their cast power.
# !!! Be warned that enabling this option will allow players to perform natural casts of enchants up to roughly 200 power !!!
empoweredChannelers=true
#TODO: Expand on this option and enable more configuration of how the enchant power addition is calculated.
#channelSkillFavorReduction: Reduces the favor costs of spells based on channeling skill.
# Reduces favor cost by 2% per channeling affinity.
# Reduces favor cost by 10% per skill over 99. No bonus at 99.00, scaling to 10% at 100.00 channeling.
# Reduces favor cost by 1% per skill over 90. No bonus at 90.00, scaling to 10% at 100.00 channeling.
channelSkillFavorReduction=true
#TODO: Split up the favor cost reductions, then expand into a multi-configuration style to allow further customization.
#TODO: Also, the code that executes these configurations is old and should be updated with new priest rework code to make it cleaner.
## >> END MASTERCRAFT MODULE << ##
## >> SKILL MODULE << ##
## The Skill Module allows control over the components of skills, including skill gain adjustments.
enableSkillModule=true
# > HYBRID SKILL GAIN < #
# Hybrid Skill Gain is the system which combines the vanilla Wurm Unlimited skill gain system with the classic Wurm Online model.
# In Wurm Unlimited, players gain skill for any successful action whether the result is 0.1 or 100. The skill tick size is the same every action.
# In Wurm Online, players gain skill for any successful action within the range 0 - 40. The skill tick size is based on the duration of the action.
# This new hybrid system makes it so players gain skill for any action, including mild failures (about -20), up to 100.
# However, the system also rewards more skill gain for actions with results closer to zero (if configured that way).
# This was done in order to discourage the "spam creation" skilling method. It is still effective, but improvement is now competitive.
# Visual graph that represents what this skill gain system looks like: https://i.imgur.com/9ykw5dJ.png
# Here is the formula which handles the multiplier for the new skill gain:
# valueAtOneHundred*Math.pow(valueAtZero/valueAtOneHundred, (2-Math.pow(100/(100+Math.max(-99,power)), negativeDecayRate))*Math.pow((100-power)*0.01, positiveDecayRate));
# If you can't read/don't understand that, don't worry! Not many people can! However, if you can read or understand the function,
# you should be able to plug in a formula into Google Sheets, Wolfram Alpha, or Excel and create your own graph where you
# can adjust the following options and give the proper result that you're looking for.
# The default values listed here result in the visual graph represented above.
enableHybridSkillGain=true
#hybridNegativeDecayRate: [Limit: > 0] How fast the function decays past zero going negative.
# Higher values will cause the "midpoint" to move in a positive direction. It will also increase the sharpness of decline after the midpoint.
# Lower values will cause the "midpoint" to move in a negative direction. It will also decrease the sharpness of the decline after the midpoint, resulting a smoother curve.
hybridNegativeDecayRate=5
#hybridPositiveDecayRate: [Limit: > 0] How quickly the function will decay past zero going positive.
# Higher values will result in a sharper curve to the 1.0 multiplier in values greater than zero.
# Lower values will result in a less sharp curve towards the 1.0 multiplier in values greater than zero.
hybridPositiveDecayRate=3
#hybridValueAtZero: [Limit: > 0, must be greater than hybridValueAtOneHundred] What the multiplier should be be when an action results in zero.
hybridValueAtZero=3.74
#hybridValueAtOneHundred: [Limit: > 0, must be less than hybridValueAtZero] What the multiplier should be when an action results in one hundred.
hybridValueAtOneHundred=0.9
# > END HYBRID SKILL GAIN < #
#skillName-#: Changes the name of a skill. Format: skillName-#:skill,newName
# skill = Either the internal ID of a skill or the name of a skill (case insensitive). Example: 1008, mining, MINING, Mining, MiNiNg
# newName = The new name for the skill. Should be allowed to have spaces and other characters, but needs additional testing.
# - Case will carry to the in-game display, so keep that in mind. Making the new name fully lower case might make it look out of place among other skills.
# Set name of Preaching to Gem Augmentation
skillName-1:Preaching,Gem augmentation
# Set name of Stealing to Soulstealing
skillName-2:Stealing,Soulstealing
#skillDifficulty-#: Changes the internal difficulty of a skill. Format: skillDifficulty-#:skill,difficulty
# skill = Either the internal ID of a skill or the name of a skill (case insensitive). Example: 1008, mining, MINING, Mining, MiNiNg
# difficulty = The new difficulty to set for the skill. Most skills default to 4000. This difficulty will affect the skill gain for that skill.
# - In the example of a 4000 difficulty skill: 2000 would double skill gain. 8000 would halve skill gain. 6000 would make it 1.5x slower.
# - For a full list of difficulty for each skill... I don't have one. Nevermind.
# Set mining to 3000 difficulty. Default is 8000. Makes it 2.66x higher skill gain.
skillDifficulty-1:Mining,3000
# Set lockpicking to 700 difficulty. Default is 2000. Makes it 2.85x higher skill gain.
skillDifficulty-2:Lock Picking,700
# Set meditating difficulty to 300. Default is 2000. Makes it 6.66x higher skill gain. Meditating is evil just like the increase.
skillDifficulty-3:Meditating,300
#skillTickTime-#: Changes the tick timer for skill gain on a skill. Format: skillTickTime-#:skill,tickTime
# skill = Either the internal ID of a skill or the name of a skill (case insensitive). Example: 1008, mining, MINING, Mining, MiNiNg
# tickTime = The interval (in milliseconds) before players can gain a skill tick for a skill.
# - Example: Lock picking has a default of 600000, or 600 seconds, for it's tick time.
# - This prevents players from being able to gain another skill tick of Lock picking until 600 seconds have passed (10 minutes).
# Set tick time of stealing to zero to remove the 10 minute interval. This is useful for Soulstealing.
skillTickTime-1:Stealing,0
# Set tick time of meditating to 3600 seconds (1 hour).
skillTickTime-2:Meditating,3600000
#changePreachingLocation: Changes the dependencies of Preaching so that it moves under Masonry.
# Recommended to set to false. Option is here temporarily until further work can be done to customize dependencies.
changePreachingLocation=true
#TODO: Add multiple configuration settings to change the dependencies of skills and remove this hold-over option.
## >> END SKILL MODULE << ##
## >> MEDITATION MODULE << ##
## The Meditation Module enables adjustments to the meditation system of Wurm.
## It includes additions that make meditation perks more reasonable at lower levels and scale better as it increases.
enableMeditationModule=true
#simplifyMeditationTerrain: Simplifies the terrain where players can meditate for a question.
# Instead of having to find specific tiles, any tile of the proper type will grant a question:
# - Insanity: Any cave tile
# - Love: Any grass, bush, or tree
# - Hate: Any mycelium, mycelium bush, or infected tree
# - Knowledge: Any sand
# - Power: Any rock or cliff tile (above ground).
simplifyMeditationTerrain=true
#removeInsanitySotG: Removes the Shield of the Gone bonus from Insanity. The buff will still show, but the effect will be gone.
removeInsanitySotG=true
#removeHateWarBonus: Removes the active effect to deal increased damage in combat from Path of Hate. Does not remove the structure damage version.
removeHateWarBonus=true
#insanitySpeedBonus: Adds new effect to Path of Insanity which grants 2% increased action speed per level starting at 7.
# At Insanity level 13, this bonus equates to 12% increased action speed. Does not affect weapon swing speed.
insanitySpeedBonus=true
#TODO: Allow configuration of the speed bonus and level it starts at.
#hateMovementBonus: Adds a new effect to Path of Hate which grants 1% increased movement speed (walking only) per level starting at 3.
# At Hate level 13, this bonus equates to 10% increased movement speed. Does not affect mounted or vehicle movement speed.
hateMovementBonus=true
#TODO: Allow configuration of the movement bonus and level it starts at.
#scalingPowerStaminaBonus: Scales the Path of Power stamina bonus from 30 at level 11 to start at 7 and increase with each level.
# Grants 5 bonus stamina at level 7, and adds 5 additional stamina per level afterwards.
# At Power level 13, this bonus equates to 30 additional Body Stamina.
scalingPowerStaminaBonus=true
#TODO: Allow configuration of the stamina bonus and level it starts at.
#scalingKnowledgeSkillGain: Scales the Path of Knowledge skill gain bonus from 25% at level 11 to start at 7 and increase with each level.
# Grants 5% increased skill gain at level 7, and adds 5% additional skill gain per level afterwards.
# At Knowledge level 13, this bonus grants 30% increased skill gain.
scalingKnowledgeSkillGain=true
#TODO: Allow configuration of the skill gain bonus and level it starts at.
#removeMeditationTickTimer: Removes the vanilla meditation tick timer which is not attached to the skill.
# This tick timer is coded differently from the skill system. It has to be removed like this in order to make the skill system version work.
# Enabling this option will allow you to configure the meditation tick timer using the Skills module.
# Without this enabled, this will override any settings from the Skills module and prevent skill gain unless the meditation system allows it.
removeMeditationTickTimer=true
#newMeditationBuffs: This option is meant to adjust the buff icons for meditation to coincide with all the options above.
# It's recommended to only allow this if all (or at least most) of the options above are enabled.
# Otherwise it probably wont display buffs correctly for some paths.
newMeditationBuffs=true
#TODO: Recode this to make it adjust properly to the configurations set throughout the rest of the module.
# > MEDITATION ABILITY COOLDOWNS < #
# Meditation Ability Cooldowns allow you to set all of the cooldowns for meditation abilities.
# All cooldowns are set using milliseconds. A setting of 1000 means 1 second in this configuration.
enableMeditationAbilityCooldowns=true
#loveRefreshCooldown: Cooldown for Path of Love's Refresh ability. (Default: 64800000 [18 hours])
loveRefreshCooldown=28800000
#loveEnchantNatureCooldown: Cooldown for Path of Love's Enchant Nature ability. (Default: 64800000 [18 hours])
loveEnchantNatureCooldown=28800000
#loveLoveEffectCooldown: Cooldown for Path of Love's Love Effect ability. (Default: 64800000 [18 hours])
loveLoveEffectCooldown=14400000
#hateWarDamageCooldown: Cooldown for Path of Hate's War Damage ability. (Default: 64800000 [18 hours])
hateWarDamageCooldown=21600000
#hateStructureDamageCooldown: Cooldown for Path of Hate's Structure Damage ability. (Default: 64800000 [18 hours])
hateStructureDamageCooldown=14400000
#hateFearCooldown: Cooldown for Path of Hate's Fear ability. (Default: 64800000 [18 hours])
hateFearCooldown=21600000
#powerElementalImmunityCooldown: Cooldown of Path of Power's Elemental Immunity ability. (Default: 64800000 [18 hours])
powerElementalImmunityCooldown=21600000
#powerEruptFreezeCooldown: Cooldown of Path of Power's Erupt/Freeze abilities. (Default: 64800000 [18 hours])
powerEruptFreezeCooldown=28800000
#powerIgnoreTrapsCooldown: Cooldown of Path of Power's Ignore Traps ability. (Default: 64800000 [18 hours])
powerIgnoreTrapsCooldown=14400000
#knowledgeInfoCreatureCooldown: Cooldown of Path of Knowledge's Get Info (Creature) ability. (Default: 64800000 [18 hours])
knowledgeInfoCreatureCooldown=14400000
#knowledgeInfoTileCooldown: Cooldown of Path of Knowledge's Get Info (Tile) ability. (Default: 64800000 [18 hours])
knowledgeInfoTileCooldown=14400000
#TODO: Add the rest of the meditation abilites as configurable options.
# > END MEDITATION ABILITY COOLDOWNS < #
## >> END MEDITATION MODULE << ##
## >> TREASURE CHEST LOOT MODULE << ##
## The Treasure Chest Loot Module affects the vanilla treasure chests.
## By default, treasure chests can spawn randomly in the wild. This module reconfigures the loot that spawns in them.

View File

@@ -24,23 +24,12 @@ import java.util.logging.Logger;
public class CombatChanges {
public static Logger logger = Logger.getLogger(CombatChanges.class.getName());
// Added to CombatHandled
public static int getWeaponType(Item weapon){
if(weapon.enchantment == Enchants.ACID_DAM){
return Wound.TYPE_ACID;
}else if(weapon.enchantment == Enchants.FROST_DAM){
return Wound.TYPE_COLD;
}else if(weapon.enchantment == Enchants.FIRE_DAM){
return Wound.TYPE_BURN;
}
return -1;
}
public static float combatRatingAdditive(float combatRating, Creature cret, Creature opponent){
//logger.info("Checking additive ("+cret.getName()+" vs "+opponent.getName()+"), combatRating = "+combatRating);
float add = 0.0f;
if(cret != null && cret.isPlayer() && (opponent != null && !opponent.isPlayer())){
if(cret.isRoyalExecutioner()){
// 2 CR against non-players for Royal Executioner kingdom title.
if(WyvernMods.royalExecutionerBonus && cret.isRoyalExecutioner()){
add += 2.0f;
}
}
@@ -51,7 +40,7 @@ public class CombatChanges {
float mult = 1.0f;
if(cret != null){
//logger.info("Cret is a pet.");
if(cret.isDominated() && cret.getDominator() != null) {
if(WyvernMods.petSoulDepthScaling && cret.isDominated() && cret.getDominator() != null) {
if (cret.getDominator() instanceof Player) {
Player owner = (Player) cret.getDominator();
double depth = owner.getSoulDepth().getKnowledge();
@@ -61,7 +50,7 @@ public class CombatChanges {
logger.info("Somehow a pet is dominated by a non-player? (" + cret.getDominator().getName() + ")");
}
}
if(QualityOfLife.getVehicleSafe(cret) != null){
if(WyvernMods.vehicleCombatRatingPenalty && QualityOfLife.getVehicleSafe(cret) != null){
mult *= 0.75f;
}
}
@@ -98,17 +87,6 @@ public class CombatChanges {
}
}
// Added (kind of) to CombatHandled
public static float getAdjustedOakshell(Creature defender, Item armour, float armourMod){
if(defender != null && armour == null){
float oakshellPower = defender.getBonusForSpellEffect(Enchants.CRET_OAKSHELL);
if(oakshellPower > 0f){
return (float) (1-(0.8f*Math.pow((oakshellPower/(oakshellPower+80)), 0.5d)));
}
}
return armourMod; // Returns previous armourMod if the target has armour.
}
protected static ArrayList<Creature> uniques = new ArrayList<>();
public static void pollUniqueCollection(){
for(Creature cret : Creatures.getInstance().getCreatures()){
@@ -151,114 +129,6 @@ public class CombatChanges {
return damage > 1D;
}
/* Disabled as of WU 1.9 - No longer necessary and no longer functions.
static void patchCombatDamageCheckCombatEngine(ClassPool classPool) throws NotFoundException, BadBytecode {
CtClass cls = classPool.getCtClass("com.wurmonline.server.combat.CombatEngine");
CtClass ctCreature = classPool.get("com.wurmonline.server.creatures.Creature");
CtClass ctString = classPool.get("java.lang.String");
CtClass ctBattle = classPool.get("com.wurmonline.server.combat.Battle");
CtClass ctCombatEngine = classPool.get("com.wurmonline.server.combat.CombatEngine");
// @Nullable Creature performer, Creature defender, byte type, int pos, double damage, float armourMod,
// String attString, @Nullable Battle battle, float infection, float poison, boolean archery, boolean alreadyCalculatedResist
CtClass[] params1 = {
ctCreature,
ctCreature,
CtClass.byteType,
CtClass.intType,
CtClass.doubleType,
CtClass.floatType,
ctString,
ctBattle,
CtClass.floatType,
CtClass.floatType,
CtClass.booleanType,
CtClass.booleanType
};
String desc1 = Descriptor.ofMethod(CtClass.booleanType, params1);
CtMethod method = cls.getMethod("addWound", desc1);
//CtMethod method = cls.getMethod("setDamage", "(Lcom/wurmonline/server/creatures/Creature;Lcom/wurmonline/server/items/Item;DBB)Z");
MethodInfo methodInfo = method.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
ConstPool constPool = codeAttribute.getConstPool();
CodeIterator codeIterator = codeAttribute.iterator();
// Scan through all the bytecode - look for a multiplication followed by comparing
while (codeIterator.hasNext()) {
int pos = codeIterator.next();
int op = codeIterator.byteAt(pos);
if (op != CodeIterator.DMUL) continue; // not multiplication - continue
op = codeIterator.byteAt(++pos);
if (op == CodeIterator.LDC2_W && codeIterator.byteAt(pos + 3) == CodeIterator.DCMPL) {
// found the pattern, check the value it's comparing to
int ref = codeIterator.u16bitAt(pos + 1);
double val = constPool.getDoubleInfo(ref);
if (val == 500.0) {
// here it is, generate new code to insert
// We'll be calling canDoDamage, the first parameter (damage) is already on the stack, prepare the rest
Bytecode newCode = new Bytecode(constPool);
newCode.add(Bytecode.ALOAD_0); // performer - first parameter of addWound
newCode.add(Bytecode.ALOAD_1); // defender - first parameter of addWound
// call our methor, result is left on the stack
newCode.addInvokestatic(
CombatChanges.class.getName(), "canDoDamage",
"(DLcom/wurmonline/server/creatures/Creature;Lcom/wurmonline/server/creatures/Creature;)Z");
// The code we're replacing is 4 bytes - LDC2_W, 2byte reference and DCMPL
// Insert a gap for to match the size of the new code
codeIterator.insertGap(pos, newCode.getSize() - 4);
// And put the new code
codeIterator.write(newCode.get(), pos);
}
}
}
}*/
/*static void patchCombatDamageCheckCombatHandler(ClassPool classPool) throws NotFoundException, BadBytecode {
CtClass cls = classPool.getCtClass("com.wurmonline.server.creatures.CombatHandler");
CtMethod method = cls.getMethod("setDamage", "(Lcom/wurmonline/server/creatures/Creature;Lcom/wurmonline/server/items/Item;DBB)Z");
MethodInfo methodInfo = method.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
ConstPool constPool = codeAttribute.getConstPool();
CodeIterator codeIterator = codeAttribute.iterator();
// Scan through all the bytecode - look for a multiplication followed by comparing
while (codeIterator.hasNext()) {
int pos = codeIterator.next();
int op = codeIterator.byteAt(pos);
if (op != CodeIterator.DMUL) continue; // not multiplication - continue
op = codeIterator.byteAt(++pos);
if (op == CodeIterator.LDC2_W && codeIterator.byteAt(pos + 3) == CodeIterator.DCMPL) {
// found the pattern, check the value it's comparing to
int ref = codeIterator.u16bitAt(pos + 1);
double val = constPool.getDoubleInfo(ref);
if (val == 500.0) {
// here it is, generate new code to insert
// We'll be calling canDoDamage, the first parameter (damage) is already on the stack, prepare the rest
Bytecode newCode = new Bytecode(constPool);
newCode.add(Bytecode.ALOAD_0); // this
newCode.addGetfield(cls, "creature", "Lcom/wurmonline/server/creatures/Creature;"); // this.creature
newCode.add(Bytecode.ALOAD_1); // defender - first parameter of setDamage
// call our methor, result is left on the stack
newCode.addInvokestatic(
CombatChanges.class.getName(), "canDoDamage",
"(DLcom/wurmonline/server/creatures/Creature;Lcom/wurmonline/server/creatures/Creature;)Z");
// The code we're replacing is 4 bytes - LDC2_W, 2byte reference and DCMPL
// Insert a gap for to match the size of the new code
codeIterator.insertGap(pos, newCode.getSize() - 4);
// And put the new code
codeIterator.write(newCode.get(), pos);
}
}
}
}*/
// Added to CombatHandled
public static void pollCreatureActionStacks(){
for(Creature c : Creatures.getInstance().getCreatures()){
@@ -278,57 +148,21 @@ public class CombatChanges {
final Class<CombatChanges> thisClass = CombatChanges.class;
String replace;
Util.setReason("Make custom combat rating changes.");
CtClass ctCombatHandler = classPool.get("com.wurmonline.server.creatures.CombatHandler");
replace = "combatRating += "+CombatChanges.class.getName()+".combatRatingAdditive(combatRating, this.creature, $1);" +
"crmod *= "+CombatChanges.class.getName()+".combatRatingMultiplicative(combatRating, this.creature, $1);" +
CtClass ctCreature = classPool.get("com.wurmonline.server.creatures.Creature");
CtClass ctItem = classPool.get("com.wurmonline.server.items.Item");
CtClass ctAttackAction = classPool.get("com.wurmonline.server.creatures.AttackAction");
if (WyvernMods.enableCombatRatingAdjustments) {
Util.setReason("Make custom combat rating changes.");
replace = "combatRating += " + CombatChanges.class.getName() + ".combatRatingAdditive(combatRating, this.creature, $1);" +
"crmod *= " + CombatChanges.class.getName() + ".combatRatingMultiplicative(combatRating, this.creature, $1);" +
"$_ = $proceed($$);";
Util.instrumentDeclared(thisClass, ctCombatHandler, "getCombatRating", "getFlankingModifier", replace);
}
CtClass ctCreature = classPool.get("com.wurmonline.server.creatures.Creature");
/* Disabled in Wurm Unlimited 1.9 - No longer necessary while using DUSKombat.
Util.setReason("Increase unique damage to pets.");
CtClass ctString = classPool.get("java.lang.String");
CtClass ctBattle = classPool.get("com.wurmonline.server.combat.Battle");
CtClass ctCombatEngine = classPool.get("com.wurmonline.server.combat.CombatEngine");
// @Nullable Creature performer, Creature defender, byte type, int pos, double damage, float armourMod,
// String attString, @Nullable Battle battle, float infection, float poison, boolean archery, boolean alreadyCalculatedResist
CtClass[] params1 = {
ctCreature,
ctCreature,
CtClass.byteType,
CtClass.intType,
CtClass.doubleType,
CtClass.floatType,
ctString,
ctBattle,
CtClass.floatType,
CtClass.floatType,
CtClass.booleanType,
CtClass.booleanType
};
String desc1 = Descriptor.ofMethod(CtClass.booleanType, params1);
replace = "if($2.isDominated() && $1 != null && $1.isUnique()){" +
//" logger.info(\"Detected unique hit on a pet. Adding damage.\");" +
" $5 = $5 * 2d;" +
"}" +
"if($2.isUnique() && $1 != null && $1.isDominated()){" +
" logger.info(\"Detected pet hit on a unique. Reducing damage.\");" +
" $5 = $5 * 0.5d;" +
"}";
Util.insertBeforeDescribed(thisClass, ctCombatEngine, "addWound", desc1, replace);*/
Util.setReason("Adjust weapon damage type based on the potion/salve applied.");
replace = "int wt = "+CombatChanges.class.getName()+".getWeaponType($1);"
+ "if(wt != -1){"
+ " type = wt;"
+ " return wt;"
+ "}";
Util.insertBeforeDeclared(thisClass, ctCombatHandler, "getType", replace);
CtClass ctItem = classPool.get("com.wurmonline.server.items.Item");
if (WyvernMods.fixMagranonDamageStacking) {
// Normal combat version
CtClass[] params2 = {
ctCreature,
ctItem,
@@ -336,12 +170,6 @@ public class CombatChanges {
};
String desc2 = Descriptor.ofMethod(CtClass.doubleType, params2);
/* Disabled in Wurm Unlimited 1.9 - Priest Rework adjusted Bloodthirst in an identical way.
Util.setReason("Adjust bloodthirst to epic settings.");
replace = "$_ = true;";
Util.instrumentDescribed(thisClass, ctCombatHandler, "getDamage", desc2, "isThisAnEpicOrChallengeServer", replace);*/
Util.setReason("Fix magranon damage bonus stacking.");
replace = "if(mildStack){" +
" $_ = $proceed($$) * 8 / 5;" +
@@ -350,7 +178,7 @@ public class CombatChanges {
"}";
Util.instrumentDescribed(thisClass, ctCombatHandler, "getDamage", desc2, "getModifiedFloatEffect", replace);
CtClass ctAttackAction = classPool.get("com.wurmonline.server.creatures.AttackAction");
// AttackAction version
CtClass[] params3 = {
ctCreature,
ctAttackAction,
@@ -358,12 +186,6 @@ public class CombatChanges {
};
String desc3 = Descriptor.ofMethod(CtClass.doubleType, params3);
/* Disabled in Wurm Unlimited 1.9 - Priest Rework adjusted Bloodthirst in an identical way.
Util.setReason("Adjust bloodthirst to epic settings.");
replace = "$_ = true;";
Util.instrumentDescribed(thisClass, ctCombatHandler, "getDamage", desc3, "isThisAnEpicOrChallengeServer", replace);*/
Util.setReason("Fix magranon damage bonus stacking.");
replace = "if(mildStack){" +
" $_ = $proceed($$) * 8 / 5;" +
@@ -371,26 +193,28 @@ public class CombatChanges {
" $_ = $proceed($$);" +
"}";
Util.instrumentDescribed(thisClass, ctCombatHandler, "getDamage", desc3, "getModifiedFloatEffect", replace);
}
if (WyvernMods.adjustCombatRatingSpellPower) {
Util.setReason("Nerf truehit/excel.");
replace = "$_ = $proceed($$) * 0.5f;";
Util.instrumentDeclared(thisClass, ctCombatHandler, "getCombatRating", "getBonusForSpellEffect", replace);
}
Util.setReason("Nerf oakshell.");
replace = "if(defender.isPlayer() && defender.getBonusForSpellEffect((byte)22) > 0f){" +
" armourMod = "+CombatChanges.class.getName()+".getAdjustedOakshell(defender, armour, armourMod);" +
"}" +
"$_ = $proceed($$);";
Util.instrumentDeclared(thisClass, ctCombatHandler, "setDamage", "getDamReductionBonusFor", replace);
Util.setReason("Disable natural regeneration on uniques.");
if (WyvernMods.disableLegendaryRegeneration) {
Util.setReason("Disable natural regeneration on legendary creatures.");
CtClass ctWound = classPool.get("com.wurmonline.server.bodys.Wound");
replace = "if(!this.creature.isUnique()){"
+ " $_ = $proceed($$);"
+ "}";
Util.instrumentDeclared(thisClass, ctWound, "poll", "modifySeverity", replace);
Util.setReason("Disable natural regeneration on legendary creatures.");
Util.instrumentDeclared(thisClass, ctWound, "poll", "checkInfection", replace);
Util.setReason("Disable natural regeneration on legendary creatures.");
Util.instrumentDeclared(thisClass, ctWound, "poll", "checkPoison", replace);
}
/* Disabled for now until it can be fixed for new Priest Update adjustments.
Util.setReason("Allow Life Transfer to stack with Rotting Touch (Mechanics-Wise).");
replace = CombatChanges.class.getName()+".doLifeTransfer(this.creature, defender, attWeapon, defdamage, armourMod);"
@@ -403,15 +227,7 @@ public class CombatChanges {
Util.setReason("Reduce Life Transfer healing amount for certain wounds.");
replace = "$_ = $proceed("+CombatChanges.class.getName()+".getLifeTransferAmountModifier($0, $1));";
Util.instrumentDeclared(thisClass, ctCombatHandler, "setDamage", "modifySeverity", replace);
Util.setReason("Make AOSP not disgustingly broken.");
replace = "if(!this.creature.isPlayer()){" +
" $_ = $proceed($$)*this.creature.addSpellResistance((short) 278);" +
"}else{" +
" $_ = $proceed($$);" +
"}";
Util.instrumentDeclared(thisClass, ctCombatHandler, "setDamage", "getSpellPainShare", replace);
Util.instrumentDeclared(thisClass, ctCombatHandler, "setDamage", "modifySeverity", replace);*/
/*Util.setReason("Debug attack method");
CtClass ctAction = classPool.get("com.wurmonline.server.behaviours.Action");

View File

@@ -0,0 +1,126 @@
package mod.sin.wyvern;
import com.wurmonline.server.Server;
import com.wurmonline.server.items.Item;
import com.wurmonline.server.players.Titles;
import com.wurmonline.server.skills.Skill;
import javassist.*;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;
import mod.sin.lib.Util;
import org.gotti.wurmunlimited.modloader.ReflectionUtil;
import org.gotti.wurmunlimited.modloader.classhooks.HookManager;
import java.util.Objects;
import java.util.logging.Logger;
public class Mastercraft {
private static Logger logger = Logger.getLogger(Mastercraft.class.getName());
public static double getNewDifficulty(Skill skill, double diff, Item item){
if(WyvernMods.affinityDifficultyBonus && skill.affinity > 0){
diff -= skill.affinity;
}
if(WyvernMods.legendDifficultyBonus && skill.getKnowledge() > 99.0d){
diff -= 2d-((100d-skill.getKnowledge())*2d);
}
if(WyvernMods.masterDifficultyBonus && skill.getKnowledge() > 90.0d){
diff -= 2d-((100d-skill.getKnowledge())*0.2d);
}
if(item != null){
if(WyvernMods.itemRarityDifficultyBonus && item.getRarity() > 0){
diff -= item.getRarity();
}
if(WyvernMods.legendItemDifficultyBonus && item.getCurrentQualityLevel() > 99.0f){
diff -= 1d-((100d-item.getCurrentQualityLevel())*1d);
}
if(WyvernMods.masterItemDifficultyBonus && item.getCurrentQualityLevel() > 90.0f){
diff -= 1d-((100d-item.getCurrentQualityLevel())*0.1d);
}
}
return diff;
}
public static float getCastPowerIncrease(Skill skill){
double addedPower = 0;
if(skill.affinity > 0){
addedPower += 2*skill.affinity;
}
if(skill.getKnowledge() > 0){
float lowFloat1 = Math.min(Server.rand.nextFloat(), Server.rand.nextFloat());
float lowFloat2 = Math.min(Server.rand.nextFloat(), Server.rand.nextFloat());
addedPower += Math.min(skill.getKnowledge()*lowFloat1, skill.getKnowledge()*lowFloat2);
}else{
logger.warning("Error: Some player just tried casting with no channeling skill!");
}
return (float) addedPower;
}
public static float getFavorCostMultiplier(Skill skill){
float mult = 1f;
if(skill.affinity > 0){
mult -= skill.affinity*0.02f; //2% reduction per affinity
}
if(skill.getKnowledge() > 90d){
mult -= 0.1d-((100d-skill.getKnowledge())*0.01d);
}
if(skill.getKnowledge() > 99d){
mult -= 0.1d-((100-skill.getKnowledge())*0.1d);
}
return mult;
}
public static void changeExistingTitles(){
for (Titles.Title title : Titles.Title.values()) {
if (Objects.equals("Pumpkin King", title.getFemaleName())){
try {
ReflectionUtil.setPrivateField(title, ReflectionUtil.getField(title.getClass(), "femaleName"), "Pumpkin Queen");
} catch (IllegalArgumentException | IllegalAccessException | ClassCastException | NoSuchFieldException e) {
e.printStackTrace();
}
}
}
}
public static void preInit(){
try {
ClassPool classPool = HookManager.getInstance().getClassPool();
Class<Mastercraft> thisClass = Mastercraft.class;
// - Reduce skill check difficulty with high skills or tools - //
CtClass ctSkill = classPool.get("com.wurmonline.server.skills.Skill");
if (WyvernMods.enableDifficultyAdjustments) {
Util.setReason("Modify difficulty for skill checks in MasterCraft.");
String replace = "$1 = " + Mastercraft.class.getName() + ".getNewDifficulty(this, $1, $2);";
Util.insertBeforeDeclared(thisClass, ctSkill, "checkAdvance", replace);
}
// - Increase spellcasting power for skilled channelers - //
CtClass ctSpell = classPool.get("com.wurmonline.server.spells.Spell");
CtMethod[] ctRuns = ctSpell.getDeclaredMethods("run");
for(CtMethod method : ctRuns){
if (WyvernMods.empoweredChannelers) {
method.instrument(new ExprEditor() {
public void edit(MethodCall m) throws CannotCompileException {
if (m.getMethodName().equals("doEffect")) {
m.replace("$2 += " + Mastercraft.class.getName() + ".getCastPowerIncrease(castSkill);"
+ "$_ = $proceed($$);");
logger.info("Instrumented doEffect in run()");
}
}
});
}
if (WyvernMods.channelSkillFavorReduction) {
method.instrument(new ExprEditor() {
public void edit(MethodCall m) throws CannotCompileException {
if (m.getMethodName().equals("depleteFavor")) {
m.replace("$1 *= " + Mastercraft.class.getName() + ".getFavorCostMultiplier(castSkill);"
+ "$_ = $proceed($$);");
logger.info("Instrumented depleteFavor in run()");
}
}
});
}
}
} catch (CannotCompileException | NotFoundException e) {
e.printStackTrace();
}
}
}

View File

@@ -60,7 +60,7 @@ public class MeditationPerks {
if(path.getPath() == Cults.PATH_HATE){
byte level = path.getLevel();
if(level >= 3){
float levelDiff = level-3f;
float levelDiff = level-2f;
return 1.0f+(levelDiff*0.01f);
}
}
@@ -156,36 +156,54 @@ public class MeditationPerks {
final Class<MeditationPerks> thisClass = MeditationPerks.class;
String replace;
Util.setReason("Enable buff icons for meditation.");
CtClass ctCultist = classPool.get("com.wurmonline.server.players.Cultist");
replace = MeditationPerks.class.getName()+".sendPassiveBuffs($0);";
Util.insertBeforeDeclared(thisClass, ctCultist, "sendPassiveBuffs", replace);
Util.setReason("Make meditating paths more straightforward.");
CtClass ctCults = classPool.get("com.wurmonline.server.players.Cults");
replace = "{ return "+MeditationPerks.class.getName()+".getNewPathFor($1, $2, $3); }";
Util.setBodyDeclared(thisClass, ctCults, "getPathFor", replace);
Util.setReason("Replace stamina modifier for new Insanity ability.");
CtClass ctActions = classPool.get("com.wurmonline.server.behaviours.Actions");
replace = "{ return "+MeditationPerks.class.getName()+".newStaminaModifierFor($1, $2); }";
Util.setBodyDeclared(thisClass, ctActions, "getStaminaModiferFor", replace);
Util.setReason("Increase movement speed for Path of Hate users.");
CtClass ctMovementScheme = classPool.get("com.wurmonline.server.creatures.MovementScheme");
CtClass ctCreatureStatus = classPool.get("com.wurmonline.server.creatures.CreatureStatus");
CtClass ctSkill = classPool.get("com.wurmonline.server.skills.Skill");
if (WyvernMods.simplifyMeditationTerrain) {
Util.setReason("Make meditating paths more straightforward.");
replace = "{ return " + MeditationPerks.class.getName() + ".getNewPathFor($1, $2, $3); }";
Util.setBodyDeclared(thisClass, ctCults, "getPathFor", replace);
}
if (WyvernMods.removeInsanitySotG) {
Util.setReason("Remove shield of the gone effect.");
replace = "{ return 0.0f; }";
Util.setBodyDeclared(thisClass, ctCultist, "getHalfDamagePercentage", replace);
}
if (WyvernMods.removeHateWarBonus) {
Util.setReason("Remove hate war damage effect.");
replace = "{ return false; }";
Util.setBodyDeclared(thisClass, ctCultist, "mayStartDoubleWarDamage", replace);
Util.setReason("Remove hate war damage effect.");
Util.setBodyDeclared(thisClass, ctCultist, "doubleWarDamage", replace);
}
if (WyvernMods.insanitySpeedBonus) {
Util.setReason("Replace stamina modifier for new Insanity ability.");
replace = "{ return " + MeditationPerks.class.getName() + ".newStaminaModifierFor($1, $2); }";
Util.setBodyDeclared(thisClass, ctActions, "getStaminaModiferFor", replace);
}
if (WyvernMods.hateMovementBonus) {
Util.setReason("Increase movement speed for Path of Hate users.");
replace = "if($_ > 0){" +
" $_ = $_ * "+MeditationPerks.class.getName()+".getCultistSpeedMultiplier(this);" +
" $_ = $_ * " + MeditationPerks.class.getName() + ".getCultistSpeedMultiplier(this);" +
"}";
Util.insertAfterDeclared(thisClass, ctMovementScheme, "getSpeedModifier", replace);
}
if (WyvernMods.scalingPowerStaminaBonus) {
Util.setReason("Scale path of power stamina bonus from level 7 onwards.");
CtClass ctCreatureStatus = classPool.get("com.wurmonline.server.creatures.CreatureStatus");
replace = "staminaMod += "+MeditationPerks.class.getName()+".getPowerStaminaBonus(this.statusHolder);" +
replace = "staminaMod += " + MeditationPerks.class.getName() + ".getPowerStaminaBonus(this.statusHolder);" +
"$_ = false;";
Util.instrumentDeclared(thisClass, ctCreatureStatus, "modifyStamina", "usesNoStamina", replace);
}
Util.setReason("Scale path of knowledge skill gain from level 7 onwards.");
CtClass ctSkill = classPool.get("com.wurmonline.server.skills.Skill");
CtClass[] params1 = {
CtClass.doubleType,
CtClass.booleanType,
@@ -194,57 +212,61 @@ public class MeditationPerks {
CtClass.doubleType
};
String desc1 = Descriptor.ofMethod(CtClass.voidType, params1);
replace = "staminaMod *= "+MeditationPerks.class.getName()+".getKnowledgeSkillGain(player);" +
if (WyvernMods.scalingKnowledgeSkillGain) {
Util.setReason("Scale path of knowledge skill gain from level 7 onwards.");
replace = "staminaMod *= " + MeditationPerks.class.getName() + ".getKnowledgeSkillGain(player);" +
"$_ = false;";
Util.instrumentDescribed(thisClass, ctSkill, "alterSkill", desc1, "levelElevenSkillgain", replace);
}
Util.setReason("Remove shield of the gone effect.");
replace = "{ return 0.0f; }";
Util.setBodyDeclared(thisClass, ctCultist, "getHalfDamagePercentage", replace);
Util.setReason("Remove hate war damage effect.");
replace = "{ return false; }";
Util.setBodyDeclared(thisClass, ctCultist, "mayStartDoubleWarDamage", replace);
Util.setBodyDeclared(thisClass, ctCultist, "doubleWarDamage", replace);
if (WyvernMods.removeMeditationTickTimer) {
Util.setReason("Remove artifical tick timer for meditation.");
replace = "$_ = 0;";
Util.instrumentDeclared(thisClass, ctCults, "meditate", "getLastMeditated", replace);
}
// - Reduce meditation cooldowns - //
replace = "return this.path == 1 && this.level > 3 && System.currentTimeMillis() - this.cooldown1 > "+(TimeConstants.HOUR_MILLIS*8)+";";
if (WyvernMods.newMeditationBuffs) {
Util.setReason("Enable buff icons for meditation.");
replace = MeditationPerks.class.getName() + ".sendPassiveBuffs($0);";
Util.insertBeforeDeclared(thisClass, ctCultist, "sendPassiveBuffs", replace);
}
if (WyvernMods.enableMeditationAbilityCooldowns) {
// - Adjust meditation ability cooldowns - //
replace = "return this.path == 1 && this.level > 3 && System.currentTimeMillis() - this.cooldown1 > " + String.valueOf(WyvernMods.loveRefreshCooldown) + ";";
Util.setBodyDeclared(thisClass, ctCultist, "mayRefresh", replace);
//ctCultist.getDeclaredMethod("mayRefresh").setBody("return this.path == 1 && this.level > 3 && System.currentTimeMillis() - this.cooldown1 > 28800000;");
replace = "return this.path == 1 && this.level > 6 && System.currentTimeMillis() - this.cooldown2 > "+(TimeConstants.HOUR_MILLIS*8)+";";
Util.setBodyDeclared(thisClass, ctCultist, "mayEnchantNature", replace);
//ctCultist.getDeclaredMethod("mayEnchantNature").setBody("return this.path == 1 && this.level > 6 && System.currentTimeMillis() - this.cooldown2 > 28800000;");
replace = "return this.path == 1 && this.level > 8 && System.currentTimeMillis() - this.cooldown3 > "+(TimeConstants.HOUR_MILLIS*4)+";";
Util.setBodyDeclared(thisClass, ctCultist, "mayStartLoveEffect", replace);
//ctCultist.getDeclaredMethod("mayStartLoveEffect").setBody("return this.path == 1 && this.level > 8 && System.currentTimeMillis() - this.cooldown3 > 14400000;");
replace = "return this.path == 2 && this.level > 6 && System.currentTimeMillis() - this.cooldown1 > "+(TimeConstants.HOUR_MILLIS*6)+";";
Util.setBodyDeclared(thisClass, ctCultist, "mayStartDoubleWarDamage", replace);
//ctCultist.getDeclaredMethod("mayStartDoubleWarDamage").setBody("return this.path == 2 && this.level > 6 && System.currentTimeMillis() - this.cooldown1 > 21600000;");
replace = "return this.path == 2 && this.level > 3 && System.currentTimeMillis() - this.cooldown2 > "+(TimeConstants.HOUR_MILLIS*4)+";";
Util.setBodyDeclared(thisClass, ctCultist, "mayStartDoubleStructDamage", replace);
//ctCultist.getDeclaredMethod("mayStartDoubleStructDamage").setBody("return this.path == 2 && this.level > 3 && System.currentTimeMillis() - this.cooldown2 > 14400000;");
replace = "return this.path == 2 && this.level > 8 && System.currentTimeMillis() - this.cooldown3 > "+(TimeConstants.HOUR_MILLIS*6)+";";
Util.setBodyDeclared(thisClass, ctCultist, "mayStartFearEffect", replace);
//ctCultist.getDeclaredMethod("mayStartFearEffect").setBody("return this.path == 2 && this.level > 8 && System.currentTimeMillis() - this.cooldown3 > 21600000;");
replace = "return this.path == 5 && this.level > 8 && System.currentTimeMillis() - this.cooldown1 > "+(TimeConstants.HOUR_MILLIS*6)+";";
Util.setBodyDeclared(thisClass, ctCultist, "mayStartNoElementalDamage", replace);
//ctCultist.getDeclaredMethod("mayStartNoElementalDamage").setBody("return this.path == 5 && this.level > 8 && System.currentTimeMillis() - this.cooldown1 > 21600000;");
replace = "return this.path == 5 && this.level > 6 && System.currentTimeMillis() - this.cooldown2 > "+(TimeConstants.HOUR_MILLIS*8)+";";
Util.setBodyDeclared(thisClass, ctCultist, "maySpawnVolcano", replace);
//ctCultist.getDeclaredMethod("maySpawnVolcano").setBody("return this.path == 5 && this.level > 6 && System.currentTimeMillis() - this.cooldown2 > 28800000;");
replace = "return this.path == 5 && this.level > 3 && System.currentTimeMillis() - this.cooldown3 > "+(TimeConstants.HOUR_MILLIS*4)+";";
Util.setBodyDeclared(thisClass, ctCultist, "mayStartIgnoreTraps", replace);
//ctCultist.getDeclaredMethod("mayStartIgnoreTraps").setBody("return this.path == 5 && this.level > 3 && System.currentTimeMillis() - this.cooldown3 > 14400000;");
replace = "return this.path == 3 && this.level > 3 && System.currentTimeMillis() - this.cooldown1 > "+(TimeConstants.HOUR_MILLIS*4)+";";
Util.setBodyDeclared(thisClass, ctCultist, "mayCreatureInfo", replace);
//ctCultist.getDeclaredMethod("mayCreatureInfo").setBody("return this.path == 3 && this.level > 3 && System.currentTimeMillis() - this.cooldown1 > 14400000;");
replace = "return this.path == 3 && this.level > 6 && System.currentTimeMillis() - this.cooldown2 > "+(TimeConstants.HOUR_MILLIS*4)+";";
Util.setBodyDeclared(thisClass, ctCultist, "mayInfoLocal", replace);
//ctCultist.getDeclaredMethod("mayInfoLocal").setBody("return this.path == 3 && this.level > 6 && System.currentTimeMillis() - this.cooldown2 > 14400000;");
replace = "return this.path == 1 && this.level > 6 && System.currentTimeMillis() - this.cooldown2 > " + String.valueOf(WyvernMods.loveEnchantNatureCooldown) + ";";
Util.setBodyDeclared(thisClass, ctCultist, "mayEnchantNature", replace);
replace = "return this.path == 1 && this.level > 8 && System.currentTimeMillis() - this.cooldown3 > " + String.valueOf(WyvernMods.loveLoveEffectCooldown) + ";";
Util.setBodyDeclared(thisClass, ctCultist, "mayStartLoveEffect", replace);
replace = "return this.path == 2 && this.level > 6 && System.currentTimeMillis() - this.cooldown1 > " + String.valueOf(WyvernMods.hateWarDamageCooldown) + ";";
Util.setBodyDeclared(thisClass, ctCultist, "mayStartDoubleWarDamage", replace);
replace = "return this.path == 2 && this.level > 3 && System.currentTimeMillis() - this.cooldown2 > " + String.valueOf(WyvernMods.hateStructureDamageCooldown) + ";";
Util.setBodyDeclared(thisClass, ctCultist, "mayStartDoubleStructDamage", replace);
replace = "return this.path == 2 && this.level > 8 && System.currentTimeMillis() - this.cooldown3 > " + String.valueOf(WyvernMods.hateFearCooldown) + ";";
Util.setBodyDeclared(thisClass, ctCultist, "mayStartFearEffect", replace);
replace = "return this.path == 5 && this.level > 8 && System.currentTimeMillis() - this.cooldown1 > " + String.valueOf(WyvernMods.powerElementalImmunityCooldown) + ";";
Util.setBodyDeclared(thisClass, ctCultist, "mayStartNoElementalDamage", replace);
replace = "return this.path == 5 && this.level > 6 && System.currentTimeMillis() - this.cooldown2 > " + String.valueOf(WyvernMods.powerEruptFreezeCooldown) + ";";
Util.setBodyDeclared(thisClass, ctCultist, "maySpawnVolcano", replace);
replace = "return this.path == 5 && this.level > 3 && System.currentTimeMillis() - this.cooldown3 > " + String.valueOf(WyvernMods.powerIgnoreTrapsCooldown) + ";";
Util.setBodyDeclared(thisClass, ctCultist, "mayStartIgnoreTraps", replace);
replace = "return this.path == 3 && this.level > 3 && System.currentTimeMillis() - this.cooldown1 > " + String.valueOf(WyvernMods.knowledgeInfoCreatureCooldown) + ";";
Util.setBodyDeclared(thisClass, ctCultist, "mayCreatureInfo", replace);
replace = "return this.path == 3 && this.level > 6 && System.currentTimeMillis() - this.cooldown2 > " + String.valueOf(WyvernMods.knowledgeInfoTileCooldown) + ";";
Util.setBodyDeclared(thisClass, ctCultist, "mayInfoLocal", replace);
}
} catch ( NotFoundException | IllegalArgumentException | ClassCastException e) {
throw new HookException(e);
}

View File

@@ -23,23 +23,6 @@ public class PlayerTitles {
// Event Title ID's
public static int TITAN_SLAYER = 10000;
public static int SPECTRAL = 10001;
//public static int PASTAMANCER = 10002;
// Player Donation Title ID's
/*public static int PATRON = 19999;
public static int DONATOR = 20000;
public static int PAZZA_FAVORITE_GM = 20001;
public static int WARRIORGEN_THAT_GUY = 20002;
public static int ETERNALLOVE_WARRIORGENS_WIFE = 20003;
public static int BAMBAM_THORN_ONE = 20004;
public static int SVENJA_CARE_DEPENDANT = 20005;
public static int ALEXIA_THE_TREASURING = 20006;
public static int REEVI_SCIENCE_GUY = 20007;
public static int GENOCIDE_GRAND_DESIGNER = 20008;
public static int SELEAS_CRAZY_CAT_LORD = 20009;
public static int PIRATEMAX_SLAVE = 20010;
public static int ELTACOLAD_TRUE_TACO = 20011;
public static int ATTICUS_THE_GREAT_ILLUMINATY = 20012;*/
public static void init(){
for (WyvernMods.CustomTitle title : WyvernMods.customTitles){
@@ -48,28 +31,8 @@ public class PlayerTitles {
// Event Titles
createTitle(TITAN_SLAYER, "Titanslayer", "Titanslayer", -1, "NORMAL");
createTitle(SPECTRAL, "Spectral", "Spectral", -1, "NORMAL");
//PlayerTitles.createTitle(buster, "Holdstrong_Architect", 702, "Holdstrong Architect", "Holdstrong Architect", -1, Titles.TitleType.NORMAL);
//PlayerTitles.createTitle(buster, "Stronghold_Architect", 703, "Stronghold Architect", "Stronghold Architect", -1, Titles.TitleType.NORMAL);
//createTitle(PASTAMANCER, "Pastamancer", "Pastamancer", -1, "NORMAL");
// Donation Titles
/* Moved to configuration
createTitle(PATRON, "Patron", "Patron", -1, "NORMAL");
createTitle(DONATOR, "Donator", "Donator", -1, "NORMAL");
createTitle(PAZZA_FAVORITE_GM, "Sindusks Favourite GM", "Sindusks Favourite GM", -1, "NORMAL");
createTitle(WARRIORGEN_THAT_GUY, "That Guy", "That Guy", -1, "NORMAL");
createTitle(ETERNALLOVE_WARRIORGENS_WIFE, "Warriorgens Wife", "Warriorgens Wife", -1, "NORMAL");
createTitle(BAMBAM_THORN_ONE, "Thorn One", "Thorn One", -1, "NORMAL");
createTitle(SVENJA_CARE_DEPENDANT, "The care-dependent", "The care-dependent", -1, "NORMAL");
createTitle(ALEXIA_THE_TREASURING, "The Treasuring", "The Treasuring", -1, "NORMAL");
createTitle(REEVI_SCIENCE_GUY, "Science Guy", "Science Guy", -1, "NORMAL");
createTitle(GENOCIDE_GRAND_DESIGNER, "Grand Designer", "Grand Designer", -1, "NORMAL");
createTitle(SELEAS_CRAZY_CAT_LORD, "The Crazy Cat Lord", "The Crazy Cat Lord", -1, "NORMAL");
createTitle(PIRATEMAX_SLAVE, "Slave", "Slave", -1, "NORMAL");
createTitle(ELTACOLAD_TRUE_TACO, "The One True Taco", "The One True Taco", -1, "NORMAL");
createTitle(ATTICUS_THE_GREAT_ILLUMINATY, "The Great Illuminaty", "The Great Illuminaty", -1, "NORMAL");*/
// Supporter titles
// Display all existing titles
logger.info(Arrays.toString(Titles.Title.values()));
}
@@ -105,61 +68,5 @@ public class PlayerTitles {
logger.warning("Failed to get title with ID "+titleId);
}
}
/*if(donatorTitles.contains(name)){
Titles.Title donator = Titles.Title.getTitle(DONATOR);
p.addTitle(donator);
}
if(patronTitles.contains(name)){
Titles.Title patron = Titles.Title.getTitle(PATRON);
p.addTitle(patron);
}
if(customTitles.containsKey(name)){
Titles.Title customTitle = Titles.Title.getTitle(customTitles.get(name));
p.addTitle(customTitle);
}*/
}
public static void preInit(){
// Donations
/*donatorTitles.add("Pazza");
customTitles.put("Pazza", PAZZA_FAVORITE_GM); // Sindusks Favorite GM
donatorTitles.add("Warriorgen");
customTitles.put("Warriorgen", WARRIORGEN_THAT_GUY); // That Guy
donatorTitles.add("Eternallove");
customTitles.put("Eternallove", ETERNALLOVE_WARRIORGENS_WIFE); // Warriorgens Wife
donatorTitles.add("Bambam");
customTitles.put("Bambam", BAMBAM_THORN_ONE); // Thorn One
donatorTitles.add("Svenja");
customTitles.put("Svenja", SVENJA_CARE_DEPENDANT); // The care-dependent
playerTitles.put("Svenja", "Akuma");
donatorTitles.add("Alexiaselena");
customTitles.put("Alexiaselena", ALEXIA_THE_TREASURING); // The Treasuring
playerTitles.put("Alexiaselena", "Kami");
donatorTitles.add("Reevi");
customTitles.put("Reevi", REEVI_SCIENCE_GUY); // Science Guy
customTitles.put("Genocide", GENOCIDE_GRAND_DESIGNER); // Grand Designer
donatorTitles.add("Seleas");
customTitles.put("Seleas", SELEAS_CRAZY_CAT_LORD); // The Crazy Cat Lord
playerTitles.put("Seleas", "No, Really");
donatorTitles.add("Piratemax");
customTitles.put("Piratemax", PIRATEMAX_SLAVE); // Slave
playerTitles.put("Piratemax", "Boy Next Door");
donatorTitles.add("Eltacolad");
customTitles.put("Eltacolad", ELTACOLAD_TRUE_TACO); // The One True Taco
patronTitles.add("Atticus");
customTitles.put("Atticus", ATTICUS_THE_GREAT_ILLUMINATY); // The Great Illuminaty
// Other rewards
customTitles.put("Critias", PASTAMANCER);*/
}
}

View File

@@ -37,10 +37,10 @@ public class SkillChanges {
try {
Skills parent = ReflectionUtil.getPrivateField(skill, ReflectionUtil.getField(skill.getClass(), "parent"));
double advanceMultiplicator = (100.0 - skill.getKnowledge()) / (skill.getDifficulty(parent.priest) * skill.getKnowledge() * skill.getKnowledge()) * learnMod * bonus;
double negativeDecayRate = 5;
double positiveDecayRate = 3;
double valueAtZero = 3.74d;
double valueAtOneHundred = 0.9d;
double negativeDecayRate = (double) WyvernMods.hybridNegativeDecayRate;
double positiveDecayRate = (double) WyvernMods.hybridPositiveDecayRate;
double valueAtZero = (double) WyvernMods.hybridValueAtZero;
double valueAtOneHundred = (double) WyvernMods.hybridValueAtOneHundred;
//advanceMultiplicator *= Math.pow(2, ((2-Math.pow((100/(100+power)), p))*(100-power)/100));
//double mult = Math.pow(2, (2-Math.pow(100/(100+power), negativeDecayRate))*Math.pow((100-power)*0.01, positiveDecayRate));
double mult = valueAtOneHundred*Math.pow(valueAtZero/valueAtOneHundred, (2-Math.pow(100/(100+Math.max(-99,power)), negativeDecayRate))*Math.pow((100-power)*0.01, positiveDecayRate));
@@ -65,65 +65,52 @@ public class SkillChanges {
return 0;
}
public static void onServerStarted(){
/*SkillTemplate exorcism = SkillSystem.templates.get(SkillList.EXORCISM);
int[] deps = {SkillList.GROUP_ALCHEMY};
public static void setSkillName(int id, String newName){
SkillTemplate skillTemplate = SkillSystem.templates.get(id);
try {
String newName = "Crystal handling";
ReflectionUtil.setPrivateField(exorcism, ReflectionUtil.getField(exorcism.getClass(), "name"), newName);
SkillSystem.skillNames.put(exorcism.getNumber(), newName);
SkillSystem.namesToSkill.put(newName, exorcism.getNumber());
ReflectionUtil.setPrivateField(exorcism, ReflectionUtil.getField(exorcism.getClass(), "dependencies"), deps);
ReflectionUtil.setPrivateField(skillTemplate, ReflectionUtil.getField(skillTemplate.getClass(), "name"), newName);
SkillSystem.skillNames.put(skillTemplate.getNumber(), newName);
SkillSystem.namesToSkill.put(newName, skillTemplate.getNumber());
} catch (IllegalAccessException | NoSuchFieldException e) {
logger.info("Failed to rename exorcism!");
logger.info("Failed to rename skill with ID "+id+"!");
e.printStackTrace();
}
SkillTemplate ballistae = SkillSystem.templates.get(SkillList.BALLISTA);
int[] deps2 = {SkillList.GROUP_ALCHEMY};
}
public static void setSkillDifficulty(int id, float difficulty){
SkillTemplate skillTemplate = SkillSystem.templates.get(id);
skillTemplate.setDifficulty(difficulty);
}
public static void setSkillTickTime(int id, long tickTime){
SkillTemplate skillTemplate = SkillSystem.templates.get(id);
try {
String newName = "Mystic components";
ReflectionUtil.setPrivateField(ballistae, ReflectionUtil.getField(ballistae.getClass(), "name"), newName);
SkillSystem.skillNames.put(ballistae.getNumber(), newName);
SkillSystem.namesToSkill.put(newName, ballistae.getNumber());
ReflectionUtil.setPrivateField(ballistae, ReflectionUtil.getField(ballistae.getClass(), "dependencies"), deps2);
ReflectionUtil.setPrivateField(skillTemplate, ReflectionUtil.getField(skillTemplate.getClass(), "tickTime"), tickTime);
} catch (IllegalAccessException | NoSuchFieldException e) {
logger.info("Failed to rename ballistae!");
logger.info("Failed to set tickTime for skill with ID "+id+"!");
e.printStackTrace();
}*/
}
}
public static void onServerStarted(){
for (int skillId : WyvernMods.skillName.keySet()){
setSkillName(skillId, WyvernMods.skillName.get(skillId));
}
for (int skillId : WyvernMods.skillDifficulty.keySet()){
setSkillDifficulty(skillId, WyvernMods.skillDifficulty.get(skillId));
}
for (int skillId : WyvernMods.skillTickTime.keySet()){
setSkillTickTime(skillId, WyvernMods.skillTickTime.get(skillId));
}
if (WyvernMods.changePreachingLocation) {
SkillTemplate preaching = SkillSystem.templates.get(SkillList.PREACHING);
int[] deps3 = {SkillList.MASONRY};
try {
String newName = "Gem augmentation";
ReflectionUtil.setPrivateField(preaching, ReflectionUtil.getField(preaching.getClass(), "name"), newName);
SkillSystem.skillNames.put(preaching.getNumber(), newName);
SkillSystem.namesToSkill.put(newName, preaching.getNumber());
ReflectionUtil.setPrivateField(preaching, ReflectionUtil.getField(preaching.getClass(), "dependencies"), deps3);
} catch (IllegalAccessException | NoSuchFieldException e) {
logger.info("Failed to rename preaching!");
e.printStackTrace();
}
SkillTemplate stealing = SkillSystem.templates.get(SkillList.STEALING);
try {
ReflectionUtil.setPrivateField(stealing, ReflectionUtil.getField(stealing.getClass(), "tickTime"), 0);
} catch (IllegalAccessException | NoSuchFieldException e) {
logger.info("Failed to set tickTime for stealing!");
e.printStackTrace();
}
SkillTemplate meditating = SkillSystem.templates.get(SkillList.MEDITATING);
try {
ReflectionUtil.setPrivateField(meditating, ReflectionUtil.getField(meditating.getClass(), "tickTime"), TimeConstants.HOUR_MILLIS);
} catch (IllegalAccessException | NoSuchFieldException e) {
logger.info("Failed to set tickTime for meditating!");
e.printStackTrace();
}
meditating.setDifficulty(300f);
// Set mining difficulty down to be equivalent to digging.
SkillTemplate mining = SkillSystem.templates.get(SkillList.MINING);
mining.setDifficulty(3000f);
// Triple lockpicking skill
SkillTemplate lockpicking = SkillSystem.templates.get(SkillList.LOCKPICKING);
lockpicking.setDifficulty(700f);
}
public static void preInit(){
@@ -132,13 +119,15 @@ public class SkillChanges {
final Class<SkillChanges> thisClass = SkillChanges.class;
String replace;
Util.setReason("Allow skill check failures to add skill gain.");
if (WyvernMods.enableHybridSkillGain) {
Util.setReason("Add hybrid skill gain system hook.");
CtClass ctSkill = classPool.get("com.wurmonline.server.skills.Skill");
replace = "{" +
" double advanceMultiplicator = "+SkillChanges.class.getName()+".newDoSkillGainNew($0, $1, $2, $3, $4, $5);" +
" double advanceMultiplicator = " + SkillChanges.class.getName() + ".newDoSkillGainNew($0, $1, $2, $3, $4, $5);" +
" $0.alterSkill(advanceMultiplicator, false, $4, true, $5);" +
"}";
Util.setBodyDeclared(thisClass, ctSkill, "doSkillGainNew", replace);
}
} catch ( NotFoundException | IllegalArgumentException | ClassCastException e) {
throw new HookException(e);

View File

@@ -16,9 +16,9 @@ import mod.sin.actions.items.SorcerySplitAction;
import mod.sin.creatures.*;
import mod.sin.creatures.titans.*;
import mod.sin.lib.Prop;
import mod.sin.lib.SkillAssist;
import mod.sin.lib.Util;
import mod.sin.wyvern.bestiary.MethodsBestiary;
import mod.sin.wyvern.mastercraft.Mastercraft;
import org.gotti.wurmunlimited.modloader.ReflectionUtil;
import org.gotti.wurmunlimited.modloader.classhooks.HookException;
import org.gotti.wurmunlimited.modloader.classhooks.HookManager;
@@ -161,6 +161,65 @@ implements WurmServerMod, Configurable, PreInitable, Initable, ItemTemplatesCrea
public static boolean mineGemsToVehicle = true;
public static boolean regenerateStaminaOnVehicleAnySlope = true;
// Combat Module Configuration
public static boolean enableCombatModule = true;
public static boolean enableCombatRatingAdjustments = true;
public static boolean royalExecutionerBonus = true;
public static boolean petSoulDepthScaling = true;
public static boolean vehicleCombatRatingPenalty = true;
public static boolean fixMagranonDamageStacking = true;
public static boolean adjustCombatRatingSpellPower = true;
public static boolean disableLegendaryRegeneration = true;
public static boolean useStaticLegendaryRegeneration = true;
// Mastercraft Module Configuration
public static boolean enableMastercraftModule = true;
public static boolean enableDifficultyAdjustments = true;
public static boolean affinityDifficultyBonus = true;
public static boolean legendDifficultyBonus = true;
public static boolean masterDifficultyBonus = true;
public static boolean itemRarityDifficultyBonus = true;
public static boolean legendItemDifficultyBonus = true;
public static boolean masterItemDifficultyBonus = true;
public static boolean empoweredChannelers = true;
public static boolean channelSkillFavorReduction = true;
// Skill Module Configuration
public static boolean enableSkillModule = true;
public static boolean enableHybridSkillGain = true;
public static float hybridNegativeDecayRate = 5f;
public static float hybridPositiveDecayRate = 3f;
public static float hybridValueAtZero = 3.74f;
public static float hybridValueAtOneHundred = 0.9f;
public static HashMap<Integer,String> skillName = new HashMap<>();
public static HashMap<Integer,Float> skillDifficulty = new HashMap<>();
public static HashMap<Integer,Long> skillTickTime = new HashMap<>();
public static boolean changePreachingLocation = true;
// Meditation Module Configuration
public static boolean enableMeditationModule = true;
public static boolean simplifyMeditationTerrain = true;
public static boolean removeInsanitySotG = true;
public static boolean removeHateWarBonus = true;
public static boolean insanitySpeedBonus = true;
public static boolean hateMovementBonus = true;
public static boolean scalingPowerStaminaBonus = true;
public static boolean scalingKnowledgeSkillGain = true;
public static boolean removeMeditationTickTimer = true;
public static boolean newMeditationBuffs = true;
public static boolean enableMeditationAbilityCooldowns = true;
public static long loveRefreshCooldown = 64800000L; // 18 hours default
public static long loveEnchantNatureCooldown = 64800000L; // 18 hours default
public static long loveLoveEffectCooldown = 64800000L; // 18 hours default
public static long hateWarDamageCooldown = 64800000L; // 18 hours default
public static long hateStructureDamageCooldown = 64800000L; // 18 hours default
public static long hateFearCooldown = 64800000L; // 18 hours default
public static long powerElementalImmunityCooldown = 64800000L; // 18 hours default
public static long powerEruptFreezeCooldown = 64800000L; // 18 hours default
public static long powerIgnoreTrapsCooldown = 64800000L; // 18 hours default
public static long knowledgeInfoCreatureCooldown = 64800000L; // 18 hours default
public static long knowledgeInfoTileCooldown = 64800000L; // 18 hours default
// Treasure Chest Loot Module Configuration
public static boolean enableTreasureChestLootModule = true;
@@ -345,6 +404,62 @@ implements WurmServerMod, Configurable, PreInitable, Initable, ItemTemplatesCrea
mineGemsToVehicle = Prop.getBooleanProperty("mineGemsToVehicle", mineGemsToVehicle);
regenerateStaminaOnVehicleAnySlope = Prop.getBooleanProperty("regenerateStaminaOnVehicleAnySlope", regenerateStaminaOnVehicleAnySlope);
// Combat Module
enableCombatModule = Prop.getBooleanProperty("enableCombatModule", enableCombatModule);
enableCombatRatingAdjustments = Prop.getBooleanProperty("enableCombatRatingAdjustments", enableCombatRatingAdjustments);
royalExecutionerBonus = Prop.getBooleanProperty("royalExecutionerBonus", royalExecutionerBonus);
petSoulDepthScaling = Prop.getBooleanProperty("petSoulDepthScaling", petSoulDepthScaling);
vehicleCombatRatingPenalty = Prop.getBooleanProperty("vehicleCombatRatingPenalty", vehicleCombatRatingPenalty);
fixMagranonDamageStacking = Prop.getBooleanProperty("fixMagranonDamageStacking", fixMagranonDamageStacking);
adjustCombatRatingSpellPower = Prop.getBooleanProperty("adjustCombatRatingSpellPower", adjustCombatRatingSpellPower);
disableLegendaryRegeneration = Prop.getBooleanProperty("disableLegendaryRegeneration", disableLegendaryRegeneration);
useStaticLegendaryRegeneration = Prop.getBooleanProperty("useStaticLegendaryRegeneration", useStaticLegendaryRegeneration);
// Mastercraft Module
enableMastercraftModule = Prop.getBooleanProperty("enableMastercraftModule", enableMastercraftModule);
enableDifficultyAdjustments = Prop.getBooleanProperty("enableDifficultyAdjustments", enableDifficultyAdjustments);
affinityDifficultyBonus = Prop.getBooleanProperty("affinityDifficultyBonus", affinityDifficultyBonus);
legendDifficultyBonus = Prop.getBooleanProperty("legendDifficultyBonus", legendDifficultyBonus);
masterDifficultyBonus = Prop.getBooleanProperty("masterDifficultyBonus", masterDifficultyBonus);
itemRarityDifficultyBonus = Prop.getBooleanProperty("itemRarityDifficultyBonus", itemRarityDifficultyBonus);
legendItemDifficultyBonus = Prop.getBooleanProperty("legendItemDifficultyBonus", legendItemDifficultyBonus);
masterItemDifficultyBonus = Prop.getBooleanProperty("masterItemDifficultyBonus", masterItemDifficultyBonus);
empoweredChannelers = Prop.getBooleanProperty("empoweredChannelers", empoweredChannelers);
channelSkillFavorReduction = Prop.getBooleanProperty("channelSkillFavorReduction", channelSkillFavorReduction);
// Skill Module
enableSkillModule = Prop.getBooleanProperty("enableSkillModule", enableSkillModule);
enableHybridSkillGain = Prop.getBooleanProperty("enableHybridSkillGain", enableHybridSkillGain);
hybridNegativeDecayRate = Prop.getFloatProperty("hybridNegativeDecayRate", hybridNegativeDecayRate);
hybridPositiveDecayRate = Prop.getFloatProperty("hybridPositiveDecayRate", hybridPositiveDecayRate);
hybridValueAtZero = Prop.getFloatProperty("hybridValueAtZero", hybridValueAtZero);
hybridValueAtOneHundred = Prop.getFloatProperty("hybridValueAtOneHundred", hybridValueAtOneHundred);
changePreachingLocation = Prop.getBooleanProperty("changePreachingLocation", changePreachingLocation);
// Meditation Module
enableMeditationModule = Prop.getBooleanProperty("enableMeditationModule", enableMeditationModule);
simplifyMeditationTerrain = Prop.getBooleanProperty("simplifyMeditationTerrain", simplifyMeditationTerrain);
removeInsanitySotG = Prop.getBooleanProperty("removeInsanitySotG", removeInsanitySotG);
removeHateWarBonus = Prop.getBooleanProperty("removeHateWarBonus", removeHateWarBonus);
insanitySpeedBonus = Prop.getBooleanProperty("insanitySpeedBonus", insanitySpeedBonus);
hateMovementBonus = Prop.getBooleanProperty("hateMovementBonus", hateMovementBonus);
scalingPowerStaminaBonus = Prop.getBooleanProperty("scalingPowerStaminaBonus", scalingPowerStaminaBonus);
scalingKnowledgeSkillGain = Prop.getBooleanProperty("scalingKnowledgeSkillGain", scalingKnowledgeSkillGain);
removeMeditationTickTimer = Prop.getBooleanProperty("removeMeditationTickTimer", removeMeditationTickTimer);
newMeditationBuffs = Prop.getBooleanProperty("newMeditationBuffs", newMeditationBuffs);
enableMeditationAbilityCooldowns = Prop.getBooleanProperty("enableMeditationAbilityCooldowns", enableMeditationAbilityCooldowns);
loveRefreshCooldown = Prop.getLongProperty("loveRefreshCooldown", loveRefreshCooldown);
loveEnchantNatureCooldown = Prop.getLongProperty("loveEnchantNatureCooldown", loveEnchantNatureCooldown);
loveLoveEffectCooldown = Prop.getLongProperty("loveLoveEffectCooldown", loveLoveEffectCooldown);
hateWarDamageCooldown = Prop.getLongProperty("hateWarDamageCooldown", hateWarDamageCooldown);
hateStructureDamageCooldown = Prop.getLongProperty("hateStructureDamageCooldown", hateStructureDamageCooldown);
hateFearCooldown = Prop.getLongProperty("hateFearCooldown", hateFearCooldown);
powerElementalImmunityCooldown = Prop.getLongProperty("powerElementalImmunityCooldown", powerElementalImmunityCooldown);
powerEruptFreezeCooldown = Prop.getLongProperty("powerEruptFreezeCooldown", powerEruptFreezeCooldown);
powerIgnoreTrapsCooldown = Prop.getLongProperty("powerIgnoreTrapsCooldown", powerIgnoreTrapsCooldown);
knowledgeInfoCreatureCooldown = Prop.getLongProperty("knowledgeInfoCreatureCooldown", knowledgeInfoCreatureCooldown);
knowledgeInfoTileCooldown = Prop.getLongProperty("knowledgeInfoTileCooldown", knowledgeInfoTileCooldown);
// Treasure Chest Loot Module
enableTreasureChestLootModule = Prop.getBooleanProperty("enableTreasureChestLootModule", enableTreasureChestLootModule);
@@ -398,6 +513,51 @@ implements WurmServerMod, Configurable, PreInitable, Initable, ItemTemplatesCrea
}
}
awardTitles.put(titleId, playerList);
}else if (name.startsWith("skillName")) {
String[] values = value.split(",");
if(values.length < 2 || values.length > 2){
logger.warning("Error parsing Skill Name: Invalid amount of arguments for following property: "+value);
}
int skillId = SkillAssist.getSkill(values[0]);
if (skillId < 0){
skillId = Integer.parseInt(values[0]);
}
if (skillName.containsKey(skillId)){
logger.warning("Duplicate skill name configurations for skill id "+skillId);
}else{
String newName = values[1];
skillName.put(skillId, newName);
}
}else if (name.startsWith("skillDifficulty")) {
String[] values = value.split(",");
if(values.length < 2 || values.length > 2){
logger.warning("Error parsing Skill Difficulty: Invalid amount of arguments for following property: "+value);
}
int skillId = SkillAssist.getSkill(values[0]);
if (skillId < 0){
skillId = Integer.parseInt(values[0]);
}
if (skillDifficulty.containsKey(skillId)){
logger.warning("Duplicate difficulty configurations for skill id "+skillId);
}else{
float difficulty = Float.parseFloat(values[1]);
skillDifficulty.put(skillId, difficulty);
}
}else if (name.startsWith("skillTickTime")) {
String[] values = value.split(",");
if(values.length < 2 || values.length > 2){
logger.warning("Error parsing Skill Tick Time: Invalid amount of arguments for following property: "+value);
}
int skillId = SkillAssist.getSkill(values[0]);
if (skillId < 0){
skillId = Integer.parseInt(values[0]);
}
if (skillTickTime.containsKey(skillId)){
logger.warning("Duplicate tick time configurations for skill id "+skillId);
}else{
long difficulty = Long.parseLong(values[1]);
skillTickTime.put(skillId, difficulty);
}
}
}
} catch (Exception e) {
@@ -545,6 +705,86 @@ implements WurmServerMod, Configurable, PreInitable, Initable, ItemTemplatesCrea
logger.info("Regenerate Stamina On Vehicle Any Slope: "+regenerateStaminaOnVehicleAnySlope);
}
logger.info("Combat Module: "+enableCombatModule);
if (enableCombatModule){
logger.info("Combat Rating Adjustments: "+enableCombatRatingAdjustments);
if (enableCombatRatingAdjustments){
logger.info("Royal Executioner Bonus: "+royalExecutionerBonus);
logger.info("Pet Soul Depth Scaling: "+petSoulDepthScaling);
logger.info("Vehicle Combat Rating Penalty: "+vehicleCombatRatingPenalty);
}
logger.info("Fix Magranon Damage Stacking: "+fixMagranonDamageStacking);
logger.info("Adjust Combat Rating Spell Power: "+adjustCombatRatingSpellPower);
logger.info("Disable Legendary Regeneration: "+disableLegendaryRegeneration);
logger.info("Use Static Legendary Regeneration: "+useStaticLegendaryRegeneration);
}
logger.info("Mastercraft Module: "+enableMastercraftModule);
if (enableMastercraftModule){
logger.info("Difficulty Adjustments: "+enableDifficultyAdjustments);
if (enableDifficultyAdjustments){
logger.info("Affinity Difficulty Bonus: "+affinityDifficultyBonus);
logger.info("Legend Difficulty Bonus: "+legendDifficultyBonus);
logger.info("Master Difficulty Bonus: "+masterDifficultyBonus);
logger.info("Item Rarity Difficulty Bonus: "+itemRarityDifficultyBonus);
logger.info("Legend Item Difficulty Bonus: "+legendItemDifficultyBonus);
logger.info("Master Item Difficulty Bonus: "+masterItemDifficultyBonus);
}
logger.info("Empowered Channelers: "+empoweredChannelers);
logger.info("Channel Skill Favor Reduction: "+channelSkillFavorReduction);
}
logger.info("Skill Module: "+enableSkillModule);
if (enableSkillModule){
logger.info("Hybrid Skill Gain: "+enableHybridSkillGain);
if (enableHybridSkillGain){
logger.info("Hybrid Negative Decay Rate: "+hybridNegativeDecayRate);
logger.info("Hybrid Positive Decay Rate: "+hybridPositiveDecayRate);
logger.info("Hybrid Value At Zero: "+hybridValueAtZero);
logger.info("Hybrid Value At One Hundred: "+hybridValueAtOneHundred);
}
for (int skillId : skillName.keySet()){
logger.info(String.format("Changing name of skill %s to %s.",
SkillAssist.getSkill(skillId), skillName.get(skillId)));
}
for (int skillId : skillDifficulty.keySet()){
logger.info(String.format("Setting difficulty of skill %s to %.2f.",
SkillAssist.getSkill(skillId), skillDifficulty.get(skillId)));
}
for (int skillId : skillTickTime.keySet()){
logger.info(String.format("Setting tick time of skill %s to %d.",
SkillAssist.getSkill(skillId), skillTickTime.get(skillId)));
}
logger.info("Change Preaching Location: "+changePreachingLocation);
}
logger.info("Meditation Module: "+enableMeditationModule);
if (enableMeditationModule){
logger.info("Simplify Meditation Terrain: "+simplifyMeditationTerrain);
logger.info("Remove Insanity Shield of the Gone: "+removeInsanitySotG);
logger.info("Remove Hate War Bonus: "+removeHateWarBonus);
logger.info("Insanity Speed Bonus: "+insanitySpeedBonus);
logger.info("Hate Movement Bonus: "+hateMovementBonus);
logger.info("Scaling Power Stamina Bonus: "+scalingPowerStaminaBonus);
logger.info("Scaling Knowledge Skill Gain: "+scalingKnowledgeSkillGain);
logger.info("Remove Meditation Tick Timer: "+removeMeditationTickTimer);
logger.info("New Meditation Buffs: "+newMeditationBuffs);
logger.info("Meditation Ability Cooldowns: "+enableMeditationAbilityCooldowns);
if (enableMeditationAbilityCooldowns){
logger.info("Love Refresh Cooldown: "+loveRefreshCooldown);
logger.info("Love Enchant Nature Cooldown: "+loveEnchantNatureCooldown);
logger.info("Love Love Effect Cooldown: "+loveLoveEffectCooldown);
logger.info("Hate War Bonus Cooldown: "+hateWarDamageCooldown);
logger.info("Hate Structure Damage Cooldown: "+hateStructureDamageCooldown);
logger.info("Hate Fear Cooldown: "+hateFearCooldown);
logger.info("Power Elemental Immunity Cooldown: "+powerElementalImmunityCooldown);
logger.info("Power Erupt/Freeze Cooldown: "+powerEruptFreezeCooldown);
logger.info("Power Ignore Traps Cooldown: "+powerIgnoreTrapsCooldown);
logger.info("Knowledge Info Creature Cooldown: "+knowledgeInfoCreatureCooldown);
logger.info("Knowledge Info Tile Cooldown: "+knowledgeInfoTileCooldown);
}
}
logger.info("Treasure Chest Loot Module: "+enableTreasureChestLootModule);
//this.logger.log(Level.INFO, "Property: " + this.somevalue);
@@ -582,11 +822,6 @@ implements WurmServerMod, Configurable, PreInitable, Initable, ItemTemplatesCrea
Arena.preInit();
}
// Custom Titles Module Pre-Init
if (enableCustomTitlesModule) {
PlayerTitles.preInit();
}
// Anti-Cheat Module Pre-Init
if (enableAntiCheatModule) {
AntiCheat.preInit();
@@ -597,6 +832,24 @@ implements WurmServerMod, Configurable, PreInitable, Initable, ItemTemplatesCrea
QualityOfLife.preInit();
}
// Combat Module Pre-Init
if (enableCombatModule) {
CombatChanges.preInit();
}
// Mastercraft Module Pre-Init
if (enableMastercraftModule) {
Mastercraft.preInit();
}
if (enableSkillModule) {
SkillChanges.preInit();
}
if (enableMeditationModule) {
MeditationPerks.preInit();
}
// Treasure Chest Loot Module Pre-Init
if (enableTreasureChestLootModule) {
TreasureChests.preInit();
@@ -607,15 +860,13 @@ implements WurmServerMod, Configurable, PreInitable, Initable, ItemTemplatesCrea
TeleportHandler.preInit();
MethodsBestiary.preInit();
MissionCreator.preInit();
SkillChanges.preInit();
MeditationPerks.preInit();
MountedChanges.preInit();
EconomicChanges.preInit();
Bloodlust.preInit();
Mastercraft.preInit();
SupplyDepots.preInit();
KeyEvent.preInit();
CombatChanges.preInit();
// Bloodlust might no longer be necessary. Code remains for reference.
//Bloodlust.preInit();
// Gem Augmentation is not complete.
//GemAugmentation.preInit();
@@ -737,8 +988,12 @@ implements WurmServerMod, Configurable, PreInitable, Initable, ItemTemplatesCrea
@Override
public void onPlayerLogin(Player p) {
DatabaseHelper.onPlayerLogin(p);
// Award Custom Titles on player login
if(enableCustomTitlesModule) {
PlayerTitles.awardCustomTitles(p);
}
}
@Override
public void onServerStarted() {
@@ -778,7 +1033,9 @@ implements WurmServerMod, Configurable, PreInitable, Initable, ItemTemplatesCrea
//espCounter = Servers.localServer.PVPSERVER; // Enables on PvP server by default.
//espCounter = false;
if (enableSkillModule) {
SkillChanges.onServerStarted();
}
CreationEntry lockpicks = CreationMatrix.getInstance().getCreationEntry(ItemList.lockpick);
try {
@@ -847,11 +1104,11 @@ implements WurmServerMod, Configurable, PreInitable, Initable, ItemTemplatesCrea
Bloodlust.pollLusts();
lastPolledBloodlust += pollBloodlustTime;
}
if(lastPolledUniqueRegeneration + pollUniqueRegenerationTime < System.currentTimeMillis()){
if(WyvernMods.useStaticLegendaryRegeneration && lastPolledUniqueRegeneration + pollUniqueRegenerationTime < System.currentTimeMillis()){
CombatChanges.pollUniqueRegeneration();
lastPolledUniqueRegeneration += pollUniqueRegenerationTime;
}
if(lastPolledUniqueCollection + pollUniqueCollectionTime < System.currentTimeMillis()){
if(WyvernMods.enableCombatModule && lastPolledUniqueCollection + pollUniqueCollectionTime < System.currentTimeMillis()){
CombatChanges.pollUniqueCollection();
lastPolledUniqueCollection += pollUniqueCollectionTime;
}

View File

@@ -1,494 +0,0 @@
package mod.sin.wyvern.mastercraft;
import javassist.bytecode.*;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.IntStream;
public class BytecodeTools extends Bytecode {
//private static final int EMPTY_INT = Integer.MAX_VALUE;
BytecodeTools(ConstPool constPool){
super(constPool);
}
/**
* Look for a class in the constant pool.
* Throws NoMatchingConstPoolIndexException if the references isn't found.
*
* @param className String Object type. Full class name using periods.
* @return int primitive, index in constant pool table.
*/
int findClassIndex(String className){
int classReferenceIndex = getClassReferenceIndex(className);
if (classReferenceIndex == -1)
throw new RuntimeException("No matching class found.");
this.add((classReferenceIndex >>> 8) & 0xFF, classReferenceIndex & 0xFF);
return classReferenceIndex;
}
int addClassIndex(String className){
int classReferenceIndex = getClassReferenceIndex(className);
if (classReferenceIndex == -1)
classReferenceIndex = this.getConstPool().addClassInfo(className);
this.add((classReferenceIndex >>> 8) & 0xFF, classReferenceIndex & 0xFF);
return classReferenceIndex;
}
int findMethodIndex(int opcode, String name, String descriptor, String className){
int methodReferenceIndex;
int classReferenceIndex = getClassReferenceIndex(className);
if (classReferenceIndex == -1)
throw new RuntimeException("No matching class found.");
methodReferenceIndex = IntStream.range(1, this.getConstPool().getSize())
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_Methodref)
.filter(value -> this.getConstPool().eqMember(name, descriptor, value) != null)
.filter(value -> Objects.equals(this.getConstPool().getMethodrefClass(value), classReferenceIndex))
.findFirst()
.orElseThrow(() -> new RuntimeException("No matching method found."));
this.addOpcode(opcode);
this.add((methodReferenceIndex >>> 8) & 0xFF, methodReferenceIndex & 0xFF);
return methodReferenceIndex;
}
int addMethodIndex(int opcode, String name, String methodDescriptor, String className){
int classReferenceIndex = getClassReferenceIndex(className);
if (classReferenceIndex == -1)
classReferenceIndex = this.getConstPool().addClassInfo(className);
int indexReference = this.getConstPool().addMethodrefInfo(classReferenceIndex, name, methodDescriptor);
this.addOpcode(opcode);
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
return indexReference;
}
int findFieldIndex(int opcode, String name, String descriptor, String className){
int fieldReferenceIndex;
int classReferenceIndex = getClassReferenceIndex(className);
if (classReferenceIndex == -1)
throw new RuntimeException("No matching class found.");
fieldReferenceIndex = IntStream.range(1, this.getConstPool().getSize())
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_Fieldref)
.filter(value -> this.getConstPool().eqMember(name, descriptor, value) != null)
.filter(value -> this.getConstPool().getFieldrefClass(value) == classReferenceIndex)
.findFirst()
.orElseThrow(() -> new RuntimeException("No matching field found."));
this.addOpcode(opcode);
this.add((fieldReferenceIndex >>> 8) & 0xFF, fieldReferenceIndex & 0xFF);
return fieldReferenceIndex;
}
int addFieldIndex(int opcode, String name, String descriptor, String className){
int classReferenceIndex = getClassReferenceIndex(className);
if (classReferenceIndex == -1)
classReferenceIndex = this.getConstPool().addClassInfo(className);
int fieldReferenceIndex = this.getConstPool().addFieldrefInfo(classReferenceIndex, name, descriptor);
this.addOpcode(opcode);
this.add((fieldReferenceIndex >>> 8) & 0xFF, fieldReferenceIndex & 0xFF);
return fieldReferenceIndex;
}
void findStringIndex(String string){
int indexReference = IntStream.range(1, this.getConstPool().getSize())
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_String)
.filter(value -> Objects.equals(this.getConstPool().getStringInfo(value), string))
.findFirst()
.orElseThrow(() -> new RuntimeException("No matching string found."));
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
}
void addStringIndex(String string){
int indexReference = this.getConstPool().addStringInfo(string);
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
}
void findLongIndex(long longValue){
int indexReference = IntStream.range(1, this.getConstPool().getSize())
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_Long)
.filter(value -> this.getConstPool().getLongInfo(value) == longValue)
.findFirst()
.orElseThrow(() -> new RuntimeException("No matching long found."));
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
}
void addLongIndex(long longValue){
int indexReference = this.getConstPool().addLongInfo(longValue);
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
}
void findFloatIndex(float floatValue){
int indexReference = IntStream.range(1, this.getConstPool().getSize())
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_Float)
.filter(value -> this.getConstPool().getFloatInfo(value) == floatValue)
.findFirst()
.orElseThrow(() -> new RuntimeException("No matching float found."));
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
}
void addFloatIndex(float floatValue){
int indexReference = this.getConstPool().addFloatInfo(floatValue);
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
}
/**
* a double value stored in the constant pool is always a LDC2_W. This is different then a local variable holding a double.
*
* @param doubleValue primitive double.
*/
void findDoubleIndex(double doubleValue){
int indexReference = IntStream.range(1, this.getConstPool().getSize())
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_Double)
.filter(value -> this.getConstPool().getDoubleInfo(value) == doubleValue)
.findFirst()
.orElseThrow(() -> new RuntimeException("No matching double found."));
this.addOpcode(Opcode.LDC2_W);
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
}
/**
* a double value stored in the constant pool is always a LDC2_W. This is different then a local variable holding a double.
*
* @param doubleValue primitive double.
*/
void addDoubleIndex(double doubleValue){
int indexReference = this.getConstPool().addDoubleInfo(doubleValue);
this.addOpcode(Opcode.LDC2_W);
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
}
private boolean hasAClassDeclaringTag(int tag){
return tag == ConstPool.CONST_Methodref || tag == ConstPool.CONST_Fieldref || tag == ConstPool.CONST_InterfaceMethodref;
}
/**
* Often a class's name will appear twice in the constant pool. One of the occurrence is not used as a declaring class for anything.
* I have no idea why it's present but it can break looking up constant pool references if the unassociated one is picked. JA has a
* built in way of finding existent references but a underlying mechanic is that a hash map uses a string class name as a key
* in a hashMap. Two equal strings will overwrite each other in this case. This is part the the tools library to look for matches
* instead of relying on JA.
*
* 1. scan the constant pool and get the class references that match className.
* 2. scan again through the constant pool looking for class associations that use the references found in #1. One of the options
* will have no references and illuminate that one to return the one that should be used.
*
* @param className String type object, uses full class name and periods.
* @return int primitive, the address in constant pool for the class matching className.
*/
private int getClassReferenceIndex(String className){
return IntStream.range(1, this.getConstPool().getSize())
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_Class)
.filter(value -> Objects.equals(Descriptor.toClassName(this.getConstPool().getClassInfoByDescriptor(value)), className))
.filter( verifyIndex ->
IntStream.range(1, this.getConstPool().getSize())
.filter(value -> hasAClassDeclaringTag(this.getConstPool().getTag(value)))
.filter(value -> {
boolean result = false;
switch (this.getConstPool().getTag(value)) {
case ConstPool.CONST_Methodref:
result = this.getConstPool().getMethodrefClass(value) == verifyIndex;
break;
case ConstPool.CONST_Fieldref:
result = this.getConstPool().getFieldrefClass(value) == verifyIndex;
break;
case ConstPool.CONST_InterfaceMethodref:
result = this.getConstPool().getInterfaceMethodrefClass(value) == verifyIndex;
break;
}
return result;})
.count() > 0
)
.findFirst()
.orElse(-1);
}
void findInterfaceMethodIndex(String name, String descriptor){
if(IntStream.range(1, this.getConstPool().getSize())
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_InterfaceMethodref)
.filter(value -> this.getConstPool().eqMember(name, descriptor, value) != null)
.count() != 1){
throw new RuntimeException("No matching interface found.");
}
else {
int indexReference = IntStream.range(1, this.getConstPool().getSize())
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_InterfaceMethodref)
.filter(value -> this.getConstPool().eqMember(name, descriptor, value) != null)
.findFirst()
.orElseThrow(() -> new RuntimeException("No matching interface found."));
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
}
}
void addInterfaceMethodIndex(String name, String descriptor){
int classIndexReference = IntStream.range(1, this.getConstPool().getSize())
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_Class)
.filter(value -> Objects.equals(this.getConstPool().getClassInfoByDescriptor(value), Descriptor.toClassName(descriptor)))
.findFirst()
.orElseThrow(() -> new RuntimeException("No matching class found."));
int indexReference = this.getConstPool().addInterfaceMethodrefInfo(classIndexReference, name, descriptor);
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
}
void codeBranching(int opcode, int branchCount){
this.addOpcode(opcode);
this.add((branchCount >>> 8) & 0xFF, branchCount & 0xFF);
}
void localVariableIndex(int opcode, int slot){
this.addOpcode(opcode);
this.add(slot);
}
void integerIndex(int opcode, int value){
switch (opcode) {
case Opcode.BIPUSH :
this.addOpcode(Opcode.BIPUSH);
this.add((byte)value);
break;
case Opcode.SIPUSH :
this.addOpcode(Opcode.SIPUSH);
this.add((value >>> 8) & 0xFF, value & 0xFF);
}
}
/**
* Encode the value for arg "integer" into the appropriate byteCode opCode + operand for the java-int. Add the
* encoded information to the byte code object "bytecode".
*
* @param integer int value.
*/
void addInteger(int integer) {
switch (integer) {
case -1:
this.add(Opcode.ICONST_M1);
break;
case 0:
this.add(Opcode.ICONST_0);
break;
case 1:
this.add(Opcode.ICONST_1);
break;
case 2:
this.add(Opcode.ICONST_2);
break;
case 3:
this.add(Opcode.ICONST_3);
break;
case 4:
this.add(Opcode.ICONST_4);
break;
case 5:
this.add(Opcode.ICONST_5);
break;
default:
if (integer >= Byte.MIN_VALUE && integer <= Byte.MAX_VALUE) {
this.add(Opcode.BIPUSH);
// integer bound to byte size.
this.add(integer);
} else if (integer >= Short.MIN_VALUE && integer <= Short.MAX_VALUE) {
this.add(Opcode.SIPUSH);
// Since byte code requires byte sized blocks, break up integer with bitmask and shift.
this.add((integer & 0xff00) >>> 8, integer & 0x00ff);
} else {
// Appends LDC or LDC_W depending on constant pool size.
this.addLdc(this.getConstPool().addIntegerInfo(integer));
}
}
}
/**
* Decode the byte code represented by a opCode + operand(s) at the position in arg "instructionIndex". Return
* decoded data as java-int.
*
* @param codeIterator JA CodeIterator object.
* @param instructionIndex int value, it is the codeIterator index of an opCode.
* @return int value.
*/
int getInteger(CodeIterator codeIterator, int instructionIndex) {
int opCode = codeIterator.byteAt(instructionIndex);
switch (opCode) {
case Opcode.ICONST_M1:
return -1;
case Opcode.ICONST_0:
return 0;
case Opcode.ICONST_1:
return 1;
case Opcode.ICONST_2:
return 2;
case Opcode.ICONST_3:
return 3;
case Opcode.ICONST_4:
return 4;
case Opcode.ICONST_5:
return 5;
case Opcode.BIPUSH:
return codeIterator.byteAt(instructionIndex + 1);
case Opcode.SIPUSH:
return codeIterator.s16bitAt(instructionIndex + 1);
case Opcode.LDC:
return this.getConstPool().getIntegerInfo(codeIterator.byteAt(instructionIndex + 1));
case Opcode.LDC_W:
return this.getConstPool().getIntegerInfo(codeIterator.u16bitAt(instructionIndex + 1));
default:
throw new RuntimeException(String.format("Failed to decode integer. Pos = %d, Bytecode = %d", instructionIndex, opCode));
}
}
static int findSlotInLocalVariableTable(CodeAttribute codeAttribute, String variableName){
LocalVariableAttribute table = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
int tableOrdinal;
tableOrdinal = IntStream.range(0,table.tableLength()).filter(value -> Objects.equals(table.variableName(value), variableName )).findFirst().orElse(-1);
if (tableOrdinal == -1){
return -1;
}
return table.index(tableOrdinal);
}
static int findLineNumberInLineNumberTable(CodeAttribute codeAttribute, String variableName){
LocalVariableAttribute table = (LocalVariableAttribute) codeAttribute.getAttribute(LineNumberAttribute.tag);
int tableOrdinal;
tableOrdinal = IntStream.range(0,table.tableLength()).filter(value -> Objects.equals(table.variableName(value), variableName )).findFirst().orElse(-1);
if (tableOrdinal == -1){
return -1;
}
return table.index(tableOrdinal);
}
private static int[] getInstruction(int size, int index, CodeIterator codeIterator) {
int[] toReturn = null;
int bitLine;
int bitLine2;
switch (size) {
case 1:
bitLine = codeIterator.byteAt(index);
toReturn = new int[]{
bitLine
};
break;
case 2:
bitLine = codeIterator.s16bitAt(index);
toReturn = new int[]{
(bitLine & 0xff00) >>> 8,
bitLine & 0x00ff
};
break;
case 3:
bitLine = codeIterator.s32bitAt(index);
toReturn = new int[]{
(bitLine & 0xff000000) >>> 24,
(bitLine & 0x00ff0000) >>> 16,
(bitLine & 0x0000ff00) >>> 8
// not using the last byte
};
break;
case 4:
bitLine = codeIterator.s32bitAt(index);
toReturn = new int[]{
(bitLine & 0xff000000) >>> 24,
(bitLine & 0x00ff0000) >>> 16,
(bitLine & 0x0000ff00) >>> 8,
(bitLine & 0x000000ff)
};
break;
case 5:
bitLine = codeIterator.s32bitAt(index);
bitLine2 = codeIterator.byteAt(index + 4);
toReturn = new int[]{
(bitLine & 0xff000000) >>> 24,
(bitLine & 0x00ff0000) >>> 16,
(bitLine & 0x0000ff00) >>> 8,
(bitLine & 0x000000ff),
bitLine2
};
break;
case 6:
bitLine = codeIterator.s32bitAt(index);
bitLine2 = codeIterator.s16bitAt(index + 4);
toReturn = new int[]{
(bitLine & 0xff000000) >>> 24,
(bitLine & 0x00ff0000) >>> 16,
(bitLine & 0x0000ff00) >>> 8,
(bitLine & 0x000000ff),
(bitLine2 & 0xff00) >>> 8,
(bitLine2 & 0x00ff)
};
break;
case 7:
bitLine = codeIterator.s32bitAt(index);
bitLine2 = codeIterator.s32bitAt(index + 4);
toReturn = new int[]{
(bitLine & 0xff000000) >>> 24,
(bitLine & 0x00ff0000) >>> 16,
(bitLine & 0x0000ff00) >>> 8,
(bitLine & 0x000000ff),
(bitLine2 & 0xff000000) >>> 24,
(bitLine2 & 0x00ff0000) >>> 16,
(bitLine2 & 0x0000ff00) >>> 8
// not using the last byte
};
break;
case 8:
bitLine = codeIterator.s32bitAt(index);
bitLine2 = codeIterator.s32bitAt(index + 4);
toReturn = new int[]{
(bitLine & 0xff000000) >>> 24,
(bitLine & 0x00ff0000) >>> 16,
(bitLine & 0x0000ff00) >>> 8,
(bitLine & 0x000000ff),
(bitLine2 & 0xff000000) >>> 24,
(bitLine2 & 0x00ff0000) >>> 16,
(bitLine2 & 0x0000ff00) >>> 8,
(bitLine2 & 0x000000ff)
};
break;
}
return toReturn;
}
public static void byteCodePrint(String destinationPath, CodeIterator codeIterator) throws FileNotFoundException, BadBytecode {
Path printPath = Paths.get(destinationPath);
PrintWriter out = new PrintWriter(printPath.toFile());
final String[] instructionOut = {""};
codeIterator.begin();
while (codeIterator.hasNext()) {
int index = codeIterator.next();
int[] instruction = getInstruction(codeIterator.lookAhead() - index, index, codeIterator);
instructionOut[0] += Integer.toString(index);
instructionOut[0] += " ";
instructionOut[0] += Mnemonic.OPCODE[instruction[0]];
if (instruction.length > 1) {
instructionOut[0] += " ";
IntStream.range(1, instruction.length)
.forEach(value -> {
instructionOut[0] += Integer.toString(instruction[value]);
instructionOut[0] += " ";
});
}
out.println(instructionOut[0]);
instructionOut[0] = "";
}
out.close();
}
static void printArrayToHex(Object[] obj, String name, Logger logger){
int length = obj.length;
int[] c = new int[length];
for (int i=0;i<length;i++){
c[i]=(int)obj[i];
}
String[] a = new String[length];
for (int i=0;i<length;i++){
a[i]=String.format("%02X", c[i] & 0xff);
}
logger.log(Level.INFO,name + " : " + Arrays.toString(a));
}
}

View File

@@ -1,223 +0,0 @@
package mod.sin.wyvern.mastercraft;
import com.wurmonline.server.skills.SkillList;
import javassist.*;
import javassist.bytecode.*;
import org.gotti.wurmunlimited.modloader.classhooks.CodeReplacer;
import org.gotti.wurmunlimited.modloader.classhooks.HookManager;
import java.util.ArrayList;
class ExtendTitleEnum {
private final String className;
private final int valuesSizerIndex; // the bytecode index which puts a size specifying value on the stack for anewarray.
private final int populateVALUESIndex; // the bytecode index where references to various enum instances are put in the $VALUES array.
private final ConstPool constPool;
private static ArrayList<EnumFields> toExtendEntries = new ArrayList<>();
private static ExtendTitleEnum singletonInstance;
private ExtendTitleEnum(String className, int valuesSizerIndex, int populateVALUESIndex, ConstPool constPool) {
this.className = className;
this.valuesSizerIndex = valuesSizerIndex;
this.populateVALUESIndex = populateVALUESIndex;
this.constPool = constPool;
}
/**
* Goes through the enum class's initiator to find bytecode index positions.
*
* @throws BadBytecode forwarded, Javassist stuff.
*/
static void builder(String className) throws BadBytecode, NotFoundException {
int valuesSizerIndex = -1;
//int indexANEWARRAY = -1;
int populateVALUESIndex = -1;
CtClass ctClassEnum = HookManager.getInstance().getClassPool().get(className);
ConstPool constPool = ctClassEnum.getClassFile().getConstPool();
CodeIterator codeIterator = ctClassEnum.getClassInitializer().getMethodInfo().getCodeAttribute().iterator();
// Get the byte code instruction index for
// 1) size value for ANEWARRAY,
// 2) the VALUES array assignment or population.
BytecodeTools b = new BytecodeTools(constPool);
String valuesDescriptor = className.replace(".", "/");
valuesDescriptor = "[L" + valuesDescriptor + ";";
int constPoolValuesIndex = b.findFieldIndex(Opcode.PUTSTATIC, "$VALUES",
valuesDescriptor, className);
codeIterator.begin();
int lastIndex = 0;
while (codeIterator.hasNext()){
int instructionIndex = codeIterator.next();
int opCode = codeIterator.byteAt(instructionIndex);
switch (opCode){
case Opcode.ANEWARRAY :
valuesSizerIndex = lastIndex;
//indexANEWARRAY = instructionIndex;
break;
case Opcode.PUTSTATIC :
int cpAddress = codeIterator.u16bitAt(instructionIndex+1);
if (cpAddress == constPoolValuesIndex){
populateVALUESIndex = instructionIndex;
}
break;
default:
break;
}
lastIndex = instructionIndex;
}
synchronized (ExtendTitleEnum.class) {
singletonInstance = new ExtendTitleEnum(className, valuesSizerIndex, populateVALUESIndex, constPool);
}
}
static ExtendTitleEnum getSingletonInstance() {
return singletonInstance;
}
/**
* A method to create data structures and add record a reference for that object.
*
* @param fieldName the name for the enum entry.
* @param titleId an ordinal for the Titles.Title enum.
* @param maleName in-game title name for male toons.
* @param femaleName in-game title name for femaleName toons.
* @param skillId A id number for the skill associated with the title, see {@link SkillList}
* @param titleTypes A string representation of entries in {@link com.wurmonline.server.players.Titles.TitleType}. In
* order to avoid premature class initialization for Javassist's bytecode stages we use a string
* instead of the WU object. The string must match one of the enum field names.
*/
synchronized void addExtendEntry(String fieldName, int titleId, String maleName, String femaleName, int skillId, String titleTypes) {
if (singletonInstance == null) {
throw new RuntimeException("ExtendTitleEnum instance is null, build it before addExtendEntry");
}
EnumFields enumFields = new EnumFields(fieldName, titleId, maleName, femaleName, skillId, titleTypes);
toExtendEntries.add(enumFields);
}
class EnumFields {
final String fieldName;
final int titleId;
final String maleName;
final String femaleName;
final int skillId;
final String titleTypes;
/**
* @param fieldName the name for the enum entry.
* @param titleId an ordinal for the Titles.Title enum.
* @param maleName in-game title name for male toons.
* @param femaleName in-game title name for femaleName toons.
* @param skillId A id number for the skill associated with the title, see {@link SkillList}
* @param titleTypes A string representation of entries in {@link com.wurmonline.server.players.Titles.TitleType}. In
* order to avoid premature class initialization for Javassist's bytecode stages we use a string
* instead of the WU object.
**/
EnumFields(String fieldName, int titleId, String maleName, String femaleName,
int skillId, String titleTypes){
this.fieldName = fieldName;
this.titleId = titleId;
this.maleName = maleName;
this.femaleName = femaleName;
this.skillId = skillId;
this.titleTypes = titleTypes;
}
}
/**
* Intended to be used in WurmServerMod-initiate section and it's for bytecode changes. This adds field objects to the enum class.
*
* @throws CannotCompileException forwarded, Javassist stuff.
*/
private synchronized void createFieldsInEnum() throws CannotCompileException, NotFoundException {
if (toExtendEntries.size() == 0){
throw new RuntimeException("Can not extend an enum without values in toExtendEntries arrayList.");
}
CtClass enumCtClass = HookManager.getInstance().getClassPool().get(this.className);
for (EnumFields enumData : toExtendEntries) {
CtField field = new CtField(enumCtClass, enumData.fieldName, enumCtClass);
field.setModifiers(Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL | Modifier.ENUM);
enumCtClass.addField(field);
}
}
/**
* This method uses JA bytecode to inject into the Enum's class initiator in order to expand the enum's $VALUES field.
*
* @throws BadBytecode forwarded, Javassist stuff.
*/
private void resizeEnumVALUES() throws BadBytecode, ClassNotFoundException, NotFoundException {
int expansion = toExtendEntries.size();
CtClass ctClassEnum = HookManager.getInstance().getClassPool().get(this.className);
CodeIterator codeIterator = ctClassEnum.getClassInitializer().getMethodInfo().getCodeAttribute().iterator();
BytecodeTools findBytecode = new BytecodeTools(this.constPool);
int currentSize = findBytecode.getInteger(codeIterator, this.valuesSizerIndex);
findBytecode.addInteger(currentSize);
findBytecode.addOpcode(Opcode.ANEWARRAY);
findBytecode.addClassIndex(this.className);
BytecodeTools replaceBytecode = new BytecodeTools(this.constPool);
replaceBytecode.addInteger(currentSize + expansion);
replaceBytecode.addOpcode(Opcode.ANEWARRAY);
replaceBytecode.addClassIndex(this.className);
CodeReplacer codeReplacer = new CodeReplacer(ctClassEnum.getClassInitializer().getMethodInfo().getCodeAttribute());
codeReplacer.replaceCode(findBytecode.get(), replaceBytecode.get());
}
/**
* This method builds bytecode to inject into the enum's initiator. The injected code initializes new enum entries and adds
* a reference of that new object to the $VALUES array.
*
* @throws BadBytecode forwarded, JA stuff.
* @throws ClassNotFoundException forwarded, JA stuff.
* @throws NotFoundException forwarded, JA stuff.
*/
synchronized void ExtendEnumEntries() throws BadBytecode, ClassNotFoundException, NotFoundException, CannotCompileException {
createFieldsInEnum();
CtClass ctClassEnum = HookManager.getInstance().getClassPool().get(this.className);
CodeIterator initiatorCodeIterator = ctClassEnum.getClassInitializer().getMethodInfo().getCodeAttribute().iterator();
BytecodeTools enumInitiator = new BytecodeTools(ctClassEnum.getClassFile().getConstPool());
BytecodeTools populateVALUES = new BytecodeTools(ctClassEnum.getClassFile().getConstPool());
int extensionCounter = 0;
int valuesSize = enumInitiator.getInteger(initiatorCodeIterator, this.valuesSizerIndex);
// Construct the two bytecode objects to be inserted. The multiple enumData in toExtendEntries are combined into one
// long bytecode sequence and inserted at the proper point.
for (EnumFields enumData : toExtendEntries) {
enumInitiator.addOpcode(Opcode.NEW);
enumInitiator.findClassIndex(this.className);
enumInitiator.addOpcode(Opcode.DUP);
enumInitiator.addLdc(enumData.fieldName);
enumInitiator.addInteger(valuesSize + extensionCounter);
enumInitiator.addInteger(enumData.titleId);
enumInitiator.addLdc(enumData.maleName);
enumInitiator.addLdc(enumData.femaleName);
enumInitiator.addInteger(enumData.skillId);
enumInitiator.addFieldIndex(Opcode.GETSTATIC, enumData.titleTypes,
"Lcom/wurmonline/server/players/Titles$TitleType;",
"com/wurmonline/server/players/Titles$TitleType");
enumInitiator.addMethodIndex(Opcode.INVOKESPECIAL, "<init>",
"(Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;ILcom/wurmonline/server/players/Titles$TitleType;)V",
this.className);
enumInitiator.addFieldIndex(Opcode.PUTSTATIC, enumData.fieldName, "Lcom/wurmonline/server/players/Titles$Title;",
this.className);
populateVALUES.addOpcode(Opcode.DUP);
populateVALUES.addInteger(valuesSize + extensionCounter);
extensionCounter++;
populateVALUES.findFieldIndex(Opcode.GETSTATIC, enumData.fieldName, "Lcom/wurmonline/server/players/Titles$Title;",
this.className);
populateVALUES.addOpcode(Opcode.AASTORE);
}
// Do bytecode changes from the bottom up so bytecode indexes don't change after every insert.
initiatorCodeIterator.insert(populateVALUESIndex, populateVALUES.get());
resizeEnumVALUES();
initiatorCodeIterator.insert(valuesSizerIndex, enumInitiator.get());
}
}

View File

@@ -1,203 +0,0 @@
package mod.sin.wyvern.mastercraft;
import com.wurmonline.server.Server;
import com.wurmonline.server.items.Item;
import com.wurmonline.server.players.Titles;
import com.wurmonline.server.skills.Skill;
import com.wurmonline.server.skills.SkillList;
import javassist.*;
import javassist.bytecode.BadBytecode;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;
import mod.sin.lib.Util;
import org.gotti.wurmunlimited.modloader.ReflectionUtil;
import org.gotti.wurmunlimited.modloader.classhooks.HookManager;
import java.util.Objects;
import java.util.logging.Logger;
public class Mastercraft {
private static Logger logger = Logger.getLogger(Mastercraft.class.getName());
public static double getNewDifficulty(Skill skill, double diff, Item item){
if(skill.affinity > 0){
diff -= skill.affinity;
}
if(skill.getKnowledge() > 99.0d){
diff -= 2d-((100d-skill.getKnowledge())*2d);
}
if(skill.getKnowledge() > 90.0d){
diff -= 2d-((100d-skill.getKnowledge())*0.2d);
}
if(item != null){
if(item.getRarity() > 0){
diff -= item.getRarity();
}
if(item.getCurrentQualityLevel() > 99.0f){
diff -= 1d-((100d-item.getCurrentQualityLevel())*1d);
}
if(item.getCurrentQualityLevel() > 90.0f){
diff -= 1d-((100d-item.getCurrentQualityLevel())*0.1d);
}
}
return diff;
}
public static float getCastPowerIncrease(Skill skill){
double addedPower = 0;
if(skill.affinity > 0){
addedPower += 2*skill.affinity;
}
if(skill.getKnowledge() > 0){
float lowFloat1 = Math.min(Server.rand.nextFloat(), Server.rand.nextFloat());
float lowFloat2 = Math.min(Server.rand.nextFloat(), Server.rand.nextFloat());
addedPower += Math.min(skill.getKnowledge()*lowFloat1, skill.getKnowledge()*lowFloat2);
}else{
logger.warning("Error: Some player just tried casting with no channeling skill!");
}
return (float) addedPower;
}
public static float getFavorCostMultiplier(Skill skill){
float mult = 1f;
if(skill.affinity > 0){
mult -= skill.affinity*0.02f; //2% reduction per affinity
}
if(skill.getKnowledge() > 90d){
mult -= 0.1d-((100d-skill.getKnowledge())*0.01d);
}
if(skill.getKnowledge() > 99d){
mult -= 0.1d-((100-skill.getKnowledge())*0.1d);
}
return mult;
}
/*public static void addNewTitles(){
try {
ExtendTitleEnum.builder("com.wurmonline.server.players.Titles$Title");
// GM/Developer Titles
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Game_Master", 2500, "Game Master", "Game Master", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Developer", 2501, "Developer", "Developer", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Pet_Me", 2502, "Pet Me", "Pet Me", -1, "NORMAL");
// Troll Titles
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Macro_King", 550, "Macro King", "Macro King", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Drama_Queen", 551, "Drama Queen", "Drama Queen", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Zergling", 552, "Zergling", "Zergling", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Special_Title", 553, "Special Guy", "Special Girl", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Prophet_Ear", 554, "Prophet Ear", "Prophet Ear", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Koza", 555, "Koza", "Koza", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Wyvern_Hunter", 556, "Wyvern Hunter", "Wyvern Hunter", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Overlord", 557, "Overlord", "Overlord", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Troll", 558, "Troll", "Troll", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Beggar", 559, "Beggar", "Beggar", -1, "NORMAL");
// Contest Titles
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Home_Decorator", 600, "Home Decorator", "Home Decorator", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Arena_Champion", 601, "Champion of the Arena", "Champion of the Arena", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Pastamancer", 602, "Pastamancer", "Pastamancer", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Pizzamancer", 603, "Pizzamancer", "Pizzamancer", -1, "NORMAL");
// Special Event Titles
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Titan_Slayer", 700, "Titanslayer", "Titanslayer", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Spectral_Slayer", 701, "Spectral Warrior", "Spectral Warrior", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Holdstrong_Architect", 702, "Holdstrong Architect", "Holdstrong Architect", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Stronghold_Architect", 703, "Stronghold Architect", "Stronghold Architect", -1, "NORMAL");
// Donation titles
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Donator", 800, "Donator", "Donator", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Pazza_FavoriteGM", 801, "Sindusks Favourite GM", "Sindusks Favourite GM", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Warriorgen_ThatGuy", 802, "That Guy", "That Guy", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Eternallove_WarriorgensWife", 803, "Warriorgens Wife", "Warriorgens Wife", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Bambam_ThornOne", 804, "Thorn One", "Thorn One", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Svenja_CareDependant", 805, "The care-dependent", "The care-dependent", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Alexia_TheTreasuring", 806, "The Treasuring", "The Treasuring", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Reevi_ScienceGuy", 807, "Science Guy", "Science Guy", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Genocide_GrandDesigner", 808, "Grand Designer", "Grand Designer", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Seleas_CrazyCatLord", 809, "The Crazy Cat Lord", "The Crazy Cat Lord", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Piratemax_Slave", 810, "Slave", "Slave", -1, "NORMAL");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Eltacolad_TrueTaco", 811, "The One True Taco", "The One True Taco", -1, "NORMAL");
// Skill Titles (100)
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Archery_Legendary", 1500, "Legendary Marksman", "Legendary Marksman", 1030, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Body_Legendary", 1501, "Hercules", "Hercules", 1, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Axes_Legendary", 1502, "Viking", "Viking", 1003, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Baking_Legendary", 1503, "Patissier", "Patissier", 10039, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Archaeology_Legendary", 1504, "Curator", "Curator", 10069, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("CarvingKnife_Legendary", 1505, "Woodsculptor", "Woodsculptor", 10007, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Taming_Legendary", 1506, "King of the Jungle", "Queen of the Jungle", 10078, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Climbing_Legendary", 1507, "Moonwalker", "Moonwalker", 10073, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Tracking_Legendary", 1508, "Bloodhound", "Bloodhound", 10018, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Clubs_Legendary", 1509, "Bam Bam", "Bam Bam", 1025, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Catapults_Legendary", 1510, "Castle Crasher", "Castle Crasher", 10077, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Firemaking_Legendary", 1511, "Incendiary", "Incendiary", 1010, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Gardening_Legendary", 1512, "Earthbound", "Earthbound", 10045, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Hammers_Legendary", 1513, "Doomhammer", "Doomhammer", 1027, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Locksmithing_Legendary", 1514, "Vault Smith", "Vault Smith", 10034, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Religion_Legendary", 1515, "Chosen", "Chosen", 1026, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Yoyo_Legendary", 1516, "String Theorist", "String Theorist", 10050, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Nature_Legendary", 1517, "Naturalist", "Naturalist", 1019, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Mind_Legendary", 1518, "Enlightened", "Enlightened", 2, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Mauls_Legendary", 1519, "Breaker", "Breaker", 1004, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Shipbuilding_Legendary", 1520, "Naval Engineer", "Naval Engineer", 10082, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("NaturalSubstances_Legendary", 1521, "Biochemist", "Biochemist", 10042, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("WarMachines_Legendary", 1522, "Eradicator", "Eradicator", 1029, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Thievery_Legendary", 1523, "Shadow", "Shadow", 1028, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Swords_Legendary", 1524, "Samurai", "Samurai", 1000, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Forestry_Legendary", 1525, "Silvanus", "Mother Nature", 10048, "LEGENDARY");
ExtendTitleEnum.getSingletonInstance().ExtendEnumEntries();
} catch (BadBytecode | ClassNotFoundException | NotFoundException | CannotCompileException e) {
logger.warning(e.getMessage());
}
}*/
public static void changeExistingTitles(){
for (Titles.Title title : Titles.Title.values()) {
if (Objects.equals("Pumpkin King", title.getFemaleName())){
try {
ReflectionUtil.setPrivateField(title, ReflectionUtil.getField(title.getClass(), "femaleName"), "Pumpkin Queen");
} catch (IllegalArgumentException | IllegalAccessException | ClassCastException | NoSuchFieldException e) {
e.printStackTrace();
}
}
}
}
public static void preInit(){
try {
ClassPool classPool = HookManager.getInstance().getClassPool();
Class<Mastercraft> thisClass = Mastercraft.class;
// - Reduce skill check difficulty with high skills or tools - //
CtClass ctSkill = classPool.get("com.wurmonline.server.skills.Skill");
/*ctSkill.getDeclaredMethod("checkAdvance").insertBefore(""
+ "$1 = "+Mastercraft.class.getName()+".getNewDifficulty(this, $1, $2);");*/
Util.setReason("Modify difficulty for skill checks in MasterCraft.");
String replace = "$1 = "+Mastercraft.class.getName()+".getNewDifficulty(this, $1, $2);";
Util.insertBeforeDeclared(thisClass, ctSkill, "checkAdvance", replace);
// - Increase spellcasting power for skilled channelers - //
CtClass ctSpell = classPool.get("com.wurmonline.server.spells.Spell");
CtMethod[] ctRuns = ctSpell.getDeclaredMethods("run");
for(CtMethod method : ctRuns){
method.instrument(new ExprEditor(){
public void edit(MethodCall m) throws CannotCompileException {
if (m.getMethodName().equals("doEffect")) {
m.replace("$2 += "+Mastercraft.class.getName()+".getCastPowerIncrease(castSkill);"
+ "$_ = $proceed($$);");
logger.info("Instrumented doEffect in run()");
}
}
});
method.instrument(new ExprEditor(){
public void edit(MethodCall m) throws CannotCompileException {
if (m.getMethodName().equals("depleteFavor")) {
m.replace("$1 *= "+Mastercraft.class.getName()+".getFavorCostMultiplier(castSkill);"
+ "$_ = $proceed($$);");
logger.info("Instrumented depleteFavor in run()");
}
}
});
}
} catch (CannotCompileException | NotFoundException e) {
e.printStackTrace();
}
}
}