 | 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[0] && x <= coords[1] &&
y >= coords[2] && y <= coords[3] &&
mapId == coords[4]) {
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;
}
}
| |