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