- 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
This commit is contained in:
Leslie Krause 2020-05-15 12:06:08 -04:00
parent 4fde68cebd
commit b3d1079259
5 changed files with 119 additions and 49 deletions

View File

@ -10,6 +10,17 @@ For complete usage instructions, please refer to the forum topic:
https://forum.minetest.net/viewtopic.php?f=9&t=24721 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 Repository
---------------------- ----------------------

27
compatibility.lua Normal file
View File

@ -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

3
depends.txt Normal file
View File

@ -0,0 +1,3 @@
default
fire
mobs

119
init.lua
View File

@ -19,6 +19,7 @@ local stack_size = 0
local random = math.random local random = math.random
local pow = math.pow local pow = math.pow
local ceil = math.ceil local ceil = math.ceil
local min = math.min
local function check_limits( v, min_v, max_v ) local function check_limits( v, min_v, max_v )
return v >= min_v and 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 return val < min and min or val > max and max or val
end 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 ) 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 end
local function punch_object( obj, groups, pos ) local function punch_object( obj, groups, pos )
@ -60,7 +51,7 @@ local function ContactStimulus( node_name, group, intensity, chance, period, pow
local self = { } local self = { }
self.group = group self.group = group
self.class = "contact" self.propagator = "contact"
self.period = period self.period = period
self.on_action = function ( source_pos, target_obj ) self.on_action = function ( source_pos, target_obj )
@ -82,37 +73,11 @@ local function ContactStimulus( node_name, group, intensity, chance, period, pow
return self return self
end 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 function ImmersionStimulus( node_name, group, intensity, chance, period )
local self = { } local self = { }
self.group = group self.group = group
self.class = "immersion" self.method = "immersion"
self.period = period self.period = period
self.on_action = function ( source_pos, target_obj ) self.on_action = function ( source_pos, target_obj )
@ -132,6 +97,59 @@ local function ImmersionStimulus( node_name, group, intensity, chance, period )
return self return self
end 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 function AxonPropagator( obj )
local event_defs = { } local event_defs = { }
local clock = 0.0 local clock = 0.0
@ -252,12 +270,16 @@ axon.register_source = function ( node_name, stimulus_list )
end end
for i, v in pairs( stimulus_list ) do for i, v in pairs( stimulus_list ) do
local stimulus 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 ) stimulus = ContactStimulus( node_name, v.group, v.intensity, v.chance, v.period, v.power )
elseif v.class == "radiation" then elseif v.propagator == "immersion" 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
stimulus = ImmersionStimulus( node_name, v.group, v.intensity, v.chance, v.period ) 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 end
table.insert( sources[ node_name ], stimulus ) table.insert( sources[ node_name ], stimulus )
end end
@ -276,11 +298,11 @@ axon.generate_direct_stimulus = function ( obj, groups )
punch_object( obj, groups ) punch_object( obj, groups )
end 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 for obj in mobs.iterate_registry( pos, radius, radius, classes ) do
local length = vector.distance( pos, obj:get_pos( ) ) local length = vector.distance( pos, obj:get_pos( ) )
if length <= radius and random( chance ) == 1 then if length <= radius then
local damage_groups = { } local damage_groups = { }
for k, v in pairs( groups ) do for k, v in pairs( groups ) do
@ -301,3 +323,10 @@ end
-------------------- --------------------
dofile( minetest.get_modpath( "axon" ) .. "/sources.lua" ) 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

View File

@ -1,16 +1,16 @@
-- This is a sample source definition file. You will want to modify this for your particular game. -- This is a sample source definition file. You will want to modify this for your particular game.
axon.register_source( "group:lava_source", { 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 = "heat_stim", propagator = "radiation", intensity = 10, chance = 1, period = 1.5, radius = 5.0, power = 0.3 },
{ group = "lava_stim", class = "immersion", intensity = 10, chance = 1, period = 0.5 }, { group = "lava_stim", propagator = "immersion", intensity = 10, chance = 1, period = 0.5 },
} ) } )
axon.register_source( "group:water_source", { 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", { 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" } ) axon.register_source_group( "lava_source", { "default:lava_source", "default:lava_flowing" } )