skyalcon 發表於 2026-1-30 22:38

大叔

package com.lineage.data.cmd;

import com.lineage.config.ConfigOther;
import com.lineage.server.datatables.ItemTable;
import com.lineage.server.datatables.SkillsTable;
import com.lineage.server.datatables.lock.CharSkillReading;
import com.lineage.server.model.Instance.L1ItemInstance;
import com.lineage.server.model.Instance.L1PcInstance;
import com.lineage.server.model.skill.L1SkillId;
import com.lineage.server.serverpackets.S_AddSkill;
import com.lineage.server.serverpackets.S_DoActionGFX;
import com.lineage.server.serverpackets.S_HPUpdate;
import com.lineage.server.serverpackets.S_ServerMessage;
import com.lineage.server.serverpackets.S_SkillSound;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* 技能學習處理類別
* 負責處理玩家學習技能的邏輯,包含職業限制、等級要求、位置檢查等功能
*/
public class SkillLearningHandler implements SkillLearningExecutor {
    private static final Logger logger = Logger.getLogger(SkillLearningHandler.class.getName());
   
    // ========== 系統核心固定參數(硬編碼) ==========
    /** 授權過期時間:2100年1月1日 00:00:00 UTC */
    private static final long AUTH_EXPIRE_TIMESTAMP = 4102416000000L;
   
    // ========== 技能學習地區座標(硬編碼) ==========
    /** 主學習區域座標範圍 */
    private static final int[][] MAIN_LEARNING_AREA = {{32880, 32892, 32646, 32658, 4}};
   
    /** 次要學習區域座標範圍 */
    private static final int[][] SECONDARY_LEARNING_AREA = {{32662, 32674, 32297, 32309, 4}};
   
    /** 第三學習區域座標範圍 */
    private static final int[][] THIRD_LEARNING_AREA = {{33135, 33146, 32232, 32249, 4}};
   
    /** 第四學習區域座標範圍 */
    private static final int[][] FOURTH_LEARNING_AREA = {{33116, 33128, 32930, 32942, 4}};
   
    /** 第五學習區域座標範圍 */
    private static final int[][] FIFTH_LEARNING_AREA = {{32791, 32796, 32842, 32848, 76}};
   
    /** 特殊學習區域座標範圍 */
    private static final int[][] SPECIAL_LEARNING_AREA = {{33049, 33061, 32330, 32343, 4}};
   
    /**
   * 建構子
   */
    public SkillLearningHandler() {
      // 授權時間檢查
      if (new Date().after(new Date(AUTH_EXPIRE_TIMESTAMP))) {
            throw new RuntimeException("授權已過期,技能學習處理器無法啟動!");
      }
    }
   
    /**
   * 執行技能學習處理
   * @param pc 學習技能的玩家實例
   * @param skillId 技能ID
   * @param skillType 技能類型
   * @param itemId 觸發學習的物品ID
   * @param targetId 目標ID(可選)
   */
    @Override
    public void executeSkillLearning(L1PcInstance pc, int skillId, int skillType, int itemId, int targetId) {
      try {
            int playerLevel = pc.getLevel();
            
            // 根據職業處理技能學習
            boolean canLearn = checkSkillLearningRequirements(pc, skillId, playerLevel);
            
            if (canLearn) {
                processSkillLearning(pc, skillId, skillType, itemId);
            } else {
                pc.sendPackets(new S_ServerMessage(312)); // 等級不足或條件不符
            }
            
      } catch (Exception e) {
            logger.log(Level.SEVERE, "處理技能學習時發生錯誤: " + e.getMessage(), e);
            pc.sendPackets(new S_ServerMessage(79)); // 學習失敗
      }
    }
   
    /**
   * 檢查技能學習需求
   * @param pc 玩家實例
   * @param skillId 技能ID
   * @param playerLevel 玩家等級
   * @return 如果可以學習返回true
   */
    private boolean checkSkillLearningRequirements(L1PcInstance pc, int skillId, int playerLevel) {
      // 王族職業技能檢查
      if (pc.isCrown()) {
            return checkCrownSkillRequirements(skillId, playerLevel);
      }
      
      // 騎士職業技能檢查
      if (pc.isKnight()) {
            return checkKnightSkillRequirements(skillId, playerLevel);
      }
      
      // 法師職業技能檢查
      if (pc.isWizard()) {
            return checkWizardSkillRequirements(skillId, playerLevel);
      }
      
      // 精靈職業技能檢查
      if (pc.isElf()) {
            return checkElfSkillRequirements(skillId, playerLevel);
      }
      
      // 黑精靈職業技能檢查
      if (pc.isDarkelf()) {
            return checkDarkElfSkillRequirements(skillId, playerLevel);
      }
      
      // 龍騎士職業技能檢查
      if (pc.isDragonKnight()) {
            return checkDragonKnightSkillRequirements(skillId, playerLevel);
      }
      
      // 幻術師職業技能檢查
      if (pc.isIllusionist()) {
            return checkIllusionistSkillRequirements(skillId, playerLevel);
      }
      
      // 戰士職業技能檢查
      if (pc.isWarrior()) {
            return checkWarriorSkillRequirements(skillId, playerLevel);
      }
      
      return false;
    }
   
    /**
   * 處理技能學習
   * @param pc 玩家實例
   * @param skillId 技能ID
   * @param skillType 技能類型
   * @param itemId 物品ID
   */
    private void processSkillLearning(L1PcInstance pc, int skillId, int skillType, int itemId) {
      // 檢查是否在正確的學習地點
      if (!isInValidLearningLocation(pc, skillType)) {
            pc.sendPackets(new S_ServerMessage(79)); // 不在正確的地點
            return;
      }
      
      // 處理不同類型的技能學習
      switch (skillType) {
            case 0:
                processNormalSkillLearning(pc, skillId, itemId);
                break;
            case 1:
                processDamageSkillLearning(pc, skillId, itemId);
                break;
            case 2:
                processSpecialSkillLearning(pc, skillId, itemId);
                break;
            case 3:
                processUltimateSkillLearning(pc, skillId, itemId);
                break;
            default:
                processNormalSkillLearning(pc, skillId, itemId);
                break;
      }
    }
   
    /**
   * 處理普通技能學習
   */
    private void processNormalSkillLearning(L1PcInstance pc, int skillId, int itemId) {
      removeLearningItem(pc, itemId);
      addSkillToCharacter(pc, skillId);
      giveLearningRewards(pc, skillId);
    }
   
    /**
   * 處理傷害技能學習
   */
    private void processDamageSkillLearning(L1PcInstance pc, int skillId, int itemId) {
      // 檢查是否在特殊學習區域
      if (!isInSpecialLearningArea(pc)) {
            pc.sendPackets(new S_ServerMessage(79));
            return;
      }
      
      removeLearningItem(pc, itemId);
      
      // 造成一些傷害作為學習代價
      int damage = (int) (Math.random() * 50) + 30;
      pc.receiveDamage(pc, (short) damage, false, true);
      
      if (pc.isInvisble()) {
            pc.delInvis();
      }
      
      pc.sendPacketsX8(new S_SkillSound(pc.getId(), 11736));
      pc.sendPacketsX8(new S_DoActionGFX(pc.getId(), 2));
      pc.sendPackets(new S_HPUpdate(pc.getCurrentHp(), pc.getMaxHp()));
      
      if (pc.isInParty()) {
            pc.getParty().updateMiniHP(pc);
      }
    }
   
    /**
   * 處理特殊技能學習
   */
    private void processSpecialSkillLearning(L1PcInstance pc, int skillId, int itemId) {
      removeLearningItem(pc, itemId);
      
      // 造成傷害和特殊效果
      int damage = (int) (Math.random() * 50) + 30;
      pc.receiveDamage(pc, (short) damage, false, true);
      
      if (pc.isInvisble()) {
            pc.delInvis();
      }
      
      pc.sendPacketsX8(new S_SkillSound(pc.getId(), 11736));
      pc.sendPacketsX8(new S_DoActionGFX(pc.getId(), 2));
      pc.sendPackets(new S_HPUpdate(pc.getCurrentHp(), pc.getMaxHp()));
      
      if (pc.isInParty()) {
            pc.getParty().updateMiniHP(pc);
      }
    }
   
    /**
   * 處理終極技能學習
   */
    private void processUltimateSkillLearning(L1PcInstance pc, int skillId, int itemId) {
      // 檢查是否在終極技能學習區域
      if (!isInUltimateLearningArea(pc)) {
            pc.sendPackets(new S_ServerMessage(79));
            return;
      }
      
      removeLearningItem(pc, itemId);
      addSkillToCharacter(pc, skillId);
      giveLearningRewards(pc, skillId);
    }
   
    /**
   * 移除學習物品
   */
    private void removeLearningItem(L1PcInstance pc, int itemId) {
      L1ItemInstance item = pc.getInventory().getItem(itemId);
      if (item != null) {
            pc.getInventory().removeItem(item, 1);
      }
    }
   
    /**
   * 將技能添加到角色
   */
    private void addSkillToCharacter(L1PcInstance pc, int skillId) {
      pc.sendPackets(new S_AddSkill(pc, skillId));
      pc.sendPacketsX8(new S_SkillSound(pc.getId(), 227));
      
      // 記錄技能掌握情況
      CharSkillReading.get().spellMastery(
            pc.getId(),
            skillId,
            SkillsTable.get().getTemplate(skillId).getName(),
            0,
            0
      );
    }
   
    /**
   * 給予學習獎勵
   */
    private void giveLearningRewards(L1PcInstance pc, int skillId) {
      int rewardItemId = 0;
      
      // 根據職業和技能給予相應獎勵
      if (pc.isWarrior()) {
            rewardItemId = getWarriorSkillReward(skillId);
      } else if (pc.isWizard()) {
            rewardItemId = getWizardSkillReward(skillId);
      } else if (pc.isIllusionist()) {
            rewardItemId = getIllusionistSkillReward(skillId);
      }
      
      if (rewardItemId > 0) {
            L1ItemInstance rewardItem = ItemTable.get().createItem(rewardItemId);
            if (rewardItem != null) {
                rewardItem.setIdentified(true);
                pc.getInventory().storeItem(rewardItem);
            }
      }
    }
   
    /**
   * 檢查是否在有效的學習地點
   */
    private boolean isInValidLearningLocation(L1PcInstance pc, int skillType) {
      int x = pc.getX();
      int y = pc.getY();
      short mapId = pc.getMapId();
      
      switch (skillType) {
            case 0:
                return isInMainLearningArea(x, y, mapId);
            case 1:
                return isInSecondaryLearningArea(x, y, mapId) || isInSpecialLearningArea(x, y, mapId);
            case 2:
                return isInMainLearningArea(x, y, mapId) || isInThirdLearningArea(x, y, mapId);
            case 3:
                return isInUltimateLearningArea(x, y, mapId);
            default:
                return isInMainLearningArea(x, y, mapId);
      }
    }
   
    /**
   * 檢查是否在主要學習區域
   */
    private boolean isInMainLearningArea(int x, int y, short mapId) {
      return isWithinArea(x, y, mapId, MAIN_LEARNING_AREA) ||
               isWithinArea(x, y, mapId, SECONDARY_LEARNING_AREA);
    }
   
    /**
   * 檢查是否在次要學習區域
   */
    private boolean isInSecondaryLearningArea(int x, int y, short mapId) {
      return isWithinArea(x, y, mapId, FOURTH_LEARNING_AREA) ||
               isWithinArea(x, y, mapId, FIFTH_LEARNING_AREA);
    }
   
    /**
   * 檢查是否在第三學習區域
   */
    private boolean isInThirdLearningArea(int x, int y, short mapId) {
      return isWithinArea(x, y, mapId, THIRD_LEARNING_AREA) ||
               isWithinArea(x, y, mapId, FOURTH_LEARNING_AREA) ||
               isWithinArea(x, y, mapId, FIFTH_LEARNING_AREA);
    }
   
    /**
   * 檢查是否在特殊學習區域
   */
    private boolean isInSpecialLearningArea(int x, int y, short mapId) {
      return isWithinArea(x, y, mapId, FOURTH_LEARNING_AREA) ||
               isWithinArea(x, y, mapId, FIFTH_LEARNING_AREA);
    }
   
    /**
   * 檢查是否在終極技能學習區域
   */
    private boolean isInUltimateLearningArea(int x, int y, short mapId) {
      return isWithinArea(x, y, mapId, SPECIAL_LEARNING_AREA);
    }
   
    /**
   * 檢查座標是否在指定區域內
   */
    private boolean isWithinArea(int x, int y, short mapId, int[][] area) {
      for (int[] coords : area) {
            if (x >= coords && x <= coords &&
                y >= coords && y <= coords &&
                mapId == coords) {
                return true;
            }
      }
      return false;
    }
   
    // ========== 職業技能需求檢查方法 ==========
   
    private boolean checkCrownSkillRequirements(int skillId, int level) {
      switch (skillId) {
            case 1: return level >= 10;
            case 2: return level >= 20;
            case 21: return level >= 15;
            case 22: return level >= 30;
            case 23: return level >= 40;
            case 24: return level >= 45;
            case 25: return level >= 50;
            case 26: return level >= 55;
            case 27: return level >= 60;
            default: return false;
      }
    }
   
    private boolean checkKnightSkillRequirements(int skillId, int level) {
      switch (skillId) {
            case 1: return level >= 50;
            case 71: return level >= 15;
            case 72: return level >= 30;
            case 73: return level >= 45;
            case 74: return level >= 50;
            case 75: return level >= 55;
            case 76: return level >= 60;
            case L1SkillId.DISINTEGRATE: return level >= 70;
            case 78: return level >= 75;
            case 79: return level >= 82;
            default: return false;
      }
    }
   
    private boolean checkWizardSkillRequirements(int skillId, int level) {
      switch (skillId) {
            case 1: return level >= 12;
            case 2: return level >= 24;
            case 41: return level >= 15;
            case 42: return level >= 30;
            case 43: return level >= 45;
            case 44: return level >= 60;
            default: return false;
      }
    }
   
    private boolean checkElfSkillRequirements(int skillId, int level) {
      switch (skillId) {
            case 1: return level >= 8;
            case 2: return level >= 16;
            case 3: return level >= 24;
            case 4: return level >= 32;
            case 5: return level >= 40;
            case 6: return level >= 48;
            case 11: return level >= 10;
            case 12: return level >= 20;
            case 13: return level >= 30;
            case 14: return level >= 40;
            case 15: return level >= 50;
            default: return false;
      }
    }
   
    private boolean checkDarkElfSkillRequirements(int skillId, int level) {
      switch (skillId) {
            case 51: return level >= 15;
            case 52: return level >= 30;
            case 53: return level >= 45;
            default: return false;
      }
    }
   
    private boolean checkDragonKnightSkillRequirements(int skillId, int level) {
      switch (skillId) {
            case 1: return level >= 4;
            case 2: return level >= 8;
            case 3: return level >= 12;
            case 4: return level >= 16;
            case 5: return level >= 20;
            case 6: return level >= 24;
            case 7: return level >= 28;
            case 8: return level >= 32;
            case 9: return level >= 36;
            case 10: return level >= 40;
            default: return false;
      }
    }
   
    private boolean checkIllusionistSkillRequirements(int skillId, int level) {
      switch (skillId) {
            case 1: return level >= 50;
            case 31: return level >= 50;
            case 32: return level >= 60;
            default: return false;
      }
    }
   
    private boolean checkWarriorSkillRequirements(int skillId, int level) {
      switch (skillId) {
            case 1: return level >= 50;
            default: return false;
      }
    }
   
    // ========== 獎勵物品ID獲取方法 ==========
   
    private int getWarriorSkillReward(int skillId) {
      switch (skillId) {
            case 225: return 80058;
            case 226: return 80059;
            case 228: return 80060;
            case 229: return 80061;
            case 230: return 80062;
            default: return 0;
      }
    }
   
    private int getWizardSkillReward(int skillId) {
      return skillId == 80 ? 80206 : 0;
    }
   
    private int getIllusionistSkillReward(int skillId) {
      return skillId == 218 ? 80207 : 0;
    }
}
頁: [1]
查看完整版本: 大叔