223 lines
7.0 KiB
Plaintext
223 lines
7.0 KiB
Plaintext
|
local flies_t = {}
|
||
|
local snd_parts_t = {}
|
||
|
|
||
|
-- Specifying default variables
|
||
|
local decomp_stages_time = corpse_fauna_mcm.get_config("decomp_interval") * 360 -- flies and sound appear in this time
|
||
|
local max_decomp_stages = corpse_fauna_mcm.get_config("max_decals") -- max amount of wallmarks
|
||
|
|
||
|
local fly_dbg = corpse_fauna_mcm.get_config("debug_mode")
|
||
|
local clear_table = corpse_fauna_mcm.get_config("clear_cache")
|
||
|
local ctime_to_t = utils_data.CTime_to_table
|
||
|
local t_to_ctime = utils_data.CTime_from_table
|
||
|
|
||
|
-- default = "bip01_spine", in table = "spine"
|
||
|
local spine_pos_t = { [clsid.burer_s] = true, [clsid.chimera_s] = true, [clsid.gigant_s] = true, ["SM_LURKER"] = true }
|
||
|
|
||
|
function npc_on_death_callback(npc)
|
||
|
pr("start id: %s", npc:id())
|
||
|
flies_t[npc:id()] = {}
|
||
|
flies_t[npc:id()].start_time = ctime_to_t(game.get_game_time())
|
||
|
flies_t[npc:id()].stage = 0
|
||
|
flies_t[npc:id()].wms = 0
|
||
|
end
|
||
|
|
||
|
local tmr = 0
|
||
|
function actor_on_update()
|
||
|
local tg = time_global()
|
||
|
if tmr > tg then return end
|
||
|
tmr = tg + 2000
|
||
|
|
||
|
for npc_id, t in pairs(flies_t) do
|
||
|
local npc = level.object_by_id(npc_id)
|
||
|
local time_diff = game.get_game_time():diffSec(t_to_ctime(t.start_time))
|
||
|
pr("npc_id: %s || npc sec: %s || stage: %s || time: %s", npc_id, npc and npc:section(), t.stage, time_diff)
|
||
|
if npc and time_diff > decomp_stages_time then
|
||
|
play_move_snd_and_part(npc, npc_id)
|
||
|
|
||
|
-- wallmarks (first wallmark in 720, second in 720 + 360, third in 720 + 720 etc)
|
||
|
flies_t[npc_id].stage = math.floor( (time_diff - decomp_stages_time) / decomp_stages_time )
|
||
|
flies_t[npc_id].stage = flies_t[npc_id].stage < max_decomp_stages and flies_t[npc_id].stage or max_decomp_stages
|
||
|
|
||
|
if flies_t[npc_id].stage > flies_t[npc_id].wms then
|
||
|
local amount = flies_t[npc_id].stage - flies_t[npc_id].wms -- for loadings and redrawing
|
||
|
|
||
|
-- draw wm (can change function to not pick same bones later)
|
||
|
for i = 1, amount do
|
||
|
draw_rot_wm(npc)
|
||
|
flies_t[npc_id].wms = flies_t[npc_id].wms + 1
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
end
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
function server_entity_on_unregister(se_obj, typ) -- stop sound and particle and remove from table when npc is released
|
||
|
if flies_t[se_obj.id] then
|
||
|
pr("server stop sound/part/remove from table id: %s", se_obj.id)
|
||
|
stop_snd_and_part(se_obj.id)
|
||
|
flies_t[se_obj.id] = nil
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function npc_on_net_destroy(npc) -- stop sound and particle when npc goes offline
|
||
|
if flies_t[npc:id()] then
|
||
|
pr("net_destroy stop sound/particles id: %s", npc:id())
|
||
|
stop_snd_and_part(npc:id())
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function npc_on_net_spawn(npc) -- reset wallmarks when npc comes online
|
||
|
if flies_t[npc:id()] then
|
||
|
pr("net_spawn reset wallmarks id: %s", npc:id())
|
||
|
flies_t[npc:id()].wms = 0
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function actor_on_first_update() -- reset wallmarks on loading
|
||
|
for npc_id, t in pairs(flies_t) do
|
||
|
pr("actor_first_update reset wallmarks id: %s", npc_id)
|
||
|
flies_t[npc_id].wms = 0
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function play_move_snd_and_part(npc, id)
|
||
|
local bone_name = "bip01_spine"
|
||
|
|
||
|
-- special mutants
|
||
|
local kind = ini_sys:r_string_ex(npc:section(), "kind")
|
||
|
if (npc:clsid() and spine_pos_t[npc:clsid()]) or (kind and spine_pos_t[kind]) then
|
||
|
bone_name = "spine"
|
||
|
end
|
||
|
|
||
|
local bone_id = npc:get_bone_id(bone_name)
|
||
|
if (not bone_id) or (bone_id == 65535) then return end
|
||
|
|
||
|
local bone_pos = vector():set(npc:bone_position(bone_name))
|
||
|
local new_pos = vector():set(bone_pos.x, bone_pos.y + 0.5, bone_pos.z)
|
||
|
|
||
|
if not (snd_parts_t[id]) then -- play
|
||
|
pr("play id: %s", id)
|
||
|
snd_parts_t[id] = {}
|
||
|
snd_parts_t[id].snd = sound_object("corpse-fauna\\flies-buzzing-" .. math.random(1, 2))
|
||
|
snd_parts_t[id].snd:play_at_pos(npc, new_pos, 0, sound_object.s3d + sound_object.looped)
|
||
|
snd_parts_t[id].part = particles_object("flies_bzzz\\insect_light")
|
||
|
snd_parts_t[id].part:play_at_pos(new_pos)
|
||
|
else -- move
|
||
|
pr("move id: %s", id)
|
||
|
snd_parts_t[id].snd:set_position(new_pos)
|
||
|
snd_parts_t[id].part:move_to(new_pos, VEC_ZERO)
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
function stop_snd_and_part(id)
|
||
|
if not (snd_parts_t[id]) then return end
|
||
|
|
||
|
pr("stop id: %s", id)
|
||
|
|
||
|
if snd_parts_t[id].snd:playing() then
|
||
|
snd_parts_t[id].snd:stop()
|
||
|
end
|
||
|
|
||
|
if snd_parts_t[id].part:playing() then
|
||
|
snd_parts_t[id].part:stop()
|
||
|
end
|
||
|
|
||
|
snd_parts_t[id] = nil
|
||
|
|
||
|
end
|
||
|
|
||
|
function on_level_changing()
|
||
|
empty_table(flies_t)
|
||
|
end
|
||
|
|
||
|
function save_state(m_data)
|
||
|
m_data.body_flies_t = flies_t
|
||
|
end
|
||
|
|
||
|
function load_state(m_data)
|
||
|
flies_t = m_data.body_flies_t or {}
|
||
|
if clear_table == true then
|
||
|
empty_table(flies_t)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function pr(...)
|
||
|
if not fly_dbg then return end
|
||
|
printf(...)
|
||
|
end
|
||
|
|
||
|
-- for wallmarks
|
||
|
function find_wm_bone_pos(npc)
|
||
|
|
||
|
-- find damage sec
|
||
|
local damage_sec = ini_sys:r_string_ex(npc:section(), "damage") or ""
|
||
|
if (not damage_sec) or (damage_sec == "") then return end
|
||
|
|
||
|
-- collect bones from damage sec
|
||
|
local bones_t = utils_data.collect_section(ini_sys, damage_sec, true)
|
||
|
if not bones_t then return end
|
||
|
|
||
|
-- exclude some bones
|
||
|
local exclude_ar = { "finger", "toe", "hand", "foot" }
|
||
|
for bone_name, _ in pairs(bones_t) do
|
||
|
local bone_id = npc:get_bone_id(bone_name)
|
||
|
if (not bone_id) or (bone_id == 65535) or (str_find_in_ar(exclude_ar, bone_name)) then
|
||
|
bones_t[bone_name] = nil
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- get bone pos
|
||
|
local rnd_bone = random_key_table(bones_t)
|
||
|
local bone_pos = rnd_bone and vector():set( npc:bone_position(rnd_bone) )
|
||
|
|
||
|
return bone_pos, rnd_bone
|
||
|
end
|
||
|
|
||
|
function draw_rot_wm(npc)
|
||
|
local bone_pos, bone_name = find_wm_bone_pos(npc)
|
||
|
pr("draw wallmark, id: %s || bone: %s", npc:id(), bone_name)
|
||
|
if not bone_pos then return end
|
||
|
|
||
|
local y_offset = flies_t[npc:id()].stage % 2 == 0 and -0.2 or 0.2
|
||
|
local from_pos = vector():set(bone_pos.x, bone_pos.y + y_offset, bone_pos.z)
|
||
|
local from_dir = vec_sub(vector():set(bone_pos), vector():set(from_pos)):normalize()
|
||
|
|
||
|
local picked_wm = "rot_stain_" .. math.random(1, 3)
|
||
|
|
||
|
wallmarks_manager():place_skeleton(npc, picked_wm, vector():set(from_pos), vector():set(from_dir), 0.75, -1)
|
||
|
end
|
||
|
|
||
|
function str_find_in_ar(ar, str)
|
||
|
for i = 1, #ar do
|
||
|
if string.find(str, ar[i]) then
|
||
|
return true
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function on_option_change()
|
||
|
decomp_stages_time = corpse_fauna_mcm.get_config("decomp_interval") * 360
|
||
|
max_decomp_stages = corpse_fauna_mcm.get_config("max_decals")
|
||
|
fly_dbg = corpse_fauna_mcm.get_config("debug_mode")
|
||
|
clear_table = corpse_fauna_mcm.get_config("clear_cache")
|
||
|
end
|
||
|
|
||
|
function on_game_start()
|
||
|
RegisterScriptCallback("npc_on_death_callback", npc_on_death_callback)
|
||
|
RegisterScriptCallback("monster_on_death_callback", npc_on_death_callback)
|
||
|
RegisterScriptCallback("actor_on_update", actor_on_update)
|
||
|
RegisterScriptCallback("server_entity_on_unregister", server_entity_on_unregister)
|
||
|
RegisterScriptCallback("npc_on_net_destroy", npc_on_net_destroy)
|
||
|
RegisterScriptCallback("monster_on_net_destroy", npc_on_net_destroy)
|
||
|
RegisterScriptCallback("npc_on_net_spawn", npc_on_net_spawn)
|
||
|
RegisterScriptCallback("monster_on_net_spawn", npc_on_net_spawn)
|
||
|
RegisterScriptCallback("actor_on_first_update", actor_on_first_update)
|
||
|
RegisterScriptCallback("save_state", save_state)
|
||
|
RegisterScriptCallback("load_state", load_state)
|
||
|
RegisterScriptCallback("on_option_change", on_option_change)
|
||
|
RegisterScriptCallback("on_level_changing", on_level_changing)
|
||
|
end
|