薛之猫大王
2026-02-23 af74b152737e345cc59908bbceb87ff82a2f79a5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
local M = {}
 
-- ---------------------------------------------------------
-- NPC行为更新(由Timer驱动,每2秒一次)
-- ---------------------------------------------------------
function M.start()
    clicli.timer.loop(2.0, function()
        local NpcMgr = require 'core.npc_manager'
        local npc_list = NpcMgr.get_npc_list()
        for _, npc in ipairs(npc_list) do
            if npc:is_alive() then
                M.tick(npc)
            end
        end
    end, 'NPC行为更新')
end
 
function M.tick(npc)
    if npc:storage_get('is_panicked') then
        return
    end
 
    local state = npc:storage_get('ai_state') or 'idle'
 
    if state == 'idle' then
        if math.random(100) <= 30 then
            M.try_interact(npc)
        else
            npc:storage_set('ai_state', 'moving')
            local road = npc:storage_get('assigned_road')
            if road then
                npc:move_along_road(road, 1, false, true, true)
            end
        end
 
    elseif state == 'moving' then
        if not npc:is_moving() then
            npc:storage_set('ai_state', 'idle')
        end
 
    elseif state == 'interacting' then
        -- 由互动计时器回调切回idle
    end
end
 
-- ---------------------------------------------------------
-- 互动点检测
-- ---------------------------------------------------------
function M.try_interact(npc)
    local interact_configs = {
        { tag = 'interact_bench',  anim = 'sit',   time_min = 8,  time_max = 15 },
        { tag = 'interact_board',  anim = 'look',  time_min = 5,  time_max = 10 },
        { tag = 'interact_well',   anim = 'wash',  time_min = 5,  time_max = 8  },
        { tag = 'interact_vendor', anim = 'trade', time_min = 6,  time_max = 12 },
    }
 
    local pos = npc:get_point()
    for _, cfg in ipairs(interact_configs) do
        local areas = clicli.area.get_circle_areas_by_tag(cfg.tag)
        for _, area in ipairs(areas) do
            if area:is_point_in_area(pos) then
                npc:stop()
                npc:play_animation(cfg.anim, 1.0, 0, -1, false, true)
                npc:storage_set('ai_state', 'interacting')
 
                local wait = math.random(cfg.time_min, cfg.time_max)
                clicli.timer.wait(wait, function()
                    if not npc:is_alive() then return end
                    npc:stop_cur_animation()
                    npc:storage_set('ai_state', 'idle')
 
                    local road = npc:storage_get('assigned_road')
                    if road then
                        npc:move_along_road(road, 1, false, true, true)
                        npc:storage_set('ai_state', 'moving')
                    end
                end)
                return true
            end
        end
    end
 
    return false
end
 
return M