|
|
@ -64,7 +64,7 @@ public class PlayerCharacter extends AbstractCharacter { |
|
|
|
public final ReadWriteLock respawnLock = new ReentrantReadWriteLock(true); |
|
|
|
public final ReadWriteLock respawnLock = new ReentrantReadWriteLock(true); |
|
|
|
public final ArrayList<Mob> necroPets = new ArrayList<>(); |
|
|
|
public final ArrayList<Mob> necroPets = new ArrayList<>(); |
|
|
|
private final Account account; |
|
|
|
private final Account account; |
|
|
|
private final Race race; |
|
|
|
|
|
|
|
private final byte skinColor; |
|
|
|
private final byte skinColor; |
|
|
|
private final byte hairColor; |
|
|
|
private final byte hairColor; |
|
|
|
private final byte beardColor; |
|
|
|
private final byte beardColor; |
|
|
@ -99,12 +99,7 @@ public class PlayerCharacter extends AbstractCharacter { |
|
|
|
public short statIntMin; |
|
|
|
public short statIntMin; |
|
|
|
public short statSpiMin; |
|
|
|
public short statSpiMin; |
|
|
|
// Current Stats before Equip and Effect
|
|
|
|
// Current Stats before Equip and Effect
|
|
|
|
// Modifiers
|
|
|
|
|
|
|
|
public short statStrBase; |
|
|
|
|
|
|
|
public short statDexBase; |
|
|
|
|
|
|
|
public short statConBase; |
|
|
|
|
|
|
|
public short statIntBase; |
|
|
|
|
|
|
|
public short statSpiBase; |
|
|
|
|
|
|
|
public short trainedStatPoints = 0; |
|
|
|
public short trainedStatPoints = 0; |
|
|
|
public boolean isCSR = false; |
|
|
|
public boolean isCSR = false; |
|
|
|
//TODO Public fields break OO!!!
|
|
|
|
//TODO Public fields break OO!!!
|
|
|
@ -117,8 +112,8 @@ public class PlayerCharacter extends AbstractCharacter { |
|
|
|
public float landingAltitude = 0; |
|
|
|
public float landingAltitude = 0; |
|
|
|
public int bindBuilding = 0; |
|
|
|
public int bindBuilding = 0; |
|
|
|
public FriendStatus friendStatus = FriendStatus.Available; |
|
|
|
public FriendStatus friendStatus = FriendStatus.Available; |
|
|
|
private BaseClass baseClass; |
|
|
|
|
|
|
|
private PromotionClass promotionClass; |
|
|
|
|
|
|
|
private ConcurrentHashMap<Integer, String> ignoredPlayerIDs = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); |
|
|
|
private ConcurrentHashMap<Integer, String> ignoredPlayerIDs = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); |
|
|
|
private boolean lfGroup = false; |
|
|
|
private boolean lfGroup = false; |
|
|
|
private boolean lfGuild = false; |
|
|
|
private boolean lfGuild = false; |
|
|
@ -1342,7 +1337,7 @@ public class PlayerCharacter extends AbstractCharacter { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//calculate ATR, damage and defense
|
|
|
|
//calculate ATR, damage and defense
|
|
|
|
pc.calculateAtrDefenseDamage(); |
|
|
|
AbstractCharacter.calculateAtrDefenseDamage(pc); |
|
|
|
|
|
|
|
|
|
|
|
//calculate movement bonus
|
|
|
|
//calculate movement bonus
|
|
|
|
pc.calculateSpeedMod(); |
|
|
|
pc.calculateSpeedMod(); |
|
|
@ -1369,12 +1364,6 @@ public class PlayerCharacter extends AbstractCharacter { |
|
|
|
return ab.getDexPenalty(); |
|
|
|
return ab.getDexPenalty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static float getModifiedAmount(CharacterSkill skill) { |
|
|
|
|
|
|
|
if (skill == null) |
|
|
|
|
|
|
|
return 0f; |
|
|
|
|
|
|
|
return skill.getModifiedAmount(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void InitializeSkillsOnLoad(PlayerCharacter pc) { |
|
|
|
public static void InitializeSkillsOnLoad(PlayerCharacter pc) { |
|
|
|
try { |
|
|
|
try { |
|
|
|
{ |
|
|
|
{ |
|
|
@ -2116,9 +2105,7 @@ public class PlayerCharacter extends AbstractCharacter { |
|
|
|
/** |
|
|
|
/** |
|
|
|
* @return the race |
|
|
|
* @return the race |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public Race getRace() { |
|
|
|
|
|
|
|
return race; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public int getRaceID() { |
|
|
|
public int getRaceID() { |
|
|
|
if (race != null) |
|
|
|
if (race != null) |
|
|
@ -2129,9 +2116,7 @@ public class PlayerCharacter extends AbstractCharacter { |
|
|
|
/** |
|
|
|
/** |
|
|
|
* @return the baseClass |
|
|
|
* @return the baseClass |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public BaseClass getBaseClass() { |
|
|
|
|
|
|
|
return baseClass; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public int getBaseClassID() { |
|
|
|
public int getBaseClassID() { |
|
|
|
if (baseClass != null) |
|
|
|
if (baseClass != null) |
|
|
@ -3359,7 +3344,7 @@ public class PlayerCharacter extends AbstractCharacter { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//calculate ATR, damage and defense
|
|
|
|
//calculate ATR, damage and defense
|
|
|
|
calculateAtrDefenseDamage(); |
|
|
|
calculateAtrDefenseDamage(this); |
|
|
|
|
|
|
|
|
|
|
|
//calculate movement bonus
|
|
|
|
//calculate movement bonus
|
|
|
|
calculateSpeedMod(); |
|
|
|
calculateSpeedMod(); |
|
|
@ -3779,344 +3764,6 @@ public class PlayerCharacter extends AbstractCharacter { |
|
|
|
this.follow = false; |
|
|
|
this.follow = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* @ Calculates Atr (both hands) Defense, and Damage for pc |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public void calculateAtrDefenseDamage() { |
|
|
|
|
|
|
|
if (this.charItemManager == null || this.charItemManager.getEquipped() == null || this.skills == null) { |
|
|
|
|
|
|
|
Logger.error("Player " + this.getObjectUUID() + " missing skills or equipment"); |
|
|
|
|
|
|
|
defaultAtrAndDamage(true); |
|
|
|
|
|
|
|
defaultAtrAndDamage(false); |
|
|
|
|
|
|
|
this.defenseRating = 0; |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ConcurrentHashMap<EquipSlotType, Item> equipped = this.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(equipped.get(EquipSlotType.RHELD), true, equipped.get(EquipSlotType.RHELD)); |
|
|
|
|
|
|
|
calculateAtrDamageForWeapon(equipped.get(EquipSlotType.LHELD), false, equipped.get(EquipSlotType.LHELD)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// No Defense while in DeathShroud
|
|
|
|
|
|
|
|
if (this.effects != null && this.effects.containsKey("DeathShroud")) |
|
|
|
|
|
|
|
this.defenseRating = (short) 0; |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
// calculate defense for equipment
|
|
|
|
|
|
|
|
float defense = this.statDexCurrent * 2; |
|
|
|
|
|
|
|
defense += getShieldDefense(equipped.get(EquipSlotType.LHELD)); |
|
|
|
|
|
|
|
defense += getArmorDefense(equipped.get(EquipSlotType.HELM)); |
|
|
|
|
|
|
|
defense += getArmorDefense(equipped.get(EquipSlotType.CHEST)); |
|
|
|
|
|
|
|
defense += getArmorDefense(equipped.get(EquipSlotType.UPARM)); |
|
|
|
|
|
|
|
defense += getArmorDefense(equipped.get(EquipSlotType.HANDS)); |
|
|
|
|
|
|
|
defense += getArmorDefense(equipped.get(EquipSlotType.LEGS)); |
|
|
|
|
|
|
|
defense += getArmorDefense(equipped.get(EquipSlotType.FEET)); |
|
|
|
|
|
|
|
defense += getWeaponDefense(equipped); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this.bonuses != null) { |
|
|
|
|
|
|
|
// add any bonuses
|
|
|
|
|
|
|
|
defense += (short) this.bonuses.getFloat(ModType.DCV, SourceType.NONE); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Finally multiply any percent modifiers. DO THIS LAST!
|
|
|
|
|
|
|
|
float pos_Bonus = this.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 = this.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; |
|
|
|
|
|
|
|
this.defenseRating = (short) (defense + 0.5f); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* @ Calculates Atr, and Damage for each weapon |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private void calculateAtrDamageForWeapon(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(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 = this.charItemManager.getEquipped().get(EquipSlotType.LHELD); |
|
|
|
|
|
|
|
if (off != null && off.getItemBase() != null && off.template.item_type.equals(ItemType.WEAPON)) |
|
|
|
|
|
|
|
this.rangeHandOne = 10 * (1 + (this.statStrBase / 600)); // Set
|
|
|
|
|
|
|
|
// to
|
|
|
|
|
|
|
|
// no
|
|
|
|
|
|
|
|
// weapon
|
|
|
|
|
|
|
|
// range
|
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
this.rangeHandOne = -1; // set to do not attack
|
|
|
|
|
|
|
|
} else |
|
|
|
|
|
|
|
this.rangeHandTwo = -1; // set to do not attack
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
skillPercentage = getModifiedAmount(this.skills.get("Unarmed Combat")); |
|
|
|
|
|
|
|
masteryPercentage = getModifiedAmount(this.skills.get("Unarmed Combat Mastery")); |
|
|
|
|
|
|
|
if (masteryPercentage == 0f) |
|
|
|
|
|
|
|
mastDam = CharacterSkill.getQuickMastery(this, "Unarmed Combat Mastery"); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
mastDam = masteryPercentage; |
|
|
|
|
|
|
|
// TODO Correct these
|
|
|
|
|
|
|
|
min = 1; |
|
|
|
|
|
|
|
max = 3; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
if (mainHand) |
|
|
|
|
|
|
|
this.rangeHandOne = weapon.getItemBase().getRange() * (1 + (this.statStrBase / 600)); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
this.rangeHandTwo = weapon.getItemBase().getRange() * (1 + (this.statStrBase / 600)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this.bonuses != null) { |
|
|
|
|
|
|
|
float range_bonus = 1 + this.bonuses.getFloatPercentAll(ModType.WeaponRange, SourceType.NONE); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (mainHand) |
|
|
|
|
|
|
|
this.rangeHandOne *= range_bonus; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
this.rangeHandTwo *= range_bonus; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
skillPercentage = getModifiedAmount(this.skills.get(weapon.template.item_skill_used)); |
|
|
|
|
|
|
|
masteryPercentage = getModifiedAmount(this.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 (this.effects != null && this.effects.containsKey("DeathShroud")) |
|
|
|
|
|
|
|
// No Atr in deathshroud.
|
|
|
|
|
|
|
|
if (mainHand) |
|
|
|
|
|
|
|
this.atrHandOne = (short) 0; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
this.atrHandTwo = (short) 0; |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
// calculate atr
|
|
|
|
|
|
|
|
float atr = 0; |
|
|
|
|
|
|
|
atr += (int) skillPercentage * 4f; //<-round down skill% -
|
|
|
|
|
|
|
|
atr += (int) masteryPercentage * 3f; |
|
|
|
|
|
|
|
if (this.statStrCurrent > this.statDexCurrent) |
|
|
|
|
|
|
|
atr += statStrCurrent / 2; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
atr += statDexCurrent / 2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// add in any bonuses to atr
|
|
|
|
|
|
|
|
if (this.bonuses != null) { |
|
|
|
|
|
|
|
// Add any base bonuses
|
|
|
|
|
|
|
|
atr += this.bonuses.getFloat(ModType.OCV, SourceType.NONE); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Finally use any multipliers. DO THIS LAST!
|
|
|
|
|
|
|
|
float pos_Bonus = (1 + this.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 = this.bonuses.getFloatPercentNegative(ModType.OCV, SourceType.NONE); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
atr *= (1 + neg_Bonus); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
atr = (atr < 1) ? 1 : atr; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// set atr
|
|
|
|
|
|
|
|
if (mainHand) |
|
|
|
|
|
|
|
this.atrHandOne = (short) (atr + 0.5f); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
this.atrHandTwo = (short) (atr + 0.5f); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//calculate speed
|
|
|
|
|
|
|
|
if (wb != null) |
|
|
|
|
|
|
|
speed = wb.getSpeed(); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
speed = 20f; //unarmed attack speed
|
|
|
|
|
|
|
|
if (weapon != null) |
|
|
|
|
|
|
|
speed *= (1 + this.bonuses.getFloatPercentAll(ModType.WeaponSpeed, SourceType.NONE)); |
|
|
|
|
|
|
|
speed *= (1 + this.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) this.statStrCurrent : (float) this.statDexCurrent; |
|
|
|
|
|
|
|
float sec = (strBased) ? (float) this.statDexCurrent : (float) this.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 (this.effects != null && this.effects.containsKey("DeathShroud")) { |
|
|
|
|
|
|
|
minDamage *= 0.5f; |
|
|
|
|
|
|
|
maxDamage *= 0.5f; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// add in any bonuses to damage
|
|
|
|
|
|
|
|
if (this.bonuses != null) { |
|
|
|
|
|
|
|
// Add any base bonuses
|
|
|
|
|
|
|
|
minDamage += this.bonuses.getFloat(ModType.MinDamage, SourceType.NONE); |
|
|
|
|
|
|
|
maxDamage += this.bonuses.getFloat(ModType.MaxDamage, SourceType.NONE); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
minDamage += this.bonuses.getFloat(ModType.MeleeDamageModifier, SourceType.NONE); |
|
|
|
|
|
|
|
maxDamage += this.bonuses.getFloat(ModType.MeleeDamageModifier, SourceType.NONE); |
|
|
|
|
|
|
|
// Finally use any multipliers. DO THIS LAST!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float percentMinDamage = 1; |
|
|
|
|
|
|
|
float percentMaxDamage = 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
percentMinDamage += this.bonuses.getFloatPercentAll(ModType.MinDamage, SourceType.NONE); |
|
|
|
|
|
|
|
percentMinDamage += this.bonuses.getFloatPercentAll(ModType.MeleeDamageModifier, SourceType.NONE); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
percentMaxDamage += this.bonuses.getFloatPercentAll(ModType.MaxDamage, SourceType.NONE); |
|
|
|
|
|
|
|
percentMaxDamage += this.bonuses.getFloatPercentAll(ModType.MeleeDamageModifier, SourceType.NONE); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
minDamage *= percentMinDamage; |
|
|
|
|
|
|
|
maxDamage *= percentMaxDamage; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// set damages
|
|
|
|
|
|
|
|
if (mainHand) { |
|
|
|
|
|
|
|
this.minDamageHandOne = (int) minDamage; |
|
|
|
|
|
|
|
this.maxDamageHandOne = (int) maxDamage; |
|
|
|
|
|
|
|
this.speedHandOne = speed; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
this.minDamageHandTwo = (int) minDamage; |
|
|
|
|
|
|
|
this.maxDamageHandTwo = (int) maxDamage; |
|
|
|
|
|
|
|
this.speedHandTwo = speed; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* @ Calculates Defense for shield |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private float getShieldDefense(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 = this.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))); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void setPassives() { |
|
|
|
public void setPassives() { |
|
|
|
if (this.bonuses != null) { |
|
|
|
if (this.bonuses != null) { |
|
|
|
ConcurrentHashMap<EquipSlotType, Item> equipped = this.charItemManager.getEquipped(); |
|
|
|
ConcurrentHashMap<EquipSlotType, Item> equipped = this.charItemManager.getEquipped(); |
|
|
@ -4153,134 +3800,15 @@ public class PlayerCharacter extends AbstractCharacter { |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* @ Calculates Defense for armor |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private float getArmorDefense(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 = this.skills.get(armor.template.item_skill_used); |
|
|
|
|
|
|
|
if (armorSkill == null) { |
|
|
|
|
|
|
|
Logger.error("Player " + this.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 float getWeaponDefense(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 = this.skills.get("Unarmed Combat"); |
|
|
|
|
|
|
|
mastery = this.skills.get("Unarmed Combat Mastery"); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
skill = this.skills.get(weapon.template.item_skill_used); |
|
|
|
|
|
|
|
mastery = this.skills.get(wb.getMastery()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (skill != null) |
|
|
|
|
|
|
|
val += (int) skill.getModifiedAmount() / 2f; |
|
|
|
|
|
|
|
if (mastery != null) |
|
|
|
|
|
|
|
val += (int) mastery.getModifiedAmount() / 2f; |
|
|
|
|
|
|
|
return val; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Call this function to recalculate granted skills and powers for player
|
|
|
|
//Call this function to recalculate granted skills and powers for player
|
|
|
|
public synchronized void calculateSkills() { |
|
|
|
public synchronized void calculateSkills() { |
|
|
|
//tell the player to applyBonuses because something has changed
|
|
|
|
//tell the player to applyBonuses because something has changed
|
|
|
|
|
|
|
|
|
|
|
|
runSkillCalc(); |
|
|
|
AbstractCharacter.runSkillCalc(this); |
|
|
|
|
|
|
|
|
|
|
|
//start running the skill/power calculations
|
|
|
|
//start running the skill/power calculations
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//Don't call this function directly. linked from pc.calculateSkills()
|
|
|
|
|
|
|
|
//through SkillCalcJob. Designed to only run from one worker thread
|
|
|
|
|
|
|
|
public void runSkillCalc() { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//see if any new skills or powers granted
|
|
|
|
|
|
|
|
CharacterSkill.calculateSkills(this); |
|
|
|
|
|
|
|
// calculate granted Trains in powers.
|
|
|
|
|
|
|
|
CharacterPower.grantTrains(this); |
|
|
|
|
|
|
|
//see if any new powers unlocked from previous check
|
|
|
|
|
|
|
|
CharacterPower.calculatePowers(this); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//calculate item bonuses here
|
|
|
|
|
|
|
|
public void calculateItemBonuses() { |
|
|
|
|
|
|
|
if (this.charItemManager == null || this.bonuses == null) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
ConcurrentHashMap<EquipSlotType, Item> equipped = this.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 void defaultAtrAndDamage(boolean mainHand) { |
|
|
|
|
|
|
|
if (mainHand) { |
|
|
|
|
|
|
|
this.atrHandOne = 0; |
|
|
|
|
|
|
|
this.minDamageHandOne = 0; |
|
|
|
|
|
|
|
this.maxDamageHandOne = 0; |
|
|
|
|
|
|
|
this.rangeHandOne = -1; |
|
|
|
|
|
|
|
this.speedHandOne = 20; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
this.atrHandTwo = 0; |
|
|
|
|
|
|
|
this.minDamageHandTwo = 0; |
|
|
|
|
|
|
|
this.maxDamageHandTwo = 0; |
|
|
|
|
|
|
|
this.rangeHandTwo = -1; |
|
|
|
|
|
|
|
this.speedHandTwo = 20; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void calculateMaxHealthManaStamina() { |
|
|
|
public void calculateMaxHealthManaStamina() { |
|
|
|
float h = 1f; |
|
|
|
float h = 1f; |
|
|
|
float m = 0f; |
|
|
|
float m = 0f; |
|
|
@ -4431,36 +3959,6 @@ public class PlayerCharacter extends AbstractCharacter { |
|
|
|
return (amount - attackerLevel + this.getLevel()) / 4; |
|
|
|
return (amount - attackerLevel + this.getLevel()) / 4; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public float getPassiveChance1(ModType modType, SourceType sourceType, int attackerLevel, boolean fromCombat) { |
|
|
|
|
|
|
|
if (this.skills == null || this.bonuses == null) |
|
|
|
|
|
|
|
return 0f; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// must be allowed to use this passive
|
|
|
|
|
|
|
|
if (!this.bonuses.getBool(modType, sourceType)) |
|
|
|
|
|
|
|
return 0f; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// must not be stunned
|
|
|
|
|
|
|
|
if (this.bonuses.getBool(ModType.Stunned, SourceType.NONE)) |
|
|
|
|
|
|
|
return 0f; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get base skill amount
|
|
|
|
|
|
|
|
CharacterSkill sk = this.skills.get(sourceType.name()); |
|
|
|
|
|
|
|
float amount; |
|
|
|
|
|
|
|
if (sk == null) |
|
|
|
|
|
|
|
amount = CharacterSkill.getQuickMastery(this, modType.name()); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
amount = sk.getModifiedAmount(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add bonuses
|
|
|
|
|
|
|
|
amount += this.bonuses.getFloat(modType, sourceType); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add item bonuses and return
|
|
|
|
|
|
|
|
if (sourceType.equals(SourceType.DODGE) && !fromCombat) |
|
|
|
|
|
|
|
return ((amount / 4) - attackerLevel + this.getLevel()) / 4; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
return (amount - attackerLevel + this.getLevel()) / 4; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public float getRegenModifier(ModType type) { |
|
|
|
public float getRegenModifier(ModType type) { |
|
|
|
float regen = 1f; |
|
|
|
float regen = 1f; |
|
|
|
|
|
|
|
|
|
|
@ -4475,40 +3973,6 @@ public class PlayerCharacter extends AbstractCharacter { |
|
|
|
return !this.isAlive(); |
|
|
|
return !this.isAlive(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void ResetLevel(short targetLevel) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (targetLevel > 13) { |
|
|
|
|
|
|
|
ChatManager.chatSystemError(this, "Please choose a level between 1 and 13."); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
this.promotionClass = null; |
|
|
|
|
|
|
|
if (targetLevel > 10) { |
|
|
|
|
|
|
|
this.level = 10; |
|
|
|
|
|
|
|
this.exp = Experience.getBaseExperience(11); |
|
|
|
|
|
|
|
int maxEXP = Experience.getBaseExperience(targetLevel); //target level exp;
|
|
|
|
|
|
|
|
this.overFlowEXP = maxEXP - this.exp; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
this.level = targetLevel; |
|
|
|
|
|
|
|
this.exp = Experience.getBaseExperience(level); |
|
|
|
|
|
|
|
this.overFlowEXP = 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (CharacterSkill skill : this.getSkills().values()) { |
|
|
|
|
|
|
|
skill.reset(this, true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (CharacterPower power : this.getPowers().values()) { |
|
|
|
|
|
|
|
power.reset(this); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.recalculatePlayerStats(initialized); |
|
|
|
|
|
|
|
this.recalculate(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ChatManager.chatSystemInfo(this, "Character reset to " + targetLevel + ". All training points have been refunded. Relog to update changes on client."); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void removeFromCache() { |
|
|
|
public void removeFromCache() { |
|
|
|
Logger.info("Removing " + this.getName() + " from Object Cache."); |
|
|
|
Logger.info("Removing " + this.getName() + " from Object Cache."); |
|
|
@ -4545,10 +4009,6 @@ public class PlayerCharacter extends AbstractCharacter { |
|
|
|
super.removeFromCache(); |
|
|
|
super.removeFromCache(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void storeIgnoreListDB() { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void updateSkillsAndPowersToDatabase() { |
|
|
|
public void updateSkillsAndPowersToDatabase() { |
|
|
|
if (this.skills != null) |
|
|
|
if (this.skills != null) |
|
|
|
for (CharacterSkill skill : this.skills.values()) { |
|
|
|
for (CharacterSkill skill : this.skills.values()) { |
|
|
@ -4572,11 +4032,11 @@ public class PlayerCharacter extends AbstractCharacter { |
|
|
|
this.setBounds(playerBounds); |
|
|
|
this.setBounds(playerBounds); |
|
|
|
|
|
|
|
|
|
|
|
//assign enum values for restrictions
|
|
|
|
//assign enum values for restrictions
|
|
|
|
String race = this.getRace().getName().replace("-", "").replace(", Male", "").replace(", Female", ""); |
|
|
|
String race = this.race.getName().replace("-", "").replace(", Male", "").replace(", Female", ""); |
|
|
|
this.absRace = Enum.MonsterType.valueOf(race); |
|
|
|
this.absRace = Enum.MonsterType.valueOf(race); |
|
|
|
|
|
|
|
|
|
|
|
if (this.baseClass != null) |
|
|
|
if (this.baseClass != null) |
|
|
|
this.absBaseClass = ClassType.valueOf(this.getBaseClass().getName()); |
|
|
|
this.absBaseClass = ClassType.valueOf(this.baseClass.getName()); |
|
|
|
|
|
|
|
|
|
|
|
if (this.promotionClass != null) |
|
|
|
if (this.promotionClass != null) |
|
|
|
this.absPromotionClass = ClassType.valueOf(this.getPromotionClass().getName()); |
|
|
|
this.absPromotionClass = ClassType.valueOf(this.getPromotionClass().getName()); |
|
|
|