diff --git a/src/engine/gameManager/CombatManager.java b/src/engine/gameManager/CombatManager.java index d709dbce..15daeace 100644 --- a/src/engine/gameManager/CombatManager.java +++ b/src/engine/gameManager/CombatManager.java @@ -12,7 +12,6 @@ import engine.job.JobContainer; import engine.job.JobScheduler; import engine.jobs.AttackJob; import engine.jobs.DeferredPowerJob; -import engine.math.Vector3f; import engine.mbEnums; import engine.net.client.ClientConnection; import engine.net.client.msg.TargetedActionMsg; @@ -119,361 +118,360 @@ public enum CombatManager { 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; if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) { if (!attacker.isCombat()) 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 + 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 (bonus != null) - rangeMod += bonus.getFloatPercentAll(mbEnums.ModType.WeaponRange, mbEnums.SourceType.None); + if (weapon != null) { + if (bonus != null) + 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 (((Mob) attacker).isSiege()) - attackRange = 300; + if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) + if (((Mob) attacker).isSiege()) + attackRange = 300; - float distanceSquared = attacker.loc.distanceSquared(target.loc); + float distanceSquared = attacker.loc.distanceSquared(target.loc); - boolean inRange = false; - if (AbstractCharacter.IsAbstractCharacter(target)) { - attackRange += ((AbstractCharacter)target).calcHitBox(); - } else { + boolean inRange = false; + if (AbstractCharacter.IsAbstractCharacter(target)) { + attackRange += ((AbstractCharacter) target).calcHitBox(); + } else { - } + } - if(attackRange > 15 && attacker.isMoving()){ - //cannot shoot bow while moving; - return; - } + if (attackRange > 15 && attacker.isMoving()) { + //cannot shoot bow while moving; + return; + } - switch (target.getObjectType()) { - case PlayerCharacter: - attackRange += ((PlayerCharacter) target).getCharacterHeight() * 0.5f; - 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) { + switch (target.getObjectType()) { + case PlayerCharacter: + attackRange += ((PlayerCharacter) target).getCharacterHeight() * 0.5f; + if (distanceSquared < attackRange * attackRange) 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))) + 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; + 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 - long delay = 5000; + //get delay for the auto attack job + 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 - wepSpeed *= (1 + weapon.getBonus(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None)); + if (weapon.getBonusPercent(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None) != 0f) //add weapon speed bonus + 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 - wepSpeed *= (1 + attacker.getBonuses().getFloatPercentAll(mbEnums.ModType.AttackDelay, mbEnums.SourceType.None)); + 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)); - if (wepSpeed < 10) - wepSpeed = 10; //Old was 10, but it can be reached lower with legit buffs,effects. + if (wepSpeed < 10) + 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)) - ((Mob) attacker).nextAttackTime = System.currentTimeMillis() + delay; + if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) + ((Mob) attacker).nextAttackTime = System.currentTimeMillis() + delay; - if (inRange) { + if (inRange) { - //handle retaliate - if (AbstractCharacter.IsAbstractCharacter(target)) { - if (((AbstractCharacter) target).combatTarget == null || !((AbstractCharacter) target).combatTarget.isAlive()) { - ((AbstractCharacter) target).combatTarget = attacker; - if (target.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter) && ((AbstractCharacter) target).isCombat()) - combatCycle((AbstractCharacter) target, attacker); + //handle retaliate + if (AbstractCharacter.IsAbstractCharacter(target)) { + if (((AbstractCharacter) target).combatTarget == null || !((AbstractCharacter) target).combatTarget.isAlive()) { + ((AbstractCharacter) target).combatTarget = attacker; + if (target.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter) && ((AbstractCharacter) target).isCombat()) + combatCycle((AbstractCharacter) target, attacker); + } } - } - // take stamina away from attacker if its not a mob - if (weapon != null && !attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) { - //check if Out of Stamina - if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) { - if (attacker.getStamina() < (weapon.template.item_wt / 3f)) { - //set auto attack job - setAutoAttackJob(attacker, slot, delay); - return; + // take stamina away from attacker if its not a mob + if (weapon != null && !attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) { + //check if Out of Stamina + if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) { + if (attacker.getStamina() < (weapon.template.item_wt / 3f)) { + //set auto attack job + setAutoAttackJob(attacker, slot, delay); + return; + } } - } - float stam = weapon.template.item_wt / 3f; - stam = (stam < 1) ? 1 : stam; - attacker.modifyStamina(-(stam), attacker, true); - } else - attacker.modifyStamina(1, attacker, true); + float stam = weapon.template.item_wt / 3f; + stam = (stam < 1) ? 1 : stam; + attacker.modifyStamina(-(stam), attacker, true); + } else + 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 max = attacker.maxDamageHandOne; - int atr = attacker.atrHandOne; + int min = attacker.minDamageHandOne; + int max = attacker.maxDamageHandOne; + 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) { - min = attacker.minDamageHandTwo; - max = attacker.maxDamageHandTwo; - atr = attacker.atrHandTwo; - } + if (slot == mbEnums.EquipSlotType.LHELD) { + min = attacker.minDamageHandTwo; + max = attacker.maxDamageHandTwo; + atr = attacker.atrHandTwo; + } - //apply weapon powers before early exit for miss or passives - DeferredPowerJob dpj = null; + //apply weapon powers before early exit for miss or passives + 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) { - dpj.attack(target, attackRange); + if (dpj != null) { + dpj.attack(target, attackRange); - if (dpj.getPower() != null && (dpj.getPowerToken() == -1851459567 || dpj.getPowerToken() == -1851489518)) - ((PlayerCharacter) attacker).setWeaponPower(dpj); + if (dpj.getPower() != null && (dpj.getPowerToken() == -1851459567 || dpj.getPowerToken() == -1851489518)) + ((PlayerCharacter) attacker).setWeaponPower(dpj); + } } - } - int def = 0; + int def = 0; - if (AbstractCharacter.IsAbstractCharacter(target)) - def = ((AbstractCharacter) target).defenseRating; + if (AbstractCharacter.IsAbstractCharacter(target)) + def = ((AbstractCharacter) target).defenseRating; - //calculate hit chance based off ATR and DEF + //calculate hit chance based off ATR and DEF - int hitChance; - if (def == 0) - def = 1; - float dif = atr * 1f / def; + int hitChance; + if (def == 0) + def = 1; + float dif = atr * 1f / def; - if (dif <= 0.8f) - hitChance = 4; - else - hitChance = ((int) (450 * (dif - 0.8f)) + 4); + if (dif <= 0.8f) + hitChance = 4; + else + hitChance = ((int) (450 * (dif - 0.8f)) + 4); - if (target.getObjectType() == mbEnums.GameObjectType.Building) - hitChance = 100; - int passiveAnim = getPassiveAnimation(mbEnums.PassiveType.None); // checking for a miss due to ATR vs Def - if (ThreadLocalRandom.current().nextInt(100) > hitChance) { - TargetedActionMsg msg = new TargetedActionMsg(attacker, target, 0f, passiveAnim); + if (target.getObjectType() == mbEnums.GameObjectType.Building) + hitChance = 100; + int passiveAnim = getPassiveAnimation(mbEnums.PassiveType.None); // checking for a miss due to ATR vs Def + if (ThreadLocalRandom.current().nextInt(100) > hitChance) { + TargetedActionMsg msg = new TargetedActionMsg(attacker, target, 0f, passiveAnim); - if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter) - DispatchManager.dispatchMsgToInterestArea(target, msg, mbEnums.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); - else - DispatchManager.sendToAllInRange(attacker, msg); + if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter) + DispatchManager.dispatchMsgToInterestArea(target, msg, mbEnums.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); + else + DispatchManager.sendToAllInRange(attacker, msg); - //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); + //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); - //set auto attack job - setAutoAttackJob(attacker, slot, delay); - return; - } + //set auto attack job + setAutoAttackJob(attacker, slot, delay); + 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())) { - mbEnums.PassiveType passiveType = mbEnums.PassiveType.None; - int hitRoll = ThreadLocalRandom.current().nextInt(100); + if (EnumSet.of(mbEnums.GameObjectType.PlayerCharacter, mbEnums.GameObjectType.NPC, mbEnums.GameObjectType.Mob).contains(target.getObjectType())) { + mbEnums.PassiveType passiveType = mbEnums.PassiveType.None; + int hitRoll = ThreadLocalRandom.current().nextInt(100); - float dodgeChance = ((AbstractCharacter) target).getPassiveChance("Dodge", attacker.getLevel(), true); - float blockChance = ((AbstractCharacter) target).getPassiveChance("Block", attacker.getLevel(), true); - float parryChance = ((AbstractCharacter) target).getPassiveChance("Parry", attacker.getLevel(), true); + float dodgeChance = ((AbstractCharacter) target).getPassiveChance("Dodge", attacker.getLevel(), true); + float blockChance = ((AbstractCharacter) target).getPassiveChance("Block", 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)); - blockChance = Math.max(0, Math.min(75, blockChance)); - parryChance = Math.max(0, Math.min(75, parryChance)); + dodgeChance = Math.max(0, Math.min(75, dodgeChance)); + blockChance = Math.max(0, Math.min(75, blockChance)); + parryChance = Math.max(0, Math.min(75, parryChance)); - if (hitRoll < dodgeChance) - passiveType = mbEnums.PassiveType.Dodge; - else if (hitRoll < blockChance) - passiveType = mbEnums.PassiveType.Block; - else if (hitRoll < parryChance) - passiveType = mbEnums.PassiveType.Parry; + if (hitRoll < dodgeChance) + passiveType = mbEnums.PassiveType.Dodge; + else if (hitRoll < blockChance) + passiveType = mbEnums.PassiveType.Block; + else if (hitRoll < parryChance) + passiveType = mbEnums.PassiveType.Parry; - if (!passiveType.equals(mbEnums.PassiveType.None)) { - passiveAnim = getPassiveAnimation(passiveType); - TargetedActionMsg msg = new TargetedActionMsg(attacker, passiveAnim, target, passiveType.value); + if (!passiveType.equals(mbEnums.PassiveType.None)) { + passiveAnim = getPassiveAnimation(passiveType); + TargetedActionMsg msg = new TargetedActionMsg(attacker, passiveAnim, target, passiveType.value); - if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter) - DispatchManager.dispatchMsgToInterestArea(target, msg, mbEnums.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); + if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter) + DispatchManager.dispatchMsgToInterestArea(target, msg, mbEnums.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); - //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); + //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); + //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 setAutoAttackJob(attacker, slot, delay); return; } - } + if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob) && ((Mob) attacker).isPet()) + calculatePetDamage(attacker); - //calculate the base damage - 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 - //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) { - 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 - //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)) - resists = ((Building) target).getResists(); //this is a building - else - resists = ((AbstractCharacter) target).getResists(); //this is a character + if (AbstractCharacter.IsAbstractCharacter(target)) { + AbstractCharacter absTarget = (AbstractCharacter) target; - if (AbstractCharacter.IsAbstractCharacter(target)) { - AbstractCharacter absTarget = (AbstractCharacter) target; + //check damage shields - //check damage shields + PlayerBonuses bonuses = absTarget.getBonuses(); - PlayerBonuses bonuses = absTarget.getBonuses(); + if (bonuses != null) { - if (bonuses != null) { + ConcurrentHashMap damageShields = bonuses.getDamageShields(); + float total = 0; - ConcurrentHashMap damageShields = bonuses.getDamageShields(); - float total = 0; + for (DamageShield ds : damageShields.values()) { - 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()) - amount = damage * ds.getAmount() / 100; - else - amount = ds.getAmount(); + //get resisted damage for damagetype - //get resisted damage for damagetype + if (resists != null) + amount = resists.getResistedDamage(absTarget, attacker, ds.getDamageType(), amount, 0); + total += amount; + } - if (resists != null) - amount = resists.getResistedDamage(absTarget, attacker, ds.getDamageType(), amount, 0); - total += amount; + if (total > 0) { + //apply Damage back + attacker.modifyHealth(-total, absTarget, true); + TargetedActionMsg cmm = new TargetedActionMsg(attacker, attacker, total, 0); + DispatchManager.sendToAllInRange(target, cmm); + } } - if (total > 0) { - //apply Damage back - attacker.modifyHealth(-total, absTarget, true); - TargetedActionMsg cmm = new TargetedActionMsg(attacker, attacker, total, 0); - DispatchManager.sendToAllInRange(target, cmm); - } - } + if (resists != null) { - 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)) { - //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; + damage = (int) resists.getResistedDamage(attacker, (AbstractCharacter) target, damageType, damage, 0); } - //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)) - ((AbstractCharacter) target).modifyHealth(-damage, attacker, true); - else - ((Building) target).modifyHealth(-damage, attacker); + if (AbstractCharacter.IsAbstractCharacter(target)) + ((AbstractCharacter) target).modifyHealth(-damage, attacker, true); + else + ((Building) target).modifyHealth(-damage, attacker); - int attackAnim = getSwingAnimation(null, null, slot); - if (attacker.charItemManager.getEquipped().get(slot) != null) { - if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) { - DeferredPowerJob weaponPower = ((PlayerCharacter) attacker).getWeaponPower(); - attackAnim = getSwingAnimation(weapon.template, weaponPower, slot); - } else { - attackAnim = getSwingAnimation(weapon.template, null, slot); + int attackAnim = getSwingAnimation(null, null, slot); + if (attacker.charItemManager.getEquipped().get(slot) != null) { + if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) { + DeferredPowerJob weaponPower = ((PlayerCharacter) attacker).getWeaponPower(); + attackAnim = getSwingAnimation(weapon.template, weaponPower, slot); + } else { + 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) { @@ -624,7 +622,20 @@ public enum CombatManager { 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 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 float range; float damage; @@ -636,7 +647,6 @@ public enum CombatManager { dmgMultiplier += agent.getLevel() * 0.1f; range = (float) (maxDmg - minDmg); damage = min + ((ThreadLocalRandom.current().nextFloat() * range) + (ThreadLocalRandom.current().nextFloat() * range)) / 2; - return (int) (damage * dmgMultiplier); } public static double getMinDmg(double min, AbstractCharacter agent) { int primary = agent.getStatStrCurrent(); diff --git a/src/engine/objects/AbstractWorldObject.java b/src/engine/objects/AbstractWorldObject.java index 12d867f9..121c77f3 100644 --- a/src/engine/objects/AbstractWorldObject.java +++ b/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 int objectTypeMask = 0; private Bounds bounds; + public ReentrantReadWriteLock combatLock = new ReentrantReadWriteLock(); /** * No Id Constructor