ABS char skill system

This commit is contained in:
2024-03-27 17:17:34 -05:00
parent 27d869276a
commit aff2a8fa0e
16 changed files with 542 additions and 656 deletions
+476 -2
View File
@@ -136,6 +136,16 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
public Enum.SexType absGender = null;
public EnumSet<DisciplineType> absDisciplines;
// Modifiers
public short statStrBase;
public short statDexBase;
public short statConBase;
public short statIntBase;
public short statSpiBase;
public Race race;
public BaseClass baseClass;
public PromotionClass promotionClass;
public AbstractCharacter() {
super();
this.firstName = "";
@@ -468,7 +478,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
//do this after all bonus updates, but before recalculations.
// recalculate everything
//calculate item bonuses
playerCharacter.calculateItemBonuses();
calculateItemBonuses(playerCharacter);
//recalculate formulas
PlayerCharacter.recalculatePlayerStatsOnLoad(playerCharacter);
@@ -587,6 +597,470 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
}
/**
* @ Calculates Atr (both hands) Defense, and Damage for pc
* @param playerCharacter
*/
public static void calculateAtrDefenseDamage(AbstractCharacter playerCharacter) {
if (playerCharacter.charItemManager == null || playerCharacter.charItemManager.getEquipped() == null || playerCharacter.skills == null) {
Logger.error("Player " + playerCharacter.getObjectUUID() + " missing skills or equipment");
defaultAtrAndDamage(playerCharacter,true);
defaultAtrAndDamage(playerCharacter,false);
playerCharacter.defenseRating = 0;
return;
}
ConcurrentHashMap<EquipSlotType, Item> equipped = playerCharacter.charItemManager.getEquipped();
// // Reset passives
// if (this.bonuses != null) {
// this.bonuses.setBool("Block", false);
// this.bonuses.setBool("Parry", false);
// if (this.baseClass != null && this.baseClass.getUUID() == 2502)
// this.bonuses.setBool("Dodge", true);
// else
// this.bonuses.setBool("Dodge", false);
// }
// calculate atr and damage for each hand
calculateAtrDamageForWeapon(playerCharacter,equipped.get(EquipSlotType.RHELD), true, equipped.get(EquipSlotType.RHELD));
calculateAtrDamageForWeapon(playerCharacter,equipped.get(EquipSlotType.LHELD), false, equipped.get(EquipSlotType.LHELD));
// No Defense while in DeathShroud
if (playerCharacter.effects != null && playerCharacter.effects.containsKey("DeathShroud"))
playerCharacter.defenseRating = (short) 0;
else {
// calculate defense for equipment
float defense = playerCharacter.statDexCurrent * 2;
defense += getShieldDefense(playerCharacter,equipped.get(EquipSlotType.LHELD));
defense += getArmorDefense(playerCharacter,equipped.get(EquipSlotType.HELM));
defense += getArmorDefense(playerCharacter,equipped.get(EquipSlotType.CHEST));
defense += getArmorDefense(playerCharacter,equipped.get(EquipSlotType.UPARM));
defense += getArmorDefense(playerCharacter,equipped.get(EquipSlotType.HANDS));
defense += getArmorDefense(playerCharacter,equipped.get(EquipSlotType.LEGS));
defense += getArmorDefense(playerCharacter,equipped.get(EquipSlotType.FEET));
defense += getWeaponDefense(playerCharacter,equipped);
if (playerCharacter.bonuses != null) {
// add any bonuses
defense += (short) playerCharacter.bonuses.getFloat(ModType.DCV, SourceType.NONE);
// Finally multiply any percent modifiers. DO THIS LAST!
float pos_Bonus = playerCharacter.bonuses.getFloatPercentPositive(ModType.DCV, SourceType.NONE);
defense = (short) (defense * (1 + pos_Bonus));
//Lucky rune applies next
//applied runes will be calculated and added to the normal bonuses. no need for this garbage anymore
//defense = (short) (defense * (1 + ((float) this.bonuses.getShort("rune.Defense") / 100)));
//and negative percent modifiers
//already done...
float neg_Bonus = playerCharacter.bonuses.getFloatPercentNegative(ModType.DCV, SourceType.NONE);
defense = (short) (defense * (1 + neg_Bonus));
} else
// TODO add error log here
Logger.error("Error: missing bonuses");
defense = (defense < 1) ? 1 : defense;
playerCharacter.defenseRating = (short) (defense + 0.5f);
}
}
/**
* @ Calculates Atr, and Damage for each weapon
*/
private static void calculateAtrDamageForWeapon(AbstractCharacter playerCharacter, Item weapon, boolean mainHand, Item otherHand) {
// make sure weapon exists
boolean noWeapon = false;
ItemBase wb = null;
if (weapon == null)
noWeapon = true;
else {
ItemBase ib = weapon.getItemBase();
if (ib == null)
noWeapon = true;
else if (!weapon.template.item_type.equals(ItemType.WEAPON)) {
defaultAtrAndDamage(playerCharacter,mainHand);
return;
} else
wb = ib;
}
float skillPercentage, masteryPercentage;
float mastDam;
float min, max;
float speed = 20f;
boolean strBased = false;
ItemBase wbMain = (weapon != null) ? weapon.getItemBase() : null;
ItemBase wbOff = (otherHand != null) ? otherHand.getItemBase() : null;
// get skill percentages and min and max damage for weapons
if (noWeapon) {
if (mainHand) {
Item off = playerCharacter.charItemManager.getEquipped().get(EquipSlotType.LHELD);
if (off != null && off.getItemBase() != null && off.template.item_type.equals(ItemType.WEAPON))
playerCharacter.rangeHandOne = 10 * (1 + (playerCharacter.statStrBase / 600)); // Set
// to
// no
// weapon
// range
else
playerCharacter.rangeHandOne = -1; // set to do not attack
} else
playerCharacter.rangeHandTwo = -1; // set to do not attack
skillPercentage = getModifiedAmount(playerCharacter.skills.get("Unarmed Combat"));
masteryPercentage = getModifiedAmount(playerCharacter.skills.get("Unarmed Combat Mastery"));
if (masteryPercentage == 0f)
mastDam = CharacterSkill.getQuickMastery(playerCharacter, "Unarmed Combat Mastery");
else
mastDam = masteryPercentage;
// TODO Correct these
min = 1;
max = 3;
} else {
if (mainHand)
playerCharacter.rangeHandOne = weapon.getItemBase().getRange() * (1 + (playerCharacter.statStrBase / 600));
else
playerCharacter.rangeHandTwo = weapon.getItemBase().getRange() * (1 + (playerCharacter.statStrBase / 600));
if (playerCharacter.bonuses != null) {
float range_bonus = 1 + playerCharacter.bonuses.getFloatPercentAll(ModType.WeaponRange, SourceType.NONE);
if (mainHand)
playerCharacter.rangeHandOne *= range_bonus;
else
playerCharacter.rangeHandTwo *= range_bonus;
}
skillPercentage = getModifiedAmount(playerCharacter.skills.get(weapon.template.item_skill_used));
masteryPercentage = getModifiedAmount(playerCharacter.skills.get(wb.getMastery()));
if (masteryPercentage == 0f)
mastDam = 0f;
// mastDam = CharacterSkill.getQuickMastery(this, wb.getMastery());
else
mastDam = masteryPercentage;
min = (float) wb.getMinDamage();
max = (float) wb.getMaxDamage();
strBased = wb.isStrBased();
//
// Add parry bonus for weapon and allow parry if needed
// // Only Fighters and Thieves can Parry
// if ((this.baseClass != null && this.baseClass.getUUID() == 2500)
// || (this.promotionClass != null && this.promotionClass.getUUID() == 2520)) {
// if (wbMain == null || wbMain.getRange() < MBServerStatics.RANGED_WEAPON_RANGE)
// if (wbOff == null || wbOff.getRange() < MBServerStatics.RANGED_WEAPON_RANGE)
// this.bonuses.setBool("Parry", true);
// }
// }
}
if (playerCharacter.effects != null && playerCharacter.effects.containsKey("DeathShroud"))
// No Atr in deathshroud.
if (mainHand)
playerCharacter.atrHandOne = (short) 0;
else
playerCharacter.atrHandTwo = (short) 0;
else {
// calculate atr
float atr = 0;
atr += (int) skillPercentage * 4f; //<-round down skill% -
atr += (int) masteryPercentage * 3f;
if (playerCharacter.statStrCurrent > playerCharacter.statDexCurrent)
atr += playerCharacter.statStrCurrent / 2;
else
atr += playerCharacter.statDexCurrent / 2;
// add in any bonuses to atr
if (playerCharacter.bonuses != null) {
// Add any base bonuses
atr += playerCharacter.bonuses.getFloat(ModType.OCV, SourceType.NONE);
// Finally use any multipliers. DO THIS LAST!
float pos_Bonus = (1 + playerCharacter.bonuses.getFloatPercentPositive(ModType.OCV, SourceType.NONE));
atr *= pos_Bonus;
// next precise
//runes will have their own bonuses.
// atr *= (1 + ((float) this.bonuses.getShort("rune.Attack") / 100));
//and negative percent modifiers
float neg_Bonus = playerCharacter.bonuses.getFloatPercentNegative(ModType.OCV, SourceType.NONE);
atr *= (1 + neg_Bonus);
}
atr = (atr < 1) ? 1 : atr;
// set atr
if (mainHand)
playerCharacter.atrHandOne = (short) (atr + 0.5f);
else
playerCharacter.atrHandTwo = (short) (atr + 0.5f);
}
//calculate speed
if (wb != null)
speed = wb.getSpeed();
else
speed = 20f; //unarmed attack speed
if (weapon != null)
speed *= (1 + playerCharacter.bonuses.getFloatPercentAll(ModType.WeaponSpeed, SourceType.NONE));
speed *= (1 + playerCharacter.bonuses.getFloatPercentAll(ModType.AttackDelay, SourceType.NONE));
if (speed < 10)
speed = 10;
//add min/max damage bonuses for weapon
if (weapon != null) {
// Add any base bonuses
min += weapon.getBonus(ModType.MinDamage, SourceType.NONE);
max += weapon.getBonus(ModType.MaxDamage, SourceType.NONE);
min += weapon.getBonus(ModType.MeleeDamageModifier, SourceType.NONE);
max += weapon.getBonus(ModType.MeleeDamageModifier, SourceType.NONE);
// Finally use any multipliers. DO THIS LAST!
float percentMinDamage = 1;
float percentMaxDamage = 1;
percentMinDamage += weapon.getBonusPercent(ModType.MinDamage, SourceType.NONE);
percentMinDamage += weapon.getBonusPercent(ModType.MeleeDamageModifier, SourceType.NONE);
percentMaxDamage += weapon.getBonusPercent(ModType.MaxDamage, SourceType.NONE);
percentMaxDamage += weapon.getBonusPercent(ModType.MeleeDamageModifier, SourceType.NONE);
min *= percentMinDamage;
max *= percentMaxDamage;
}
//if duel wielding, cut damage by 30%
if (otherHand != null) {
ItemBase ibo = otherHand.getItemBase();
if (ibo != null && otherHand.template.equals(ItemType.WEAPON)) {
min *= 0.7f;
max *= 0.7f;
}
}
// calculate damage
float minDamage;
float maxDamage;
float pri = (strBased) ? (float) playerCharacter.statStrCurrent : (float) playerCharacter.statDexCurrent;
float sec = (strBased) ? (float) playerCharacter.statDexCurrent : (float) playerCharacter.statStrCurrent;
minDamage = (float) (min * ((0.0315f * Math.pow(pri, 0.75f)) + (0.042f * Math.pow(sec, 0.75f)) + (0.01f * ((int) skillPercentage + (int) mastDam))));
maxDamage = (float) (max * ((0.0785f * Math.pow(pri, 0.75f)) + (0.016f * Math.pow(sec, 0.75f)) + (0.0075f * ((int) skillPercentage + (int) mastDam))));
minDamage = (float) ((int) (minDamage + 0.5f)); //round to nearest decimal
maxDamage = (float) ((int) (maxDamage + 0.5f)); //round to nearest decimal
// Half damage if in death shroud
if (playerCharacter.effects != null && playerCharacter.effects.containsKey("DeathShroud")) {
minDamage *= 0.5f;
maxDamage *= 0.5f;
}
// add in any bonuses to damage
if (playerCharacter.bonuses != null) {
// Add any base bonuses
minDamage += playerCharacter.bonuses.getFloat(ModType.MinDamage, SourceType.NONE);
maxDamage += playerCharacter.bonuses.getFloat(ModType.MaxDamage, SourceType.NONE);
minDamage += playerCharacter.bonuses.getFloat(ModType.MeleeDamageModifier, SourceType.NONE);
maxDamage += playerCharacter.bonuses.getFloat(ModType.MeleeDamageModifier, SourceType.NONE);
// Finally use any multipliers. DO THIS LAST!
float percentMinDamage = 1;
float percentMaxDamage = 1;
percentMinDamage += playerCharacter.bonuses.getFloatPercentAll(ModType.MinDamage, SourceType.NONE);
percentMinDamage += playerCharacter.bonuses.getFloatPercentAll(ModType.MeleeDamageModifier, SourceType.NONE);
percentMaxDamage += playerCharacter.bonuses.getFloatPercentAll(ModType.MaxDamage, SourceType.NONE);
percentMaxDamage += playerCharacter.bonuses.getFloatPercentAll(ModType.MeleeDamageModifier, SourceType.NONE);
minDamage *= percentMinDamage;
maxDamage *= percentMaxDamage;
}
// set damages
if (mainHand) {
playerCharacter.minDamageHandOne = (int) minDamage;
playerCharacter.maxDamageHandOne = (int) maxDamage;
playerCharacter.speedHandOne = speed;
} else {
playerCharacter.minDamageHandTwo = (int) minDamage;
playerCharacter.maxDamageHandTwo = (int) maxDamage;
playerCharacter.speedHandTwo = speed;
}
}
/**
* @ Calculates Defense for shield
*/
private static float getShieldDefense(AbstractCharacter playerCharacter, Item shield) {
if (shield == null)
return 0;
if (ItemTemplate.isShield(shield) == false)
return 0;
ItemBase ab = shield.getItemBase();
if (ab == null)
return 0;
CharacterSkill blockSkill = playerCharacter.skills.get("Block");
float skillMod;
if (blockSkill == null) {
skillMod = 0;
} else
skillMod = blockSkill.getModifiedAmount();
float def = ab.getDefense();
//apply item defense bonuses
if (shield != null) {
def += shield.getBonus(ModType.DR, SourceType.NONE);
def *= (1 + shield.getBonusPercent(ModType.DR, SourceType.NONE));
}
// float val = ((float)ab.getDefense()) * (1 + (skillMod / 100));
return (def * (1 + ((int) skillMod / 100f)));
}
/**
* @ Calculates Defense for armor
*/
private static float getArmorDefense(AbstractCharacter playerCharacter, Item armor) {
if (armor == null)
return 0;
ItemBase ib = armor.getItemBase();
if (ib == null)
return 0;
if (!armor.template.item_type.equals(ItemType.ARMOR))
return 0;
if (armor.template.item_skill_used.isEmpty())
return ib.getDefense();
CharacterSkill armorSkill = playerCharacter.skills.get(armor.template.item_skill_used);
if (armorSkill == null) {
Logger.error("Player " + playerCharacter.getObjectUUID()
+ " has armor equipped without the nescessary skill to equip it");
return ib.getDefense();
}
float def = ib.getDefense();
//apply item defense bonuses
if (armor != null) {
def += armor.getBonus(ModType.DR, SourceType.NONE);
def *= (1 + armor.getBonusPercent(ModType.DR, SourceType.NONE));
}
return (def * (1 + ((int) armorSkill.getModifiedAmount() / 50f)));
}
/**
* @ Calculates Defense for weapon
*/
private static float getWeaponDefense(AbstractCharacter playerCharacter, ConcurrentHashMap<EquipSlotType, Item> equipped) {
Item weapon = equipped.get(EquipSlotType.RHELD);
ItemBase wb = null;
CharacterSkill skill, mastery;
float val = 0;
boolean unarmed = false;
if (weapon == null) {
weapon = equipped.get(EquipSlotType.LHELD);
if (weapon == null || ItemTemplate.isShield(weapon))
unarmed = true;
else
wb = weapon.getItemBase();
} else
wb = weapon.getItemBase();
if (wb == null)
unarmed = true;
if (unarmed) {
skill = playerCharacter.skills.get("Unarmed Combat");
mastery = playerCharacter.skills.get("Unarmed Combat Mastery");
} else {
skill = playerCharacter.skills.get(weapon.template.item_skill_used);
mastery = playerCharacter.skills.get(wb.getMastery());
}
if (skill != null)
val += (int) skill.getModifiedAmount() / 2f;
if (mastery != null)
val += (int) mastery.getModifiedAmount() / 2f;
return val;
}
//Don't call this function directly. linked from pc.calculateSkills()
//through SkillCalcJob. Designed to only run from one worker thread
public static void runSkillCalc(AbstractCharacter playerCharacter) {
try {
//see if any new skills or powers granted
CharacterSkill.calculateSkills(playerCharacter);
// calculate granted Trains in powers.
CharacterPower.grantTrains(playerCharacter);
//see if any new powers unlocked from previous check
CharacterPower.calculatePowers(playerCharacter);
} catch (Exception e) {
}
}
//calculate item bonuses here
public static void calculateItemBonuses(AbstractCharacter playerCharacter) {
if (playerCharacter.charItemManager == null || playerCharacter.bonuses == null)
return;
ConcurrentHashMap<EquipSlotType, Item> equipped = playerCharacter.charItemManager.getEquipped();
for (Item item : equipped.values()) {
ItemBase ib = item.getItemBase();
if (ib == null)
continue;
//TODO add effect bonuses in here for equipped items
}
}
/**
* @ Defaults ATR, Defense and Damage for player
*/
private static void defaultAtrAndDamage(AbstractCharacter playerCharacter, boolean mainHand) {
if (mainHand) {
playerCharacter.atrHandOne = 0;
playerCharacter.minDamageHandOne = 0;
playerCharacter.maxDamageHandOne = 0;
playerCharacter.rangeHandOne = -1;
playerCharacter.speedHandOne = 20;
} else {
playerCharacter.atrHandTwo = 0;
playerCharacter.minDamageHandTwo = 0;
playerCharacter.maxDamageHandTwo = 0;
playerCharacter.rangeHandTwo = -1;
playerCharacter.speedHandTwo = 20;
}
}
private static float getModifiedAmount(CharacterSkill skill) {
if (skill == null)
return 0f;
return skill.getModifiedAmount();
}
private void initializeCharacter() {
this.timers = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
this.timestamps = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
@@ -1850,7 +2324,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
PlayerCharacter pc = (PlayerCharacter) this;
//calculate item bonuses
pc.calculateItemBonuses();
calculateItemBonuses(pc);
//recalculate formulas
pc.recalculatePlayerStats(true);