/* * This file is part of aion-unique <aion-unique.org>. * * aion-unique is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * aion-unique is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with aion-unique. If not, see <http://www.gnu.org/licenses/>. */ package com.aionemu.gameserver.controllers.attack; import java.util.ArrayList; import java.util.Collections; import java.util.List; import com.aionemu.commons.utils.Rnd; import com.aionemu.gameserver.model.SkillElement; import com.aionemu.gameserver.model.gameobjects.Creature; import com.aionemu.gameserver.model.gameobjects.player.Player; import com.aionemu.gameserver.model.gameobjects.stats.CreatureGameStats; import com.aionemu.gameserver.model.gameobjects.stats.StatEnum; import com.aionemu.gameserver.model.templates.item.WeaponType; import com.aionemu.gameserver.skillengine.model.Effect; import com.aionemu.gameserver.utils.stats.StatFunctions; /** * @author ATracer * * Probably this is a temporary class for attack calculation * cause i need it during refactoring */ public class AttackUtil { /** * @param attacker * @param attacked * @return List<AttackResult> */ public static List<AttackResult> calculateAttackResult(Creature attacker, Creature attacked) { int damage = StatFunctions.calculateBaseDamageToTarget(attacker, attacked); AttackStatus status = calculatePhysicalStatus(attacker, attacked); CreatureGameStats<?> gameStats = attacker.getGameStats(); if(attacker instanceof Player && ((Player)attacker).getEquipment().getOffHandWeaponType() != null) { AttackStatus offHandStatus; switch(status) { case BLOCK: offHandStatus = AttackStatus.OFFHAND_BLOCK; break; case DODGE: offHandStatus = AttackStatus.OFFHAND_DODGE; break; case CRITICAL: offHandStatus = AttackStatus.OFFHAND_CRITICAL; break; case PARRY: offHandStatus = AttackStatus.OFFHAND_PARRY; break; default: offHandStatus = AttackStatus.OFFHAND_NORMALHIT; break; } int offHandDamage = StatFunctions.calculateOffHandPhysicDamageToTarget(attacker, attacked); int mainHandHits = Rnd.get(1,gameStats.getCurrentStat(StatEnum.MAIN_HAND_HITS)); int offHandHits = Rnd.get(1,gameStats.getCurrentStat(StatEnum.OFF_HAND_HITS)); List<AttackResult> attackList = new ArrayList<AttackResult>(); attackList.addAll(splitPhysicalDamage(attacker, attacked, mainHandHits, damage, status)); attackList.addAll(splitPhysicalDamage(attacker, attacked, offHandHits, offHandDamage, offHandStatus)); attacked.getObserveController().checShieldStatus(attackList); return attackList; } int hitCount = Rnd.get(1,gameStats.getCurrentStat(StatEnum.MAIN_HAND_HITS)); List<AttackResult> attackList = splitPhysicalDamage(attacker, attacked, hitCount, damage, status); attacked.getObserveController().checShieldStatus(attackList); return attackList; } public static List<AttackResult> splitPhysicalDamage(Creature attacker, Creature attacked, int hitCount, int damage, AttackStatus status) { List<AttackResult> attackList = new ArrayList<AttackResult>(); for (int i=0; i < hitCount; i++) { int damages = damage; if (i!=0) { damages = Math.round(damage * 0.1f); } WeaponType weaponType; //TODO this is very basic calcs, for initial testing only switch(status) { case BLOCK: case OFFHAND_BLOCK: int shieldDamageReduce = ((Player)attacked).getGameStats().getCurrentStat(StatEnum.DAMAGE_REDUCE); damages -= Math.round((damages * shieldDamageReduce) / 100); break; case DODGE: case OFFHAND_DODGE: damages = 0; break; case CRITICAL: weaponType = ((Player)attacker).getEquipment().getMainHandWeaponType(); damages = calculateWeaponCritical(damages, weaponType); break; case OFFHAND_CRITICAL: weaponType = ((Player)attacker).getEquipment().getOffHandWeaponType(); damages = calculateWeaponCritical(damages, weaponType); break; case PARRY: case OFFHAND_PARRY: damages *= 0.5; break; default: break; } attackList.add(new AttackResult(damages, status)); } return attackList; } /** * [Critical] * Spear : x1.5 * Sword : x2.5 * Dagger : x2.3 * Mace : x2.0 * Greatsword : x1.5 * Orb : x2.0 * Spellbook : x2.0 * Bow : x1.4 * Staff : x1.5 * * @param damages * @param weaponType * @return */ private static int calculateWeaponCritical(int damages, WeaponType weaponType) { switch(weaponType) { case DAGGER_1H: damages = Math.round(damages * 2.3f); break; case SWORD_1H: damages = Math.round(damages * 2.2f); break; case MACE_1H: damages *= 2; break; case SWORD_2H: case POLEARM_2H: damages = Math.round(damages * 1.8f); break; case STAFF_2H: case BOW: damages = Math.round(damages * 1.8f); break; default: damages = Math.round(damages * 1.5f); break; } return damages; } /** * * @param effect * @param skillDamage */ public static void calculatePhysicalSkillAttackResult(Effect effect, int skillDamage) { Creature effector = effect.getEffector(); Creature effected = effect.getEffected(); int damage = StatFunctions.calculatePhysicDamageToTarget(effector, effected, skillDamage); AttackStatus status = calculatePhysicalStatus(effector, effected); switch(status) { case BLOCK: int shieldDamageReduce = ((Player)effected).getGameStats().getCurrentStat(StatEnum.DAMAGE_REDUCE); damage -= Math.round((damage * shieldDamageReduce) / 100); break; case DODGE: damage = 0; break; case CRITICAL: damage *= 2; break; case PARRY: damage *= 0.5; break; default: break; } calculateEffectResult(effect, effected, damage, status); } /** * * @param effect * @param effected * @param damage * @param status */ private static void calculateEffectResult(Effect effect, Creature effected, int damage, AttackStatus status) { AttackResult attackResult = new AttackResult(damage, status); effected.getObserveController().checShieldStatus(Collections.singletonList(attackResult)); effect.setReserved1(attackResult.getDamage()); effect.setAttackStatus(attackResult.getAttackStatus()); effect.setShieldDefense(attackResult.getShieldType()); } /** * * @param effect * @param skillDamage * @param element */ public static void calculateMagicalSkillAttackResult(Effect effect, int skillDamage, SkillElement element) { Creature effector = effect.getEffector(); Creature effected = effect.getEffected(); int damage = StatFunctions.calculateMagicDamageToTarget(effector, effected, skillDamage, element); //TODO SkillElement AttackStatus status = calculateMagicalStatus(effector, effected); switch(status) { case RESIST: damage = 0; break; default: break; } calculateEffectResult(effect, effected, damage, status); } /** * Manage attack status rate * @source http://www.aionsource.com/forum/mechanic-analysis/42597-character-stats-xp-dp-origin-gerbator-team-july-2009-a.html * @return AttackStatus */ public static AttackStatus calculatePhysicalStatus(Creature attacker, Creature attacked) { if( Rnd.get( 0, 100 ) < StatFunctions.calculatePhysicalDodgeRate(attacker, attacked) ) return AttackStatus.DODGE; if( attacked instanceof Player && ((Player)attacked).getEquipment().getMainHandWeaponType() != null // PARRY can only be done with weapon, also weapon can have humanoid mobs, && Rnd.get( 0, 100 ) < StatFunctions.calculatePhysicalParryRate(attacker, attacked) ) // but for now there isnt implementation of monster category return AttackStatus.PARRY; if( attacked instanceof Player && ((Player) attacked).getEquipment().isShieldEquipped() && Rnd.get( 0, 100 ) < StatFunctions.calculatePhysicalBlockRate(attacker, attacked) ) return AttackStatus.BLOCK; if( attacker instanceof Player && ((Player)attacker).getEquipment().getMainHandWeaponType() != null // CRITICAL can only be done with weapon, weapon can have humanoid mobs also, && Rnd.get( 0, 100 ) < StatFunctions.calculatePhysicalCriticalRate(attacker) ) // but for now there isnt implementation of monster category return AttackStatus.CRITICAL; return AttackStatus.NORMALHIT; } public static AttackStatus calculateMagicalStatus(Creature attacker, Creature attacked) { if(Rnd.get( 0, 100 ) < StatFunctions.calculateMagicalResistRate(attacker, attacked)) return AttackStatus.RESIST; return AttackStatus.NORMALHIT; } }