animalia/api/libri.lua

586 lines
17 KiB
Lua

-----------
-- Libri --
-----------
local libri = {}
local path = minetest.get_modpath(minetest.get_current_modname())
local color = minetest.colorize
local page_spacing = 0.5
local libri_bg = {
"formspec_version[3]",
"size[16,10]",
"background[-0.7,-0.5;17.5,11.5;animalia_libri_bg.png]"
}
local libri_btn_next = "image_button[15,9;1,1;animalia_libri_icon_next.png;btn_next;;true;false]"
local libri_btn_last = "image_button[1,9;1,1;animalia_libri_icon_last.png;btn_last;;true;false]"
local libri_drp_font_scale = "dropdown[17,0;0.75,0.5;drp_font_scale;0.25,0.5,0.75,1;1]"
local function correct_string(str)
if str then
if str:match(":") then str = str:split(":")[2] end
return (string.gsub(" " .. str, "%W%l", string.upper):sub(2):gsub("_", " "))
end
end
local pages = {}
local generate_mobs = {
["animalia:bat"] = "Bat",
["animalia:bird"] = "Song Bird",
["animalia:cat"] = "Cat",
["animalia:chicken"] = "Chicken",
["animalia:cow"] = "Cow",
--["animalia:tropical_fish"] = "Tropical Fish",
["animalia:frog"] = "Frog",
["animalia:horse"] = "Horse",
["animalia:pig"] = "Pig",
["animalia:reindeer"] = "Reindeer",
["animalia:sheep"] = "Sheep",
["animalia:turkey"] = "Turkey",
["animalia:wolf"] = "Wolf",
}
local spawn_biomes = {
["animalia:bat"] = "cave",
["animalia:bird"] = "temperate",
["animalia:cat"] = "urban",
["animalia:chicken"] = "tropical",
["animalia:cow"] = "grassland",
["animalia:tropical_fish"] = "ocean",
["animalia:frog"] = "swamp",
["animalia:horse"] = "grassland",
["animalia:pig"] = "temperate",
["animalia:reindeer"] = "boreal",
["animalia:sheep"] = "grassland",
["animalia:turkey"] = "boreal",
["animalia:wolf"] = "boreal",
}
-----------
-- Pages --
-----------
local function get_spawn_biomes(name)
local biome_group = spawn_biomes[name]
local biomes = animalia.registered_biome_groups[biome_group].biomes
return (#biomes > 0 and biomes) or {"grassland"}
end
local function can_lasso(name)
return tostring(minetest.registered_entities[name].catch_with_lasso or false)
end
local function can_net(name)
return tostring(minetest.registered_entities[name].catch_with_net or false)
end
local function max_health(name)
return minetest.registered_entities[name].max_health or 20
end
local function mob_textures(name)
local def = minetest.registered_entities[name]
return def.textures or {unpack(def.male_textures), unpack(def.female_textures)}
end
local biome_cubes = {}
local function generate_page(mob)
local name = mob:split(":")[2]
local page = {
{ -- Info
element_type = "label",
center_text = true,
font_size = 20,
offset = {x = 9, y = 1.5},
file = "animalia_libri_" .. name .. ".txt"
},
{ -- Image
element_type = "model",
offset = {x = 1.5, y = 1.5},
size = {x = 5, y = 5},
texture_iter = 1,
text = "mesh;animalia_bat.b3d;" .. mob_textures(mob)[1] .. ";-30,225;false;false;0,0;0"
},
{ -- Spawn Biome
element_type = "image",
offset = {x = 0.825, y = 8.15},
size = {x = 1, y = 1},
biome_iter = 1,
text = biome_cubes[get_spawn_biomes(mob)[1]]
},
{ -- Biome Label
element_type = "tooltip",
offset = {x = 0.825, y = 8.15},
size = {x = 1, y = 1},
biome_iter = 1,
text = correct_string(get_spawn_biomes(mob)[1])
},
libri.render_element({ -- Health Icon
element_type = "image",
offset = {x = 2.535, y = 8.15},
size = {x = 1, y = 1},
text = "animalia_libri_health_fg.png"
}),
libri.render_element({ -- Health Amount
element_type = "label",
offset = {x = 3.25, y = 9},
text = "x" .. max_health(mob) / 2
}),
libri.render_element({ -- Lasso Icon
element_type = "item_image",
offset = {x = 4.25, y = 8.15},
size = {x = 1, y = 1},
text = "animalia:lasso"
}),
libri.render_element({ -- Lasso Indication Icon
element_type = "image",
offset = {x = 4.75, y = 8.75},
size = {x = 0.5, y = 0.5},
text = "animalia_libri_" .. can_lasso(mob) .. "_icon.png"
}),
libri.render_element({ -- Net Icon
element_type = "item_image",
offset = {x = 6, y = 8.15},
size = {x = 1, y = 1},
text = "animalia:net"
}),
libri.render_element({ -- Net Indication Icon
element_type = "image",
offset = {x = 6.5, y = 8.75},
size = {x = 0.5, y = 0.5},
text = "animalia_libri_" .. can_net(mob) .. "_icon.png"
}),
libri.render_element({ -- Styling
element_type = "image",
offset = {x = -0.7, y = -0.5},
size = {x = 17.5, y = 11.5},
text = "animalia_libri_info_fg.png"
})
}
pages[mob] = page
end
minetest.register_on_mods_loaded(function()
-- Register Biome Cubes
for name, def in pairs(minetest.registered_biomes) do
if def.node_top then
local tiles = {
"unknown_node.png",
"unknown_node.png",
"unknown_node.png"
}
local n_def = minetest.registered_nodes[def.node_top]
if n_def then
local def_tiles = table.copy(n_def.tiles or n_def.textures)
for i, tile in ipairs(def_tiles) do
if tile.name then
def_tiles[i] = tile.name
end
end
tiles = (#def_tiles > 0 and def_tiles) or tiles
end
biome_cubes[name] = minetest.inventorycube(tiles[1], tiles[3], tiles[3])
else
biome_cubes[name] = minetest.inventorycube("unknown_node.png", "unknown_node.png", "unknown_node.png")
end
end
pages = {
["home_1"] = {
{ -- Info
element_type = "label",
center_text = true,
font_size = 24,
offset = {x = 1, y = 1.5},
file = "animalia_libri_home.txt"
},
{
element_type = "mobs",
start_iter = 0,
offset = {x = 10.25, y = 1.5}
}
},
["home_2"] = {
{
element_type = "mobs",
start_iter = 4,
offset = {x = 1.75, y = 1.5}
}
},
["home_3"] = {
{
element_type = "mobs",
start_iter = 12,
offset = {x = 1.75, y = 1.5}
}
},
["animalia:tropical_fish"] = {
{ -- Info
element_type = "label",
center_text = true,
font_size = 20,
offset = {x = 9, y = 1.5},
file = "animalia_libri_tropical_fish.txt"
},
{ -- Image
element_type = "model",
offset = {x = 1.5, y = 1.5},
size = {x = 5, y = 5},
texture_iter = 1,
models = {
"animalia_clownfish.b3d",
"animalia_clownfish.b3d",
"animalia_angelfish.b3d"
},
text = "mesh;animalia_clownfish.b3d;" .. mob_textures("animalia:tropical_fish")[1] .. ";-30,225;false;false;0,0;0"
},
{ -- Spawn Biome
element_type = "image",
offset = {x = 0.825, y = 8.15},
size = {x = 1, y = 1},
biome_iter = 1,
text = biome_cubes[get_spawn_biomes("animalia:tropical_fish")[1]]
},
{ -- Biome Label
element_type = "tooltip",
offset = {x = 0.825, y = 8.15},
size = {x = 1, y = 1},
biome_iter = 1,
text = correct_string(get_spawn_biomes("animalia:tropical_fish")[1])
},
libri.render_element({ -- Health Icon
element_type = "image",
offset = {x = 2.535, y = 8.15},
size = {x = 1, y = 1},
text = "animalia_libri_health_fg.png"
}),
libri.render_element({ -- Health Amount
element_type = "label",
offset = {x = 3.25, y = 9},
text = "x" .. max_health("animalia:tropical_fish") / 2
}),
libri.render_element({ -- Lasso Icon
element_type = "item_image",
offset = {x = 4.25, y = 8.15},
size = {x = 1, y = 1},
text = "animalia:lasso"
}),
libri.render_element({ -- Lasso Indication Icon
element_type = "image",
offset = {x = 4.75, y = 8.75},
size = {x = 0.5, y = 0.5},
text = "animalia_libri_" .. can_lasso("animalia:tropical_fish") .. "_icon.png"
}),
libri.render_element({ -- Net Icon
element_type = "item_image",
offset = {x = 6, y = 8.15},
size = {x = 1, y = 1},
text = "animalia:net"
}),
libri.render_element({ -- Net Indication Icon
element_type = "image",
offset = {x = 6.5, y = 8.75},
size = {x = 0.5, y = 0.5},
text = "animalia_libri_" .. can_net("animalia:tropical_fish") .. "_icon.png"
}),
libri.render_element({ -- Styling
element_type = "image",
offset = {x = -0.7, y = -0.5},
size = {x = 17.5, y = 11.5},
text = "animalia_libri_info_fg.png"
})
}
}
for mob in pairs(generate_mobs) do
generate_page(mob)
end
end)
---------
-- API --
---------
local function get_item_list(list, offset_x, offset_y) -- Creates a visual list of items for Libri formspecs
local size = 1 / ((#list < 3 and #list) or 3)
if size < 0.45 then size = 0.45 end
local spacing = size * 0.5
local total_scale = size + spacing
local max_horiz = 3
local form = ""
for i, item in ipairs(list) do
local vert_multi = math.floor((i - 1) / max_horiz)
local horz_multi = (total_scale * max_horiz) * vert_multi
local pos_x = offset_x + ((total_scale * i) - horz_multi)
local pos_y = offset_y + (total_scale * vert_multi )
form = form .. "item_image[" .. pos_x .. "," .. pos_y .. ";" .. size .. "," .. size .. ";" .. item .. "]"
end
return form
end
function libri.generate_list(meta, offset, start_iter)
local chapters = minetest.deserialize(meta:get_string("chapters")) or {}
local i = 0
local elements = ""
local offset_x = offset.x
local offset_y = offset.y
for mob in pairs(chapters) do
if not mob then break end
i = i + 1
if i > start_iter then
local mob_name = mob:split(":")[2]
local offset_txt = offset_x .. "," .. offset_y
local element = "button[" .. offset_txt .. ";4,1;btn_" .. mob_name .. ";" .. correct_string(mob_name) .. "]"
elements = elements .. element
offset_y = offset_y + 2
if offset_y > 7.5 then
offset_x = offset_x + 8.5
if offset_x > 10.25 then
return elements
end
offset_y = 1.5
end
end
end
return elements
end
function libri.render_element(def, meta, playername)
local chapters = (meta and minetest.deserialize(meta:get_string("chapters"))) or {}
local chap_no = 0
for _ in pairs(chapters) do
chap_no = chap_no + 1
end
local offset_x = def.offset.x
local offset_y = def.offset.y
local form = ""
-- Add text
if def.element_type == "label" then
local font_size_x = (animalia.libri_font_size[playername] or 1)
local font_size = (def.font_size or 16) * font_size_x
form = form .. "style_type[label;font_size=" .. font_size .. "]"
if def.file then
local filename = path .. "/libri/" .. def.file
local file = io.open(filename)
if file then
local i = 0
for line in file:lines() do
i = i + 1
local center_offset = 0
local max_length = 42
local line_length = line:len()
if line_length > max_length then line_length = max_length end
local total_line_area = font_size * line_length
local total_max_area = font_size * max_length
if def.center_text then
center_offset = ((total_max_area - total_line_area) / 100) * 0.3
end
local line_unit = (max_length * 0.075)
local align_x = (offset_x + line_unit - (line_unit * font_size_x)) + center_offset
local align_y = offset_y + (page_spacing * font_size_x) * i
form = form .. "label[" .. align_x .. "," .. align_y .. ";" .. color("#000000", line .. "\n") .. "]"
end
file:close()
end
else
local line = def.text
form = form .. "label[" .. offset_x .. "," .. offset_y .. ";" .. color("#000000", line .. "\n") .. "]"
end
elseif def.element_type == "mobs" then
form = form .. libri.generate_list(meta, def.offset, def.start_iter)
if chap_no > def.start_iter + 4 then form = form .. libri_btn_next end
if def.start_iter > 3 then form = form .. libri_btn_last end
else
-- Add Images/Interaction
local render_element = false
if def.unlock_key
and #chapters > 0 then
for _, chapter in ipairs(chapters) do
if chapter
and chapter == def.unlock_key then
render_element = true
break
end
end
elseif not def.unlock_key then
render_element = true
end
if render_element then
local offset = def.offset.x .. "," .. def.offset.y
local size = def.size.x .. "," .. def.size.y
form = form .. def.element_type .. "[" .. offset .. ";" .. size .. ";" .. def.text .. "]"
end
end
return form
end
local function get_page(key, meta, playername)
local form = table.copy(libri_bg)
local chapters = minetest.deserialize(meta:get_string("chapters")) or {}
local chap_no = 0
for _ in pairs(chapters) do
chap_no = chap_no + 1
end
local page = pages[key]
for _, element in ipairs(page) do
if type(element) == "table" then
local element_rendered = libri.render_element(element, meta, playername)
table.insert(form, element_rendered)
else
table.insert(form, element)
end
end
table.insert(form, "style[drp_font_scale;noclip=true]")
table.insert(form, libri_drp_font_scale)
table.insert(form, "style[drp_font_scale;noclip=true]")
local def = minetest.registered_entities[key]
if def then
if def.follow then
table.insert(form, get_item_list(def.follow, 12.45, 8.05))
end
if def.drops then
local drops = {}
for i = 1, #def.drops do
table.insert(drops, def.drops[i].name)
end
table.insert(form, get_item_list(drops, 8, 8.05))
end
end
return table.concat(form, "")
end
-- Iterate through Animal textures and Biomes
local libri_players = {}
local function iterate_libri_images()
for page, elements in pairs(pages) do
if page ~= "home" then
for _, info in ipairs(elements) do
if info.texture_iter then
local textures = mob_textures(page)
if textures[info.texture_iter + 1] then
info.texture_iter = info.texture_iter + 1
else
info.texture_iter = 1
end
local mesh = (info.models and info.models[info.texture_iter]) or minetest.registered_entities[page].mesh
info.text = "mesh;" .. mesh .. ";" .. textures[info.texture_iter] .. ";-30,225;false;false;0,0;0]"
end
if info.biome_iter then
local biome_group = spawn_biomes[page]
local registered_groups = animalia.registered_biome_groups
if registered_groups[biome_group].biomes[info.biome_iter + 1] then
info.biome_iter = info.biome_iter + 1
else
info.biome_iter = 1
end
local spawn_biome = registered_groups[biome_group].biomes[info.biome_iter] or "grassland"
if info.element_type == "image" then
info.text = biome_cubes[spawn_biome]
else
info.text = correct_string(spawn_biome)
end
end
end
end
end
for name, page in pairs(libri_players) do
local player = minetest.get_player_by_name(name)
if player
and spawn_biomes[page] then
local meta = player:get_wielded_item():get_meta()
minetest.show_formspec(name, "animalia:libri_" .. page:split(":")[2], get_page(page, meta, name))
end
end
minetest.after(2, iterate_libri_images)
end
iterate_libri_images()
-- Craftitem
minetest.register_craftitem("animalia:libri_animalia", {
description = "Libri Animalia",
inventory_image = "animalia_libri_animalia.png",
stack_max = 1,
on_place = function(itemstack, player)
local meta = itemstack:get_meta()
if meta:get_string("pages") ~= "" then meta:set_string("pages", "") end
local name = player:get_player_name()
minetest.show_formspec(name, "animalia:libri_home_1", get_page("home_1", meta, name))
libri_players[name] = "home_1"
end,
on_secondary_use = function(itemstack, player, pointed)
local meta = itemstack:get_meta()
if meta:get_string("pages") ~= "" then meta:set_string("pages", "") end
local chapters = minetest.deserialize(meta:get_string("chapters")) or {}
if pointed
and pointed.type == "object" then
local ent = pointed.ref and pointed.ref:get_luaentity()
if ent
and pages[ent.name]
and not chapters[ent.name] then
chapters[ent.name] = true
itemstack:get_meta():set_string("chapters", minetest.serialize(chapters))
player:set_wielded_item(itemstack)
end
return itemstack
end
local name = player:get_player_name()
minetest.show_formspec(name, "animalia:libri_home_1", get_page("home_1", meta, name))
libri_players[name] = "home_1"
end
})
minetest.register_on_player_receive_fields(function(player, formname, fields)
local plyr_name = player:get_player_name()
local wielded_item = player:get_wielded_item()
local meta = wielded_item:get_meta()
if formname:match("animalia:libri_") then
for page in pairs(pages) do
if not page:match("^home") then
local name = page:split(":")[2]
if fields["btn_" .. name] then
minetest.show_formspec(plyr_name, "animalia:libri_" .. name, get_page(page, meta, plyr_name))
libri_players[plyr_name] = page
return true
end
end
end
if fields.btn_next then
local current_no = tonumber(formname:sub(-1))
local page = "home_" .. current_no + 1
if pages[page] then
minetest.show_formspec(plyr_name, "animalia:libri_" .. page, get_page(page, meta, plyr_name))
libri_players[plyr_name] = page
return true
end
end
if fields.btn_last then
local current_no = tonumber(formname:sub(-1))
local page = "home_" .. current_no - 1
if pages[page] then
minetest.show_formspec(plyr_name, "animalia:libri_" .. page, get_page(page, meta, plyr_name))
libri_players[plyr_name] = page
return true
end
end
if fields.drp_font_scale then
animalia.libri_font_size[plyr_name] = fields.drp_font_scale
local page = libri_players[plyr_name]
minetest.show_formspec(plyr_name, "animalia:libri_" .. page, get_page(page, meta, plyr_name))
end
if fields.quit or fields.key_enter then
libri_players[plyr_name] = nil
end
end
end)