216 lines
6.0 KiB
Plaintext
216 lines
6.0 KiB
Plaintext
|
-- Artefacts movement module for DAO
|
||
|
|
||
|
-- Shuffle table, Fisher-Yates shuffle with preserving original table
|
||
|
local function shuffle(t)
|
||
|
local s = {}
|
||
|
for i = 1, #t do s[i] = t[i] end
|
||
|
for i = #t, 2, -1 do
|
||
|
local j = math.random(i)
|
||
|
s[i], s[j] = s[j], s[i]
|
||
|
end
|
||
|
return s
|
||
|
end
|
||
|
|
||
|
local function vec_to_table(vec)
|
||
|
return {
|
||
|
x = vec.x,
|
||
|
y = vec.y,
|
||
|
z = vec.z
|
||
|
}
|
||
|
end
|
||
|
|
||
|
local function table_to_vec(vec)
|
||
|
return vector():set(vec.x, vec.y, vec.z)
|
||
|
end
|
||
|
|
||
|
local function distance_to_xz_sqr(a, b)
|
||
|
if a.distance_to_xz_sqr then
|
||
|
return a:distance_to_xz_sqr(b)
|
||
|
end
|
||
|
|
||
|
local va = b.x - a.x
|
||
|
local vb = b.z - a.z
|
||
|
return va * va + vb * vb
|
||
|
end
|
||
|
|
||
|
local function table_nexter(t)
|
||
|
local nexter = {}
|
||
|
nexter.t = t
|
||
|
nexter.current = nil
|
||
|
nexter.next = function(self)
|
||
|
if self.current ~= nil and not self.t[self.current] then
|
||
|
self.current = nil
|
||
|
end
|
||
|
self.current = next(self.t, self.current)
|
||
|
if self.current == nil then
|
||
|
self.current = next(self.t, self.current)
|
||
|
end
|
||
|
return self.current, self.t[self.current]
|
||
|
end
|
||
|
return nexter
|
||
|
end
|
||
|
|
||
|
artefact_ids_to_way = table_nexter({})
|
||
|
|
||
|
spawn_artefact_on_smart = drx_da_main.spawn_artefact_on_smart
|
||
|
drx_da_main.spawn_artefact_on_smart = function(level_file, smart_name, picked_artefact, level_name)
|
||
|
local id = spawn_artefact_on_smart(level_file, smart_name, picked_artefact, level_name)
|
||
|
if not id then return end
|
||
|
|
||
|
-- 50% chance for way generation
|
||
|
if math.random() < 0.5 then
|
||
|
generate_ways_for_id(id, smart_name, picked_artefact, level_name)
|
||
|
end
|
||
|
return id
|
||
|
end
|
||
|
|
||
|
clean_artefacts_on_level = drx_da_main.clean_artefacts_on_level
|
||
|
drx_da_main.clean_artefacts_on_level = function(level_name)
|
||
|
clean_artefacts_on_level(level_name)
|
||
|
for id, v in pairs(artefact_ids_to_way.t) do
|
||
|
if v.level_name == level_name then
|
||
|
artefact_ids_to_way.t[id] = nil
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function generate_ways_for_id(id, smart_name, picked_artefact, level_name)
|
||
|
if artefact_ids_to_way.t[id] then
|
||
|
-- printf("artefact way is already generated for %s on %s in %s", id, smart_name, level_name)
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local anomalies = drx_da_main.updated_anomaly_levels[level_name] and drx_da_main.updated_anomaly_levels[level_name].anomalies_by_smart and drx_da_main.updated_anomaly_levels[level_name].anomalies_by_smart[smart_name]
|
||
|
if not anomalies then
|
||
|
-- printf("no anomalies are in db on smart for %s on %s in %s", id, smart_name, level_name)
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local se_objs = {}
|
||
|
for id, _ in pairs(anomalies) do
|
||
|
local se_obj = alife_object(id)
|
||
|
if se_obj then
|
||
|
se_objs[#se_objs + 1] = se_obj
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if is_empty(se_objs) then
|
||
|
-- printf("no anomalies se_objs found on smart for %s on %s in %s", id, smart_name, level_name)
|
||
|
return
|
||
|
end
|
||
|
|
||
|
artefact_ids_to_way.t[id] = {
|
||
|
points = {},
|
||
|
current_point_index = 1,
|
||
|
smart_name = smart_name,
|
||
|
level_name = level_name,
|
||
|
update_time = 0
|
||
|
}
|
||
|
local points = artefact_ids_to_way.t[id].points
|
||
|
se_objs = shuffle(se_objs)
|
||
|
for i, se_obj in ipairs(se_objs) do
|
||
|
points[#points + 1] = vec_to_table(se_obj.position)
|
||
|
-- printf("adding point for %s on %s in %s: %s,%s,%s", id, smart_name, level_name, round_idp(se_obj.position.x, 2), round_idp(se_obj.position.y, 2), round_idp(se_obj.position.z, 2))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function move_artefact(obj, t)
|
||
|
local id = obj:id()
|
||
|
local pos = obj:position()
|
||
|
local point = t.points[t.current_point_index]
|
||
|
if not point then
|
||
|
-- printf("update artefact %s, point not found by index %s", id, t.current_point_index)
|
||
|
point = t.points[1]
|
||
|
t.current_point_index = 1
|
||
|
end
|
||
|
point = table_to_vec(point)
|
||
|
if distance_to_xz_sqr(pos, point) < 2 then
|
||
|
t.current_point_index = t.current_point_index + 1
|
||
|
-- printf("update artefact %s, artefact near current point, new point index %s", id, t.current_point_index)
|
||
|
point = t.points[t.current_point_index]
|
||
|
if not point then
|
||
|
-- printf("update artefact %s, point not found by index %s", id, t.current_point_index)
|
||
|
point = t.points[1]
|
||
|
t.current_point_index = 1
|
||
|
end
|
||
|
end
|
||
|
point = table_to_vec(point)
|
||
|
|
||
|
local lvid = obj:level_vertex_id()
|
||
|
local lvid_pos = level.vertex_position(lvid)
|
||
|
point.y = lvid_pos.y + 0.1
|
||
|
local dir = vector():set(point):sub(pos):normalize()
|
||
|
-- demonized_geometry_ray.VisualizeRay(pos, point, nil, 500)
|
||
|
|
||
|
-- obj:set_const_force(vector():set(dir.x, dir.y, dir.z), 100, 1000)
|
||
|
local ph = obj:get_physics_shell()
|
||
|
if ph then
|
||
|
local mass = obj:mass()
|
||
|
dir.y = dir.y + 1
|
||
|
dir:mul(mass)
|
||
|
ph:apply_force(dir.x * 150, dir.y * 250, dir.z * 150)
|
||
|
obj:set_const_force(vector():set(dir.x, dir.y / 5, dir.z), 2.5, 1000)
|
||
|
-- printf("move artefact %s, index %s", id, t.current_point_index)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local tg = 0
|
||
|
function update_artefacts()
|
||
|
if time_global() == tg then return end
|
||
|
tg = time_global()
|
||
|
|
||
|
local id, t = artefact_ids_to_way:next()
|
||
|
if not id then return end
|
||
|
|
||
|
local obj = level.object_by_id(id)
|
||
|
if not obj then
|
||
|
-- printf("no artefact obj by %s", id)
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if time_global() < (t.update_time or 0) then return end
|
||
|
t.update_time = time_global() + math.random(500, 1500)
|
||
|
|
||
|
move_artefact(obj, t)
|
||
|
end
|
||
|
|
||
|
function save_state(m_data)
|
||
|
m_data.dao_artefact_movement = artefact_ids_to_way
|
||
|
end
|
||
|
|
||
|
function load_state(m_data)
|
||
|
if m_data.dao_artefact_movement then
|
||
|
artefact_ids_to_way = m_data.dao_artefact_movement
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function actor_on_item_take(obj)
|
||
|
if artefact_ids_to_way.t[obj:id()] then
|
||
|
artefact_ids_to_way.t[obj:id()] = nil
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function npc_on_item_take(npc, obj)
|
||
|
actor_on_item_take(obj)
|
||
|
end
|
||
|
|
||
|
-- Next actor tick enabling
|
||
|
function actor_on_first_update()
|
||
|
CreateTimeEvent("drx_da_main_artefacts_movement", 0, 0, function()
|
||
|
AddUniqueCall(update_artefacts)
|
||
|
return true
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
function on_game_start()
|
||
|
RegisterScriptCallback("actor_on_first_update", actor_on_first_update)
|
||
|
RegisterScriptCallback("save_state", save_state)
|
||
|
RegisterScriptCallback("load_state", load_state)
|
||
|
RegisterScriptCallback("actor_on_item_take", actor_on_item_take)
|
||
|
RegisterScriptCallback("npc_on_item_take", npc_on_item_take)
|
||
|
end
|
||
|
|
||
|
function refresh_artefacts()
|
||
|
drx_da_main.clean_artefacts_on_level(level.name())
|
||
|
drx_da_main.spawn_artefacts_on_level(level.name())
|
||
|
end
|