테스트

aion-server 4.8

Gitteol
최고관리자 · 1 · 💬 0 클론/새로받기
 4.8 61f661d · 1 commits 새로받기(Pull)
game-server/src/com/aionemu/gameserver/controllers/observer/AttackShieldObserver.java
package com.aionemu.gameserver.controllers.observer;

import java.util.List;

import com.aionemu.commons.utils.Rnd;
import com.aionemu.gameserver.controllers.attack.AttackResult;
import com.aionemu.gameserver.controllers.attack.AttackStatus;
import com.aionemu.gameserver.dataholders.DataManager;
import com.aionemu.gameserver.model.gameobjects.Creature;
import com.aionemu.gameserver.model.gameobjects.Npc;
import com.aionemu.gameserver.model.gameobjects.Summon;
import com.aionemu.gameserver.model.summons.SummonMode;
import com.aionemu.gameserver.network.aion.serverpackets.SM_ATTACK_STATUS;
import com.aionemu.gameserver.network.aion.serverpackets.SM_ATTACK_STATUS.LOG;
import com.aionemu.gameserver.network.aion.serverpackets.SM_ATTACK_STATUS.TYPE;
import com.aionemu.gameserver.skillengine.effect.EffectTemplate;
import com.aionemu.gameserver.skillengine.model.*;
import com.aionemu.gameserver.skillengine.model.Effect.ForceType;
import com.aionemu.gameserver.utils.PositionUtil;

/**
 * @author ATracer, Sippolo, kecimis, Luzien, Neon
 */
public class AttackShieldObserver extends AttackCalcObserver {

	private final Effect effect;
	private final HitType hitType;
	private final ShieldType shieldType;
	private final int hit;
	private final boolean hitPercent;
	private int totalHit;
	private final boolean totalHitPercent;
	private final int probability;
	private final int minRadius;
	private final int maxRadius;
	private final HealType healType;
	private final int mpValue;

	private boolean totalHitPercentSet = false;

	public AttackShieldObserver(int hit, int totalHit, boolean percent, Effect effect, HitType type, ShieldType shieldType, int probability) {
		this(hit, totalHit, percent, false, effect, type, shieldType, probability, 0, 100, null, 0);
	}

	public AttackShieldObserver(int hit, int totalHit, boolean percent, Effect effect, HitType type, ShieldType shieldType, int probability,
		int mpValue) {
		this(hit, totalHit, percent, false, effect, type, shieldType, probability, 0, 100, null, mpValue);
	}

	public AttackShieldObserver(int hit, int totalHit, boolean hitPercent, boolean totalHitPercent, Effect effect, HitType type, ShieldType shieldType,
		int probability, int minRadius, int maxRadius, HealType healType, int mpValue) {
		this.hit = hit;
		this.totalHit = totalHit; // total absorbed dmg for shield, percentage for reflector, received dmg percentage for protect
		this.effect = effect;
		this.hitPercent = hitPercent;
		this.totalHitPercent = totalHitPercent;
		this.hitType = type;
		this.shieldType = shieldType;
		this.probability = probability;
		this.minRadius = minRadius; // only for reflector
		this.maxRadius = maxRadius; // for reflector / protect
		this.healType = healType; // only for ConvertHeal
		this.mpValue = mpValue;
	}

	@Override
	public void checkShield(List<AttackResult> attackList, Effect attackerEffect, Creature attacker) {
		for (AttackResult attackResult : attackList) {
			AttackStatus baseStatus = AttackStatus.getBaseStatus(attackResult.getAttackStatus());
			if (baseStatus == AttackStatus.DODGE || baseStatus == AttackStatus.RESIST)
				continue;

			// Handle Hit Types for Shields
			switch (hitType) {
				case EVERYHIT:
					break;
				case SKILL:
					if (attackerEffect == null)
						continue;
					break;
				default:
					if (attackResult.getHitType() != null && hitType != attackResult.getHitType())
						continue;
			}

			if (probability < 100 && Rnd.chance() >= probability)
				continue;

			// shield type 2 or 16, normal shield, MP
			if (shieldType == ShieldType.NORMAL || shieldType == ShieldType.MPSHIELD) {
				int damage = attackResult.getDamage();

				int absorbedDamage;
				if (hitPercent)
					absorbedDamage = damage * hit / 100;
				else
					absorbedDamage = Math.min(damage, hit);

				absorbedDamage = Math.min(absorbedDamage, totalHit);
				totalHit -= absorbedDamage;

				if (absorbedDamage > 0)
					attackResult.setShieldType(shieldType.getId());
				attackResult.setDamage(damage - absorbedDamage);

				// don't launch sub effect if damage is fully absorbed
				if (absorbedDamage >= damage && !isPunchShield(attackerEffect))
					attackResult.setLaunchSubEffect(false);

				if (mpValue != 0) {
					int mp = (int) (absorbedDamage * 0.01f * mpValue);
					// TODO recheck sm_attack_status
					effect.getEffected().getLifeStats().reduceMp(SM_ATTACK_STATUS.TYPE.USED_MP, mp, 0, SM_ATTACK_STATUS.LOG.REGULAR);
					attackResult.setMpAbsorbed(mp);
					attackResult.setMpShieldSkillId(effect.getSkillId());
				}

				if (totalHit <= 0) {
					effect.endEffect();
					return;
				}
			} else if (shieldType == ShieldType.REFLECTOR || shieldType == ShieldType.SKILL_REFLECTOR) { // shield type 1, reflected damage
				if (minRadius != 0) {
					if (PositionUtil.isInRange(attacker, effect.getEffected(), minRadius, false))
						continue;
				}
				if (PositionUtil.isInRange(attacker, effect.getEffected(), maxRadius, false)) {
					int reflectedHit = attackResult.getDamage();
					if (hit > 0 || totalHit > 0) {
						int reflectedDamage = attackResult.getDamage() * totalHit / 100;
						reflectedHit = Math.max(reflectedDamage, hit); // percentage of damage, but at least hit value
					}
					attackResult.setShieldType(shieldType.getId());
					if (attacker instanceof Npc) {
						reflectedHit = (int) attacker.getAi().modifyDamage(attacker, reflectedHit, effect);
					}
					attackResult.setReflectedDamage(reflectedHit);
					attackResult.setReflectedSkillId(effect.getSkillId());

					if (shieldType == ShieldType.SKILL_REFLECTOR) { // whole skill reflections are applied implicitly, see Effect#getEffected()
						attackerEffect.setForceType(ForceType.DEFAULT); // make sure it hits the effector (no checks needed at this point)
						effect.endEffect(); // one skill reflection ends the shield effect
						return;
					} else { // apply reflect damage
						attacker.getController().onAttack(effect.getEffected(), effect, TYPE.REGULAR, reflectedHit, false, LOG.REGULAR, null, null);
					}
				}
				break;
			} else if (shieldType == ShieldType.PROTECT) { // shield type 8, protect effect (ex. skillId: 417 Bodyguard I)
				if (effect.getEffector() == null || effect.getEffector().isDead()) {
					effect.endEffect();
					break;
				}
				if (effect.getEffector() instanceof Summon
					&& (((Summon) effect.getEffector()).getMode() == SummonMode.RELEASE || ((Summon) effect.getEffector()).getMaster() == null)) {
					effect.endEffect();
					break;
				}

				if (PositionUtil.isInRange(effect.getEffector(), effect.getEffected(), maxRadius, false)) {
					int damageProtected = 0;
					int effectorDamage = 0;

					if (hitPercent) {
						damageProtected = (int) (attackResult.getDamage() * hit * 0.01);
						if (totalHit > 0) // reduce the effectively received damage (totalHit = percent of received dmg)
							effectorDamage = attackResult.getDamage() * totalHit / 100;
						else
							effectorDamage = attackResult.getDamage();
					} else
						damageProtected = hit;
					int finalDamage = Math.max(0, attackResult.getDamage() - damageProtected);
					attackResult.setDamage(finalDamage);
					attackResult.setShieldType(shieldType.getId());
					attackResult.setProtectedSkillId(effect.getSkillId());
					attackResult.setProtectedDamage(effectorDamage);
					attackResult.setProtectorId(effect.getEffectorId());
					effect.getEffector().getController().onAttack(attacker, attackerEffect, TYPE.PROTECTDMG, effectorDamage, false, LOG.REGULAR,
						attackResult.getAttackStatus(), null);
					// dont launch subeffect if damage is fully absorbed
					if (!isPunchShield(attackerEffect))
						attackResult.setLaunchSubEffect(false);
				}
			} else if (shieldType == ShieldType.CONVERT) { // shield type 0, convertHeal
				int damage = attackResult.getDamage();

				int absorbedDamage = damage;

				if (totalHitPercent && !totalHitPercentSet) {
					totalHit = (int) (totalHit * 0.01 * effect.getEffected().getGameStats().getHealth().getCurrent());
					totalHitPercentSet = true;
				}

				absorbedDamage = Math.min(absorbedDamage, totalHit);
				totalHit -= absorbedDamage;

				attackResult.setDamage(damage - absorbedDamage);

				// heal part
				int healValue = 0;
				if (hitPercent)
					healValue = damage * hit / 100;
				else
					healValue = hit;

				switch (healType) {
					case HP:
						effect.getEffected().getLifeStats().increaseHp(TYPE.HP, healValue, effect, LOG.REGULAR);
						break;
					case MP:
						effect.getEffected().getLifeStats().increaseMp(TYPE.HEAL_MP, healValue, effect.getSkillId(), LOG.REGULAR);
						break;
				}

				// dont launch subeffect if damage is fully absorbed
				if (absorbedDamage >= damage && !isPunchShield(attackerEffect))
					attackResult.setLaunchSubEffect(false);

				if (totalHit <= 0) {
					effect.endEffect();
					return;
				}
			}
		}
	}

	private boolean isPunchShield(Effect effect) {
		if (effect == null)
			return false;
		for (EffectTemplate template : effect.getEffectTemplates()) {
			if (template.getSubEffect() != null) {
				SkillTemplate skill = DataManager.SKILL_DATA.getSkillTemplate(template.getSubEffect().getSkillId());
				if (skill.isProvoked())
					return true;
			}
		}
		return false;
	}

	public ShieldType getShieldType() {
		return shieldType;
	}

}

📎 첨부파일

댓글 작성 권한이 없습니다.
🏆 포인트 랭킹 TOP 10
순위 닉네임 포인트
1 no_profile 타키야겐지쪽지보내기 자기소개 아이디로 검색 전체게시물 102,949
2 no_profile 동가리쪽지보내기 자기소개 아이디로 검색 전체게시물 63,733
3 no_profile 라프텔쪽지보내기 자기소개 아이디로 검색 전체게시물 51,771
4 no_profile 불멸의행복쪽지보내기 자기소개 아이디로 검색 전체게시물 36,923
5 서번트쪽지보내기 자기소개 아이디로 검색 전체게시물 35,011
6 no_profile 닥터스쪽지보내기 자기소개 아이디로 검색 전체게시물 29,470
7 no_profile 검은고양이쪽지보내기 자기소개 아이디로 검색 전체게시물 29,077
8 no_profile Revolution쪽지보내기 자기소개 아이디로 검색 전체게시물 28,199
9 no_profile 보거스쪽지보내기 자기소개 아이디로 검색 전체게시물 26,731
10 no_profile 호롤롤로쪽지보내기 자기소개 아이디로 검색 전체게시물 17,020
알림 0