edit | blame | history | raw
local CONST   = require 'config.const'
local Balance = require 'config.balance'

local M = {}

-- { player_id -> { player, unit, profession, score, respawn_left, alive, team, is_vip } }
local player_data = {}

-- ---------------------------------------------------------
-- 初始化所有玩家
-- ---------------------------------------------------------
function M.init_all_players()
    local players = clicli.player_group.get_all_players():pick()
    for _, player in ipairs(players) do
        M.create_player_unit(player)
    end
end

-- ---------------------------------------------------------
-- 为单个玩家创建单位
-- ---------------------------------------------------------
function M.create_player_unit(player)
    local spawn = M.get_random_spawn_point()
    local unit  = clicli.unit.create_unit(player, CONST.PLAYER_UNIT_KEY, spawn, math.random(0, 360))

    local prof = player:storage_get('selected_profession') or 'shadow_blade'
    local hp   = Balance.PROFESSION_HP[prof] or 100
    unit:set_attr('最大生命', hp, '基础')
    unit:set_hp(hp)
    unit:set_attr('移动速度', Balance.BASE_MOVE_SPEED, '基础')
    unit:set_bar_cnt(2)
    unit:set_pkg_cnt(0)

    -- 初始伪装:随机NPC外观
    local model = M.get_random_npc_model()
    if model then
        unit:replace_model(model)
    end

    unit:add_tag('player_controlled')
    unit:storage_set('current_model',  model)
    unit:storage_set('previous_model', model)
    unit:storage_set('suspicion', 0)
    unit:storage_set('profession', prof)
    unit:storage_set('idle_time', 0)
    unit:storage_set('kill_cd', 0)

    local abi_key = CONST.PROFESSION_ABILITY[prof]
    if abi_key and abi_key ~= 0 then
        unit:add_ability('英雄', abi_key, 0, 1)
    end

    player_data[player:get_id()] = {
        player       = player,
        unit         = unit,
        profession   = prof,
        score        = 0,
        respawn_left = Balance.RESPAWN_COUNT,
        alive        = true,
        team         = nil,
        is_vip       = false,
    }

    return unit
end

-- ---------------------------------------------------------
-- 玩家死亡处理
-- ---------------------------------------------------------
function M.on_player_killed(killer_unit, victim_unit)
    local victim_pd = M.get_data_by_unit(victim_unit)
    local killer_pd = M.get_data_by_unit(killer_unit)

    if not victim_pd then return end
    victim_pd.alive = false

    if killer_pd then
        killer_pd.score = killer_pd.score + Balance.SCORE_KILL_PLAYER
    end
    victim_pd.score = victim_pd.score + Balance.SCORE_DEATH

    victim_unit:add_tag('corpse')
    victim_unit:set_recycle_on_remove(false)

    local mode = require 'core.mode_manager'
    if mode.can_respawn(victim_pd) then
        victim_pd.respawn_left = victim_pd.respawn_left - 1
        clicli.timer.wait(Balance.RESPAWN_TIME, function()
            M.respawn(victim_pd)
        end)
    end

    mode.check_victory()
end

-- ---------------------------------------------------------
-- 复活
-- ---------------------------------------------------------
function M.respawn(pd)
    local spawn = M.get_random_spawn_point()
    pd.unit:reborn(spawn)
    pd.unit:set_hp(pd.unit:get_attr('最大生命'))

    local model = M.get_random_npc_model()
    if model then
        pd.unit:replace_model(model)
        pd.unit:storage_set('current_model', model)
    end
    pd.unit:storage_set('suspicion', 0)
    pd.alive = true
end

-- ---------------------------------------------------------
-- 积分
-- ---------------------------------------------------------
function M.add_score(player, delta)
    local pd = player_data[player:get_id()]
    if pd then
        pd.score = pd.score + delta
    end
end

-- ---------------------------------------------------------
-- 查询
-- ---------------------------------------------------------
function M.get_data_by_unit(unit)
    for _, pd in pairs(player_data) do
        if pd.unit == unit then return pd end
    end
    return nil
end

function M.get_all_player_units()
    local list = {}
    for _, pd in pairs(player_data) do
        table.insert(list, pd)
    end
    return list
end

function M.get_alive_count(camp)
    local n = 0
    for _, pd in pairs(player_data) do
        if pd.alive then
            if not camp or pd.unit:get_camp_id() == camp then
                n = n + 1
            end
        end
    end
    return n
end

function M.get_alive_count_by_team(team_name)
    local n = 0
    for _, pd in pairs(player_data) do
        if pd.alive and pd.team == team_name then
            n = n + 1
        end
    end
    return n
end

function M.get_rankings()
    local list = M.get_all_player_units()
    table.sort(list, function(a, b) return a.score > b.score end)
    for i, pd in ipairs(list) do
        pd.rank = i
    end
    return list
end

-- ---------------------------------------------------------
-- 工具
-- ---------------------------------------------------------
function M.get_random_spawn_point()
    local spawns = clicli.area.get_circle_areas_by_tag('player_spawn')
    if #spawns == 0 then
        return clicli.point.create(0, 0)
    end
    local area = spawns[math.random(#spawns)]
    return area:get_center_point()
end

function M.get_random_npc_model()
    local pool = CONST.NPC_MODEL_POOL
    if #pool == 0 then return nil end
    return pool[math.random(#pool)]
end

return M