테스트

aion-server 4.8

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

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import com.aionemu.gameserver.ai.AIActions;
import com.aionemu.gameserver.ai.AIName;
import com.aionemu.gameserver.ai.AIRequest;
import com.aionemu.gameserver.ai.NpcAI;
import com.aionemu.gameserver.custom.pvpmap.PvpMapService;
import com.aionemu.gameserver.dataholders.DataManager;
import com.aionemu.gameserver.model.ChatType;
import com.aionemu.gameserver.model.TaskId;
import com.aionemu.gameserver.model.gameobjects.Creature;
import com.aionemu.gameserver.model.gameobjects.Item;
import com.aionemu.gameserver.model.gameobjects.Npc;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.model.items.ItemCooldown;
import com.aionemu.gameserver.model.skill.PlayerSkillEntry;
import com.aionemu.gameserver.model.templates.item.ItemTemplate;
import com.aionemu.gameserver.model.templates.item.ItemUseLimits;
import com.aionemu.gameserver.network.aion.serverpackets.*;
import com.aionemu.gameserver.skillengine.model.SkillTargetSlot;
import com.aionemu.gameserver.skillengine.model.SkillTemplate;
import com.aionemu.gameserver.skillengine.model.TransformType;
import com.aionemu.gameserver.utils.PacketSendUtility;
import com.aionemu.gameserver.utils.PositionUtil;
import com.aionemu.gameserver.utils.ThreadPoolManager;
import com.aionemu.gameserver.world.geo.GeoService;

/**
 * @author Yeats, Neon
 */
@AIName("customcdreset")
public class SkillCooltimeResetAI extends NpcAI {

	private static final int PRICE = 50_000;
	private static final int MAX_SKILL_COOLDOWN_TIME = 3060; // = 5min 6sec
	private static final int MAX_ITEM_COOLDOWN_SECONDS = 300; // excludes items like Fine Bracing Water, Leader's Recovery Scroll, Recovery Crystal etc.

	private final Map<Integer, Long> playersInSight = new ConcurrentHashMap<>();

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

	@Override
	protected void handleSpawned() {
		super.handleSpawned();
		if (PvpMapService.getInstance().isOnPvPMap(getOwner())) {
			getOwner().getController().addTask(TaskId.DESPAWN, ThreadPoolManager.getInstance().schedule(() -> getOwner().getController().delete(), 30000));
			ThreadPoolManager.getInstance().schedule(() -> getOwner().getKnownList().forEachPlayer(this::tryNotify), 1000);
		}
	}

	@Override
	protected void handleDialogStart(Player player) {
		playersInSight.values().removeIf(time -> System.currentTimeMillis() > time + 300000); // remove players if they are already 5 mins+ in the map
		if (player.getLifeStats().isAboutToDie() || player.isDead())
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_CANNOT_USE_IN_DEAD_STATE());
		else if (!PvpMapService.getInstance().isOnPvPMap(player) && player.getController().isInCombat())
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_SKILL_CANT_CAST_IN_COMBAT_STATE());
		else if (player.isTransformed() && player.getTransformModel().getType() == TransformType.AVATAR)
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_SKILL_CAN_NOT_ACT_WHILE_IN_ABNORMAL_STATE());
		else if (collectResettableSkillCooldownIds(player).isEmpty() && collectResettableItemCooldownIds(player).isEmpty())
			PacketSendUtility.sendPacket(player, new SM_MESSAGE(getOwner(), "Daeva has no skill cooldowns to reset, yang.", ChatType.NPC));
		else
			sendRequest(player);
	}

	@Override
	public void handleCreatureMoved(Creature creature) {
		if (creature instanceof Player player)
			tryNotify(player);
	}

	private void tryNotify(Player player) {
		if (player.isDead())
			return;
		if (!getOwner().canSee(player))
			return;
		if (playersInSight.containsKey(player.getObjectId()))
			return;
		if (PositionUtil.isInRange(getOwner(), player, 8) && GeoService.getInstance().canSee(getOwner(), player)) {
			playersInSight.put(player.getObjectId(), System.currentTimeMillis());
			PacketSendUtility.sendPacket(player,
				new SM_MESSAGE(getOwner(), String.format("I can heal you and reset your skill cooldowns for %,d Kinah, yang yang.", PRICE), ChatType.NPC));
		}
	}

	private void sendRequest(Player player) {
		AIActions.addRequest(this, player, 1300765, getObjectTemplate().getTalkDistance(), new AIRequest() {

			@Override
			public void acceptRequest(Creature requester, Player responder, int requestId) {
				if (responder.getInventory().getKinah() < PRICE)
					PacketSendUtility.sendPacket(responder, SM_SYSTEM_MESSAGE.STR_MSG_NOT_ENOUGH_KINA(PRICE));
				else if (responder.getLifeStats().isAboutToDie() || responder.isDead())
					PacketSendUtility.sendPacket(responder, SM_SYSTEM_MESSAGE.STR_CANNOT_USE_IN_DEAD_STATE());
				else if (responder.getController().isInCombat())
					PacketSendUtility.sendPacket(responder, SM_SYSTEM_MESSAGE.STR_SKILL_CANT_CAST_IN_COMBAT_STATE());
				else if (responder.isTransformed() && responder.getTransformModel().getType() == TransformType.AVATAR)
					PacketSendUtility.sendPacket(responder, SM_SYSTEM_MESSAGE.STR_SKILL_CAN_NOT_ACT_WHILE_IN_ABNORMAL_STATE());
				else {
					Set<Integer> skillCooldownIds = collectResettableSkillCooldownIds(responder);
					Set<Integer> itemCooldownIds = collectResettableItemCooldownIds(responder);
					if (!skillCooldownIds.isEmpty() || !itemCooldownIds.isEmpty()) {
						if (responder.getInventory().tryDecreaseKinah(PRICE)) {
							responder.getLifeStats().increaseHp(SM_ATTACK_STATUS.TYPE.HP, responder.getLifeStats().getMaxHp(), getOwner());
							responder.getLifeStats().increaseMp(SM_ATTACK_STATUS.TYPE.HEAL_MP, responder.getLifeStats().getMaxMp(), 0, SM_ATTACK_STATUS.LOG.MPHEAL);
							if (!skillCooldownIds.isEmpty()) {
								skillCooldownIds.forEach(responder::removeSkillCoolDown);
								PacketSendUtility.sendPacket(responder, new SM_SKILL_COOLDOWN(
									skillCooldownIds.stream().collect(Collectors.toMap(cooldownId -> cooldownId, cooldownId -> System.currentTimeMillis()))));
							}
							if (!itemCooldownIds.isEmpty()) {
								Map<Integer, ItemCooldown> dummyCds = new HashMap<>(); // 4.8 client ignores reuseTime <= currentTime, but sending old cds + useDelay 0 works
								itemCooldownIds.forEach(itemCooldownId -> {
									dummyCds.put(itemCooldownId, new ItemCooldown(responder.getItemReuseTime(itemCooldownId), 0));
									responder.removeItemCoolDown(itemCooldownId);
								});
								PacketSendUtility.sendPacket(responder, new SM_ITEM_COOLDOWN(dummyCds));
							}
							if (PvpMapService.getInstance().isOnPvPMap(getOwner())) {
								getOwner().getController().delete();
							}
						} else {
							PacketSendUtility.sendPacket(responder, SM_SYSTEM_MESSAGE.STR_MSG_NOT_ENOUGH_KINA(PRICE));
						}
					}
				}
			}
		});
	}

	private Set<Integer> collectResettableItemCooldownIds(Player player) {
		Set<Integer> itemCooldownIds = player.getItemCoolDowns().entrySet().stream()
			.filter(e -> e.getValue().getUseDelay() <= MAX_ITEM_COOLDOWN_SECONDS && e.getValue().getReuseTime() > System.currentTimeMillis())
			.map(Map.Entry::getKey)
			.collect(Collectors.toSet());
		if (!itemCooldownIds.isEmpty())
			itemCooldownIds.retainAll(collectBuffItemAndPotionCooldownIds(player));
		return itemCooldownIds;
	}

	private Set<Integer> collectBuffItemAndPotionCooldownIds(Player player) {
		Set<Integer> cooldownIds = new HashSet<>();
		for (Item item : player.getInventory().getItems()) {
			ItemTemplate itemTemplate = item.getItemTemplate();
			ItemUseLimits useLimits = itemTemplate.getUseLimits();
			if (useLimits == null || useLimits.getDelayId() == 0)
				continue;
			if (itemTemplate.getActions() == null || itemTemplate.getActions().getSkillUseAction() == null)
				continue;
			SkillTemplate skillTemplate = DataManager.SKILL_DATA.getSkillTemplate(itemTemplate.getActions().getSkillUseAction().getSkillId());
			if (skillTemplate == null || skillTemplate.getTargetSlot() != SkillTargetSlot.BUFF && !skillTemplate.getStack().startsWith("ITEM_POTION_")
				&& !skillTemplate.getStack().startsWith("ITEM_ARENA_POTION_"))
				continue;
			cooldownIds.add(useLimits.getDelayId());
		}
		return cooldownIds;
	}

	private Set<Integer> collectResettableSkillCooldownIds(Player player) {
		Set<Integer> cooldownIds = new HashSet<>();
		for (PlayerSkillEntry skill : player.getSkillList().getAllSkills()) {
			SkillTemplate st = DataManager.SKILL_DATA.getSkillTemplate(skill.getSkillId());
			if (st == null || st.getCooldown() > MAX_SKILL_COOLDOWN_TIME)
				continue;
			if (st.isDeityAvatar())
				continue;
			if (player.getSkillCoolDown(st.getCooldownId()) < System.currentTimeMillis())
				continue;
			cooldownIds.add(st.getCooldownId());
		}
		return cooldownIds;
	}
}

📎 첨부파일

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