查看: 849|回復: 0

[閒聊閒語] L1AutoHuntHandler

[複製鏈接]

66

主題

162

帖子

5629

金錢

火焰之影

Rank: 8Rank: 8

威望
0
精華
0
貢獻
0
鑽石
0
閱讀權限
50
積分
5791
在線時間
78 小時
相冊
0
日誌
0
好友
0
發表於 2026-1-13 18:30 | 顯示全部樓層 |閱讀模式
package l1j.server.server.model.Instance;

import l1j.server.server.model.L1Object;
import l1j.server.server.model.L1World;
import l1j.server.server.serverpackets.S_NPCPack;

import java.util.ArrayList;
import java.util.List;

public class L1AutoHuntHandler implements Runnable {
    private final L1PcInstance _pc;
    private L1MonsterInstance _target = null;
    private int _stuckCounter = 0;
    private int _lastX = -1;
    private int _lastY = -1;

    public L1AutoHuntHandler(L1PcInstance pc) {
        this._pc = pc;
        this._lastX = pc.getX();
        this._lastY = pc.getY();
    }

    @Override
    public void run() {
        try {
            while (_pc.isAutoHunting()
                    && _pc.getNetConnection() != null
                    && !_pc.isDead()) {

                // 1. 檢查自動喝水
                checkAutoPotion();

                // 2. 更新視野內的怪物顯示
                updateMonsterVisibility();

                // 3. 檢查目標有效性
                if (!isValidTarget(_target)) {
                    _target = findBestTarget();
                    if (_target == null) {
                        Thread.sleep(300);
                        continue;
                    }
                }

                // 4. 執行戰鬥邏輯
                executeCombat(_target);

                // 5. 防卡點檢測
                checkStuck();

                // 6. 頻率控制
                Thread.sleep(300);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 清理資源
            cleanup();
        }
    }

    /**
     * 執行戰鬥邏輯
     */
    private void executeCombat(L1MonsterInstance target) {
        if (target == null || target.isDead()) {
            _target = null;
            return;
        }

        int dist = calculateDistance(_pc, target);

        if (dist > 1) {
            // 移動到目標
            boolean moved = moveToTarget(target);

            if (!moved) {
                // 移動失敗,重新選擇目標
                _target = null;
            }
        } else {
            // 進行攻擊
            attackTarget(target);
        }
    }

    /**
     * 移動到目標
     */
    private boolean moveToTarget(L1MonsterInstance target) {
        // 檢查目標是否在視野內
        if (!isInScreen(target)) {
            _target = null;
            return false;
        }

        // 記錄移動前位置
        int oldX = _pc.getX();
        int oldY = _pc.getY();

        // 執行移動
        L1AutoMoveService.moveToTarget(_pc, target.getX(), target.getY());

        // 檢查是否移動成功
        if (oldX != _pc.getX() || oldY != _pc.getY()) {
            _stuckCounter = 0; // 重置卡點計數器
            return true;
        } else {
            _stuckCounter++;
            return false;
        }
    }

    /**
     * 攻擊目標
     */
    private void attackTarget(L1MonsterInstance target) {
        try {
            // 設置面向目標的方向
            int dir = _pc.targetDirection(target.getX(), target.getY());
            _pc.setHeading(dir);

            // 執行攻擊
            target.onAction(_pc);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 尋找最佳目標
     */
    private L1MonsterInstance findBestTarget() {
        List<L1MonsterInstance> visibleMonsters = new ArrayList<>();

        // 獲取所有可見的怪物
        for (L1Object obj : L1World.getInstance().getVisibleObjects(_pc, 15)) {
            if (obj instanceof L1MonsterInstance) {
                L1MonsterInstance monster = (L1MonsterInstance) obj;

                // 檢查怪物是否有效
                if (isValidMonster(monster)) {
                    visibleMonsters.add(monster);
                }
            }
        }

        if (visibleMonsters.isEmpty()) {
            return null;
        }

        // 選擇最近的怪物
        L1MonsterInstance bestTarget = null;
        int minDistance = Integer.MAX_VALUE;

        for (L1MonsterInstance monster : visibleMonsters) {
            int distance = calculateDistance(_pc, monster);

            if (distance < minDistance) {
                minDistance = distance;
                bestTarget = monster;
            }
        }

        return bestTarget;
    }

    /**
     * 檢查目標有效性
     */
    private boolean isValidTarget(L1MonsterInstance target) {
        if (target == null) return false;

        return !target.isDead() &&
               target.getMapId() == _pc.getMapId() &&
               isInScreen(target) &&
               calculateDistance(_pc, target) <= 15;
    }

    /**
     * 檢查怪物是否有效
     */
    private boolean isValidMonster(L1MonsterInstance monster) {
        if (monster == null) return false;

        return !monster.isDead() &&
               !monster.isInvisble() &&
               monster.getMapId() == _pc.getMapId() &&
               monster.getCurrentHp() > 0 &&
               !monster.isParalyzed();
    }

    /**
     * 更新怪物顯示
     */
    private void updateMonsterVisibility() {
        try {
            // 獲取當前視野範圍內的怪物
            for (L1Object obj : L1World.getInstance().getVisibleObjects(_pc, 15)) {
                if (obj instanceof L1MonsterInstance) {
                    L1MonsterInstance monster = (L1MonsterInstance) obj;

                    // 如果怪物在畫面內,確保發送顯示封包
                    if (isInScreen(monster)) {
                        _pc.sendPackets(new S_NPCPack(monster));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 檢查是否在畫面內
     */
    private boolean isInScreen(L1MonsterInstance monster) {
        if (monster == null) return false;

        int screenRange = 15; // 天堂標準視野範圍

        int dx = Math.abs(_pc.getX() - monster.getX());
        int dy = Math.abs(_pc.getY() - monster.getY());

        return dx <= screenRange && dy <= screenRange;
    }

    /**
     * 計算距離(使用 Chebyshev 距離,天堂的標準算法)
     */
    private int calculateDistance(L1PcInstance pc, L1MonsterInstance monster) {
        int dx = Math.abs(pc.getX() - monster.getX());
        int dy = Math.abs(pc.getY() - monster.getY());
        return Math.max(dx, dy);
    }

    /**
     * 防卡點檢測
     */
    private void checkStuck() {
        // 檢查是否卡在同一個位置太久
        if (_pc.getX() == _lastX && _pc.getY() == _lastY) {
            _stuckCounter++;

            // 如果連續卡住超過5次,嘗試隨機移動
            if (_stuckCounter > 5) {
                tryRandomMove();
                _stuckCounter = 0;
            }
        } else {
            _stuckCounter = 0;
            _lastX = _pc.getX();
            _lastY = _pc.getY();
        }
    }

    /**
     * 嘗試隨機移動(解卡)
     */
    private void tryRandomMove() {
        try {
            int randomDir = (int) (Math.random() * 8);
            int newX = _pc.getX() + L1AutoMoveService.HEADING_TABLE_X[randomDir];
            int newY = _pc.getY() + L1AutoMoveService.HEADING_TABLE_Y[randomDir];

            if (_pc.getMap().isPassable(newX, newY, _pc)) {
                L1AutoMoveService.setLocation(_pc, newX, newY, randomDir);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 檢查自動喝水
     */
    private void checkAutoPotion() {
        try {
            // HP 低於 30% 時自動喝水
            int currentHp = _pc.getCurrentHp();
            int maxHp = _pc.getMaxHp();

            if (currentHp < maxHp * 0.3) {
                // 這裡應該調用使用藥水的邏輯
                // _pc.useItem(L1ItemId.POTION_OF_HEALING);
            }

            // MP 低於 20% 時自動喝水
            int currentMp = _pc.getCurrentMp();
            int maxMp = _pc.getMaxMp();

            if (currentMp < maxMp * 0.2) {
                // _pc.useItem(L1ItemId.POTION_OF_MANA);
            }

        } catch (Exception e) {
            // 忽略錯誤,不影響主要邏輯
        }
    }

    /**
     * 清理資源
     */
    private void cleanup() {
        _target = null;
        _stuckCounter = 0;
        _pc.setAutoHunting(false);
    }
}





上一篇︰L1AutoMoveService
下一篇︰2026-01-13 搖一搖!! New New
您需要登錄後才可以回帖 登錄 | 註冊會員

本版積分規則

天堂私服列表

45客服

Archiver| 45天堂私服論壇   分享到微博! 分享到臉書! 分享到噗浪! 分享到維特! 分享到Google+! 分享到LINE!

45天堂私服發佈站 ©    天堂私服架設教學  提供最新天堂私服最新資訊

流量最高、品質最好、服務最優、玩家首選、最新天堂私服資訊,都在45天堂私服發佈站.    免責聲明

Sitetag
line客服聯繫
掃一掃二碼
Line客服聯繫
24H專人回覆
返回頂部 返回列表