Browse Source

rentrant lock on combat

combat-3
FatBoy-DOTC 5 months ago
parent
commit
cf58e7b984
  1. 518
      src/engine/gameManager/CombatManager.java
  2. 1
      src/engine/objects/AbstractWorldObject.java

518
src/engine/gameManager/CombatManager.java

@ -12,7 +12,6 @@ import engine.job.JobContainer;
import engine.job.JobScheduler; import engine.job.JobScheduler;
import engine.jobs.AttackJob; import engine.jobs.AttackJob;
import engine.jobs.DeferredPowerJob; import engine.jobs.DeferredPowerJob;
import engine.math.Vector3f;
import engine.mbEnums; import engine.mbEnums;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.msg.TargetedActionMsg; import engine.net.client.msg.TargetedActionMsg;
@ -119,361 +118,360 @@ public enum CombatManager {
public static void processAttack(AbstractCharacter attacker, AbstractWorldObject target, mbEnums.EquipSlotType slot) { public static void processAttack(AbstractCharacter attacker, AbstractWorldObject target, mbEnums.EquipSlotType slot) {
if(slot == null || target == null || attacker == null) if (slot == null || target == null || attacker == null)
return; return;
if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) { if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) {
if (!attacker.isCombat()) if (!attacker.isCombat())
return; return;
//check if this slot is on attack timer, if timer has passed clear it, else early exit
if(attacker.getTimers() != null && attacker.getTimers().containsKey("Attack"+slot.name()))
if(attacker.getTimers().get("Attack"+slot.name()).timeToExecutionLeft() <= 0)
attacker.getTimers().remove("Attack"+slot.name());
else
return;
} }
target.combatLock.writeLock().lock();
// check if character is in range to attack target // check if character is in range to attack target
try {
PlayerBonuses bonus = attacker.getBonuses();
PlayerBonuses bonus = attacker.getBonuses(); float rangeMod = 1.0f;
float attackRange = MBServerStatics.NO_WEAPON_RANGE;
float rangeMod = 1.0f;
float attackRange = MBServerStatics.NO_WEAPON_RANGE;
Item weapon = attacker.charItemManager.getEquipped(slot); Item weapon = attacker.charItemManager.getEquipped(slot);
if (weapon != null) { if (weapon != null) {
if (bonus != null) if (bonus != null)
rangeMod += bonus.getFloatPercentAll(mbEnums.ModType.WeaponRange, mbEnums.SourceType.None); rangeMod += bonus.getFloatPercentAll(mbEnums.ModType.WeaponRange, mbEnums.SourceType.None);
attackRange += weapon.template.item_weapon_max_range * rangeMod; attackRange += weapon.template.item_weapon_max_range * rangeMod;
} }
if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob))
if (((Mob) attacker).isSiege()) if (((Mob) attacker).isSiege())
attackRange = 300; attackRange = 300;
float distanceSquared = attacker.loc.distanceSquared(target.loc); float distanceSquared = attacker.loc.distanceSquared(target.loc);
boolean inRange = false; boolean inRange = false;
if (AbstractCharacter.IsAbstractCharacter(target)) { if (AbstractCharacter.IsAbstractCharacter(target)) {
attackRange += ((AbstractCharacter)target).calcHitBox(); attackRange += ((AbstractCharacter) target).calcHitBox();
} else { } else {
} }
if(attackRange > 15 && attacker.isMoving()){ if (attackRange > 15 && attacker.isMoving()) {
//cannot shoot bow while moving; //cannot shoot bow while moving;
return; return;
} }
switch (target.getObjectType()) { switch (target.getObjectType()) {
case PlayerCharacter: case PlayerCharacter:
attackRange += ((PlayerCharacter) target).getCharacterHeight() * 0.5f; attackRange += ((PlayerCharacter) target).getCharacterHeight() * 0.5f;
if (distanceSquared < attackRange * attackRange) if (distanceSquared < attackRange * attackRange)
inRange = true;
break;
case Mob:
attackRange += ((AbstractCharacter) target).calcHitBox();
if (distanceSquared < attackRange * attackRange)
inRange = true;
break;
case Building:
if(attackRange > 15){
float rangeSquared = (attackRange + target.getBounds().getHalfExtents().x) * (attackRange + target.getBounds().getHalfExtents().x);
//float distanceSquared = attacker.loc.distanceSquared(target.loc);
if(distanceSquared < rangeSquared) {
inRange = true; inRange = true;
break; break;
} case Mob:
}else { attackRange += ((AbstractCharacter) target).calcHitBox();
float locX = target.loc.x - target.getBounds().getHalfExtents().x; if (distanceSquared < attackRange * attackRange)
float locZ = target.loc.z - target.getBounds().getHalfExtents().y;
float sizeX = (target.getBounds().getHalfExtents().x + attackRange) * 2;
float sizeZ = (target.getBounds().getHalfExtents().y + attackRange) * 2;
Rectangle2D.Float rect = new Rectangle2D.Float(locX, locZ, sizeX, sizeZ);
if (rect.contains(new Point2D.Float(attacker.loc.x, attacker.loc.z)))
inRange = true; inRange = true;
break; break;
} case Building:
} if (attackRange > 15) {
float rangeSquared = (attackRange + target.getBounds().getHalfExtents().x) * (attackRange + target.getBounds().getHalfExtents().x);
//float distanceSquared = attacker.loc.distanceSquared(target.loc);
if (distanceSquared < rangeSquared) {
inRange = true;
break;
}
} else {
float locX = target.loc.x - target.getBounds().getHalfExtents().x;
float locZ = target.loc.z - target.getBounds().getHalfExtents().y;
float sizeX = (target.getBounds().getHalfExtents().x + attackRange) * 2;
float sizeZ = (target.getBounds().getHalfExtents().y + attackRange) * 2;
Rectangle2D.Float rect = new Rectangle2D.Float(locX, locZ, sizeX, sizeZ);
if (rect.contains(new Point2D.Float(attacker.loc.x, attacker.loc.z)))
inRange = true;
break;
}
}
//get delay for the auto attack job //get delay for the auto attack job
long delay = 5000; long delay = 5000;
if (weapon != null) { if (weapon != null) {
int wepSpeed = (int) (weapon.template.item_weapon_wepspeed); int wepSpeed = (int) (weapon.template.item_weapon_wepspeed);
if (weapon.getBonusPercent(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None) != 0f) //add weapon speed bonus if (weapon.getBonusPercent(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None) != 0f) //add weapon speed bonus
wepSpeed *= (1 + weapon.getBonus(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None)); wepSpeed *= (1 + weapon.getBonus(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None));
if (attacker.getBonuses() != null && attacker.getBonuses().getFloatPercentAll(mbEnums.ModType.AttackDelay, mbEnums.SourceType.None) != 0f) //add effects speed bonus if (attacker.getBonuses() != null && attacker.getBonuses().getFloatPercentAll(mbEnums.ModType.AttackDelay, mbEnums.SourceType.None) != 0f) //add effects speed bonus
wepSpeed *= (1 + attacker.getBonuses().getFloatPercentAll(mbEnums.ModType.AttackDelay, mbEnums.SourceType.None)); wepSpeed *= (1 + attacker.getBonuses().getFloatPercentAll(mbEnums.ModType.AttackDelay, mbEnums.SourceType.None));
if (wepSpeed < 10) if (wepSpeed < 10)
wepSpeed = 10; //Old was 10, but it can be reached lower with legit buffs,effects. wepSpeed = 10; //Old was 10, but it can be reached lower with legit buffs,effects.
delay = wepSpeed * 100L; delay = wepSpeed * 100L;
} }
if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob))
((Mob) attacker).nextAttackTime = System.currentTimeMillis() + delay; ((Mob) attacker).nextAttackTime = System.currentTimeMillis() + delay;
if (inRange) { if (inRange) {
//handle retaliate //handle retaliate
if (AbstractCharacter.IsAbstractCharacter(target)) { if (AbstractCharacter.IsAbstractCharacter(target)) {
if (((AbstractCharacter) target).combatTarget == null || !((AbstractCharacter) target).combatTarget.isAlive()) { if (((AbstractCharacter) target).combatTarget == null || !((AbstractCharacter) target).combatTarget.isAlive()) {
((AbstractCharacter) target).combatTarget = attacker; ((AbstractCharacter) target).combatTarget = attacker;
if (target.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter) && ((AbstractCharacter) target).isCombat()) if (target.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter) && ((AbstractCharacter) target).isCombat())
combatCycle((AbstractCharacter) target, attacker); combatCycle((AbstractCharacter) target, attacker);
}
} }
}
// take stamina away from attacker if its not a mob // take stamina away from attacker if its not a mob
if (weapon != null && !attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) { if (weapon != null && !attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) {
//check if Out of Stamina //check if Out of Stamina
if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) { if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) {
if (attacker.getStamina() < (weapon.template.item_wt / 3f)) { if (attacker.getStamina() < (weapon.template.item_wt / 3f)) {
//set auto attack job //set auto attack job
setAutoAttackJob(attacker, slot, delay); setAutoAttackJob(attacker, slot, delay);
return; return;
}
} }
} float stam = weapon.template.item_wt / 3f;
float stam = weapon.template.item_wt / 3f; stam = (stam < 1) ? 1 : stam;
stam = (stam < 1) ? 1 : stam; attacker.modifyStamina(-(stam), attacker, true);
attacker.modifyStamina(-(stam), attacker, true); } else
} else attacker.modifyStamina(1, attacker, true);
attacker.modifyStamina(1, attacker, true);
//cancel things that are cancelled by an attack //cancel things that are cancelled by an attack
attacker.cancelOnAttackSwing(); attacker.cancelOnAttackSwing();
//declare relevant variables //declare relevant variables
int min = attacker.minDamageHandOne; int min = attacker.minDamageHandOne;
int max = attacker.maxDamageHandOne; int max = attacker.maxDamageHandOne;
int atr = attacker.atrHandOne; int atr = attacker.atrHandOne;
//get the proper stats based on which slot is attacking //get the proper stats based on which slot is attacking
if (slot == mbEnums.EquipSlotType.LHELD) { if (slot == mbEnums.EquipSlotType.LHELD) {
min = attacker.minDamageHandTwo; min = attacker.minDamageHandTwo;
max = attacker.maxDamageHandTwo; max = attacker.maxDamageHandTwo;
atr = attacker.atrHandTwo; atr = attacker.atrHandTwo;
} }
//apply weapon powers before early exit for miss or passives //apply weapon powers before early exit for miss or passives
DeferredPowerJob dpj = null; DeferredPowerJob dpj = null;
if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) { if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) {
dpj = ((PlayerCharacter) attacker).getWeaponPower(); dpj = ((PlayerCharacter) attacker).getWeaponPower();
if (dpj != null) { if (dpj != null) {
dpj.attack(target, attackRange); dpj.attack(target, attackRange);
if (dpj.getPower() != null && (dpj.getPowerToken() == -1851459567 || dpj.getPowerToken() == -1851489518)) if (dpj.getPower() != null && (dpj.getPowerToken() == -1851459567 || dpj.getPowerToken() == -1851489518))
((PlayerCharacter) attacker).setWeaponPower(dpj); ((PlayerCharacter) attacker).setWeaponPower(dpj);
}
} }
}
int def = 0; int def = 0;
if (AbstractCharacter.IsAbstractCharacter(target)) if (AbstractCharacter.IsAbstractCharacter(target))
def = ((AbstractCharacter) target).defenseRating; def = ((AbstractCharacter) target).defenseRating;
//calculate hit chance based off ATR and DEF //calculate hit chance based off ATR and DEF
int hitChance; int hitChance;
if (def == 0) if (def == 0)
def = 1; def = 1;
float dif = atr * 1f / def; float dif = atr * 1f / def;
if (dif <= 0.8f) if (dif <= 0.8f)
hitChance = 4; hitChance = 4;
else else
hitChance = ((int) (450 * (dif - 0.8f)) + 4); hitChance = ((int) (450 * (dif - 0.8f)) + 4);
if (target.getObjectType() == mbEnums.GameObjectType.Building) if (target.getObjectType() == mbEnums.GameObjectType.Building)
hitChance = 100; hitChance = 100;
int passiveAnim = getPassiveAnimation(mbEnums.PassiveType.None); // checking for a miss due to ATR vs Def int passiveAnim = getPassiveAnimation(mbEnums.PassiveType.None); // checking for a miss due to ATR vs Def
if (ThreadLocalRandom.current().nextInt(100) > hitChance) { if (ThreadLocalRandom.current().nextInt(100) > hitChance) {
TargetedActionMsg msg = new TargetedActionMsg(attacker, target, 0f, passiveAnim); TargetedActionMsg msg = new TargetedActionMsg(attacker, target, 0f, passiveAnim);
if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter) if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter)
DispatchManager.dispatchMsgToInterestArea(target, msg, mbEnums.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); DispatchManager.dispatchMsgToInterestArea(target, msg, mbEnums.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
else else
DispatchManager.sendToAllInRange(attacker, msg); DispatchManager.sendToAllInRange(attacker, msg);
//we need to send the animation even if the attacker misses //we need to send the animation even if the attacker misses
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon.template,null,slot)); TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon.template, null, slot));
DispatchManager.sendToAllInRange(target, cmm); DispatchManager.sendToAllInRange(target, cmm);
//set auto attack job //set auto attack job
setAutoAttackJob(attacker, slot, delay); setAutoAttackJob(attacker, slot, delay);
return; return;
} }
//calculate passive chances only if target is AbstractCharacter //calculate passive chances only if target is AbstractCharacter
if (EnumSet.of(mbEnums.GameObjectType.PlayerCharacter, mbEnums.GameObjectType.NPC, mbEnums.GameObjectType.Mob).contains(target.getObjectType())) { if (EnumSet.of(mbEnums.GameObjectType.PlayerCharacter, mbEnums.GameObjectType.NPC, mbEnums.GameObjectType.Mob).contains(target.getObjectType())) {
mbEnums.PassiveType passiveType = mbEnums.PassiveType.None; mbEnums.PassiveType passiveType = mbEnums.PassiveType.None;
int hitRoll = ThreadLocalRandom.current().nextInt(100); int hitRoll = ThreadLocalRandom.current().nextInt(100);
float dodgeChance = ((AbstractCharacter) target).getPassiveChance("Dodge", attacker.getLevel(), true); float dodgeChance = ((AbstractCharacter) target).getPassiveChance("Dodge", attacker.getLevel(), true);
float blockChance = ((AbstractCharacter) target).getPassiveChance("Block", attacker.getLevel(), true); float blockChance = ((AbstractCharacter) target).getPassiveChance("Block", attacker.getLevel(), true);
float parryChance = ((AbstractCharacter) target).getPassiveChance("Parry", attacker.getLevel(), true); float parryChance = ((AbstractCharacter) target).getPassiveChance("Parry", attacker.getLevel(), true);
// Passive chance clamped at 75 // Passive chance clamped at 75
dodgeChance = Math.max(0, Math.min(75, dodgeChance)); dodgeChance = Math.max(0, Math.min(75, dodgeChance));
blockChance = Math.max(0, Math.min(75, blockChance)); blockChance = Math.max(0, Math.min(75, blockChance));
parryChance = Math.max(0, Math.min(75, parryChance)); parryChance = Math.max(0, Math.min(75, parryChance));
if (hitRoll < dodgeChance) if (hitRoll < dodgeChance)
passiveType = mbEnums.PassiveType.Dodge; passiveType = mbEnums.PassiveType.Dodge;
else if (hitRoll < blockChance) else if (hitRoll < blockChance)
passiveType = mbEnums.PassiveType.Block; passiveType = mbEnums.PassiveType.Block;
else if (hitRoll < parryChance) else if (hitRoll < parryChance)
passiveType = mbEnums.PassiveType.Parry; passiveType = mbEnums.PassiveType.Parry;
if (!passiveType.equals(mbEnums.PassiveType.None)) { if (!passiveType.equals(mbEnums.PassiveType.None)) {
passiveAnim = getPassiveAnimation(passiveType); passiveAnim = getPassiveAnimation(passiveType);
TargetedActionMsg msg = new TargetedActionMsg(attacker, passiveAnim, target, passiveType.value); TargetedActionMsg msg = new TargetedActionMsg(attacker, passiveAnim, target, passiveType.value);
if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter) if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter)
DispatchManager.dispatchMsgToInterestArea(target, msg, mbEnums.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); DispatchManager.dispatchMsgToInterestArea(target, msg, mbEnums.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
//we need to send the animation even if the attacker misses //we need to send the animation even if the attacker misses
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon.template,null,slot)); TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon.template, null, slot));
DispatchManager.sendToAllInRange(target, cmm); DispatchManager.sendToAllInRange(target, cmm);
//set auto attack job
setAutoAttackJob(attacker, slot, delay);
return;
}
}
//calculate the base damage
int damage = ThreadLocalRandom.current().nextInt(min, max + 1);
if (damage == 0) {
//set auto attack job //set auto attack job
setAutoAttackJob(attacker, slot, delay); setAutoAttackJob(attacker, slot, delay);
return; return;
} }
} if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob) && ((Mob) attacker).isPet())
calculatePetDamage(attacker);
//calculate the base damage //get the damage type
int damage = ThreadLocalRandom.current().nextInt(min, max + 1);
if (damage == 0) {
//set auto attack job
setAutoAttackJob(attacker, slot, delay);
return;
}
if(attacker.getObjectType().equals(mbEnums.GameObjectType.Mob) && ((Mob)attacker).isPet())
calculatePetDamage(attacker);
//get the damage type mbEnums.DamageType damageType;
mbEnums.DamageType damageType; if (attacker.charItemManager.getEquipped().get(slot) == null) {
damageType = mbEnums.DamageType.CRUSHING;
if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob))
if (((Mob) attacker).isSiege())
damageType = mbEnums.DamageType.SIEGE;
} else {
damageType = (mbEnums.DamageType) attacker.charItemManager.getEquipped().get(slot).template.item_weapon_damage.keySet().toArray()[0];
}
if (attacker.charItemManager.getEquipped().get(slot) == null) { //get resists
damageType = mbEnums.DamageType.CRUSHING;
if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob))
if (((Mob) attacker).isSiege())
damageType = mbEnums.DamageType.SIEGE;
} else {
damageType = (mbEnums.DamageType) attacker.charItemManager.getEquipped().get(slot).template.item_weapon_damage.keySet().toArray()[0];
}
//get resists Resists resists;
Resists resists; if (!AbstractCharacter.IsAbstractCharacter(target))
resists = ((Building) target).getResists(); //this is a building
else
resists = ((AbstractCharacter) target).getResists(); //this is a character
if (!AbstractCharacter.IsAbstractCharacter(target)) if (AbstractCharacter.IsAbstractCharacter(target)) {
resists = ((Building) target).getResists(); //this is a building AbstractCharacter absTarget = (AbstractCharacter) target;
else
resists = ((AbstractCharacter) target).getResists(); //this is a character
if (AbstractCharacter.IsAbstractCharacter(target)) { //check damage shields
AbstractCharacter absTarget = (AbstractCharacter) target;
//check damage shields PlayerBonuses bonuses = absTarget.getBonuses();
PlayerBonuses bonuses = absTarget.getBonuses(); if (bonuses != null) {
if (bonuses != null) { ConcurrentHashMap<AbstractEffectModifier, DamageShield> damageShields = bonuses.getDamageShields();
float total = 0;
ConcurrentHashMap<AbstractEffectModifier, DamageShield> damageShields = bonuses.getDamageShields(); for (DamageShield ds : damageShields.values()) {
float total = 0;
for (DamageShield ds : damageShields.values()) { //get amount to damage back
//get amount to damage back float amount;
float amount; if (ds.usePercent())
amount = damage * ds.getAmount() / 100;
else
amount = ds.getAmount();
if (ds.usePercent()) //get resisted damage for damagetype
amount = damage * ds.getAmount() / 100;
else
amount = ds.getAmount();
//get resisted damage for damagetype if (resists != null)
amount = resists.getResistedDamage(absTarget, attacker, ds.getDamageType(), amount, 0);
total += amount;
}
if (resists != null) if (total > 0) {
amount = resists.getResistedDamage(absTarget, attacker, ds.getDamageType(), amount, 0); //apply Damage back
total += amount; attacker.modifyHealth(-total, absTarget, true);
TargetedActionMsg cmm = new TargetedActionMsg(attacker, attacker, total, 0);
DispatchManager.sendToAllInRange(target, cmm);
}
} }
if (total > 0) { if (resists != null) {
//apply Damage back
attacker.modifyHealth(-total, absTarget, true);
TargetedActionMsg cmm = new TargetedActionMsg(attacker, attacker, total, 0);
DispatchManager.sendToAllInRange(target, cmm);
}
}
if (resists != null) { //check for damage type immunities
//check for damage type immunities if (resists.immuneTo(damageType)) {
//set auto attack job
//we need to send the animation even if the attacker misses
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon.template, null, slot));
DispatchManager.sendToAllInRange(target, cmm);
setAutoAttackJob(attacker, slot, delay);
return;
}
//calculate resisted damage including fortitude
if (resists.immuneTo(damageType)) { damage = (int) resists.getResistedDamage(attacker, (AbstractCharacter) target, damageType, damage, 0);
//set auto attack job
//we need to send the animation even if the attacker misses
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon.template,null,slot));
DispatchManager.sendToAllInRange(target, cmm);
setAutoAttackJob(attacker, slot, delay);
return;
} }
//calculate resisted damage including fortitude
damage = (int) resists.getResistedDamage(attacker, (AbstractCharacter) target, damageType, damage, 0);
} }
}
//remove damage from target health //remove damage from target health
if (damage > 0) { if (damage > 0) {
if (AbstractCharacter.IsAbstractCharacter(target)) if (AbstractCharacter.IsAbstractCharacter(target))
((AbstractCharacter) target).modifyHealth(-damage, attacker, true); ((AbstractCharacter) target).modifyHealth(-damage, attacker, true);
else else
((Building) target).modifyHealth(-damage, attacker); ((Building) target).modifyHealth(-damage, attacker);
int attackAnim = getSwingAnimation(null, null, slot); int attackAnim = getSwingAnimation(null, null, slot);
if (attacker.charItemManager.getEquipped().get(slot) != null) { if (attacker.charItemManager.getEquipped().get(slot) != null) {
if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) { if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) {
DeferredPowerJob weaponPower = ((PlayerCharacter) attacker).getWeaponPower(); DeferredPowerJob weaponPower = ((PlayerCharacter) attacker).getWeaponPower();
attackAnim = getSwingAnimation(weapon.template, weaponPower, slot); attackAnim = getSwingAnimation(weapon.template, weaponPower, slot);
} else { } else {
attackAnim = getSwingAnimation(weapon.template, null, slot); attackAnim = getSwingAnimation(weapon.template, null, slot);
}
} }
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) damage, attackAnim);
DispatchManager.sendToAllInRange(target, cmm);
} }
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) damage, attackAnim);
DispatchManager.sendToAllInRange(target, cmm);
} }
}
//set auto attack job
setAutoAttackJob(attacker, slot, delay);
//set auto attack job
setAutoAttackJob(attacker, slot, delay);
} catch (Exception ex) {
cancelAutoAttackJob(attacker,slot);
//Logger.error("COMBAT CAUGHT ERROR: " + ex.getMessage());
} finally {
target.combatLock.writeLock().unlock();
}
} }
public static void toggleCombat(boolean toggle, ClientConnection origin) { public static void toggleCombat(boolean toggle, ClientConnection origin) {
@ -624,7 +622,20 @@ public enum CombatManager {
Logger.error("Unable to find Timers for Character " + attacker.getObjectUUID()); Logger.error("Unable to find Timers for Character " + attacker.getObjectUUID());
} }
public static int calculatePetDamage(AbstractCharacter agent) { public static void cancelAutoAttackJob(AbstractCharacter attacker, mbEnums.EquipSlotType slot) {
attacker.getTimestamps().put("Attack" + slot.name(), System.currentTimeMillis());
//handle auto attack job creation
ConcurrentHashMap<String, JobContainer> timers = attacker.getTimers();
if (timers != null) {
timers.get("Attack" + slot.name()).cancelJob();
} else
Logger.error("Unable to find Timers for Character " + attacker.getObjectUUID());
}
public static void calculatePetDamage(AbstractCharacter agent) {
//damage calc for pet //damage calc for pet
float range; float range;
float damage; float damage;
@ -636,7 +647,6 @@ public enum CombatManager {
dmgMultiplier += agent.getLevel() * 0.1f; dmgMultiplier += agent.getLevel() * 0.1f;
range = (float) (maxDmg - minDmg); range = (float) (maxDmg - minDmg);
damage = min + ((ThreadLocalRandom.current().nextFloat() * range) + (ThreadLocalRandom.current().nextFloat() * range)) / 2; damage = min + ((ThreadLocalRandom.current().nextFloat() * range) + (ThreadLocalRandom.current().nextFloat() * range)) / 2;
return (int) (damage * dmgMultiplier);
} }
public static double getMinDmg(double min, AbstractCharacter agent) { public static double getMinDmg(double min, AbstractCharacter agent) {
int primary = agent.getStatStrCurrent(); int primary = agent.getStatStrCurrent();

1
src/engine/objects/AbstractWorldObject.java

@ -59,6 +59,7 @@ public abstract class AbstractWorldObject extends AbstractGameObject {
private Vector3f rot = new Vector3f(0.0f, 0.0f, 0.0f); private Vector3f rot = new Vector3f(0.0f, 0.0f, 0.0f);
private int objectTypeMask = 0; private int objectTypeMask = 0;
private Bounds bounds; private Bounds bounds;
public ReentrantReadWriteLock combatLock = new ReentrantReadWriteLock();
/** /**
* No Id Constructor * No Id Constructor

Loading…
Cancel
Save