Initial commit (everything)

This commit is contained in:
raymoo 2016-02-11 23:57:16 -08:00
commit 2324eaccce
6 changed files with 240 additions and 0 deletions

0
depends.txt Normal file
View File

1
description.txt Normal file
View File

@ -0,0 +1 @@
Library for tech/skill/whatever advancement trees (DAGs).

155
init.lua Normal file
View File

@ -0,0 +1,155 @@
progress_tree = {}
-- A progress tree is a map from string names to nodes in adjacency list
-- representation.
local tree_methods = {}
local tree_metatab = { __index = tree_methods }
function progress_tree.new_tree()
local ret = {}
setmetatable(ret, tree_metatab)
return ret
end
-- A node is a table with these fields:
-- - children - A list of child nodes
-- - parents - A list of parent nodes
local node_methods = {}
local node_metatab = { __index = node_methods }
function progress_tree.new_node(parents)
local ret = { children = {},
parents = parents,
}
setmetatable(ret, node_metatab)
return ret
end
-- Adds one node, and takes a list of parents. Each parent must be in the tree
-- already.
function tree_methods.add(self, name, parents)
for i, parent in ipairs(parents) do
if not self[parent] then
local err_msg = "[progress_tree]"
.. " Node " .. name ..
" is child of nonexistent parent " .. parent
error(err_msg)
end
end
if self[name] then
error("[progress_tree] Duplicate node " .. name)
end
self[name] = progress_tree.new_node(parents)
for i, parent in ipairs(parents) do
table.insert(self[parent].children, name)
end
end
-- Each player can ahve data related to their completion of the tree, namely a table
-- with these fields:
-- - tree - The original tree this data tracks
-- - remaining_deps - A map from node names to the number of unfulfilled
-- prerequisite nodes.
-- - available - A set { ["node1"] = true, ["node2"] = true, ... } of nodes
-- that have no prerequisites left to fulfill, and have not been taken yet
-- - learned - A set of nodes the player has taken already.
local pd_methods = {}
local pd_metatab = { __index = pd_methods }
-- Argument is the tree to create the data against. learned is an optional
-- argument for a set of initial learned techs.
function progress_tree.new_player_data(tree, learned)
local data = { tree = tree,
remaining_deps = {},
available = {},
learned = {},
}
setmetatable(data, pd_metatab)
for name, node in pairs(tree) do
local rem_deps = #(node.parents)
data.remaining_deps[name] = rem_deps
if rem_deps == 0 then
data.available[name] = true
end
end
if learned then
for k in pairs(learned) do
data:learn(k)
end
end
return data
end
-- Serialization to a string
function pd_methods.serialize(self)
return minetest.serialize(self.learned)
end
-- Deserialization. Data can only be deserialized against a particular tree.
-- Returns nil on failure.
function progress_tree.deserialize_player_data(tree, learned_string)
local learned = minetest.deserialize(learned_string)
if not learned then return end
return progress_tree.new_player_data(tree, learned)
end
-- Tells whether the tech is already learned
function pd_methods.knows(self, name)
return self.learned[name] == true -- Want false when not in
end
-- Tells whether the tech is learnable with the current level of techs.
function pd_methods.can_learn(self, name)
return (not self.learned[name]) and self.available[name] == true
end
-- Learn a new tech. Returns true on success, returns false on failure. It can
-- fail if the tech doesn't exist or if it is already learned. It does not fail
-- if it is learned out of order, so use can_learn if you want to be sure.
function pd_methods.learn(self, name)
if self:knows(name) then return false end
local node = self.tree[name]
if not node then return false end
local children = node.children
-- Decrement the remaining deps for each child
for i, child in ipairs(children) do
local new_rem = self.remaining_deps[child] - 1
print(child, new_rem)
-- If the player learned it out of order, don't put it as
-- available.
if new_rem == 0 and not self:knows(child) then
self.available[child] = true
end
self.remaining_deps[child] = new_rem
end
self.learned[name] = true
self.available[name] = nil
end
dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/test.lua")

1
mod.conf Normal file
View File

@ -0,0 +1 @@
progress_tree

83
test.lua Normal file
View File

@ -0,0 +1,83 @@
local test_tree = progress_tree.new_tree()
test_tree:add("rock", {})
test_tree:add("wood", {})
test_tree:add("plant", {})
test_tree:add("axe", {"rock", "wood"})
test_tree:add("plank", {"wood"})
test_tree:add("plankaxe", {"axe", "plank"})
test_tree:add("wheat", {"plant"})
local data = progress_tree.new_player_data(test_tree, {"wood"})
local infos = {
rock = {x=0, y=0, texture="default_stone.png", desc="Rock"},
wood = {x=1.5, y=0, texture="default_tree.png", desc="Wood"},
plant = {x=5, y=0, texture="default_grass.png", desc="Plant"},
axe = {x=1, y=1.5, texture="default_tool_stoneaxe.png", desc="Axe"},
plank = {x=2.5, y=1.5, texture="default_stick.png", desc="Plank"},
plankaxe = {x=2, y=3, texture="default_tool_woodaxe.png", desc="Plank Axe"},
wheat = {x=5, y=1.5, texture="farming_wheat.png", desc="Wheat"},
}
local function build_formspec()
local formspec = "size[8,8]"
print(dump(data.available))
local nodes = {}
for k in pairs(data.learned) do
local info = infos[k]
local texture = info.texture .. "^progress_tree_check.png^[colorize:#00FF00:50"
local fs = "image_button[" .. info.x .. "," .. info.y .. ";1,1;"
.. minetest.formspec_escape(texture) .. ";" .. k .. ";]"
local tooltip = "tooltip[" .. k .. ";" .. info.desc .. "]"
table.insert(nodes, fs)
table.insert(nodes, tooltip)
end
for k in pairs(data.available) do
local info = infos[k]
local fs = "image_button[" .. info.x .. "," .. info.y .. ";1,1;" .. info.texture
.. ";" .. k .. ";]"
local tooltip = "tooltip[" .. k .. ";" .. info.desc .. "]"
table.insert(nodes, fs)
table.insert(nodes, tooltip)
end
formspec = formspec .. table.concat(nodes)
return formspec
end
local function show(player)
minetest.show_formspec(player:get_player_name(), "progress_tree:test", build_formspec())
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "progress_tree:test" then return end
for node in pairs(data.available) do
if fields[node] then
data:learn(node)
end
end
if not fields["quit"] then
show(player)
end
end)
minetest.register_craftitem("progress_tree:test_book", {
description = "Ultimate Techs",
groups = { not_in_creative_inventory = 1 },
inventory_image = "default_book.png",
on_use = function(itemstack, player)
show(player)
end,
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B