2024-10-20 01:06:16 +02:00
function forestry_bees . serialize ( t )
-- i know that core.serialize exists but it is non deterministic
-- for bees and thus creates bees with the same "genes" table but
-- a different "genes" string, thus making different itemstacks
-- for this reason this function is necessary
-- the tables in this mod are like {"a"={1,2},"b"={"c","d"}}
-- for this reason the function is much simpler
local function add_gene ( str , tab , label )
local t2 = tab [ label ]
return str .. label .. " \t " .. tostring ( t2 [ 1 ] ) .. " \t " .. tostring ( t2 [ 2 ] ) .. " \t \n "
end
local result = " "
for i , label in ipairs ( { " type_gene " , " production " , " fertility " , " lifespan " ,
" nocturnal " , " cave " , " flyer " , " flower " , " radius " } ) do
result = add_gene ( result , t , label )
end
return result
end
function forestry_bees . deserialize ( str )
--same as above
local function unravel ( str1 )
local first_gene_str = string.match ( str1 , " ^(.-) \n " )
local iter = string.gmatch ( first_gene_str , " (.-) \t " )
local label = iter ( )
local result_tab = { iter ( ) , iter ( ) }
return label , result_tab , string.match ( str1 , " \n (.+) " )
end
local fin_tab = { }
local label , result_tab , rest_str = unravel ( str )
fin_tab [ label ] = result_tab
while rest_str do
label , result_tab , rest_str = unravel ( rest_str )
fin_tab [ label ] = result_tab
end
return fin_tab
end
2024-10-08 22:14:20 +02:00
function forestry_bees . Bee ( bee_type , genes )
local itemstack = ItemStack ( { name = forestry_bees.bee_name ( bee_type , genes [ " type_gene " ] [ 1 ] ) } ) --the "1" is cuz the table genes["type_gene"] has 2 entries: active and inactive
2024-10-20 01:06:16 +02:00
itemstack : get_meta ( ) : set_string ( " genes " , forestry_bees.serialize ( genes ) )
2024-10-07 14:31:20 +02:00
return itemstack
end
2024-10-12 18:39:42 +02:00
function forestry_bees . can_queen_work ( queen , pos )
2024-10-20 01:06:16 +02:00
local genes = forestry_bees.deserialize ( queen : get_meta ( ) : get_string ( " genes " ) )
2024-10-12 18:39:42 +02:00
local biome_data = minetest.get_biome_data ( pos )
local biome_name = minetest.get_biome_name ( biome_data [ " biome " ] )
local humidity = biome_data [ " humidity " ]
local heat = biome_data [ " heat " ]
--now get the environmental data
local is_right_heat = true --futureproofing
local is_right_humidity = true --futureproofing
local is_right_biome = true --futureproofing
local is_sky_access = ( genes [ " cave " ] [ 1 ] or ( minetest.get_natural_light ( vector.offset ( pos , 0 , 1 , 0 ) , 0.5 ) == 15 ) )
local is_not_raining = ( genes [ " flyer " ] [ 1 ] or true ) --would require additional mods
local is_day = ( genes [ " nocturnal " ] [ 1 ] or ( ( 0.25 < minetest.get_timeofday ( ) ) and ( minetest.get_timeofday ( ) < 0.75 ) ) )
2024-10-16 16:32:58 +02:00
local is_flower = not ( minetest.find_node_near ( pos , genes [ " radius " ] [ 1 ] , forestry_bees.flower_table [ genes [ " flower " ] [ 1 ] ] ) == nil )
return is_sky_access and is_not_raining and is_day and is_flower
2024-10-12 18:39:42 +02:00
end
2024-10-09 22:06:52 +02:00
function forestry_bees . calculate_drop ( bee )
2024-10-20 01:06:16 +02:00
local genes = forestry_bees.deserialize ( bee : get_meta ( ) : get_string ( " genes " ) )
2024-10-09 22:06:52 +02:00
local possible_drops = forestry_bees.bee_drops [ genes [ " type_gene " ] [ 1 ] ] --this gets us a table
2024-10-08 16:37:23 +02:00
local out_table = { }
for drop , chance in pairs ( possible_drops ) do
2024-10-09 22:06:52 +02:00
if math.random ( ) < chance * genes [ " production " ] [ 1 ] then --the prob of getting something is P = (base chance from bee_drops) * (item modifier (frames and stuff)) * (bee production gene)
2024-10-08 16:37:23 +02:00
table.insert ( out_table , ItemStack ( drop ) )
end
end
return out_table
end
2024-10-08 22:14:20 +02:00
function forestry_bees . bee_name ( bee_type , active_type_gene )
return " forestry_bees: " .. active_type_gene .. " _ " .. bee_type
2024-10-07 14:31:20 +02:00
end
function forestry_bees . stacks_in_inv ( inv , listname )
local stack_list = inv : get_list ( listname )
local result = 0
for i = 1 , # stack_list do
if not stack_list [ i ] : is_empty ( ) then
result = result + 1
end
end
return result
2024-10-07 19:52:09 +02:00
end
2024-10-11 19:39:04 +02:00
function forestry_bees . format_bee ( bee )
local name = bee : get_name ( )
local meta = bee : get_meta ( )
local genes = forestry_bees.return_all_genes_double ( string.sub ( string.match ( string.match ( name , " :.* " ) , " .*_ " ) , 2 , - 2 ) )
return forestry_bees.Bee ( string.sub ( string.match ( string.sub ( string.match ( name , " _.* " ) , 2 ) , " _.* " ) , 2 ) , genes )
end
2024-10-07 19:52:09 +02:00
function forestry_bees . breed_princess_drone ( princess , drone )
2024-10-20 01:06:16 +02:00
local princess_genes = forestry_bees.deserialize ( princess : get_meta ( ) : get_string ( " genes " ) ) --princess_meta["genes"]
local drone_genes = forestry_bees.deserialize ( drone : get_meta ( ) : get_string ( " genes " ) )
2024-10-15 20:14:56 +02:00
--fix for missing genes in bees, if we have bees with missing genes we just give them the default ones
if princess_genes == nil then
local princess_type = string.sub ( string.match ( string.match ( princess : get_name ( ) , " :.* " ) , " .*_ " ) , 2 , - 2 )
princess_genes = forestry_bees.return_all_genes_double ( princess_type )
end
if drone_genes == nil then
local drone_type = string.sub ( string.match ( string.match ( drone : get_name ( ) , " :.* " ) , " .*_ " ) , 2 , - 2 )
drone_genes = forestry_bees.return_all_genes_double ( drone_type )
end
2024-10-08 22:14:20 +02:00
local queen = forestry_bees.Bee ( " queen " , princess_genes )
2024-10-07 19:52:09 +02:00
local queen_meta = queen : get_meta ( )
2024-10-20 01:06:16 +02:00
queen_meta : set_string ( " drone_genes " , forestry_bees.serialize ( drone_genes ) )
2024-10-07 19:52:09 +02:00
return queen
end
2024-10-08 22:14:20 +02:00
local function final_gene ( gene1 , gene2 )
local output = { }
--randomly choose if the genes are 1,2 or 2,1
if math.random ( 2 ) == 2 then
output [ 1 ] = gene1
output [ 2 ] = gene2
else
output [ 1 ] = gene2
output [ 2 ] = gene1
end
return output
end
2024-10-11 19:39:04 +02:00
local function mutation ( type1 , type2 , pos )
2024-10-07 19:52:09 +02:00
local out_table1 = { }
local out_table2 = { }
2024-10-09 21:28:02 +02:00
local mutation = { false , false }
2024-10-07 19:52:09 +02:00
--check every possible mutation to see if we may obtain it
if ( ( not ( forestry_bees.bee_mutations [ type1 ] == nil ) ) and ( not ( forestry_bees.bee_mutations [ type1 ] [ type2 ] == nil ) ) ) then
2024-10-11 19:39:04 +02:00
for out_type , t in pairs ( forestry_bees.bee_mutations [ type1 ] [ type2 ] ) do
2024-10-07 19:52:09 +02:00
local prob1 = math.random ( )
local prob2 = math.random ( )
2024-10-11 19:39:04 +02:00
local flag = t [ " check_fun " ] ( pos )
if ( t [ " chance " ] > prob1 ) and flag then
2024-10-07 19:52:09 +02:00
table.insert ( out_table1 , out_type )
end
2024-10-11 19:39:04 +02:00
if ( t [ " chance " ] > prob2 ) and flag then
2024-10-07 19:52:09 +02:00
table.insert ( out_table2 , out_type )
end
end
end
2024-10-08 22:14:20 +02:00
local output = final_gene ( type1 , type2 )
2024-10-07 19:52:09 +02:00
if next ( out_table1 ) then --if a mutation accurred in gene 1
2024-10-09 21:28:02 +02:00
mutation [ 1 ] = true
2024-10-07 19:52:09 +02:00
output [ 1 ] = out_table1 [ math.random ( # out_table1 ) ]
end
if next ( out_table2 ) then --if a mutation accurred in gene 2
2024-10-09 21:28:02 +02:00
mutation [ 2 ] = true
2024-10-07 19:52:09 +02:00
output [ 2 ] = out_table2 [ math.random ( # out_table2 ) ]
end
--out_table is always non-empty, now we uniformally
--sample from out_table to get the output gene
2024-10-09 21:28:02 +02:00
return output , mutation
2024-10-07 19:52:09 +02:00
end
2024-10-08 22:14:20 +02:00
local function choose_genes ( genes )
--from the table "genes" we for each entry randomly choose 1,2 and keep that gene
--returning a table
local output = { }
for key , gene_pair in pairs ( genes ) do
output [ key ] = gene_pair [ math.random ( 2 ) ]
end
return output
end
2024-10-11 19:39:04 +02:00
local function output_genes ( mother_genes , father_genes , pos )
2024-10-08 22:14:20 +02:00
local mother_chosen_genes = choose_genes ( mother_genes )
local father_chosen_genes = choose_genes ( father_genes )
local genes = { }
2024-10-09 21:28:02 +02:00
2024-10-11 19:39:04 +02:00
genes [ " type_gene " ] , is_mutated = mutation ( mother_chosen_genes [ " type_gene " ] , father_chosen_genes [ " type_gene " ] , pos )
2024-10-09 21:28:02 +02:00
2024-10-08 22:14:20 +02:00
for key , _ in pairs ( mother_chosen_genes ) do
2024-10-09 21:28:02 +02:00
--if key == "type_gene" then
-- genes[key] = mutation(mother_chosen_genes[key], father_chosen_genes[key])
if not ( key == " type_gene " ) then
2024-10-08 22:14:20 +02:00
genes [ key ] = final_gene ( mother_chosen_genes [ key ] , father_chosen_genes [ key ] )
end
end
2024-10-09 21:28:02 +02:00
--if a mutation occurred we change the corresponding genes to the base_genes of the mutated bee
if is_mutated [ 1 ] then
for key , value in pairs ( forestry_bees.return_genes ( genes [ " type_gene " ] [ 1 ] ) ) do
genes [ key ] [ 1 ] = value
end
end
if is_mutated [ 2 ] then
for key , value in pairs ( forestry_bees.return_genes ( genes [ " type_gene " ] [ 2 ] ) ) do
genes [ key ] [ 2 ] = value
end
end
2024-10-08 22:14:20 +02:00
return genes
end
2024-10-11 19:39:04 +02:00
function forestry_bees . apiary_result ( queen , pos )
2024-10-07 19:52:09 +02:00
--given a queen calculates the correct princess + drone output
local meta = queen : get_meta ( )
2024-10-20 01:06:16 +02:00
local mother_genes = forestry_bees.deserialize ( meta : get_string ( " genes " ) )
local father_genes = forestry_bees.deserialize ( meta : get_string ( " drone_genes " ) )
2024-10-11 19:39:04 +02:00
local genes = output_genes ( mother_genes , father_genes , pos )
2024-10-08 22:14:20 +02:00
--local genes = final_gene(mother_chosen_gene, father_chosen_gene)
local princess = forestry_bees.Bee ( " princess " , genes )
2024-10-07 19:52:09 +02:00
local dronelist = { }
2024-10-08 22:14:20 +02:00
local fertility = mother_genes [ " fertility " ] [ 1 ]
for i = 1 , fertility do
2024-10-11 19:39:04 +02:00
local genes = output_genes ( mother_genes , father_genes , pos )
2024-10-08 22:14:20 +02:00
local drone = forestry_bees.Bee ( " drone " , genes )
2024-10-07 19:52:09 +02:00
table.insert ( dronelist , drone )
end
return princess , dronelist
end