minetest_ltool/init.lua

364 lines
12 KiB
Lua

ltool = {}
ltool.playerinfos = {}
ltool.trees = {}
ltool.emptytreedef = {
axiom="",
rules_a="",
rules_b="",
rules_c="",
rules_d="",
trunk="",
leaves="",
leaves2="",
leaves2_chance="",
fruit="",
fruit_chance="",
angle="",
iterations="",
random_level="",
trunk_type="",
thin_branches="",
}
function ltool.add_tree(name, author, treedef)
table.insert(ltool.trees, {name = name, author = author, treedef = treedef})
end
do
local filepath = minetest.get_worldpath().."/ltool.mt"
local file = io.open(filepath, "r")
if(file) then
local string = file:read()
io.close(file)
if(string ~= nil) then
local savetable = minetest.deserialize(string)
if(savetable.trees ~= nil) then
ltool.trees = savetable.trees
end
end
minetest.log("action", "[ltool] Tree data loaded from "..filepath..".")
end
end
ltool.seed = os.time()
ltool.loadtreeform = "size[6,7]"
function ltool.header(index)
return "tabheader[0,0;ltool_tab;Edit,Database,Plant,Cheat sheet;"..tostring(index)..";true;false]"
end
function ltool.edit(tree)
local treedef, name
if(tree==nil) then
treedef = ltool.emptytreedef
name = ""
else
treedef = tree.treedef
name = tree.name
end
local s = function(input)
if(input==nil) then
ret = ""
else
ret = minetest.formspec_escape(tostring(input))
end
return ret
end
return ""..
"field[0.2,-4;6,10;axiom;Axiom;"..s(treedef.axiom).."]"..
"field[0.2,-3.4;6,10;rules_a;Rules set A;"..s(treedef.rules_a).."]"..
"field[0.2,-2.7;6,10;rules_b;Rules set B;"..s(treedef.rules_b).."]"..
"field[0.2,-2.1;6,10;rules_c;Rules set C;"..s(treedef.rules_c).."]"..
"field[0.2,-1.5;6,10;rules_d;Rules set D;"..s(treedef.rules_d).."]"..
"field[0.2,-0.9;3,10;trunk;Trunk node name;"..s(treedef.trunk).."]"..
"field[0.2,-0.3;3,10;leaves;Leaves node name;"..s(treedef.leaves).."]"..
"field[0.2,0.3;3,10;leaves2;Secondary leaves node name;"..s(treedef.leaves2).."]"..
"field[0.2,0.9;3,10;leaves2_chance;Secondary leaves chance (in percent);"..s(treedef.leaves2_chance).."]"..
"field[0.2,1.5;3,10;fruit;Fruit node name;"..s(treedef.fruit).."]"..
"field[0.2,2.1;3,10;fruit_chance;Fruit chance (in percent);"..s(treedef.fruit_chance).."]"..
"field[3.2,-0.9;3,10;angle;Angle (in degrees);"..s(treedef.angle).."]"..
"field[3.2,-0.3;3,10;iterations;Iterations;"..s(treedef.iterations).."]"..
"field[3.2,0.3;3,10;random_level;Randomness level;"..s(treedef.random_level).."]"..
"field[3.2,0.9;3,10;trunk_type;Trunk type (single/double/crossed);"..s(treedef.trunk_type).."]"..
"field[3.2,1.5;3,10;thin_branches;Thin branches? (true/false);"..s(treedef.thin_branches).."]"..
"field[3.2,2.1;3,10;name;Name;"..s(name).."]"..
"button[0,6.5;2,1;edit_save;Save]"
end
function ltool.database(index)
local treestr = ltool.get_tree_names(index)
if(treestr ~= nil) then
return ""..
"textlist[0,0;5,6;treelist;"..treestr..";"..tostring(index)..";false]"..
"button[0,6.5;2,1;database_copy;Copy to editor]"..
"button[2.1,6.5;2,1;database_update;Reload]"
else
return "label[0,0;The tree database is empty.]"..
"button[2.1,6.5;2,1;database_update;Reload]"
end
end
function ltool.cheat_sheet()
return ""..
"tablecolumns[text;text]"..
"tableoptions[background=#000000;highlight=#000000;border=false]"..
"table[0,0;6,7;cheat_sheet;"..
"Symbol,Action,"..
"G,Move forward one unit with the pen up,"..
"F,Move forward one unit with the pen down drawing trunks and branches,"..
"f,Move forward one unit with the pen down drawing leaves (100% chance),"..
"T,Move forward one unit with the pen down drawing trunks only,"..
"R,Move forward one unit with the pen down placing fruit,"..
"A,Replace with rules set A,"..
"B,Replace with rules set B,"..
"C,Replace with rules set C,"..
"D,Replace with rules set D,"..
"a,Replace with rules set A\\, chance 90%,"..
"b,Replace with rules set B\\, chance 80%,"..
"c,Replace with rules set C\\, chance 70%,"..
"d,Replace with rules set D\\, chance 60%,"..
"+,Yaw the turtle right by angle parameter,"..
"-,Yaw the turtle left by angle parameter,"..
"&,Pitch the turtle down by angle parameter,"..
"^,Pitch the turtle up by angle parameter,"..
"/,Roll the turtle to the right by angle parameter,"..
"*,Roll the turtle to the left by angle parameter,"..
"\\[,Save in stack current state info,"..
"\\],Recover from stack state info]"
end
function ltool.evaluate_edit_fields(fields)
local treedef = {}
treedef.axiom = fields.axiom
treedef.rules_a = fields.rules_a
treedef.rules_b = fields.rules_b
treedef.rules_c = fields.rules_c
treedef.rules_d = fields.rules_d
treedef.trunk = fields.trunk
treedef.leaves = fields.leaves
treedef.leaves2 = fields.leaves2
treedef.leaves2_chance = fields.leaves2_chance
treedef.angle = tonumber(fields.angle)
if(treedef.angle == nil) then
return nil, "The field \"Angle\" must contain a number."
end
treedef.iterations = tonumber(fields.iterations)
if(treedef.iterations == nil) then
return nil, "The field \"Iterations\" must contain a natural number greater or equal to 0."
elseif(treedef.iterations < 0) then
return nil, "The field \"Iterations\" must contain a natural number greater or equal to 0."
end
treedef.random_level = tonumber(fields.random_level)
if(treedef.random_level == nil) then
return nil, "The field \"Randomness level\" must contain a number."
end
treedef.fruit = fields.fruit
treedef.fruit_chance = tonumber(fields.fruit_chance)
if(treedef.fruit_chance == nil) then
return nil, "The field \"Fruit chance\" must contain a number."
elseif(treedef.fruit_chance > 100 or treedef.fruit_chance < 0) then
return nil, "Fruit chance must be between 0% and 100%."
end
if(fields.trunk_type == "single" or fields.trunk_type == "double" or fields.trunk_type == "crossed") then
treedef.trunk_type = fields.trunk_type
else
return nil, "Trunk type must be \"single\", \"double\" or \"crossed\"."
end
treedef.thin_branches = fields.thin_branches
if(fields.thin_branches == "true") then
treedef.thin_branches = true
elseif(fields.thin_branches == "false") then
treedef.thin_branches = false
else
return nil, "Field \"Thin branches?\" must be \"true\" or \"false\"."
end
local name = fields.name
if(name == "") then
return nil, "Name is empty."
end
return treedef, name
end
function ltool.plant(tree)
if(tree ~= nil) then
return ""..
"label[0,0;Selected tree: "..minetest.formspec_escape(tree.name).."]"..
-- "dropdown[0,0.3;5;plantmode;Absolute coordinates,Relative coordinates,Distance to view;1]"..
-- "field[0.2,-2.7;6,10;x;x;]"..
-- "field[0.2,-2.1;6,10;y;y;]"..
-- "field[0.2,-1.5;6,10;z;z;]"..
"field[0.2,0;6,10;seed;Seed;"..ltool.seed.."]"..
"button[0,6.5;2,1;plant_plant;Plant]"
else
return "label[0,0;There are no trees to plant.]"
end
end
function ltool.get_tree_names(index)
local string = ""
if(#ltool.trees == 0) then
return nil
end
for t=1,#ltool.trees do
string = string .. minetest.formspec_escape(ltool.trees[t].name)
if(t < #ltool.trees) then
string = string .. ","
end
end
return string
end
ltool.treeform = ltool.loadtreeform..ltool.header(1)..ltool.edit()
minetest.register_chatcommand("treeform",
{
params = "",
description = "Open L-system tree builder formular.",
privs = {privs=false},
func = function(player_name, param)
local player = minetest.get_player_by_name(player_name)
local formspec
-- if(ltool.playerinfos[player] == nil) then
formspec = ltool.treeform
--[[ else
local i = ltool.playerinfos[player]
formspec =
"size[6,7]"..
"field[0.2,-4;6,10;axiom;Axiom;"..i.axiom.."]"..
"field[0.2,-3.4;6,10;rules_a;Rules set A;"..i.rules_a.."]"..
"field[0.2,-2.7;6,10;rules_b;Rules set B;"..i.rules_b.."]"..
"field[0.2,-2.1;6,10;rules_c;Rules set C;"..i.rules_c.."]"..
"field[0.2,-1.5;6,10;rules_d;Rules set D;"..i.ruled_d.."]"..
"field[0.2,-0.9;3,10;trunk;Trunk node name;"..i.trunk.."]"..
"field[0.2,-0.3;3,10;leaves;Leaves node name;"..i.leaves.."]"..
"field[0.2,0.3;3,10;leaves2;Secondary leaves node name;"..i.leaves2.."]"..
"field[0.2,0.9;3,10;leaves2_chance;Secondary leaves chance;"..i.leaves2_chance.."]"..
"field[0.2,1.5;3,10;fruit;Fruit node name;"..i.fruit.."]"..
"field[0.2,2.1;3,10;fruit_chance;Fruit chance;"..i.fruit_chance.."]"..
"field[3.2,-0.9;3,10;angle;Angle;"..i.angle.."]"..
"field[3.2,-0.3;3,10;iterations;Iterations;"..i.iterations.."]"..
"field[3.2,0.3;3,10;random_level;Randomness level;"..i.random_level.."]"..
"field[3.2,0.9;3,10;trunk_type;Trunk type (single/double/crossed);"..i.trunk_type.."]"..
"field[3.2,1.5;3,10;thin_branches;Thin branches? (true/false);"..i.thin_branches.."]"..
"button[0.6,6.5;2,1;edit_save;Save]"..
end
]]
minetest.show_formspec(player_name, "ltool:treeform", formspec)
end
})
function ltool.process_form(player,formname,fields)
local playername = player:get_player_name()
if(formname == "ltool:treeform") then
if fields.ltool_tab ~= nil then
local tab = tonumber(fields.ltool_tab)
local formspec, contents
if(tab==1) then
contents = ltool.edit()
elseif(tab==2) then
contents = ltool.database(ltool.playerinfos[playername].dbsel)
elseif(tab==3) then
if(#ltool.trees > 0) then
contents = ltool.plant(ltool.trees[ltool.playerinfos[playername].dbsel])
else
contents = ltool.plant()
end
elseif(tab==4) then
contents = ltool.cheat_sheet()
end
formspec = ltool.loadtreeform..ltool.header(tab)..contents
minetest.show_formspec(playername, "ltool:treeform", formspec)
return
end
if(fields.plant_plant) then
minetest.log("action","[ltool] Planting tree")
local tree = ltool.trees[ltool.playerinfos[playername].dbsel]
local treedef = tree.treedef
local tree_pos = player:getpos()
tree_pos.x = tree_pos.x + 5
treedef.seed = fields.seed
minetest.spawn_tree(tree_pos, treedef)
treedef.seed = nil
elseif(fields.edit_save) then
local param1, param2
param1, param2 = ltool.evaluate_edit_fields(fields)
if(param1 ~= nil) then
local treedef = param1
local name = param2
ltool.add_tree(name, playername, treedef)
else
local formspec = "size[6,2;]label[0,0.2;Error: The tree definition is invalid.]"..
"label[0,0.4;"..minetest.formspec_escape(param2).."]"..
"button[2,1.5;2,1;okay;OK]"
minetest.show_formspec(playername, "ltool:treeform_error_badtreedef", formspec)
end
elseif(fields.treelist) then
local event = minetest.explode_textlist_event(fields.treelist)
if(event.type == "CHG") then
ltool.playerinfos[playername].dbsel = event.index
local formspec = ltool.loadtreeform..ltool.header(2)..ltool.database(event.index)
minetest.show_formspec(playername, "ltool:treeform", formspec)
end
elseif(fields.database_copy) then
if(ltool.playerinfos[playername] ~= nil) then
sel = ltool.playerinfos[playername].dbsel
else
sel = 1
end
local formspec = ltool.loadtreeform..ltool.header(1)..ltool.edit(ltool.trees[sel])
minetest.show_formspec(playername, "ltool:treeform", formspec)
elseif(fields.database_update) then
local formspec = ltool.loadtreeform..ltool.header(2)..ltool.database(ltool.playerinfos[playername].dbsel)
minetest.show_formspec(playername, "ltool:treeform", formspec)
end
elseif(formname == "ltool:treeform_error_badtreedef") then
local formspec = ltool.loadtreeform..ltool.header(1)..ltool.edit()
minetest.show_formspec(playername, "ltool:treeform", formspec)
end
end
function ltool.leave(player)
ltool.playerinfos[player:get_player_name()] = nil
end
function ltool.join(player)
ltool.playerinfos[player:get_player_name()] = { dbsel = 1 }
end
function ltool.save_to_file()
local savetable = {}
savetable.trees = ltool.trees
local savestring = minetest.serialize(savetable)
local filepath = minetest.get_worldpath().."/ltool.mt"
local file = io.open(filepath, "w")
if(file) then
file:write(savestring)
io.close(file)
minetest.log("action", "[ltool] Tree data saved to "..filepath..".")
else
minetest.log("error", "[ltool] Failed to write ltool data to "..filepath".")
end
end
minetest.register_on_player_receive_fields(ltool.process_form)
minetest.register_on_leaveplayer(ltool.leave)
minetest.register_on_joinplayer(ltool.join)
minetest.register_on_shutdown(ltool.save_to_file)