diff --git a/src/engine/gameManager/CombatManager.java b/src/engine/gameManager/CombatManager.java deleted file mode 100644 index 9ab48c84..00000000 --- a/src/engine/gameManager/CombatManager.java +++ /dev/null @@ -1,1358 +0,0 @@ -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - -package engine.gameManager; - -import engine.Enum.*; -import engine.job.JobContainer; -import engine.job.JobScheduler; -import engine.jobs.AttackJob; -import engine.jobs.DeferredPowerJob; -import engine.math.Vector3fImmutable; -import engine.net.DispatchMessage; -import engine.net.client.ClientConnection; -import engine.net.client.msg.*; -import engine.objects.*; -import engine.powers.DamageShield; -import engine.powers.PowersBase; -import engine.powers.effectmodifiers.AbstractEffectModifier; -import engine.powers.effectmodifiers.WeaponProcEffectModifier; -import engine.server.MBServerStatics; -import org.pmw.tinylog.Logger; - -import java.util.HashSet; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ThreadLocalRandom; - -public enum CombatManager { - - COMBATMANAGER; - - public static int animation = 0; - - /** - * Message sent by player to attack something. - */ - - public static void AttackTarget(PlayerCharacter playerCharacter, AbstractWorldObject target) { - - boolean swingOffhand = false; - - //check my weapon can I do an offhand attack - - Item weaponOff = playerCharacter.getCharItemManager().getEquipped().get(EquipSlotType.LHELD); - Item weaponMain = playerCharacter.getCharItemManager().getEquipped().get(EquipSlotType.RHELD); - - // if you carry something in the offhand thats a weapon you get to swing it - - if (weaponOff != null) - if (weaponOff.template.item_type.equals(ItemType.WEAPON)) - swingOffhand = true; - - // if you carry nothing in either hand you get to swing your offhand - - if (weaponOff == null && weaponMain == null) - swingOffhand = true; - - - //we always swing our mainhand if we are not on timer - - JobContainer main = playerCharacter.getTimers().get("Attack" + EquipSlotType.RHELD.ordinal()); - - // no timers on the mainhand, lets submit a job to swing - - if (main == null) - CombatManager.createTimer(playerCharacter, EquipSlotType.RHELD.ordinal(), 1, true); // attack in 0.1 of a second - - /* - only swing offhand if we have a weapon in it or are unarmed in both hands - and no timers running - */ - - if (swingOffhand) { - - JobContainer off = playerCharacter.getTimers().get("Attack" + EquipSlotType.LHELD.ordinal()); - - if (off == null) - CombatManager.createTimer(playerCharacter, EquipSlotType.LHELD.ordinal(), 1, true); // attack in 0.1 of a second - } - } - - public static void setAttackTarget(PetAttackMsg msg, ClientConnection origin) { - - PlayerCharacter player; - Mob pet; - int targetType; - AbstractWorldObject target; - - if (TargetedActionMsg.un2cnt == 60 || TargetedActionMsg.un2cnt == 70) - return; - - player = SessionManager.getPlayerCharacter(origin); - - if (player == null) - return; - - pet = player.getPet(); - - if (pet == null) - return; - - targetType = msg.getTargetType(); - - if (targetType == GameObjectType.PlayerCharacter.ordinal()) - target = PlayerCharacter.getFromCache(msg.getTargetID()); - else if (targetType == GameObjectType.Building.ordinal()) - target = BuildingManager.getBuildingFromCache(msg.getTargetID()); - else if (targetType == GameObjectType.Mob.ordinal()) - target = Mob.getFromCache(msg.getTargetID()); - else { - pet.setCombatTarget(null); - return; //not valid type to attack - } - - if (pet.equals(target)) - return; - - // quit of the combat target is already the current combat target - // or there is no combat target - - if (target == null || target == pet.getCombatTarget()) - return; - - //set sources target - - pet.setCombatTarget(target); - - //put in combat if not already - - if (!pet.isCombat()) - pet.setCombat(true); - - //make character stand if sitting - - if (pet.isSit()) - toggleSit(false, origin); - - } - - private static void removeAttackTimers(AbstractCharacter ac) { - - JobContainer main; - JobContainer off; - - if (ac == null) - return; - - main = ac.getTimers().get("Attack" + EquipSlotType.RHELD.ordinal()); - off = ac.getTimers().get("Attack" + EquipSlotType.LHELD.ordinal()); - - if (main != null) - JobScheduler.getInstance().cancelScheduledJob(main); - - ac.getTimers().remove("Attack" + EquipSlotType.RHELD.ordinal()); - - if (off != null) - JobScheduler.getInstance().cancelScheduledJob(off); - - ac.getTimers().remove("Attack" + EquipSlotType.LHELD.ordinal()); - - ac.setCombatTarget(null); - - } - - /** - * Begin Attacking - */ - public static void doCombat(AbstractCharacter ac, int slot) { - - int ret = 0; - - if (ac == null) - return; - - // Attempt to eat null targets until we can clean - // up this unholy mess and refactor it into a thread. - - ret = attemptCombat(ac, slot); - - //handle pets - if (ret < 2 && ac.getObjectType().equals(GameObjectType.Mob)) { - - Mob mob = (Mob) ac; - - if (mob.isPet()) - return; - } - - //ret values - //0: not valid attack, fail attack - //1: cannot attack, wrong hand - //2: valid attack - //3: cannot attack currently, continue checking - - if (ret == 0 || ret == 1) { - - //Could not attack, clear timer - - ConcurrentHashMap timers = ac.getTimers(); - - if (timers != null) - timers.remove("Attack" + slot); - - //clear combat target if not valid attack - - if (ret == 0) - ac.setCombatTarget(null); - - } else if (ret == 3) //Failed but continue checking. reset timer - createTimer(ac, slot, 5, false); - } - - /** - * Verify can attack target - */ - private static int attemptCombat(AbstractCharacter abstractCharacter, int slot) { - - EquipSlotType weaponSlot = EquipSlotType.RHELD.values()[slot]; - - if (abstractCharacter == null) - return 0; - - try { - - //Make sure player can attack - - PlayerBonuses bonus = abstractCharacter.getBonuses(); - - if (bonus != null && bonus.getBool(ModType.ImmuneToAttack, SourceType.NONE)) - return 0; - - AbstractWorldObject target = abstractCharacter.getCombatTarget(); - - if (target == null) - return 0; - - //target must be valid type - - if (AbstractWorldObject.IsAbstractCharacter(target)) { - - AbstractCharacter tar = (AbstractCharacter) target; - - //must be alive, attackable and in World - - if (!tar.isAlive()) - return 0; - else if (tar.isSafeMode()) - return 0; - else if (!tar.isActive()) - return 0; - - if (target.getObjectType().equals(GameObjectType.PlayerCharacter) && abstractCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) && abstractCharacter.getTimers().get("Attack" + slot) == null) - if (!((PlayerCharacter) abstractCharacter).canSee((PlayerCharacter) target)) - return 0; - - //must not be immune to all or immune to attack - - Resists res = tar.getResists(); - bonus = tar.getBonuses(); - - if (bonus != null && !bonus.getBool(ModType.NoMod, SourceType.IMMUNETOATTACK)) - if (res != null) - if (res.immuneToAll() || res.immuneToAttacks()) - return 0; - } else if (target.getObjectType().equals(GameObjectType.Building)) { - Building tar = (Building) target; - - // Cannot attack an invuln building - - if (tar.isVulnerable() == false) - return 0; - - } else - return 0; //only characters and buildings may be attacked - - //source must be in world and alive - - if (!abstractCharacter.isActive()) - return 0; - else if (!abstractCharacter.isAlive()) - return 0; - - //make sure source is in combat mode - - if (!abstractCharacter.isCombat()) - return 0; - - //See if either target is in safe zone - - if (abstractCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) && target.getObjectType().equals(GameObjectType.PlayerCharacter)) - if (((PlayerCharacter) abstractCharacter).inSafeZone() || ((PlayerCharacter) target).inSafeZone()) - return 0; - - if (!(weaponSlot == EquipSlotType.RHELD || weaponSlot == EquipSlotType.LHELD)) - return 0; - - if (abstractCharacter.getCharItemManager() == null) - return 0; - - //get equippment - - ConcurrentHashMap equipped = abstractCharacter.getCharItemManager().getEquipped(); - boolean hasNoWeapon = false; - - if (equipped == null) - return 0; - - //get Weapon - - boolean isWeapon = true; - Item weapon = equipped.get(weaponSlot); - ItemTemplate wb = null; - - if (weapon == null) - isWeapon = false; - else { - ItemTemplate ib = weapon.template; - - if (ib == null || !weapon.template.item_type.equals(ItemType.WEAPON)) - isWeapon = false; - else - wb = ib; - } - - //no weapon, see if other hand has a weapon - - if (!isWeapon) - if (weaponSlot == EquipSlotType.RHELD) { - - //make sure offhand has weapon, not shield - - Item weaponOff = equipped.get(EquipSlotType.RHELD); - - if (weaponOff != null) { - ItemTemplate ib = weaponOff.template; - - if (ib == null || !weaponOff.template.item_type.equals(ItemType.WEAPON)) - hasNoWeapon = true; - else - return 1; //no need to attack with this hand - - } else - hasNoWeapon = true; - - } else if (equipped.get(EquipSlotType.RHELD) == null) - return 1; //no need to attack with this hand - - //Source can attack. - //NOTE Don't 'return;' beyond this point until timer created - - boolean attackFailure = (wb != null) && (wb.item_weapon_max_range > 35f) && abstractCharacter.isMoving(); - - //Target can't attack on move with ranged weapons. - //if not enough stamina, then skip attack - - if (wb == null) { - if (abstractCharacter.getStamina() < 1) - attackFailure = true; - } else if (abstractCharacter.getStamina() < weapon.template.item_wt) - attackFailure = true; - - //see if attacker is stunned. If so, stop here - - bonus = abstractCharacter.getBonuses(); - - if (bonus != null && bonus.getBool(ModType.Stunned, SourceType.NONE)) - attackFailure = true; - - //Get Range of weapon - - float range; - - if (hasNoWeapon) - range = MBServerStatics.NO_WEAPON_RANGE; - else - range = getWeaponRange(wb, bonus); - - if (abstractCharacter.getObjectType() == GameObjectType.Mob) { - - Mob minion = (Mob) abstractCharacter; - - if (minion.isSiege()) - range = 300f; - } - - //Range check. - - if (NotInRange(abstractCharacter, target, range)) { - - //target is in stealth and can't be seen by source - - if (target.getObjectType().equals(GameObjectType.PlayerCharacter) && abstractCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)) - if (!((PlayerCharacter) abstractCharacter).canSee((PlayerCharacter) target)) - return 0; - - attackFailure = true; - } - - //handle pet, skip timers (handled by AI) - - if (abstractCharacter.getObjectType().equals(GameObjectType.Mob)) { - - Mob mob = (Mob) abstractCharacter; - - if (mob.isPet()) { - attack(abstractCharacter, target, weapon, wb, slot == EquipSlotType.RHELD.ordinal()); - return 2; - } - } - - //TODO Verify attacker has los (if not ranged weapon). - - if (!attackFailure) { - - if (hasNoWeapon || abstractCharacter.getObjectType().equals(GameObjectType.Mob)) - createTimer(abstractCharacter, slot, 20, true); //2 second for no weapon - else { - int wepSpeed = (int) (wb.item_weapon_wepspeed); - - if (weapon != null && weapon.getBonusPercent(ModType.WeaponSpeed, SourceType.NONE) != 0f) //add weapon speed bonus - wepSpeed *= (1 + weapon.getBonus(ModType.WeaponSpeed, SourceType.NONE)); - - if (abstractCharacter.getBonuses() != null && abstractCharacter.getBonuses().getFloatPercentAll(ModType.AttackDelay, SourceType.NONE) != 0f) //add effects speed bonus - wepSpeed *= (1 + abstractCharacter.getBonuses().getFloatPercentAll(ModType.AttackDelay, SourceType.NONE)); - - if (wepSpeed < 10) - wepSpeed = 10; //Old was 10, but it can be reached lower with legit buffs,effects. - - createTimer(abstractCharacter, slot, wepSpeed, true); - } - - attack(abstractCharacter, target, weapon, wb, slot == EquipSlotType.RHELD.ordinal()); - } else - createTimer(abstractCharacter, slot, 5, false); // changed this to half a second to make combat attempts more aggressive than movement sync - - } catch (Exception e) { - return 0; - } - return 2; - } - - private static void createTimer(AbstractCharacter ac, int slot, int time, boolean success) { - - ConcurrentHashMap timers = ac.getTimers(); - - if (timers != null) { - AttackJob aj = new AttackJob(ac, slot, success); - JobContainer job; - job = JobScheduler.getInstance().scheduleJob(aj, (time * 100)); - timers.put("Attack" + slot, job); - } else { - Logger.error("Unable to find Timers for Character " + ac.getObjectUUID()); - } - } - - /** - * Attempt to attack target - */ - private static void attack(AbstractCharacter attacker, AbstractWorldObject target, Item weapon, ItemTemplate wb, boolean mainHand) { - - float atr; - int minDamage, maxDamage; - int errorTrack = 0; - - try { - - if (attacker == null) - return; - - if (target == null) - return; - - if (mainHand) { - atr = attacker.getAtrHandOne(); - minDamage = attacker.getMinDamageHandOne(); - maxDamage = attacker.getMaxDamageHandOne(); - } else { - atr = attacker.getAtrHandTwo(); - minDamage = attacker.getMinDamageHandTwo(); - maxDamage = attacker.getMaxDamageHandTwo(); - } - - boolean tarIsRat = false; - - if (target.getObjectTypeMask() == MBServerStatics.MASK_RAT) - tarIsRat = true; - else if (target.getObjectType() == GameObjectType.PlayerCharacter) { - - PlayerCharacter pTar = (PlayerCharacter) target; - - for (Effect eff : pTar.getEffects().values()) - if (eff.getPowerToken() == 429513599 || eff.getPowerToken() == 429415295) - tarIsRat = true; - } - - //Dont think we need to do this anymore. - - if (tarIsRat) - if (attacker.getBonuses().getFloatPercentAll(ModType.Slay, SourceType.RAT) != 0) { //strip away current % dmg buffs then add with rat % - - float percent = 1 + attacker.getBonuses().getFloatPercentAll(ModType.Slay, SourceType.RAT); - - minDamage *= percent; - maxDamage *= percent; - } - - errorTrack = 1; - - //subtract stamina - - if (wb == null) - attacker.modifyStamina(-0.5f, attacker, true); - else { - float stam = weapon.template.item_wt / 3f; - stam = (stam < 1) ? 1 : stam; - attacker.modifyStamina(-(stam), attacker, true); - } - - attacker.cancelOnAttackSwing(); - - errorTrack = 2; - - //set last time this player has attacked something. - - if (target.getObjectType().equals(GameObjectType.PlayerCharacter) && target.getObjectUUID() != attacker.getObjectUUID() && attacker.getObjectType() == GameObjectType.PlayerCharacter) { - attacker.setTimeStamp("LastCombatPlayer", System.currentTimeMillis()); - ((PlayerCharacter) target).setTimeStamp("LastCombatPlayer", System.currentTimeMillis()); - } else - attacker.setTimeStamp("LastCombatMob", System.currentTimeMillis()); - - errorTrack = 3; - - //Get defense for target - - float defense; - - if (target.getObjectType().equals(GameObjectType.Building)) { - - if (BuildingManager.getBuildingFromCache(target.getObjectUUID()) == null) { - attacker.setCombatTarget(null); - return; - } - - defense = 0; - - } else { - AbstractCharacter tar = (AbstractCharacter) target; - defense = tar.getDefenseRating(); - handleRetaliate(tar, attacker); //Handle target attacking back if in combat and has no other target - } - - errorTrack = 4; - - //Get hit chance - - int chance; - float dif = atr - defense; - - if (dif > 100) - chance = 94; - else if (dif < -100) - chance = 4; - else - chance = (int) ((0.45 * dif) + 49); - - errorTrack = 5; - - //calculate hit/miss - - int roll = ThreadLocalRandom.current().nextInt(100); - DeferredPowerJob dpj = null; - - if (roll < chance) { - - if (attacker.getObjectType().equals(GameObjectType.PlayerCharacter)) - updateAttackTimers((PlayerCharacter) attacker, target, true); - - boolean skipPassives = false; - PlayerBonuses bonuses = attacker.getBonuses(); - - if (bonuses != null && bonuses.getBool(ModType.IgnorePassiveDefense, SourceType.NONE)) - skipPassives = true; - - AbstractCharacter tarAc = null; - - if (AbstractWorldObject.IsAbstractCharacter(target)) - tarAc = (AbstractCharacter) target; - - errorTrack = 6; - - // Apply Weapon power effect if any. don't try to apply twice if - // dual wielding. Perform after passive test for sync purposes. - - //ItemTemplate template = ItemTemplate.templates.get(wb.getUUID()); - - if (attacker.getObjectType().equals(GameObjectType.PlayerCharacter) && (mainHand || ItemTemplate.isTwoHanded(wb))) { - - dpj = ((PlayerCharacter) attacker).getWeaponPower(); - - if (dpj != null) { - - PlayerBonuses bonus = attacker.getBonuses(); - float attackRange = getWeaponRange(wb, bonus); - dpj.attack(target, attackRange); - - if (dpj.getPower() != null && (dpj.getPowerToken() == -1851459567 || dpj.getPowerToken() == -1851489518)) - ((PlayerCharacter) attacker).setWeaponPower(dpj); - } - } - - //check to apply second backstab. - - if (attacker.getObjectType().equals(GameObjectType.PlayerCharacter) && !mainHand) { - - dpj = ((PlayerCharacter) attacker).getWeaponPower(); - - if (dpj != null && dpj.getPower() != null && (dpj.getPowerToken() == -1851459567 || dpj.getPowerToken() == -1851489518)) { - float attackRange = getWeaponRange(wb, bonuses); - dpj.attack(target, attackRange); - } - } - - errorTrack = 7; - - //Hit, check if passive kicked in - - boolean passiveFired = false; - - if (!skipPassives && tarAc != null) { - - if (target.getObjectType().equals(GameObjectType.PlayerCharacter)) { - - //Handle Block passive - - if (testPassive(attacker, tarAc, "Block") && canTestBlock(attacker, target)) { - - if (!target.isAlive()) - return; - - sendPassiveDefenseMessage(attacker, wb, target, MBServerStatics.COMBAT_SEND_BLOCK, dpj, mainHand); - passiveFired = true; - } - - //Handle Parry passive - - if (!passiveFired) - if (canTestParry(attacker, target) && testPassive(attacker, tarAc, "Parry")) { - - if (!target.isAlive()) - return; - - sendPassiveDefenseMessage(attacker, wb, target, MBServerStatics.COMBAT_SEND_PARRY, dpj, mainHand); - passiveFired = true; - } - - } - - errorTrack = 8; - - //Handle Dodge passive - - if (!passiveFired) - if (testPassive(attacker, tarAc, "Dodge")) { - - if (!target.isAlive()) - return; - - sendPassiveDefenseMessage(attacker, wb, target, MBServerStatics.COMBAT_SEND_DODGE, dpj, mainHand); - passiveFired = true; - } - } - - //return if passive (Block, Parry, Dodge) fired - - if (passiveFired) - return; - - errorTrack = 9; - - //Hit and no passives - //if target is player, set last attack timestamp - - if (target.getObjectType().equals(GameObjectType.PlayerCharacter)) - updateAttackTimers((PlayerCharacter) target, attacker, false); - - //Get damage Type - - SourceType damageType; - - if (wb != null) - damageType = (SourceType) wb.item_weapon_damage.keySet().toArray()[0]; - else if (attacker.getObjectType().equals(GameObjectType.Mob) && ((Mob) attacker).isSiege()) - damageType = SourceType.SIEGE; - else - damageType = SourceType.CRUSHING; - - errorTrack = 10; - - //Get target resists - - Resists resists = null; - - if (tarAc != null) - resists = tarAc.getResists(); - else if (target.getObjectType().equals(GameObjectType.Building)) - resists = ((Building) target).getResists(); - - //make sure target is not immune to damage type; - - if (resists != null && resists.immuneTo(damageType)) { - sendCombatMessage(attacker, target, 0f, wb, dpj, mainHand); - return; - } - - errorTrack = 11; - - //Calculate Damage done - - float damage; - - if (wb != null) - damage = calculateDamage(attacker, tarAc, minDamage, maxDamage, damageType, resists); - else - damage = calculateDamage(attacker, tarAc, minDamage, maxDamage, damageType, resists); - - float d = 0f; - - errorTrack = 12; - - //Subtract Damage from target's health - - if (tarAc != null) { - - if (tarAc.isSit()) - damage *= 2.5f; //increase damage if sitting - - if (tarAc.getHealth() > 0) - d = tarAc.modifyHealth(-damage, attacker, false); - - } else if (target.getObjectType().equals(GameObjectType.Building)) { - - if (BuildingManager.getBuildingFromCache(target.getObjectUUID()) == null) { - attacker.setCombatTarget(null); - return; - } - - if (target.getHealth() > 0) - d = ((Building) target).modifyHealth(-damage, attacker); - } - - errorTrack = 13; - - //Test to see if any damage needs done to weapon or armor - - testItemDamage(attacker, target, weapon, wb); - - // if target is dead, we got the killing blow, remove attack timers on our weapons - - if (tarAc != null && !tarAc.isAlive()) - removeAttackTimers(attacker); - - //test double death fix - - if (d != 0) - sendCombatMessage(attacker, target, damage, wb, dpj, mainHand); //send damage message - - errorTrack = 14; - - //handle procs - - if (weapon != null && tarAc != null && tarAc.isAlive()) { - - ConcurrentHashMap effects = weapon.getEffects(); - - for (Effect eff : effects.values()) { - if (eff == null) - continue; - - HashSet aems = eff.getEffectModifiers(); - - if (aems != null) { - for (AbstractEffectModifier aem : aems) { - - if (!tarAc.isAlive()) - break; - - if (aem instanceof WeaponProcEffectModifier) { - - int procChance = ThreadLocalRandom.current().nextInt(100); - - if (procChance < MBServerStatics.PROC_CHANCE) - ((WeaponProcEffectModifier) aem).applyProc(attacker, target); - - } - } - } - } - } - - errorTrack = 15; - - //handle damage shields - - if (attacker.isAlive() && tarAc != null && tarAc.isAlive()) - handleDamageShields(attacker, tarAc, damage); - - } else { - - // Apply Weapon power effect if any. - // don't try to apply twice if dual wielding. - - if (attacker.getObjectType().equals(GameObjectType.PlayerCharacter) && (mainHand || ItemTemplate.isTwoHanded(wb))) { - dpj = ((PlayerCharacter) attacker).getWeaponPower(); - - if (dpj != null) { - - PowersBase wp = dpj.getPower(); - - if (wp.requiresHitRoll() == false) { - PlayerBonuses bonus = attacker.getBonuses(); - float attackRange = getWeaponRange(wb, bonus); - dpj.attack(target, attackRange); - } else - ((PlayerCharacter) attacker).setWeaponPower(null); - } - } - - if (target.getObjectType() == GameObjectType.Mob) - ((Mob) target).handleDirectAggro(attacker); - - errorTrack = 17; - - //miss, Send miss message - - sendCombatMessage(attacker, target, 0f, wb, dpj, mainHand); - - //if attacker is player, set last attack timestamp - - if (attacker.getObjectType().equals(GameObjectType.PlayerCharacter)) - updateAttackTimers((PlayerCharacter) attacker, target, true); - } - - errorTrack = 18; - - //cancel effects that break on attack or attackSwing - attacker.cancelOnAttack(); - - } catch (Exception e) { - Logger.error(attacker.getName() + ' ' + errorTrack + ' ' + e); - } - } - - public static boolean canTestParry(AbstractCharacter ac, AbstractWorldObject target) { - - if (ac == null || target == null || !AbstractWorldObject.IsAbstractCharacter(target)) - return false; - - AbstractCharacter tar = (AbstractCharacter) target; - - CharacterItemManager acItem = ac.getCharItemManager(); - CharacterItemManager tarItem = tar.getCharItemManager(); - - if (acItem == null || tarItem == null) - return false; - - Item acMain = acItem.getItemFromEquipped(EquipSlotType.RHELD); - Item acOff = acItem.getItemFromEquipped(EquipSlotType.LHELD); - Item tarMain = tarItem.getItemFromEquipped(EquipSlotType.RHELD); - Item tarOff = tarItem.getItemFromEquipped(EquipSlotType.LHELD); - - return !isRanged(acMain) && !isRanged(acOff) && !isRanged(tarMain) && !isRanged(tarOff); - } - - public static boolean canTestBlock(AbstractCharacter ac, AbstractWorldObject target) { - - if (ac == null || target == null || !AbstractWorldObject.IsAbstractCharacter(target)) - return false; - - AbstractCharacter tar = (AbstractCharacter) target; - - CharacterItemManager acItem = ac.getCharItemManager(); - CharacterItemManager tarItem = tar.getCharItemManager(); - - if (acItem == null || tarItem == null) - return false; - - Item tarOff = tarItem.getItemFromEquipped(EquipSlotType.LHELD); - - if (tarOff == null) - return false; - - return ItemTemplate.isShield((tarOff)); - } - - private static boolean isRanged(Item item) { - - if (item == null) - return false; - - ItemTemplate ib = item.template; - - if (ib == null) - return false; - - if (item.template.item_type.equals(ItemType.WEAPON) == false) - return false; - - return ib.item_weapon_max_range > MBServerStatics.RANGED_WEAPON_RANGE; - - } - - private static float calculateDamage(AbstractCharacter source, AbstractCharacter target, float minDamage, float maxDamage, SourceType damageType, Resists resists) { - - //get range between min and max - - float range = maxDamage - minDamage; - - //Damage is calculated twice to average a more central point - - float damage = ThreadLocalRandom.current().nextFloat() * range; - damage = (damage + (ThreadLocalRandom.current().nextFloat() * range)) * .5f; - - //put it back between min and max - - damage += minDamage; - - //calculate resists in if any - - if (resists != null) - return resists.getResistedDamage(source, target, damageType, damage, 0); - else - return damage; - } - - private static void sendPassiveDefenseMessage(AbstractCharacter source, ItemTemplate wb, AbstractWorldObject target, int passiveType, DeferredPowerJob dpj, boolean mainHand) { - - int swingAnimation = getSwingAnimation(wb, dpj, mainHand); - - if (dpj != null) - if (PowersManager.AnimationOverrides.containsKey(dpj.getAction().getEffectID())) - swingAnimation = PowersManager.AnimationOverrides.get(dpj.getAction().getEffectID()); - - TargetedActionMsg cmm = new TargetedActionMsg(source, swingAnimation, target, passiveType); - DispatchMessage.sendToAllInRange(target, cmm); - - } - - private static void sendCombatMessage(AbstractCharacter source, AbstractWorldObject target, float damage, ItemTemplate wb, DeferredPowerJob dpj, boolean mainHand) { - - int swingAnimation = getSwingAnimation(wb, dpj, mainHand); - - if (dpj != null) - if (PowersManager.AnimationOverrides.containsKey(dpj.getAction().getEffectID())) - swingAnimation = PowersManager.AnimationOverrides.get(dpj.getAction().getEffectID()); - - if (source.getObjectType() == GameObjectType.PlayerCharacter) - for (Effect eff : source.getEffects().values()) - if (eff.getPower() != null && (eff.getPower().getToken() == 429506943 || eff.getPower().getToken() == 429408639 || eff.getPower().getToken() == 429513599 || eff.getPower().getToken() == 429415295)) - swingAnimation = 0; - - TargetedActionMsg cmm = new TargetedActionMsg(source, target, damage, swingAnimation); - DispatchMessage.sendToAllInRange(target, cmm); - } - - public static int getSwingAnimation(ItemTemplate wb, DeferredPowerJob dpj, boolean mainHand) { - int token = 0; - - if (dpj != null) - token = (dpj.getPower() != null) ? dpj.getPower().getToken() : 0; - - if (token == 563721004) //kick animation - return 79; - - if (CombatManager.animation != 0) - return CombatManager.animation; - - if (wb == null) - return 75; - - ItemTemplate template = wb; - - if (mainHand) { - if (template.weapon_attack_anim_right.size() > 0) { - - int animation; - - int random = ThreadLocalRandom.current().nextInt(template.weapon_attack_anim_right.size()); - - try { - animation = template.weapon_attack_anim_right.get(random)[0]; - return animation; - } catch (Exception e) { - Logger.error(e.getMessage()); - return template.weapon_attack_anim_right.get(0)[0]; - } - - } else if (template.weapon_attack_anim_left.size() > 0) { - - int animation; - int random = ThreadLocalRandom.current().nextInt(template.weapon_attack_anim_left.size()); - - try { - animation = template.weapon_attack_anim_left.get(random)[0]; - return animation; - } catch (Exception e) { - Logger.error(e.getMessage()); - return template.weapon_attack_anim_right.get(0)[0]; - } - } - } else { - if (template.weapon_attack_anim_left.size() > 0) { - int animation; - int random = ThreadLocalRandom.current().nextInt(template.weapon_attack_anim_left.size()); - - try { - animation = template.weapon_attack_anim_left.get(random)[0]; - return animation; - } catch (Exception e) { - Logger.error(e.getMessage()); - return template.weapon_attack_anim_right.get(0)[0]; - - } - } else if (template.weapon_attack_anim_left.size() > 0) { - - int animation; - int random = ThreadLocalRandom.current().nextInt(template.weapon_attack_anim_left.size()); - - try { - animation = template.weapon_attack_anim_left.get(random)[0]; - return animation; - } catch (Exception e) { - Logger.error(e.getMessage()); - return template.weapon_attack_anim_right.get(0)[0]; - - } - - } - } - - String required = template.item_skill_used; - String mastery = wb.item_skill_mastery_used; - - if (required.equals("Unarmed Combat")) - return 75; - else if (required.equals("Sword")) { - - if (ItemTemplate.isTwoHanded(template)) - return 105; - else - return 98; - - } else if (required.equals("Staff") || required.equals("Pole Arm")) { - return 85; - } else if (required.equals("Spear")) { - return 92; - } else if (required.equals("Hammer") || required.equals("Axe")) { - if (ItemTemplate.isTwoHanded(template)) { - return 105; - } else if (mastery.equals("Throwing")) { - return 115; - } else { - return 100; - } - } else if (required.equals("Dagger")) { - if (mastery.equals("Throwing")) { - return 117; - } else { - return 81; - } - } else if (required.equals("Crossbow")) { - return 110; - } else if (required.equals("Bow")) { - return 109; - } else if (ItemTemplate.isTwoHanded(template)) { - return 105; - } else { - return 100; - } - } - - private static boolean testPassive(AbstractCharacter source, AbstractCharacter target, String type) { - - float chance = target.getPassiveChance(type, source.getLevel(), true); - - if (chance == 0f) - return false; - - //max 75% chance of passive to fire - - if (chance > 75f) - chance = 75f; - - int roll = ThreadLocalRandom.current().nextInt(100); - - return roll < chance; - - } - - private static void updateAttackTimers(PlayerCharacter pc, AbstractWorldObject target, boolean attack) { - - //Set Attack Timers - - if (target.getObjectType().equals(GameObjectType.PlayerCharacter)) - pc.setLastPlayerAttackTime(); - } - - public static float getWeaponRange(ItemTemplate weapon, PlayerBonuses bonus) { - - float rangeMod = 1.0f; - - if (weapon == null) - return 0f; - - if (bonus != null) - rangeMod += bonus.getFloatPercentAll(ModType.WeaponRange, SourceType.NONE); - - return weapon.item_weapon_max_range * rangeMod; - } - - public static void toggleCombat(ToggleCombatMsg msg, ClientConnection origin) { - toggleCombat(msg.toggleCombat(), origin); - } - - public static void toggleCombat(SetCombatModeMsg msg, ClientConnection origin) { - toggleCombat(msg.getToggle(), origin); - } - - public static void toggleCombat(boolean toggle, ClientConnection origin) { - - PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); - - if (pc == null) - return; - - pc.setCombat(toggle); - - if (!toggle) // toggle is move it to false so clear combat target - pc.setCombatTarget(null); //clear last combat target - - UpdateStateMsg rwss = new UpdateStateMsg(); - rwss.setPlayer(pc); - DispatchMessage.dispatchMsgToInterestArea(pc, rwss, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); - } - - public static void toggleSit(boolean toggle, ClientConnection origin) { - - PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); - - if (pc == null) - return; - - pc.setSit(toggle); - - UpdateStateMsg rwss = new UpdateStateMsg(); - rwss.setPlayer(pc); - DispatchMessage.dispatchMsgToInterestArea(pc, rwss, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); - } - - public static boolean NotInRange(AbstractCharacter ac, AbstractWorldObject target, float range) { - - Vector3fImmutable sl = ac.getLoc(); - Vector3fImmutable tl = target.getLoc(); - - //add Hitbox to range. - - range += (calcHitBox(ac) + calcHitBox(target)); - - float magnitudeSquared = tl.distanceSquared(sl); - - return magnitudeSquared > range * range; - - } - - //Called when character takes damage. - public static void handleRetaliate(AbstractCharacter target, AbstractCharacter attacker) { - - if (attacker == null || target == null) - return; - - if (attacker.equals(target)) - return; - - if (target.isMoving() && target.getObjectType().equals(GameObjectType.PlayerCharacter)) - return; - - if (!target.isAlive() || !attacker.isAlive()) - return; - - boolean isCombat = target.isCombat(); - - //If target in combat and has no target, then attack back - - AbstractWorldObject awoCombTar = target.getCombatTarget(); - - if ((target.isCombat() && awoCombTar == null) || (isCombat && awoCombTar != null && (!awoCombTar.isAlive() || target.isCombat() && NotInRange(target, awoCombTar, target.getRange()))) || (target != null && target.getObjectType() == GameObjectType.Mob && ((Mob) target).isSiege())) - if (target.getObjectType().equals(GameObjectType.PlayerCharacter)) { // we are in combat with no valid target - - PlayerCharacter pc = (PlayerCharacter) target; - target.setCombatTarget(attacker); - pc.setLastTarget(attacker.getObjectType(), attacker.getObjectUUID()); - - if (target.getTimers() != null) - if (!target.getTimers().containsKey("Attack" + EquipSlotType.RHELD.ordinal())) - CombatManager.AttackTarget((PlayerCharacter) target, target.getCombatTarget()); - } - - //Handle pet retaliate if assist is on and pet doesn't have a target. - - if (target.getObjectType().equals(GameObjectType.PlayerCharacter)) { - - Mob pet = ((PlayerCharacter) target).getPet(); - - if (pet != null && pet.assist && pet.getCombatTarget() == null) - pet.setCombatTarget(attacker); - } - - //Handle Mob Retaliate. - - if (target.getObjectType() == GameObjectType.Mob) { - - Mob attackedMobile = (Mob) target; - - //handle minion informing his captain of an attack - - if (attackedMobile.agentType.equals(AIAgentType.GUARDMINION) && attackedMobile.guardCaptain != null && attackedMobile.guardCaptain.isAlive()) { - - if (attackedMobile.guardCaptain.combatTarget == null) - attackedMobile.guardCaptain.setCombatTarget(attacker); - - } - - // Mobile already has a target; don't switch. - - if (attackedMobile.getCombatTarget() != null && !attackedMobile.isSiege()) - return; - - attackedMobile.setCombatTarget(attacker); - - } - } - - public static void handleDamageShields(AbstractCharacter ac, AbstractCharacter target, float damage) { - - if (ac == null || target == null) - return; - - PlayerBonuses bonuses = target.getBonuses(); - - if (bonuses != null) { - - ConcurrentHashMap damageShields = bonuses.getDamageShields(); - float total = 0; - - for (DamageShield ds : damageShields.values()) { - - //get amount to damage back - - float amount; - - if (ds.usePercent()) - amount = damage * ds.getAmount() / 100; - else - amount = ds.getAmount(); - - //get resisted damage for damagetype - - Resists resists = ac.getResists(); - - if (resists != null) - amount = resists.getResistedDamage(target, ac, ds.getDamageType(), amount, 0); - - total += amount; - } - - if (total > 0) { - - //apply Damage back - - ac.modifyHealth(-total, target, true); - - TargetedActionMsg cmm = new TargetedActionMsg(ac, ac, total, 0); - DispatchMessage.sendToAllInRange(target, cmm); - - } - } - } - - public static float calcHitBox(AbstractWorldObject ac) { - - //TODO Figure out how Str Affects HitBox - - float hitBox = 1; - - switch (ac.getObjectType()) { - case PlayerCharacter: - PlayerCharacter pc = (PlayerCharacter) ac; - if (MBServerStatics.COMBAT_TARGET_HITBOX_DEBUG) { - Logger.info("Hit box radius for " + pc.getFirstName() + " is " + ((int) pc.statStrBase / 20f)); - } - hitBox = 1.5f + (int) ((PlayerCharacter) ac).statStrBase / 20f; - break; - - case Mob: - Mob mob = (Mob) ac; - if (MBServerStatics.COMBAT_TARGET_HITBOX_DEBUG) - Logger.info("Hit box radius for " + mob.getFirstName() - + " is " + ((Mob) ac).getMobBase().getHitBoxRadius()); - - hitBox = ((Mob) ac).getMobBase().getHitBoxRadius(); - break; - case Building: - Building building = (Building) ac; - if (building.getBlueprint() == null) - return 32; - hitBox = Math.max(building.getBlueprint().getBuildingGroup().getExtents().x, - building.getBlueprint().getBuildingGroup().getExtents().y); - if (MBServerStatics.COMBAT_TARGET_HITBOX_DEBUG) - Logger.info("Hit box radius for " + building.getName() + " is " + hitBox); - break; - - } - return hitBox; - } - - private static void testItemDamage(AbstractCharacter ac, AbstractWorldObject awo, Item weapon, ItemTemplate wb) { - - if (ac == null) - return; - - //get chance to damage - - int chance = 4500; - - if (wb != null) - if (wb.obj_name.contains("Glass")) //glass used weighted so fast weapons don't break faster - chance = 9000 / weapon.template.item_wt; - - //test damaging attackers weapon - - int takeDamage = ThreadLocalRandom.current().nextInt(chance); - - if (takeDamage == 0 && wb != null && (ac.getObjectType().equals(GameObjectType.PlayerCharacter))) - ac.getCharItemManager().damageItem(weapon, 1); - - - //test damaging targets gear - - takeDamage = ThreadLocalRandom.current().nextInt(chance); - - if (takeDamage == 0 && awo != null && (awo.getObjectType().equals(GameObjectType.PlayerCharacter))) - ((AbstractCharacter) awo).getCharItemManager().damageRandomArmor(1); - } - -} diff --git a/src/engine/gameManager/FinalCombatManager.java b/src/engine/gameManager/FinalCombatManager.java new file mode 100644 index 00000000..4b74077d --- /dev/null +++ b/src/engine/gameManager/FinalCombatManager.java @@ -0,0 +1,427 @@ +package engine.gameManager; + +import engine.Enum; +import engine.job.JobContainer; +import engine.job.JobScheduler; +import engine.jobs.AttackJob; +import engine.jobs.DeferredPowerJob; +import engine.net.DispatchMessage; +import engine.net.client.ClientConnection; +import engine.net.client.msg.TargetedActionMsg; +import engine.net.client.msg.UpdateStateMsg; +import engine.objects.*; +import engine.powers.DamageShield; +import engine.powers.effectmodifiers.AbstractEffectModifier; +import engine.server.MBServerStatics; +import org.pmw.tinylog.Logger; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ThreadLocalRandom; + +public class FinalCombatManager { + public static void combatCycle(AbstractCharacter attacker, AbstractWorldObject target) { + //early exit checks + if(attacker == null || target == null || !attacker.isAlive() || !target.isAlive()) + return; + + switch(target.getObjectType()){ + case Building: + if(((Building)target).isVulnerable() == false) + return; + break; + case PlayerCharacter: + case Mob: + PlayerBonuses bonuses = ((AbstractCharacter)target).getBonuses(); + if(bonuses != null && bonuses.getBool(Enum.ModType.ImmuneToAttack, Enum.SourceType.NONE)) + return; + break; + case NPC: + return; + } + + Item mainWeapon = attacker.getCharItemManager().getEquipped().get(Enum.EquipSlotType.RHELD); + Item offWeapon = attacker.getCharItemManager().getEquipped().get(Enum.EquipSlotType.LHELD); + if(mainWeapon == null && offWeapon == null){ + //no weapons equipped, punch with both fists + processAttack(attacker,target,Enum.EquipSlotType.RHELD); + processAttack(attacker,target,Enum.EquipSlotType.LHELD); + }else if(mainWeapon == null && offWeapon != null && offWeapon.template.item_skill_required.containsKey("Block")){ + //no weapon equipped with a shield, punch with one hand + processAttack(attacker,target,Enum.EquipSlotType.RHELD); + }else if(mainWeapon != null && offWeapon != null && offWeapon.template.item_skill_required.containsKey("Block")){ + //one weapon equipped with a shield, swing with one hand + processAttack(attacker,target,Enum.EquipSlotType.RHELD); + }else if(mainWeapon != null && offWeapon != null && offWeapon.template.item_skill_required.containsKey("Block") == false){ + //two weapons equipped, swing both hands + processAttack(attacker,target,Enum.EquipSlotType.RHELD); + processAttack(attacker,target,Enum.EquipSlotType.LHELD); + } else if(mainWeapon == null && offWeapon != null && offWeapon.template.item_skill_required.containsKey("Block") == false){ + //swing left hand only + processAttack(attacker,target,Enum.EquipSlotType.LHELD); + } + } + + public static void processAttack(AbstractCharacter attacker, AbstractWorldObject target, Enum.EquipSlotType slot){ + //check if character can even attack yet + if(attacker.getTimestamps().containsKey("Attack" + slot.name())) + if(System.currentTimeMillis() < attacker.getTimestamps().get("Attack" + slot.name())) + return; + + //check if character is in range to attack target + PlayerBonuses bonus = attacker.getBonuses(); + float rangeMod = 1.0f; + float attackRange = MBServerStatics.NO_WEAPON_RANGE; + Item weapon = attacker.getCharItemManager().getEquipped(slot); + if (weapon != null) { + if (bonus != null) + rangeMod += bonus.getFloatPercentAll(Enum.ModType.WeaponRange, Enum.SourceType.NONE); + + attackRange = weapon.template.item_weapon_max_range * rangeMod; + } + if(attacker.getObjectType().equals(Enum.GameObjectType.Mob)) + if(((Mob)attacker).isSiege()) + attackRange = 300; + + float distanceSquared = attacker.loc.distanceSquared(target.loc); + if(distanceSquared > attackRange * attackRange) + return; + + //take stamina away from attacker + if (weapon == null) + attacker.modifyStamina(-0.5f, attacker, true); + else { + float stam = weapon.template.item_wt / 3f; + stam = (stam < 1) ? 1 : stam; + attacker.modifyStamina(-(stam), attacker, true); + } + + //cancel things that are cancelled by an attack + attacker.cancelOnAttackSwing(); + + //declare relevant variables + int min = attacker.minDamageHandOne; + int max = attacker.maxDamageHandOne; + int atr = attacker.atrHandOne; + + //get the proper stats based on which slot is attacking + if(slot == Enum.EquipSlotType.LHELD){ + min = attacker.minDamageHandTwo; + max = attacker.maxDamageHandTwo; + atr = attacker.atrHandTwo; + } + int def = 0; + if(AbstractCharacter.IsAbstractCharacter(target)) + def = ((AbstractCharacter)target).defenseRating; + + //calculate hit chance based off ATR and DEF + int hitChance; + float dif = atr / def; + if (dif <= 0.8f) + hitChance = 4; + else + hitChance = ((int) (450 * (dif - 0.8f)) + 4); + if (target.getObjectType() == Enum.GameObjectType.Building) + hitChance = 100; + + int passiveAnim = getSwingAnimation(attacker.getCharItemManager().getEquipped().get(slot).template, null, true); + + if(ThreadLocalRandom.current().nextInt(100) > hitChance) { + TargetedActionMsg msg = new TargetedActionMsg(attacker, target, 0f, passiveAnim); + + if (target.getObjectType() == Enum.GameObjectType.PlayerCharacter) + DispatchMessage.dispatchMsgToInterestArea(target, msg, Enum.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); + else + DispatchMessage.sendToAllInRange(attacker, msg); + + return; + } + + //calculate passive chances only if target is AbstractCharacter + if(AbstractCharacter.IsAbstractCharacter(target)){ + 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); + if(hitRoll > dodgeChance || hitRoll > parryChance || hitRoll > blockChance){ + TargetedActionMsg msg = new TargetedActionMsg(attacker, passiveAnim, target, MBServerStatics.COMBAT_SEND_BLOCK); + + if (target.getObjectType() == Enum.GameObjectType.PlayerCharacter) + DispatchMessage.dispatchMsgToInterestArea(target, msg, Enum.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); + else + DispatchMessage.sendToAllInRange(attacker, msg); + + return; + } + } + + //calculate the base damage + int damage = ThreadLocalRandom.current().nextInt(min,max + 1); + if(damage == 0) + return; + + //get the damage type + Enum.SourceType damageType; + if(attacker.getCharItemManager().getEquipped().get(slot) == null) { + damageType = Enum.SourceType.CRUSHING; + if(attacker.getObjectType().equals(Enum.GameObjectType.Mob)) + if(((Mob)attacker).isSiege()) + damageType = Enum.SourceType.SIEGE; + }else { + damageType = (Enum.SourceType) attacker.getCharItemManager().getEquipped().get(slot).template.item_weapon_damage.keySet().toArray()[0]; + } + + //get resists + Resists resists; + if(AbstractCharacter.IsAbstractCharacter(target) == false){ + //this is a building + resists = ((Building) target).getResists(); + }else{ + //this is a character + resists = ((AbstractCharacter) target).getResists(); + } + + if(AbstractCharacter.IsAbstractCharacter(target)) { + AbstractCharacter absTarget = (AbstractCharacter) target; + //check damage shields + PlayerBonuses bonuses = absTarget.getBonuses(); + + if (bonuses != null) { + + ConcurrentHashMap damageShields = bonuses.getDamageShields(); + float total = 0; + + for (DamageShield ds : damageShields.values()) { + + //get amount to damage back + float amount; + if (ds.usePercent()) + 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 (total > 0) { + //apply Damage back + attacker.modifyHealth(-total, absTarget, true); + TargetedActionMsg cmm = new TargetedActionMsg(attacker, attacker, total, 0); + DispatchMessage.sendToAllInRange(target, cmm); + } + } + if (resists != null) { + //check for damage type immunities + if (resists.immuneTo(damageType)) + return; + //calculate resisted damage including fortitude + damage = (int) resists.getResistedDamage(attacker,(AbstractCharacter)target,damageType,damage,0); + } + } + + //remove damage from target health + if(damage > 0){ + if(AbstractCharacter.IsAbstractCharacter(target)){ + ((AbstractCharacter)target).modifyHealth(-damage, attacker, true); + }else{ + ((Building)target).setCurrentHitPoints(target.getCurrentHitpoints() - damage); + } + TargetedActionMsg cmm = new TargetedActionMsg(attacker,target, (float) damage,0); + DispatchMessage.sendToAllInRange(target, cmm); + } + + //calculate next allowed attack and update the timestamp + long delay = 20 * 100; + if (weapon != null){ + int wepSpeed = (int) (weapon.template.item_weapon_wepspeed); + + if (weapon.getBonusPercent(Enum.ModType.WeaponSpeed, Enum.SourceType.NONE) != 0f) //add weapon speed bonus + wepSpeed *= (1 + weapon.getBonus(Enum.ModType.WeaponSpeed, Enum.SourceType.NONE)); + + if (attacker.getBonuses() != null && attacker.getBonuses().getFloatPercentAll(Enum.ModType.AttackDelay, Enum.SourceType.NONE) != 0f) //add effects speed bonus + wepSpeed *= (1 + attacker.getBonuses().getFloatPercentAll(Enum.ModType.AttackDelay, Enum.SourceType.NONE)); + + if (wepSpeed < 10) + wepSpeed = 10; //Old was 10, but it can be reached lower with legit buffs,effects. + + delay = wepSpeed * 100; + } + attacker.getTimestamps().put("Attack" + slot.name(),System.currentTimeMillis() + delay); + + //handle auto attack job creation + ConcurrentHashMap timers = attacker.getTimers(); + + if (timers != null) { + AttackJob aj = new AttackJob(attacker, slot.ordinal(), true); + JobContainer job; + job = JobScheduler.getInstance().scheduleJob(aj, (delay + 1)); // offset 1 millisecond so no overlap issue + timers.put("Attack" + slot, job); + } else { + Logger.error("Unable to find Timers for Character " + attacker.getObjectUUID()); + } + } + + public static void toggleCombat(boolean toggle, ClientConnection origin) { + + PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); + if (pc == null) + return; + + pc.setCombat(toggle); + if (!toggle) // toggle is move it to false so clear combat target + pc.setCombatTarget(null); //clear last combat target + + UpdateStateMsg rwss = new UpdateStateMsg(); + rwss.setPlayer(pc); + DispatchMessage.dispatchMsgToInterestArea(pc, rwss, Enum.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); + } + + public static void toggleSit(boolean toggle, ClientConnection origin) { + + PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); + if (pc == null) + return; + + pc.setSit(toggle); + UpdateStateMsg rwss = new UpdateStateMsg(); + rwss.setPlayer(pc); + DispatchMessage.dispatchMsgToInterestArea(pc, rwss, Enum.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); + } + + //Called when character takes damage. + public static void handleRetaliate(AbstractCharacter target, AbstractCharacter attacker) { + + if (attacker == null || target == null) + return; + + if (attacker.equals(target)) + return; + + if (target.isMoving() && target.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)) + return; + + if (!target.isAlive() || !attacker.isAlive()) + return; + + boolean isCombat = target.isCombat(); + + //If target in combat and has no target, then attack back + if(isCombat && target.combatTarget == null) + target.setCombatTarget(attacker); + } + + public static int getSwingAnimation(ItemTemplate wb, DeferredPowerJob dpj, boolean mainHand) { + int token = 0; + + if (dpj != null) + token = (dpj.getPower() != null) ? dpj.getPower().getToken() : 0; + + if (token == 563721004) //kick animation + return 79; + + if (wb == null) + return 75; + + ItemTemplate template = wb; + + if (mainHand) { + if (template.weapon_attack_anim_right.size() > 0) { + + int animation; + + int random = ThreadLocalRandom.current().nextInt(template.weapon_attack_anim_right.size()); + + try { + animation = template.weapon_attack_anim_right.get(random)[0]; + return animation; + } catch (Exception e) { + Logger.error(e.getMessage()); + return template.weapon_attack_anim_right.get(0)[0]; + } + + } else if (template.weapon_attack_anim_left.size() > 0) { + + int animation; + int random = ThreadLocalRandom.current().nextInt(template.weapon_attack_anim_left.size()); + + try { + animation = template.weapon_attack_anim_left.get(random)[0]; + return animation; + } catch (Exception e) { + Logger.error(e.getMessage()); + return template.weapon_attack_anim_right.get(0)[0]; + } + } + } else { + if (template.weapon_attack_anim_left.size() > 0) { + int animation; + int random = ThreadLocalRandom.current().nextInt(template.weapon_attack_anim_left.size()); + + try { + animation = template.weapon_attack_anim_left.get(random)[0]; + return animation; + } catch (Exception e) { + Logger.error(e.getMessage()); + return template.weapon_attack_anim_right.get(0)[0]; + + } + } else if (template.weapon_attack_anim_left.size() > 0) { + + int animation; + int random = ThreadLocalRandom.current().nextInt(template.weapon_attack_anim_left.size()); + + try { + animation = template.weapon_attack_anim_left.get(random)[0]; + return animation; + } catch (Exception e) { + Logger.error(e.getMessage()); + return template.weapon_attack_anim_right.get(0)[0]; + + } + + } + } + + String required = template.item_skill_used; + String mastery = wb.item_skill_mastery_used; + + if (required.equals("Unarmed Combat")) + return 75; + else if (required.equals("Sword")) { + + if (ItemTemplate.isTwoHanded(template)) + return 105; + else + return 98; + + } else if (required.equals("Staff") || required.equals("Pole Arm")) { + return 85; + } else if (required.equals("Spear")) { + return 92; + } else if (required.equals("Hammer") || required.equals("Axe")) { + if (ItemTemplate.isTwoHanded(template)) { + return 105; + } else if (mastery.equals("Throwing")) { + return 115; + } else { + return 100; + } + } else if (required.equals("Dagger")) { + if (mastery.equals("Throwing")) { + return 117; + } else { + return 81; + } + } else if (required.equals("Crossbow")) { + return 110; + } else if (required.equals("Bow")) { + return 109; + } else if (ItemTemplate.isTwoHanded(template)) { + return 105; + } else { + return 100; + } + } +} \ No newline at end of file diff --git a/src/engine/jobs/AttackJob.java b/src/engine/jobs/AttackJob.java index affed880..572884d9 100644 --- a/src/engine/jobs/AttackJob.java +++ b/src/engine/jobs/AttackJob.java @@ -9,7 +9,7 @@ package engine.jobs; -import engine.gameManager.CombatManager; +import engine.gameManager.FinalCombatManager; import engine.job.AbstractJob; import engine.objects.AbstractCharacter; @@ -28,7 +28,7 @@ public class AttackJob extends AbstractJob { @Override protected void doJob() { - CombatManager.doCombat(this.source, slot); + FinalCombatManager.combatCycle(this.source,this.source.combatTarget); } public boolean success() { diff --git a/src/engine/jobs/DeferredPowerJob.java b/src/engine/jobs/DeferredPowerJob.java index 6cd6973f..2ba231f7 100644 --- a/src/engine/jobs/DeferredPowerJob.java +++ b/src/engine/jobs/DeferredPowerJob.java @@ -9,7 +9,6 @@ package engine.jobs; -import engine.gameManager.CombatManager; import engine.gameManager.PowersManager; import engine.math.Vector3fImmutable; import engine.objects.AbstractCharacter; @@ -77,10 +76,12 @@ public class DeferredPowerJob extends AbstractEffectJob { // Wtf? Method returns TRUE if rage test fails? Seriously? //DO valid range check ONLY for weapon powers with range less than attack range. - if (attackRange > powerRange) - if (CombatManager.NotInRange((AbstractCharacter) this.source, tar, powerRange)) + if (attackRange > powerRange) { + float rangeSquared = this.source.loc.distanceSquared(tar.loc); + if (rangeSquared > powerRange * powerRange) { return; - + } + } //Range check passed, apply power and clear weapon power. ((PlayerCharacter) this.source).setWeaponPower(null); diff --git a/src/engine/mobileAI/MobAI.java b/src/engine/mobileAI/MobAI.java index 995501a7..32297837 100644 --- a/src/engine/mobileAI/MobAI.java +++ b/src/engine/mobileAI/MobAI.java @@ -16,7 +16,6 @@ import engine.math.Vector3f; import engine.math.Vector3fImmutable; import engine.mobileAI.Threads.MobAIThread; import engine.mobileAI.Threads.Respawner; -import engine.mobileAI.utilities.CombatUtilities; import engine.mobileAI.utilities.MovementUtilities; import engine.net.DispatchMessage; import engine.net.client.msg.PerformActionMsg; @@ -66,7 +65,7 @@ public class MobAI { } - if (!CombatUtilities.inRangeToAttack(mob, target)) + if (mob.getRange() * mob.getRange() < mob.loc.distanceSquared(target.loc)) return; switch (target.getObjectType()) { @@ -108,7 +107,7 @@ public class MobAI { return; } - if (CombatUtilities.inRange2D(mob, target, mob.getRange())) { + if (mob.getRange() * mob.getRange() >= mob.loc.distanceSquared(target.loc)) { //no weapons, default mob attack speed 3 seconds. @@ -126,7 +125,7 @@ public class MobAI { ItemBase offHand = mob.getWeaponItemBase(false); if (mainHand == null && offHand == null) { - CombatUtilities.combatCycle(mob, target, true, null); + FinalCombatManager.combatCycle(mob, target); int delay = 3000; if (mob.isSiege()) delay = 11000; @@ -135,13 +134,13 @@ public class MobAI { int delay = 3000; if (mob.isSiege()) delay = 11000; - CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); + FinalCombatManager.combatCycle(mob, target); mob.setLastAttackTime(System.currentTimeMillis() + delay); } else if (mob.getWeaponItemBase(false) != null) { int attackDelay = 3000; if (mob.isSiege()) attackDelay = 11000; - CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); + FinalCombatManager.combatCycle(mob, target); mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); } } @@ -180,7 +179,7 @@ public class MobAI { ItemBase offHand = mob.getWeaponItemBase(false); if (mainHand == null && offHand == null) { - CombatUtilities.combatCycle(mob, target, true, null); + FinalCombatManager.combatCycle(mob, target); int delay = 3000; if (mob.isSiege()) delay = 15000; @@ -189,13 +188,13 @@ public class MobAI { int attackDelay = 3000; if (mob.isSiege()) attackDelay = 15000; - CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); + FinalCombatManager.combatCycle(mob, target); mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); } else if (mob.getWeaponItemBase(false) != null) { int attackDelay = 3000; if (mob.isSiege()) attackDelay = 15000; - CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); + FinalCombatManager.combatCycle(mob, target); mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); } @@ -223,7 +222,7 @@ public class MobAI { ItemBase offHand = mob.getWeaponItemBase(false); if (mainHand == null && offHand == null) { - CombatUtilities.combatCycle(mob, target, true, null); + FinalCombatManager.combatCycle(mob, target); int delay = 3000; if (mob.isSiege()) delay = 11000; @@ -232,13 +231,13 @@ public class MobAI { int attackDelay = 3000; if (mob.isSiege()) attackDelay = 11000; - CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); + FinalCombatManager.combatCycle(mob, target); mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); } else if (mob.getWeaponItemBase(false) != null) { int attackDelay = 3000; if (mob.isSiege()) attackDelay = 11000; - CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); + FinalCombatManager.combatCycle(mob, target); mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); if (target.getCombatTarget() == null) { target.setCombatTarget(mob); @@ -423,15 +422,9 @@ public class MobAI { if (mob.isPlayerGuard()) powerRank = getGuardPowerRank(mob); - //check for hit-roll - - if (mobPower.requiresHitRoll) - if (CombatUtilities.triggerDefense(mob, mob.getCombatTarget())) - return false; - // Cast the spell - if (CombatUtilities.inRange2D(mob, mob.getCombatTarget(), mobPower.getRange())) { + if (mob.getRange() * mob.getRange() >= mob.loc.distanceSquared(target.loc)) { PerformActionMsg msg; @@ -745,7 +738,7 @@ public class MobAI { //move back to owner - if (CombatUtilities.inRange2D(mob, mob.guardCaptain, 6)) + if (mob.getRange() * mob.getRange() >= mob.loc.distanceSquared(mob.guardCaptain.loc)) return; mob.destination = mob.guardCaptain.getLoc(); @@ -852,7 +845,7 @@ public class MobAI { try { - if (mob.getCombatTarget() != null && CombatUtilities.inRange2D(mob, mob.getCombatTarget(), MobAIThread.AI_BASE_AGGRO_RANGE * 0.5f)) + if (mob.getCombatTarget() != null && mob.getRange() * mob.getRange() >= MobAIThread.AI_BASE_AGGRO_RANGE * 0.5f) return; if (mob.isPlayerGuard() && !mob.despawned) { @@ -902,7 +895,7 @@ public class MobAI { mob.getTimestamps().put("lastChase",System.currentTimeMillis()); - if (CombatUtilities.inRange2D(mob, mob.getCombatTarget(), mob.getRange()) == false) { + if (mob.getRange() * mob.getRange() <= mob.loc.distanceSquared(mob.combatTarget.loc)) { if (mob.getRange() > 15) { mob.destination = mob.getCombatTarget().getLoc(); MovementUtilities.moveToLocation(mob, mob.destination, 0, false); diff --git a/src/engine/mobileAI/utilities/CombatUtilities.java b/src/engine/mobileAI/utilities/CombatUtilities.java deleted file mode 100644 index ad0a5fce..00000000 --- a/src/engine/mobileAI/utilities/CombatUtilities.java +++ /dev/null @@ -1,360 +0,0 @@ -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - -package engine.mobileAI.utilities; - -import engine.Enum.DispatchChannel; -import engine.Enum.GameObjectType; -import engine.Enum.ModType; -import engine.Enum.SourceType; -import engine.gameManager.ChatManager; -import engine.gameManager.CombatManager; -import engine.math.Vector3fImmutable; -import engine.net.DispatchMessage; -import engine.net.client.msg.TargetedActionMsg; -import engine.objects.*; -import engine.server.MBServerStatics; -import org.pmw.tinylog.Logger; - -import java.util.concurrent.ThreadLocalRandom; - -import static engine.math.FastMath.sqr; - -public class CombatUtilities { - - public static boolean inRangeToAttack(Mob agent, AbstractWorldObject target) { - - if (Float.isNaN(agent.getLoc().x)) - return false; - - try { - Vector3fImmutable sl = agent.getLoc(); - Vector3fImmutable tl = target.getLoc(); - - //add Hitbox's to range. - float range = agent.getRange(); - range += CombatManager.calcHitBox(target) + CombatManager.calcHitBox(agent); - - return !(sl.distanceSquared(tl) > sqr(range)); - } catch (Exception e) { - Logger.error(e.toString()); - return false; - } - - } - - public static boolean inRange2D(AbstractWorldObject entity1, AbstractWorldObject entity2, double range) { - return entity1.getLoc().distanceSquared2D(entity2.getLoc()) < range * range; - } - - public static void swingIsBlock(Mob agent, AbstractWorldObject target, int animation) { - - if (!target.isAlive()) - return; - - TargetedActionMsg msg = new TargetedActionMsg(agent, animation, target, MBServerStatics.COMBAT_SEND_BLOCK); - - if (target.getObjectType() == GameObjectType.PlayerCharacter) - DispatchMessage.dispatchMsgToInterestArea(target, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); - else - DispatchMessage.sendToAllInRange(agent, msg); - - } - - public static void swingIsParry(Mob agent, AbstractWorldObject target, int animation) { - - if (!target.isAlive()) - return; - - TargetedActionMsg msg = new TargetedActionMsg(agent, animation, target, MBServerStatics.COMBAT_SEND_PARRY); - - if (target.getObjectType() == GameObjectType.PlayerCharacter) - DispatchMessage.dispatchMsgToInterestArea(target, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); - else - DispatchMessage.sendToAllInRange(agent, msg); - - } - - public static void swingIsDodge(Mob agent, AbstractWorldObject target, int animation) { - - if (!target.isAlive()) - return; - - TargetedActionMsg msg = new TargetedActionMsg(agent, animation, target, MBServerStatics.COMBAT_SEND_DODGE); - - if (target.getObjectType() == GameObjectType.PlayerCharacter) - DispatchMessage.dispatchMsgToInterestArea(target, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); - else - DispatchMessage.sendToAllInRange(agent, msg); - } - - public static void swingIsDamage(Mob agent, AbstractWorldObject target, float damage, int animation) { - if (agent.isSiege() == true) { - damage = ThreadLocalRandom.current().nextInt(1000) + 1500; - } - float trueDamage = damage; - - if (!target.isAlive()) - return; - - if (AbstractWorldObject.IsAbstractCharacter(target)) - trueDamage = ((AbstractCharacter) target).modifyHealth(-damage, agent, false); - else if (target.getObjectType() == GameObjectType.Building) - trueDamage = ((Building) target).modifyHealth(-damage, agent); - - //Don't send 0 damage kay thanx. - - if (trueDamage == 0) - return; - - TargetedActionMsg msg = new TargetedActionMsg(agent, target, damage, animation); - - if (target.getObjectType() == GameObjectType.PlayerCharacter) - DispatchMessage.dispatchMsgToInterestArea(target, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); - else - DispatchMessage.sendToAllInRange(agent, msg); - - //check damage shields - if (AbstractWorldObject.IsAbstractCharacter(target) && target.isAlive() && target.getObjectType() != GameObjectType.Mob) - CombatManager.handleDamageShields(agent, (AbstractCharacter) target, damage); - } - - public static boolean canSwing(Mob agent) { - return (agent.isAlive() && !agent.getBonuses().getBool(ModType.Stunned, SourceType.NONE)); - } - - public static void swingIsMiss(Mob agent, AbstractWorldObject target, int animation) { - - TargetedActionMsg msg = new TargetedActionMsg(agent, target, 0f, animation); - - if (target.getObjectType() == GameObjectType.PlayerCharacter) - DispatchMessage.dispatchMsgToInterestArea(target, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); - else - DispatchMessage.sendToAllInRange(agent, msg); - - } - - public static boolean triggerDefense(Mob agent, AbstractWorldObject target) { - int defenseScore = 0; - int attackScore = agent.getAtrHandOne(); - switch (target.getObjectType()) { - case PlayerCharacter: - defenseScore = ((AbstractCharacter) target).getDefenseRating(); - break; - case Mob: - - Mob mob = (Mob) target; - if (mob.isSiege()) - defenseScore = attackScore; - break; - case Building: - return false; - } - - int hitChance; - if (attackScore > defenseScore || defenseScore == 0) - hitChance = 94; - else if (attackScore == defenseScore && target.getObjectType() == GameObjectType.Mob) - hitChance = 10; - else { - float dif = attackScore / defenseScore; - if (dif <= 0.8f) - hitChance = 4; - else - hitChance = ((int) (450 * (dif - 0.8f)) + 4); - if (target.getObjectType() == GameObjectType.Building) - hitChance = 100; - } - return ThreadLocalRandom.current().nextInt(100) > hitChance; - } - - public static boolean triggerBlock(Mob agent, AbstractWorldObject ac) { - return triggerPassive(agent, ac, "Block"); - } - - public static boolean triggerParry(Mob agent, AbstractWorldObject ac) { - return triggerPassive(agent, ac, "Parry"); - } - - public static boolean triggerDodge(Mob agent, AbstractWorldObject ac) { - return triggerPassive(agent, ac, "Dodge"); - } - - public static boolean triggerPassive(Mob agent, AbstractWorldObject ac, String type) { - float chance = 0; - if (AbstractWorldObject.IsAbstractCharacter(ac)) - chance = ((AbstractCharacter) ac).getPassiveChance(type, agent.getLevel(), true); - - if (chance > 75f) - chance = 75f; - if (agent.isSiege() && AbstractWorldObject.IsAbstractCharacter(ac)) - chance = 100; - - return ThreadLocalRandom.current().nextInt(100) < chance; - } - - public static void combatCycle(Mob agent, AbstractWorldObject target, boolean mainHand, ItemBase wb) { - - ItemTemplate template = ItemTemplate.templates.get(wb.getUUID()); - - if (!agent.isAlive() || !target.isAlive()) - return; - - if (target.getObjectType() == GameObjectType.PlayerCharacter) - if (!((PlayerCharacter) target).isActive()) - return; - - int anim = 75; - float speed; - - if (mainHand) - speed = agent.getSpeedHandOne(); - else - speed = agent.getSpeedHandTwo(); - - SourceType dt = SourceType.CRUSHING; - - if (agent.isSiege()) - dt = SourceType.SIEGE; - if (wb != null) { - anim = CombatManager.getSwingAnimation(template, null, mainHand); - dt = wb.getDamageType(); - } else if (!mainHand) - return; - - Resists res = null; - PlayerBonuses bonus = null; - - switch (target.getObjectType()) { - case Building: - res = ((Building) target).getResists(); - break; - case PlayerCharacter: - res = ((PlayerCharacter) target).getResists(); - bonus = ((PlayerCharacter) target).getBonuses(); - break; - case Mob: - Mob mob = (Mob) target; - res = mob.getResists(); - bonus = ((Mob) target).getBonuses(); - break; - } - - //must not be immune to all or immune to attack - - if (bonus != null && !bonus.getBool(ModType.NoMod, SourceType.IMMUNETOATTACK)) - if (res != null && (res.immuneToAll() || res.immuneToAttacks() || res.immuneTo(dt))) - return; - - int passiveAnim = CombatManager.getSwingAnimation(template, null, mainHand); - - if (canSwing(agent)) { - if (triggerDefense(agent, target)) { - swingIsMiss(agent, target, passiveAnim); - return; - } else if (triggerDodge(agent, target)) { - swingIsDodge(agent, target, passiveAnim); - return; - } else if (triggerParry(agent, target)) { - swingIsParry(agent, target, passiveAnim); - - return; - } else if (triggerBlock(agent, target)) { - swingIsBlock(agent, target, passiveAnim); - return; - } - - swingIsDamage(agent, target, determineDamage(agent), anim); - - - if (agent.getWeaponPower() != null) - agent.getWeaponPower().attack(target, MBServerStatics.ONE_MINUTE); - } - - if (target.getObjectType().equals(GameObjectType.PlayerCharacter)) { - PlayerCharacter player = (PlayerCharacter) target; - - if (player.getDebug(64)) - ChatManager.chatSayInfo(player, "Debug Combat: Mob UUID " + agent.getObjectUUID() + " || Building ID = " + agent.getBuildingID() + " || Floor = " + agent.getInFloorID() + " || Level = " + agent.getInBuilding());//combat debug - } - - //SIEGE MONSTERS DO NOT ATTACK GUARDSs - if (target.getObjectType() == GameObjectType.Mob) - if (((Mob) target).isSiege()) - return; - - //handle the retaliate - - if (AbstractWorldObject.IsAbstractCharacter(target)) - CombatManager.handleRetaliate((AbstractCharacter) target, agent); - - if (target.getObjectType() == GameObjectType.Mob) { - Mob targetMob = (Mob) target; - if (targetMob.isSiege()) - return; - } - - } - - public static float determineDamage(Mob agent) { - - //early exit for null - - if (agent == null) - return 0; - - AbstractWorldObject target = agent.getCombatTarget(); - - if (target == null) - return 0; - - int damage = 0; - - SourceType dt = getDamageType(agent); - damage = ThreadLocalRandom.current().nextInt((int)getMinDmg(agent), (int)getMaxDmg(agent) + 1); - if (AbstractWorldObject.IsAbstractCharacter(target)) { - if (((AbstractCharacter) target).isSit()) { - damage *= 2.5f; //increase damage if sitting - } - return (int) (((AbstractCharacter) target).getResists().getResistedDamage(agent, (AbstractCharacter) target, dt, damage, 0)); - } - if (target.getObjectType() == GameObjectType.Building) { - Building building = (Building) target; - Resists resists = building.getResists(); - return (int) ((damage * (1 - (resists.getResist(dt, 0) / 100)))); - } - return damage; - } - - public static SourceType getDamageType(Mob agent) { - SourceType dt = SourceType.CRUSHING; - if (agent.getEquip().get(1) != null) { - return agent.getEquip().get(1).getItemBase().getDamageType(); - } - if (agent.getEquip().get(2) != null && ItemTemplate.isShield(agent.getEquip().get(2).template) == false) { - return agent.getEquip().get(2).getItemBase().getDamageType(); - } - return dt; - } - - public static double getMinDmg(Mob agent) { - if (agent.equip.get(2) != null && !ItemTemplate.isShield(agent.equip.get(2).template)) - return agent.minDamageHandTwo; - else - return agent.minDamageHandOne; - } - - public static double getMaxDmg(Mob agent) { - if (agent.equip.get(2) != null && !ItemTemplate.isShield(agent.equip.get(2).template)) - return agent.maxDamageHandTwo; - else - return agent.maxDamageHandOne; - } - -} diff --git a/src/engine/net/client/ClientMessagePump.java b/src/engine/net/client/ClientMessagePump.java index 2a4f83a4..6b4208b1 100644 --- a/src/engine/net/client/ClientMessagePump.java +++ b/src/engine/net/client/ClientMessagePump.java @@ -1237,7 +1237,22 @@ public class ClientMessagePump implements NetMsgHandler { && (msg.getTargetType() == GameObjectType.PlayerCharacter.ordinal())) return; - CombatManager.setAttackTarget(msg, conn); + //CombatManager.setAttackTarget(msg, conn); + if(msg.getTargetType() == GameObjectType.Building.ordinal()){ + conn.getPlayerCharacter().getPet().setCombatTarget(PlayerCharacter.getPlayerCharacter(msg.getTargetID())); + } + switch(msg.getTargetType()) { + case 53: //player character + conn.getPlayerCharacter().getPet().setCombatTarget(PlayerCharacter.getPlayerCharacter(msg.getTargetID())); + break; + case 37://mob + conn.getPlayerCharacter().getPet().setCombatTarget(Mob.getMob(msg.getTargetID())); + break; + case 8://mob + conn.getPlayerCharacter().getPet().setCombatTarget(BuildingManager.getBuilding(msg.getTargetID())); + break; + } + if (pet.getCombatTarget() == null) return; } @@ -1430,10 +1445,10 @@ public class ClientMessagePump implements NetMsgHandler { social((SocialMsg) msg, origin); break; case COMBATMODE: - CombatManager.toggleCombat((ToggleCombatMsg) msg, origin); + FinalCombatManager.toggleCombat(((ToggleCombatMsg) msg).toggleCombat(),origin); break; case ARCCOMBATMODEATTACKING: - CombatManager.toggleCombat((SetCombatModeMsg) msg, origin); + FinalCombatManager.toggleCombat(((SetCombatModeMsg) msg).getToggle(),origin); break; case MODIFYGUILDSTATE: ToggleLfgRecruitingMsg tlrm = (ToggleLfgRecruitingMsg) msg; diff --git a/src/engine/net/client/handlers/AttackCmdMsgHandler.java b/src/engine/net/client/handlers/AttackCmdMsgHandler.java index a849cb92..76460144 100644 --- a/src/engine/net/client/handlers/AttackCmdMsgHandler.java +++ b/src/engine/net/client/handlers/AttackCmdMsgHandler.java @@ -3,7 +3,7 @@ package engine.net.client.handlers; import engine.Enum; import engine.exception.MsgSendException; import engine.gameManager.BuildingManager; -import engine.gameManager.CombatManager; +import engine.gameManager.FinalCombatManager; import engine.net.client.ClientConnection; import engine.net.client.msg.AttackCmdMsg; import engine.net.client.msg.ClientNetMsg; @@ -70,15 +70,16 @@ public class AttackCmdMsgHandler extends AbstractClientMsgHandler { //put in combat if not already - if (!playerCharacter.isCombat()) - CombatManager.toggleCombat(true, origin); - + if (!playerCharacter.isCombat()) { + //CombatManager.toggleCombat(true, origin); + FinalCombatManager.toggleCombat(true,origin); + } //make character stand if sitting if (playerCharacter.isSit()) - CombatManager.toggleSit(false, origin); + FinalCombatManager.toggleSit(false, origin); - CombatManager.AttackTarget(playerCharacter, target); + FinalCombatManager.combatCycle(playerCharacter,target); return true; } diff --git a/src/engine/objects/AbstractCharacter.java b/src/engine/objects/AbstractCharacter.java index 18f0f63e..e3394984 100644 --- a/src/engine/objects/AbstractCharacter.java +++ b/src/engine/objects/AbstractCharacter.java @@ -1332,7 +1332,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject { //TODO why is Handle REtaliate and cancelontakedamage in modifyHealth? shouldnt this be outside this method? if (value < 0f && !fromCost) { this.cancelOnTakeDamage(); - CombatManager.handleRetaliate(this, attacker); + FinalCombatManager.handleRetaliate(this, attacker); } if(this.getObjectType().equals(GameObjectType.Mob)){ @@ -1399,7 +1399,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject { } if (value < 0f && !fromCost) { this.cancelOnTakeDamage(); - CombatManager.handleRetaliate(this, attacker); + FinalCombatManager.handleRetaliate(this, attacker); } return newMana - oldMana; } @@ -1438,7 +1438,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject { } if (value < 0f && !fromCost) { this.cancelOnTakeDamage(); - CombatManager.handleRetaliate(this, attacker); + FinalCombatManager.handleRetaliate(this, attacker); } return newStamina - oldStamina; } @@ -1473,7 +1473,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject { } if (oldMana > newMana && !fromCost) { this.cancelOnTakeDamage(); - CombatManager.handleRetaliate(this, attacker); + FinalCombatManager.handleRetaliate(this, attacker); } return newMana - oldMana; } @@ -1508,7 +1508,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject { } if (oldStamina > newStamina && !fromCost) { this.cancelOnTakeDamage(); - CombatManager.handleRetaliate(this, attacker); + FinalCombatManager.handleRetaliate(this, attacker); } return newStamina - oldStamina; diff --git a/src/engine/powers/poweractions/StealPowerAction.java b/src/engine/powers/poweractions/StealPowerAction.java index 77133125..ee1c41db 100644 --- a/src/engine/powers/poweractions/StealPowerAction.java +++ b/src/engine/powers/poweractions/StealPowerAction.java @@ -12,7 +12,7 @@ package engine.powers.poweractions; import engine.Enum; import engine.Enum.ItemType; import engine.gameManager.ChatManager; -import engine.gameManager.CombatManager; +import engine.gameManager.FinalCombatManager; import engine.math.Vector3fImmutable; import engine.net.Dispatch; import engine.net.DispatchMessage; @@ -132,7 +132,7 @@ public class StealPowerAction extends AbstractPowerAction { ownerPC.setLastPlayerAttackTime(); //Handle target attacking back if in combat and has no other target - CombatManager.handleRetaliate(ownerAC, sourcePlayer); + FinalCombatManager.handleRetaliate(ownerAC, sourcePlayer); } else return;