217 lines
8.2 KiB
Lua
217 lines
8.2 KiB
Lua
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
|
|
|
|
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
|
|
itemstack:get_meta():set_string("genes", forestry_bees.serialize(genes))
|
|
return itemstack
|
|
end
|
|
|
|
function forestry_bees.can_queen_work(queen, pos)
|
|
local genes = forestry_bees.deserialize(queen:get_meta():get_string("genes"))
|
|
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)))
|
|
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
|
|
end
|
|
|
|
function forestry_bees.calculate_drop(bee)
|
|
local genes = forestry_bees.deserialize(bee:get_meta():get_string("genes"))
|
|
local possible_drops = forestry_bees.bee_drops[genes["type_gene"][1]] --this gets us a table
|
|
local out_table = {}
|
|
for drop,chance in pairs(possible_drops) do
|
|
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)
|
|
table.insert(out_table,ItemStack(drop))
|
|
end
|
|
end
|
|
return out_table
|
|
end
|
|
|
|
function forestry_bees.bee_name(bee_type,active_type_gene)
|
|
return "forestry_bees:"..active_type_gene.."_"..bee_type
|
|
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
|
|
end
|
|
|
|
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
|
|
|
|
function forestry_bees.breed_princess_drone(princess,drone)
|
|
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"))
|
|
--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
|
|
local queen = forestry_bees.Bee("queen",princess_genes)
|
|
local queen_meta = queen:get_meta()
|
|
queen_meta:set_string("drone_genes",forestry_bees.serialize(drone_genes))
|
|
return queen
|
|
end
|
|
|
|
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
|
|
|
|
local function mutation(type1,type2,pos)
|
|
local out_table1 = {}
|
|
local out_table2 = {}
|
|
local mutation = {false, false}
|
|
--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
|
|
for out_type, t in pairs(forestry_bees.bee_mutations[type1][type2]) do
|
|
local prob1 = math.random()
|
|
local prob2 = math.random()
|
|
local flag = t["check_fun"](pos)
|
|
if (t["chance"] > prob1) and flag then
|
|
table.insert(out_table1, out_type)
|
|
end
|
|
if (t["chance"] > prob2) and flag then
|
|
table.insert(out_table2, out_type)
|
|
end
|
|
end
|
|
end
|
|
|
|
local output = final_gene(type1,type2)
|
|
|
|
if next(out_table1) then --if a mutation accurred in gene 1
|
|
mutation[1] = true
|
|
output[1] = out_table1[math.random(#out_table1)]
|
|
end
|
|
if next(out_table2) then --if a mutation accurred in gene 2
|
|
mutation[2] = true
|
|
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
|
|
return output, mutation
|
|
end
|
|
|
|
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
|
|
|
|
local function output_genes(mother_genes,father_genes,pos)
|
|
local mother_chosen_genes = choose_genes(mother_genes)
|
|
local father_chosen_genes = choose_genes(father_genes)
|
|
local genes = {}
|
|
|
|
genes["type_gene"], is_mutated = mutation(mother_chosen_genes["type_gene"], father_chosen_genes["type_gene"],pos)
|
|
|
|
for key,_ in pairs(mother_chosen_genes) do
|
|
--if key == "type_gene" then
|
|
-- genes[key] = mutation(mother_chosen_genes[key], father_chosen_genes[key])
|
|
if not (key == "type_gene") then
|
|
genes[key] = final_gene(mother_chosen_genes[key], father_chosen_genes[key])
|
|
end
|
|
end
|
|
--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
|
|
return genes
|
|
end
|
|
|
|
function forestry_bees.apiary_result(queen, pos)
|
|
--given a queen calculates the correct princess + drone output
|
|
local meta = queen:get_meta()
|
|
local mother_genes = forestry_bees.deserialize(meta:get_string("genes"))
|
|
local father_genes = forestry_bees.deserialize(meta:get_string("drone_genes"))
|
|
local genes = output_genes(mother_genes,father_genes,pos)
|
|
--local genes = final_gene(mother_chosen_gene, father_chosen_gene)
|
|
local princess = forestry_bees.Bee("princess", genes)
|
|
local dronelist = {}
|
|
local fertility = mother_genes["fertility"][1]
|
|
for i=1,fertility do
|
|
local genes = output_genes(mother_genes,father_genes,pos)
|
|
local drone = forestry_bees.Bee("drone", genes)
|
|
table.insert(dronelist, drone)
|
|
end
|
|
return princess, dronelist
|
|
end
|