I was poking through entities.lua which is in radiant.smod and found a few functions that might help? I dunno.
function entities.teleport_items(items, origin, min_radius, max_radius)
for _, e in pairs(items) do
local location = radiant.terrain.find_placement_point(origin, min_radius, max_radius)
radiant.terrain.place_entity(e, location)
end
end
function entities.distance_between(object_a, object_b)
local point_a, point_b
assert(object_a and object_b)
if radiant.util.is_a(object_a, Point3) then
point_a = object_a
elseif radiant.util.is_a(object_a, Entity) then
local mob = object_a:get_component('mob')
point_a = mob and mob:get_world_location()
else
error('unexpected type for arg1 "%s"', type(object_a))
end
if radiant.util.is_a(object_b, Point3) then
point_b = object_b
elseif radiant.util.is_a(object_b, Entity) then
local rcs = object_b:get_component('region_collision_shape')
if rcs then
-- find the point on the region closets to point_a
local region = rcs:get_region()
if region then
local world_space_region = entities.local_to_world(region:get(), object_b)
point_b = world_space_region:get_closest_point(point_a)
end
end
if not point_b then
-- still no point? use the world location
local mob = object_b:get_component('mob')
point_b = mob and mob:get_world_location()
end
end
if not point_a or not point_b then
-- either a or b was an entity that's not in the world. doh!
return radiant.math.INFINITY
end
return point_a:distance_to(point_b)
end
-- A function that calculates JUST the distance between the world grid locations of two entities
function entities.distance_between_entities(entity_a, entity_b)
local point_a = entity_a:get_component('mob'):get_world_location()
local point_b = entity_b:get_component('mob'):get_world_location()
if not point_a or not point_b then
-- either a or b was an entity that's not in the world. doh!
return radiant.math.INFINITY
end
return point_a:distance_to(point_b)
end
function entities.exists(entity)
return entity and entity:is_valid()
end
function entities.move_to(entity, location)
radiant.check.is_entity(entity)
if type(location) == "table" then
location = Point3(location.x, location.y, location.z)
end
entity:add_component('mob'):move_to(location)
end
function entities.move_to_absolute(entity, location)
local parent_origin = entities.get_world_location(entities.get_parent(entity))
entity:add_component('mob'):move_to(location - parent_origin)
end
function entities.move_to_grid_aligned(entity, location)
radiant.check.is_entity(entity)
if type(location) == "table" then
location = Point3(location.x, location.y, location.z)
end
entity:add_component('mob'):move_to_grid_aligned(location)
end
function entities.turn_to(entity, degrees)
if not entity or not entity:is_valid() then
return
end
radiant.check.is_number(degrees)
entity:add_component('mob'):turn_to(degrees)
end
function entities.turn_to_face(entity, target, opt_no_interpolate)
local point = entities.get_facing_point(entity, target)
local no_interpolate = not not opt_no_interpolate
if no_interpolate then
entity:get_component('mob'):set_skip_interpolation(true)
end
if point then
entity:get_component('mob'):turn_to_face_point(point)
end
end
-- Returns the (voxel, integer) grid location in front of the specified entity.
function entities.get_grid_in_front(entity)
local mob = entity:get_component('mob')
local facing = radiant.math.round(mob:get_facing() / 90) * 90
local location = mob:get_world_grid_location()
local offset = radiant.math.rotate_about_y_axis(-Point3.unit_z, facing):to_closest_int()
return location + offset
end
function entities.get_facing_point(entity, target)
if not entity or not entity:is_valid() then
return nil
end
local point = nil
if radiant.util.is_a(target, Entity) then
-- if the target has a non-empty destination region, face the closest point in that region
local dest_component = target:get_component('destination')
local boxed_dest_region = dest_component and dest_component:get_region()
local dest_region = boxed_dest_region and boxed_dest_region:get()
if dest_region and not dest_region:empty() then
local dest_region_world = entities.local_to_world(dest_region, target)
local entity_location = entities.get_world_location(entity)
point = dest_region_world:get_closest_point(entity_location)
else
point = entities.get_world_location(target)
end
elseif radiant.util.is_a(target, Point3) then
point = target
end
return point
end
function entities.get_facing(entity)
if not entity or not entity:is_valid() then
return nil
end
local mob = entity:get_component('mob')
local facing = mob and mob:get_facing()
return facing
end
function entities.get_entity(id)
local entity = radiant.get_entity(id)
return entity
end
function entities.get_animation_table(entity)
local name
local render_info = entity:get_component('render_info')
if render_info then
name = render_info:get_animation_table()
end
return name
end
function entities.set_animation_table(entity, animation_table_name)
local render_info = entity:get_component('render_info')
if render_info and animation_table_name then
render_info:set_animation_table(animation_table_name)
end
end
function entities.get_attribute(entity, attribute_name, default)
if entity and entity:is_valid() then
local ac = entity:get_component('stonehearth:attributes')
if ac then
return ac:get_attribute(attribute_name, default)
end
end
return default
end
function entities.is_adjacent_to(source, target)
if not source or not target then
return false
end
if radiant.util.is_a(source, Entity) and radiant.util.is_a(target, Entity) then
local result = _radiant.sim.is_adjacent_to(source, target)
return result
end
if radiant.util.is_a(source, Point3) and radiant.util.is_a(target, Point3) then
local result = source:is_adjacent_to(target)
return result
end
log:error('invalid parameters %s, %s', tostring(source), tostring(target))
assert(false)
end
local function is_xz_adjacent(p1, p2)
if not p1 or not p2 then
return false
end
local q1 = Point2(p1.x, p1.z)
local q2 = Point2(p2.x, p2.z)
local result = q1:is_adjacent_to(q2)
return result
end
function entities.location_within_reach(entity, target_location)
if not entity or not entity:is_valid() then
return false
end
if not target_location then
return false
end
local mob = entity:get_component('mob')
if not mob then
return false
end
local entity_location = mob:get_world_grid_location()
if not entity_location then
return false
end
if not is_xz_adjacent(target_location, entity_location) then
return false
end
local collision_type = mob:get_mob_collision_type()
local max_reach_up, max_reach_down = _radiant.sim.get_entity_reach(collision_type)
local delta = target_location - entity_location
local result = radiant.math.in_bounds(delta.y, -max_reach_down, max_reach_up)
return result
end
function entities.get_target_table(entity, table_name)
if not entity or not entity:is_valid() then
return nil
end
return entity:add_component('stonehearth:target_tables')
:get_target_table(table_name)
end
function entities.is_standing_on_ladder(entity)
local entity_location = entities.get_world_grid_location(entity)
local support_location = entity_location - Point3.unit_y
-- quick rejection test
if _physics:is_blocked(entity, support_location) then
return false
end
local support_entities = radiant.terrain.get_entities_at_point(support_location)
for id, entity in pairs(support_entities) do
if entity:get_component('vertical_pathing_region') then
return true, entity
end
end
return false
end