테스트

aion-server 4.8

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

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import com.aionemu.commons.utils.Rnd;
import com.aionemu.gameserver.ai.AILogger;
import com.aionemu.gameserver.ai.AISubState;
import com.aionemu.gameserver.ai.NpcAI;
import com.aionemu.gameserver.ai.event.AIEventType;
import com.aionemu.gameserver.controllers.attack.AggroInfo;
import com.aionemu.gameserver.dataholders.DataManager;
import com.aionemu.gameserver.model.gameobjects.*;
import com.aionemu.gameserver.model.skill.NpcSkillEntry;
import com.aionemu.gameserver.model.skill.NpcSkillList;
import com.aionemu.gameserver.model.templates.npcskill.NpcSkillTargetAttribute;
import com.aionemu.gameserver.model.templates.npcskill.NpcSkillTemplate;
import com.aionemu.gameserver.skillengine.effect.AbnormalState;
import com.aionemu.gameserver.skillengine.model.SkillTemplate;
import com.aionemu.gameserver.skillengine.model.SkillType;
import com.aionemu.gameserver.skillengine.properties.FirstTargetAttribute;
import com.aionemu.gameserver.skillengine.properties.Properties;
import com.aionemu.gameserver.skillengine.properties.TargetRangeAttribute;
import com.aionemu.gameserver.utils.PositionUtil;
import com.aionemu.gameserver.utils.ThreadPoolManager;
import com.aionemu.gameserver.world.geo.GeoService;

/**
 * @author ATracer, Yeats
 */
public class SkillAttackManager {

	public static void performAttack(NpcAI npcAI, int delay) {
		if (npcAI.getOwner().getObjectTemplate().getAttackRange() == 0) {
			if (npcAI.getOwner().getTarget() != null
				&& !PositionUtil.isInRange(npcAI.getOwner(), npcAI.getOwner().getTarget(), npcAI.getOwner().getAggroRange())) {
				npcAI.getOwner().getController().abortCast();
				npcAI.onGeneralEvent(AIEventType.TARGET_TOOFAR);
				return;
			}
		}
		if (npcAI.setSubStateIfNot(AISubState.CAST)) {
			if (delay > 0) {
				ThreadPoolManager.getInstance().schedule(() -> skillAction(npcAI), delay);
			} else {
				skillAction(npcAI);
			}
		}
	}

	protected static void skillAction(NpcAI npcAI) {
		if (npcAI.getSubState() != AISubState.CAST)
			return;
		Npc owner = npcAI.getOwner();
		VisibleObject target = owner.getTarget();
		NpcSkillEntry skill = owner.getGameStats().getLastSkill();
		if (!(target instanceof Creature) || ((Creature) target).isDead() || skill == null) {
			npcAI.setSubStateIfNot(AISubState.NONE);
			npcAI.onGeneralEvent(AIEventType.TARGET_GIVEUP);
			return;
		}
		if (owner.getObjectTemplate().getAttackRange() == 0 && !PositionUtil.isInRange(owner, target, owner.getAggroRange())) {
			owner.getController().abortCast();
			npcAI.onGeneralEvent(AIEventType.TARGET_TOOFAR);
			return;
		}
		SkillTemplate template = DataManager.SKILL_DATA.getSkillTemplate(skill.getSkillId());
		if (npcAI.isLogging()) {
			AILogger.info(npcAI, "Using skill " + skill.getSkillId() + " level: " + skill.getSkillLevel() + " duration: " + template.getDuration());
		}
		if ((template.getType() == SkillType.MAGICAL && owner.getEffectController().isAbnormalSet(AbnormalState.SILENCE))
			|| (template.getType() == SkillType.PHYSICAL && owner.getEffectController().isAbnormalSet(AbnormalState.BIND))
			|| (owner.getEffectController().isInAnyAbnormalState(AbnormalState.CANT_ATTACK_STATE))
			|| (owner.isTransformed() && owner.getTransformModel().getBanUseSkills() == 1)) {
			afterUseSkill(npcAI);
		} else {
			if (template.getProperties().getFirstTarget() == FirstTargetAttribute.ME) {
				owner.setTarget(owner);
			} else {
				NpcSkillEntry lastSkill = owner.getGameStats().getLastSkill();
				if (lastSkill != null) {
					NpcSkillTemplate temp = lastSkill.getTemplate();
					if (temp != null) {
						switch (temp.getTarget()) {
							case FRIEND:
								owner.getKnownList().getKnownObjects().values().stream()
									.filter(vo -> vo instanceof Npc npc && !npc.isDead() && !npc.getLifeStats().isAboutToDie() && !owner.isEnemy(npc)
										&& owner.canSee(npc) && PositionUtil.isInRange(owner, npc, template.getProperties().getFirstTargetRange(), false)
										&& GeoService.getInstance().canSee(owner, npc))
									.findAny().ifPresent(owner::setTarget);
								break;
							case ME:
								if (!target.equals(owner)) {
									owner.setTarget(owner);
								}
								break;
							case MOST_HATED:
								Creature target2 = owner.getAggroList().getMostHated();
								if (target2 != null && !target2.isDead()) {
									if (!target.equals(target2)) {
										owner.setTarget(target2);
									}
								}
								break;
							case SECOND_MOST_HATED:
							case THIRD_MOST_HATED:
								int limit = temp.getTarget() == NpcSkillTargetAttribute.SECOND_MOST_HATED ? 2 : 3;
								List<AggroInfo> topThree = owner.getAggroList().getList().stream().filter(ai -> ai.getAttacker() instanceof Creature c && !c.isDead())
									.sorted(Comparator.comparingInt(AggroInfo::getHate).reversed()).limit(limit).toList();

								if (!topThree.isEmpty())
									owner.setTarget((Creature) topThree.getLast().getAttacker());
								break;
							case RANDOM:
							case RANDOM_EXCEPT_MOST_HATED:
								List<Creature> knownCreatures = new ArrayList<>();
								for (VisibleObject obj : owner.getKnownList().getKnownObjects().values()) {
									if (obj instanceof Creature target3 && !(obj instanceof Summon) && !(obj instanceof SummonedObject)) {
										if (target3.isDead() || target3.getLifeStats().isAboutToDie())
											continue;
										if (temp.getTarget() == NpcSkillTargetAttribute.RANDOM_EXCEPT_MOST_HATED && owner.getAggroList().getMostHated().equals(target3))
											continue;
										if (owner.isEnemy(target3) && owner.canSee(target3)
											&& PositionUtil.isInRange(owner, target3, template.getProperties().getFirstTargetRange(), false)
											&& GeoService.getInstance().canSee(owner, target3)) {
											knownCreatures.add(target3);
										}
									}
								}
								if (!knownCreatures.isEmpty()) {
									Creature target3 = Rnd.get(knownCreatures);
									if (target3 != null) {
										owner.setTarget(target3);
									}
								}
								break;
						}
					}
				}
			}
			boolean success = owner.getController().useSkill(skill.getSkillId(), skill.getSkillLevel());
			if (!success) {
				afterUseSkill(npcAI);
			}
		}
	}

	/**
	 * @param npcAI
	 */
	public static void afterUseSkill(NpcAI npcAI) {
		npcAI.setSubStateIfNot(AISubState.NONE);
		npcAI.onGeneralEvent(AIEventType.ATTACK_COMPLETE);
	}

	/**
	 * @param npcAI
	 * @return
	 */
	public static NpcSkillEntry chooseNextSkill(NpcAI npcAI) {
		if (npcAI.isInSubState(AISubState.CAST)) {
			return null;
		}

		Npc owner = npcAI.getOwner();

		NpcSkillEntry queuedSkill = owner.getQueuedSkills().peek();
		if (queuedSkill != null && queuedSkill.getNextSkillTime() == 0 && isReady(owner, queuedSkill)) {
			return getNpcSkillEntryIfNotTooFarAway(owner, queuedSkill);
		}

		if (((System.currentTimeMillis() - owner.getGameStats().getFightStartingTime()) > owner.getGameStats().getInitialSkillDelay())
			&& owner.getGameStats().canUseNextSkill()) {
			if (queuedSkill != null && isReady(owner, queuedSkill)) {
				return getNpcSkillEntryIfNotTooFarAway(owner, queuedSkill);
			}

			NpcSkillList skillList = owner.getSkillList();
			if (skillList.isEmpty()) {
				return null;
			}

			NpcSkillEntry lastSkill = owner.getGameStats().getLastSkill();
			if (lastSkill != null && lastSkill.hasChain() && lastSkill.canUseNextChain(owner)) {
				List<NpcSkillEntry> chainSkills = skillList.getChainSkills(lastSkill);
				if (chainSkills.size() > 1) {
					if (chainSkills.stream().anyMatch(cs -> cs.getPriority() > 0)) {
						chainSkills.sort(Comparator.comparingInt(NpcSkillEntry::getPriority).reversed());
					} else {
						Collections.shuffle(chainSkills);
					}
				}
				for (NpcSkillEntry entry : chainSkills) {
					if (entry != null && isReady(owner, entry)) {
						return getNpcSkillEntryIfNotTooFarAway(owner, entry);
					}
				}
			}

			int[] priorities = skillList.getPriorities();
			if (priorities != null) {
				for (int priority : priorities) {
					List<NpcSkillEntry> skillsByPriority = skillList.getSkillsByPriority(priority);
					if (skillsByPriority.size() > 1)
						Collections.shuffle(skillsByPriority);

					for (NpcSkillEntry entry : skillsByPriority) {
						if (entry.getChainId() == 0 && isReady(owner, entry)) {
							return getNpcSkillEntryIfNotTooFarAway(owner, entry);
						}
					}
				}
			}
		}
		return null;
	}

	private static NpcSkillEntry getNpcSkillEntryIfNotTooFarAway(Npc owner, NpcSkillEntry entry) {
		if (targetTooFar(owner, entry)) {
			owner.getGameStats().setNextSkillDelay(5000);
			return null;
		}
		return entry;
	}

	// check for bind/silence/fear/stun etc debuffs on npc
	private static boolean isReady(Npc owner, NpcSkillEntry entry) {
		if (entry.isReady(owner.getLifeStats().getHpPercentage(), System.currentTimeMillis() - owner.getGameStats().getFightStartingTime())) {
			if (entry.conditionReady(owner)) {
				SkillTemplate template = DataManager.SKILL_DATA.getSkillTemplate(entry.getSkillId());
				if ((template.getType() == SkillType.MAGICAL && owner.getEffectController().isAbnormalSet(AbnormalState.SILENCE))
					|| (template.getType() == SkillType.PHYSICAL && owner.getEffectController().isAbnormalSet(AbnormalState.BIND))
					|| (owner.getEffectController().isInAnyAbnormalState(AbnormalState.CANT_ATTACK_STATE))
					|| (owner.isTransformed() && owner.getTransformModel().getBanUseSkills() == 1)) {
					return false;
				} else {
					return true;
				}
			}
		}
		return false;
	}

	private static boolean targetTooFar(Npc owner, NpcSkillEntry entry) {
		SkillTemplate template = DataManager.SKILL_DATA.getSkillTemplate(entry.getSkillId());
		Properties prop = template.getProperties();
		if (prop.getFirstTarget() != FirstTargetAttribute.ME && entry.getTemplate().getTarget() != NpcSkillTargetAttribute.NONE
			&& entry.getTemplate().getTarget() != NpcSkillTargetAttribute.MOST_HATED && entry.getTemplate().getTarget() != NpcSkillTargetAttribute.ME) {
			if (owner.getTarget()instanceof Creature target) {
				if (target.isDead() || !owner.canSee(target)) {
					return true;
				}
				if (prop.getTargetType() != TargetRangeAttribute.AREA) {
					if (!PositionUtil.isInRange(owner, target, prop.getFirstTargetRange(), false)) {
						return true;
					}
				}
			} else {
				return true;
			}
		}
		return false;
	}

}

📎 첨부파일

댓글 작성 권한이 없습니다.
🏆 포인트 랭킹 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