테스트

aion-server 4.8

Gitteol
최고관리자 · 1 · 💬 0 클론/새로받기
 4.8 61f661d · 1 commits 새로받기(Pull)
game-server/data/handlers/ai/instance/danuarReliquary/CursedQueenModorAI.java
package ai.instance.danuarReliquary;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import com.aionemu.commons.utils.Rnd;
import com.aionemu.gameserver.ai.AIName;
import com.aionemu.gameserver.ai.HpPhases;
import com.aionemu.gameserver.geoEngine.math.Vector3f;
import com.aionemu.gameserver.model.animations.AttackHandAnimation;
import com.aionemu.gameserver.model.gameobjects.Creature;
import com.aionemu.gameserver.model.gameobjects.Npc;
import com.aionemu.gameserver.model.skill.NpcSkillEntry;
import com.aionemu.gameserver.network.aion.serverpackets.SM_FORCED_MOVE;
import com.aionemu.gameserver.network.aion.serverpackets.SM_HEADING_UPDATE;
import com.aionemu.gameserver.skillengine.model.Effect;
import com.aionemu.gameserver.skillengine.model.SkillTemplate;
import com.aionemu.gameserver.utils.PacketSendUtility;
import com.aionemu.gameserver.utils.PositionUtil;
import com.aionemu.gameserver.utils.ThreadPoolManager;
import com.aionemu.gameserver.world.World;

import ai.AggressiveNpcAI;

/**
 * @author Yeats
 */
@AIName("cursed_queen_modor")
public class CursedQueenModorAI extends AggressiveNpcAI implements HpPhases.PhaseHandler {

	private final HpPhases hpPhases = new HpPhases(100, 81, 77, 61, 50);
	private List<Vector3f> platformLocations = new ArrayList<>(5);
	private AtomicInteger stage = new AtomicInteger();
	private float multiplier = 1f;
	private Vector3f nextPosition = null;

	public CursedQueenModorAI(Npc owner) {
		super(owner);
	}

	@Override
	protected void handleSpawned() {
		super.handleSpawned();
		addPlatformLocations();
	}

	@Override
	public AttackHandAnimation modifyAttackHandAnimation(AttackHandAnimation attackHandAnimation) {
		return Rnd.get(AttackHandAnimation.values());
	}

	@Override
	protected void handleAttack(Creature creature) {
		hpPhases.tryEnterNextPhase(this);
		super.handleAttack(creature);
	}

	@Override
	public void handleHpPhase(int phaseHpPercent) {
		switch (phaseHpPercent) {
			case 100:
				queueSkill(21181, 1); // Malevolence
				queueSkill(21171, 1); // Grendal's Explosive Wrath
				break;
			case 81:
				PacketSendUtility.broadcastMessage(getOwner(), 1500741);
				queueSkill(21171, 1); // Grendal's Explosive Wrath
				queueSkill(21229, 1);  // Dragon Lords Lightning Shock
				break;
			case 77:
				queueSkill(21165, 2, 4000);
				queueSkill(21179, 1, 4000); // ice storm when going up 1st time
				break;
			case 61:
				queueSkill(21165, 3);
				break;
			case 50:
				queueSkill(21175, 4);
				break;
		}
	}

	@Override
	public float modifyOwnerDamage(float damage, Creature effected, Effect effect) {
		return damage * multiplier;  // fix skill dmg until new calculations are available
	}

	@Override
	public void onStartUseSkill(SkillTemplate skillTemplate, int skillLevel) {
		switch (skillTemplate.getSkillId()) {
			case 21171:
				multiplier = 1.2f;
				break;
			case 21165: // teleport
				if (skillLevel != 10) {
					stage.set(skillLevel);
					if (skillLevel == 2) {
						PacketSendUtility.broadcastMessage(getOwner(), 1500750);
					} else if (skillLevel == 3) {
						nextPosition = getRandomPosFromCenter(8);
						spawn(284385, nextPosition.x, nextPosition.y, nextPosition.getZ(), (byte) 0);
					}
				}
				break;
			case 21181: // Malevolence, buff
				stage.set(1);
				PacketSendUtility.broadcastMessage(getOwner(), 1500740);
				break;
			case 21175: // frozen domain of revenge
				if (skillLevel == 4) { // use this skill to despawn modor and spawn clones
					stage.set(4);
					PacketSendUtility.broadcastMessage(getOwner(), 1500742);
				}
			case 21174:
			case 21229:
			case 21173:
				multiplier = 0.5f;
				break;
			default:
				break;
		}
	}

	@Override
	public void onEndUseSkill(SkillTemplate skillTemplate, int skillLevel) {
		int curStage = stage.get();
		switch (skillTemplate.getSkillId()) {
			case 21165: // teleport
				switch (curStage) {
					case 2:
						if (skillLevel != 10) {
							spawnAdds();
						} else {
							queueSkill(21179, 1, Rnd.get(3000, 5000)); // ice storm when going up 1st time
						}
						break;
					case 3:
						queueSkill(21229, 1); //  Dragon Lords Lightning Shock
						break;
					default:
						break;
				}
				updatePosition(curStage);
				break;
			case 21174: // frozen domain of rancour
				multiplier = 1f;
				if (skillLevel == 1 && (curStage == 1 || curStage == 5)) {
					float rnd = Rnd.chance();
					if (rnd < 15) {
						queueSkill(21175, 2, 5000); // lv 2 prevent skill loop
					} else if (rnd < 45) {
						queueSkill(21173, 1, 5000); // summon frost storm
					}
				}
				break;
			case 21175: // frozen domain of revenge
				multiplier = 1f;
				switch (curStage) {
					case 2: // going up 1st time, switch platforms
						if (shouldUsePlatformSkills(skillLevel)) {
							queueSkill(21165, 10, 5000);
						}
						break;
					case 4: // = hp <= 50%
						spawnClones();
						getOwner().getController().delete();
						break;
					case 1:
					case 3: // when she's not on a platform/last stage use aoe skills
						if (skillLevel == 1) {
							float rnd = Rnd.chance();
							if (rnd < 15) {
								queueSkill(21174, 2, 5000); // lv 2 to prevent skill loop
							} else if (rnd < 45) {
								queueSkill(21229, 1, 5000); //  Dragon Lords Lightning Shock
							}
						}
						break;
				}
				break;
			case 21179: // ice storm
				Vector3f pos = getRandomPosFromCenter(Rnd.nextInt(9));
				spawn(284528, pos.getX(), pos.getY(), pos.getZ(), (byte) 10);
				if (curStage == 2 && shouldUsePlatformSkills(skillLevel)) {
					queueSkill(21174, 1, 5000); // frozen domain of rancour
					queueSkill(21175, 1, 5000); // frozen domain of revenge
				}
				break;
			default:
				multiplier = 1f;
				break;
		}
	}

	private void spawnClones() {
		int spawnCase = Rnd.get(1, 5);
		// spawn real clone
		switch (spawnCase) {
			case 1:
				spawn(getRealCloneId(), 255.5489f, 293.42154f, 253.78925f, (byte) 90);
				break;
			case 2:
				spawn(getRealCloneId(), 232.5363f, 263.90112f, 248.65384f, (byte) 114);
				break;
			case 3:
				spawn(getRealCloneId(), 240.11194f, 235.08876f, 251.14906f, (byte) 17);
				break;
			case 4:
				spawn(getRealCloneId(), 271.23627f, 230.30913f, 250.92981f, (byte) 42);
				break;
			case 5:
				spawn(getRealCloneId(), 284.6919f, 262.7201f, 248.75252f, (byte) 63);
				break;
		}
		// spawn fake clones
		if (spawnCase != 1)
			spawn(getFakeCloneId(), 255.5489f, 293.42154f, 253.78925f, (byte) 90);
		if (spawnCase != 2)
			spawn(getFakeCloneId(), 232.5363f, 263.90112f, 248.65384f, (byte) 114);
		if (spawnCase != 3)
			spawn(getFakeCloneId(), 240.11194f, 235.08876f, 251.14906f, (byte) 17);
		if (spawnCase != 4)
			spawn(getFakeCloneId(), 271.23627f, 230.30913f, 250.92981f, (byte) 42);
		if (spawnCase != 5)
			spawn(getFakeCloneId(), 284.6919f, 262.7201f, 248.75252f, (byte) 63);
	}

	private void spawnAdds() {
		spawn(284380, 266.26517f, 273.97614f, 241.54623f, (byte) 83);
		spawn(284381, 256.57727f, 278.18225f, 241.54623f, (byte) 90);
		spawn(284382, 246.65663f, 275.51996f, 241.54623f, (byte) 96);
	}

	private void queueSkill(int id, int lvl) {
		queueSkill(id, lvl, 0);
	}

	private void queueSkill(int id, int lvl, int nextSkillTime) {
		getOwner().queueSkill(id, lvl, nextSkillTime);
	}

	private void updatePosition(final int curStage) {
		ThreadPoolManager.getInstance().schedule(() -> {
			if (!getOwner().isDead() && getOwner().isSpawned()) {
				switch (curStage) {
					case 1: // coming down for 1st time
						World.getInstance().updatePosition(getOwner(), 256.62f, 257.79f, 241.79f, (byte) 90);
						break;
					case 2: // going up 1st time // switch platform
						Vector3f loc = platformLocations.remove(0);
						platformLocations.add(loc); // re-add to be able to teleport to loc again
						World.getInstance().updatePosition(getOwner(), loc.getX(), loc.getY(), loc.getZ(),
								PositionUtil.getHeadingTowards(loc.getX(), loc.getY(), 256.62f, 257.79f)); // heading towards center
						break;
					case 3:  // coming down 2nd time: spawn at random loc
						World.getInstance().updatePosition(getOwner(), nextPosition.getX(), nextPosition.getY(), nextPosition.getZ(),
								PositionUtil.getHeadingTowards(nextPosition.getX(), nextPosition.getY(), 256.62f, 257.79f));
						break;
					default:
						break;
				}
				PacketSendUtility.broadcastPacket(getOwner(), new SM_HEADING_UPDATE(getOwner()));
				PacketSendUtility.broadcastPacket(getOwner(), new SM_FORCED_MOVE(getOwner(), getOwner()));
			}
		}, 500);
	}

	private void addPlatformLocations() {
		platformLocations.clear();
		platformLocations.add(new Vector3f(255.49063f, 293.35785f, 253.79933f));
		platformLocations.add(new Vector3f(284.359f, 262.854f, 248.76f));
		platformLocations.add(new Vector3f(271.169f, 230.531f, 250.955f));
		platformLocations.add(new Vector3f(240.273f, 235.181f, 251.153f));
		platformLocations.add(new Vector3f(232.448f, 263.886f, 248.642f));
	}

	@Override
	public int modifyInitialSkillDelay(int delay) {
		return 0;
	}

	@Override
	protected void handleBackHome() {
		super.handleBackHome();
		stage.set(0);
		hpPhases.reset();
		addPlatformLocations();
		World.getInstance().updatePosition(getOwner(), 256.62f, 257.79f, 241.79f, (byte) 90);
		PacketSendUtility.broadcastPacket(getOwner(), new SM_HEADING_UPDATE(getOwner()));
		PacketSendUtility.broadcastPacket(getOwner(), new SM_FORCED_MOVE(getOwner(), getOwner()));
	}

	private boolean shouldUsePlatformSkills(int skillLevel) {
		for (NpcSkillEntry skill : getOwner().getQueuedSkills()) {
			// if another teleport skill(=21165) is queued with level != 10 -> next stage is ready so stop switching platforms
			if (skill.getSkillLevel() != 10 && skill.getSkillId() == 21165 && skill.getSkillLevel() != skillLevel) {
				return false;
			}
		}
		return true;
	}

	private int getRealCloneId() {
		return getNpcId() == 234690 ? 855244 : 284383;
	}

	private int getFakeCloneId() {
		return getNpcId() == 234690 ? 855245 : 284384;
	}

	private Vector3f getRandomPosFromCenter(int distance) {
		Vector3f center = new Vector3f(256.62f, 257.79f, 241.8f);
		double angleRadians = Math.toRadians(Rnd.nextFloat(360f));
		center.setX(center.x + (float) (Math.cos(angleRadians) * distance));
		center.setY(center.y + (float) (Math.sin(angleRadians) * distance));
		return center;
	}
}

📎 첨부파일

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