From b3d1079259ec8160e4dfc0cb08bf5ce63170ec72 Mon Sep 17 00:00:00 2001 From: Leslie Krause Date: Fri, 15 May 2020 12:06:08 -0400 Subject: [PATCH] Build 04 - minor code reorganization - renamed 'class' to 'propagator' for consistency - added compatibility layer for Minetest S3 engine - implemented emission propagator with example code - updated README.txt with dependency information --- README.txt | 11 +++++ compatibility.lua | 27 +++++++++++ depends.txt | 3 ++ init.lua | 119 ++++++++++++++++++++++++++++------------------ sources.lua | 8 ++-- 5 files changed, 119 insertions(+), 49 deletions(-) create mode 100644 compatibility.lua create mode 100644 depends.txt diff --git a/README.txt b/README.txt index fe1b05d..67f4e34 100644 --- a/README.txt +++ b/README.txt @@ -10,6 +10,17 @@ For complete usage instructions, please refer to the forum topic: https://forum.minetest.net/viewtopic.php?f=9&t=24721 +Compatability +---------------------- + +Requires PR #9717 for Minetest 5.3-dev + +Dependencies +---------------------- + +Mobs Lite Mod (required) + https://bitbucket.org/sorcerykid/mobs + Repository ---------------------- diff --git a/compatibility.lua b/compatibility.lua new file mode 100644 index 0000000..d6bb7e8 --- /dev/null +++ b/compatibility.lua @@ -0,0 +1,27 @@ +minetest.count_nodes_in_area = function( pos_min, pos_max, names, is_group ) + local counts, node_counts + local voxel_manip = minetest.get_voxel_manip( ) + + voxel_manip:read_from_map( pos_min, pos_max ) + node_counts = select( 2, minetest.find_nodes_in_area( pos_min, pos_max, names ) ) + + if is_group == false then + return counts + end + + counts = { } -- use new table for transposing node counts into group counts + for _, name in ipairs( names ) do + local group_name = string.match( name, "group:(.+)" ) + if group_name then + counts[ name ] = 0 + for node_name, node_count in pairs( node_counts ) do + if minetest.registered_nodes[ node_name ].groups[ group_name ] then + counts[ name ] = counts[ name ] + node_count + end + end + else + counts[ name ] = node_counts[ name ] + end + end + return counts +end diff --git a/depends.txt b/depends.txt new file mode 100644 index 0000000..84909dd --- /dev/null +++ b/depends.txt @@ -0,0 +1,3 @@ +default +fire +mobs diff --git a/init.lua b/init.lua index f5ac19c..eb43e69 100644 --- a/init.lua +++ b/init.lua @@ -19,6 +19,7 @@ local stack_size = 0 local random = math.random local pow = math.pow local ceil = math.ceil +local min = math.min local function check_limits( v, min_v, max_v ) return v >= min_v and v <= max_v @@ -28,18 +29,8 @@ local function clamp( val, min, max ) return val < min and min or val > max and max or val end -local function get_power_decrease( scale, power, ratio ) - return ratio <= 1 - scale and 1.0 or - max( 1 - pow( ( scale + ratio - 1 ) / scale, 1 + power ), 0 ) -end - -local function get_power_increase( scale, power, ratio ) - return ratio >= scale and 1.0 or - 1 - pow( ( scale - ratio ) / scale, 1 + power ) -end - local function get_signal_strength( max_value, cur_value, slope ) - return math.pow( cur_value / max_value, 1 - clamp( slope, 0, 1 ) ) + return pow( cur_value / max_value, 1 - clamp( slope, 0, 1 ) ) end local function punch_object( obj, groups, pos ) @@ -60,7 +51,7 @@ local function ContactStimulus( node_name, group, intensity, chance, period, pow local self = { } self.group = group - self.class = "contact" + self.propagator = "contact" self.period = period self.on_action = function ( source_pos, target_obj ) @@ -82,37 +73,11 @@ local function ContactStimulus( node_name, group, intensity, chance, period, pow return self end -local function RadiationStimulus( node_name, group, intensity, chance, period, radius, scale, power, max_count ) - local self = { } - - self.group = group - self.class = "radiation" - self.period = period - - self.on_action = function ( source_pos, target_obj ) - if random( chance ) == 1 then - local touch_counts = minetest.count_nodes_in_area( - vector.add( source_pos, -radius ), vector.add( source_pos, radius ), { node_name }, true ) - local count = touch_counts[ node_name ] - - if count > 0 then - local damage = intensity * get_power_increase( scale, power, count / max_count ) - target_obj:punch( target_obj, period, { - full_punch_interval = period, - damage_groups = { [group] = damage }, - }, nil ) - end - end - end - - return self -end - local function ImmersionStimulus( node_name, group, intensity, chance, period ) local self = { } self.group = group - self.class = "immersion" + self.method = "immersion" self.period = period self.on_action = function ( source_pos, target_obj ) @@ -132,6 +97,59 @@ local function ImmersionStimulus( node_name, group, intensity, chance, period ) return self end +local function RadiationStimulus( node_name, group, intensity, chance, period, radius, power ) + local self = { } + + self.group = group + self.propagator = "radiation" + self.period = period + + self.on_action = function ( source_pos, target_obj ) + if random( chance ) == 1 then + local touch_counts = minetest.count_nodes_in_area( + vector.add( source_pos, -radius ), vector.add( source_pos, radius ), { node_name }, true ) + local count = touch_counts[ node_name ] + + if count > 0 then + local damage = intensity * pow( count, power ) + target_obj:punch( target_obj, period, { + full_punch_interval = period, + damage_groups = { [group] = damage }, + }, nil ) + end + end + end + + return self +end + +local function EmissionStimulus( node_name, group, intensity, chance, period, radius, slope ) + local self = { } + + self.group = group + self.propagator = "radiation" + self.period = period + + self.on_action = function ( source_pos, target_obj ) + if random( chance ) == 1 then + -- get nearest node position in a radius, including the center + local node_pos = minetest.find_node_near( source_pos, radius, { node_name }, true ) + + if node_pos then + local length = min( radius, vector.distance( node_pos, source_pos ) ) + local damage = ceil( intensity * get_signal_strength( radius, radius - length, slope ) ) + + target_obj:punch( target_obj, period, { + full_punch_interval = period, + damage_groups = { [group] = damage }, + }, nil ) + end + end + end + + return self +end + local function AxonPropagator( obj ) local event_defs = { } local clock = 0.0 @@ -252,12 +270,16 @@ axon.register_source = function ( node_name, stimulus_list ) end for i, v in pairs( stimulus_list ) do local stimulus - if v.class == "contact" then + if v.propagator == "contact" then stimulus = ContactStimulus( node_name, v.group, v.intensity, v.chance, v.period, v.power ) - elseif v.class == "radiation" then - stimulus = RadiationStimulus( node_name, v.group, v.intensity, v.chance, v.period, v.radius, v.scale, v.power, v.max_count ) - elseif v.class == "immersion" then + elseif v.propagator == "immersion" then stimulus = ImmersionStimulus( node_name, v.group, v.intensity, v.chance, v.period ) + elseif v.propagator == "radiation" then + stimulus = RadiationStimulus( node_name, v.group, v.intensity, v.chance, v.period, v.radius, v.power ) + elseif v.propagator == "emission" then + stimulus = EmissionStimulus( node_name, v.group, v.intensity, v.chance, v.period, v.radius, v.slope ) + else + error( "axon.register_source(): Unknown propagator specified in stimulus property table" ) end table.insert( sources[ node_name ], stimulus ) end @@ -276,11 +298,11 @@ axon.generate_direct_stimulus = function ( obj, groups ) punch_object( obj, groups ) end -axon.generate_radial_stimulus = function ( pos, radius, speed, slope, chance, groups, classes ) +axon.generate_radial_stimulus = function ( pos, radius, speed, slope, groups, classes ) for obj in mobs.iterate_registry( pos, radius, radius, classes ) do local length = vector.distance( pos, obj:get_pos( ) ) - if length <= radius and random( chance ) == 1 then + if length <= radius then local damage_groups = { } for k, v in pairs( groups ) do @@ -301,3 +323,10 @@ end -------------------- dofile( minetest.get_modpath( "axon" ) .. "/sources.lua" ) + +-- compatibility for Minetest S3 engine + +if not minetest.count_nodes_in_area then + dofile( minetest.get_modpath( "axon" ) .. "/compatibility.lua" ) +end + diff --git a/sources.lua b/sources.lua index f640758..577ad55 100644 --- a/sources.lua +++ b/sources.lua @@ -1,16 +1,16 @@ -- This is a sample source definition file. You will want to modify this for your particular game. axon.register_source( "group:lava_source", { - { group = "heat_stim", class = "radiation", intensity = 30, chance = 1, period = 1.5, radius = 5.0, scale = 1.0, power = 0.0, max_count = 6 }, - { group = "lava_stim", class = "immersion", intensity = 10, chance = 1, period = 0.5 }, + { group = "heat_stim", propagator = "radiation", intensity = 10, chance = 1, period = 1.5, radius = 5.0, power = 0.3 }, + { group = "lava_stim", propagator = "immersion", intensity = 10, chance = 1, period = 0.5 }, } ) axon.register_source( "group:water_source", { - { group = "water_stim", class = "immersion", intensity = 5, chance = 1, period = 0.5 }, + { group = "water_stim", propagator = "immersion", intensity = 10, chance = 1, period = 0.5 }, } ) axon.register_source( "group:heat_source", { - { group = "heat_stim", class = "contact", intensity = 3, chance = 2, period = 1.0, power = 0.8 }, + { group = "heat_stim", propagator = "contact", intensity = 3, chance = 2, period = 1.0, power = 0.8 }, } ) axon.register_source_group( "lava_source", { "default:lava_source", "default:lava_flowing" } )