Start on new unified Hint API
- Move hint handling down to API layer - Simplify stat data; old nc_stats counting can be moved out to a separate mod. We only need whether the player has seen or not. - Invert inventory tab responsibility. - Merge witness system in from crafting. TODO: - Redistribute hint registration responsibility to individual mods. - Test external mod compat. - Retire old nc_stats and nc_guide systems. - Add a way to reset hints.
This commit is contained in:
parent
5c73331ec2
commit
edea123a1e
@ -124,9 +124,7 @@ local function craftcheck(recipe, pos, node, data, xx, xz, zx, zz)
|
||||
end
|
||||
if recipe.after then recipe.after(pos, data) end
|
||||
if data.after then data.after(pos, data) end
|
||||
if nodecore.player_stat_add then
|
||||
nodecore.player_stat_add(1, data.crafter, "craft", recipe.label)
|
||||
end
|
||||
nodecore.player_discover(data.crafter, "craft:" .. recipe.label)
|
||||
if recipe.witness then
|
||||
local lut = {}
|
||||
for _, v in pairs(recipe.nodes) do
|
||||
|
@ -5,7 +5,6 @@ local include, nodecore
|
||||
|
||||
nodecore.amcoremod()
|
||||
|
||||
include("witness")
|
||||
include("register_craft")
|
||||
include("craft_check")
|
||||
include("item_place_node")
|
||||
|
@ -20,7 +20,7 @@ nodecore.register_on_joinplayer("join hint setup", function(player)
|
||||
msgcache[pname] = {}
|
||||
end)
|
||||
|
||||
nodecore.register_on_player_discover(function(player)
|
||||
nodecore.register_on_discover(function(player)
|
||||
local pname = player:get_player_name()
|
||||
local dc = donecache[pname]
|
||||
if not dc then return end
|
11
mods/nc_api_hints/disable.lua
Normal file
11
mods/nc_api_hints/disable.lua
Normal file
@ -0,0 +1,11 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local minetest, nodecore, string
|
||||
= minetest, nodecore, string
|
||||
local string_lower
|
||||
= string.lower
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
function nodecore.hints_disabled()
|
||||
return minetest.settings:get_bool(
|
||||
string_lower(nodecore.product) .. "_disable_hints")
|
||||
end
|
112
mods/nc_api_hints/discover.lua
Normal file
112
mods/nc_api_hints/discover.lua
Normal file
@ -0,0 +1,112 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local minetest, nodecore, pairs, string, type
|
||||
= minetest, nodecore, pairs, string, type
|
||||
local string_format
|
||||
= string.format
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
|
||||
nodecore.register_on_discover,
|
||||
nodecore.registered_on_discovers
|
||||
= nodecore.mkreg()
|
||||
|
||||
local cache = {}
|
||||
|
||||
local function loaddb(p)
|
||||
if nodecore.hints_disabled() then return end
|
||||
if not p then return end
|
||||
local player
|
||||
local pname
|
||||
if type(p) == "string" then
|
||||
player, pname = minetest.get_player_by_name(p), p
|
||||
else
|
||||
player, pname = p, p:get_player_name()
|
||||
end
|
||||
if not (player and pname) then return end
|
||||
|
||||
local db = cache[pname]
|
||||
if not db then
|
||||
local s = player:get_meta():get_string(modname) or ""
|
||||
db = s and minetest.deserialize(s) or {}
|
||||
cache[pname] = db
|
||||
end
|
||||
|
||||
return db, player, pname
|
||||
end
|
||||
nodecore.get_player_discovered = loaddb
|
||||
|
||||
local function discover(p, k)
|
||||
local db, player, pname = loaddb(p)
|
||||
if not db then return end
|
||||
|
||||
db[k] = true
|
||||
player:get_meta():set_string(modname, minetest.serialize(db))
|
||||
minetest.log("action", string_format("player %q discovered %q", pname, k))
|
||||
for _, cb in pairs(nodecore.registered_on_discovers) do
|
||||
cb(player, k, pname, db)
|
||||
end
|
||||
end
|
||||
nodecore.player_discover = discover
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- PLAYER EVENTS
|
||||
|
||||
local function reghook(func, stat, pwhom, npos)
|
||||
return func("stat hook", function(...)
|
||||
local t = {...}
|
||||
local whom = t[pwhom]
|
||||
local n = npos and t[npos].name or nil
|
||||
if n then stat = stat .. ":" .. n end
|
||||
return discover(whom, stat)
|
||||
end)
|
||||
end
|
||||
reghook(nodecore.register_on_punchnode, "punch", 3, 2)
|
||||
reghook(nodecore.register_on_dignode, "dig", 3, 2)
|
||||
reghook(nodecore.register_on_placenode, "place", 3, 2)
|
||||
reghook(nodecore.register_on_dieplayer, "die", 1)
|
||||
reghook(nodecore.register_on_respawnplayer, "spawn", 1)
|
||||
reghook(nodecore.register_on_joinplayer, "join", 1)
|
||||
|
||||
local function unpackreason(reason)
|
||||
if type(reason) ~= "table" then return reason or "?" end
|
||||
if reason.nc_type then return "nc", reason.nc_type end
|
||||
if reason.from then return reason.from, reason.type or nil end
|
||||
return reason.type or "?"
|
||||
end
|
||||
|
||||
nodecore.register_on_player_hpchange("hurt/heal stats", function(whom, change, reason)
|
||||
if change < 0 then
|
||||
return discover(whom, "hurt:" .. unpackreason(reason))
|
||||
else
|
||||
return discover(whom, "heal:" .. unpackreason(reason))
|
||||
end
|
||||
end)
|
||||
|
||||
nodecore.register_on_cheat("cheat stats", function(player, reason)
|
||||
discover(player, "cheat: " .. unpackreason(reason))
|
||||
end)
|
||||
|
||||
nodecore.register_on_chat_message("chat message stats", function(name, msg)
|
||||
discover(name, "chat:" .. (msg:sub(1, 1) == "/") and "command" or "message")
|
||||
end)
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- PLAYER INVENTORY SCAN
|
||||
|
||||
nodecore.register_playerstep({
|
||||
label = "inv",
|
||||
action = function(player)
|
||||
local inv = player:get_inventory()
|
||||
local t = {}
|
||||
for i = 1, inv:get_size("main") do
|
||||
local stack = inv:get_stack("main", i)
|
||||
if not stack:is_empty() then
|
||||
t[stack:get_name()] = true
|
||||
end
|
||||
end
|
||||
for k in pairs(t) do
|
||||
discover(player, "inv", k)
|
||||
end
|
||||
end
|
||||
})
|
13
mods/nc_api_hints/init.lua
Normal file
13
mods/nc_api_hints/init.lua
Normal file
@ -0,0 +1,13 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local include, nodecore
|
||||
= include, nodecore
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
nodecore.amcoremod()
|
||||
|
||||
include("disable")
|
||||
include("discover")
|
||||
include("witness")
|
||||
include("register")
|
||||
include("state")
|
||||
include("alerts")
|
1
mods/nc_api_hints/mod.conf
Normal file
1
mods/nc_api_hints/mod.conf
Normal file
@ -0,0 +1 @@
|
||||
depends = nc_api_active, nc_api_hud
|
42
mods/nc_api_hints/register.lua
Normal file
42
mods/nc_api_hints/register.lua
Normal file
@ -0,0 +1,42 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local nodecore, type
|
||||
= nodecore, type
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
nodecore.hints = {}
|
||||
|
||||
local function conv(spec)
|
||||
if not spec then
|
||||
return function() return true end
|
||||
end
|
||||
if type(spec) == "function" then return spec end
|
||||
if type(spec) == "table" then
|
||||
local f = spec[1]
|
||||
if f == true then
|
||||
return function(db)
|
||||
for i = 2, #spec do
|
||||
if db[spec[i]] then return true end
|
||||
end
|
||||
end
|
||||
end
|
||||
return function(db)
|
||||
for i = 1, #spec do
|
||||
if not db[spec[i]] then return end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
return function(db) return db[spec] end
|
||||
end
|
||||
|
||||
function nodecore.register_hint(text, goal, reqs)
|
||||
local hints = nodecore.hints
|
||||
local t = nodecore.translate(text)
|
||||
local h = {
|
||||
text = t,
|
||||
goal = conv(goal),
|
||||
reqs = conv(reqs)
|
||||
}
|
||||
hints[#hints + 1] = h
|
||||
return h
|
||||
end
|
46
mods/nc_api_hints/state.lua
Normal file
46
mods/nc_api_hints/state.lua
Normal file
@ -0,0 +1,46 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local ipairs, minetest, nodecore, pairs, string
|
||||
= ipairs, minetest, nodecore, pairs, string
|
||||
local string_gsub, string_match
|
||||
= string.gsub, string.match
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
function nodecore.hint_state(pspec)
|
||||
local rawdb, player, pname = nodecore.get_player_discovered(pspec)
|
||||
if not rawdb then return {}, {} end
|
||||
|
||||
local db = {}
|
||||
for k in pairs(rawdb) do
|
||||
db[k] = true
|
||||
while string_match(k, ":") do
|
||||
k = string_gsub(k, "^[^:]*:", "")
|
||||
db[k] = true
|
||||
end
|
||||
end
|
||||
for k, v in pairs(minetest.registered_items) do
|
||||
if db[k] then
|
||||
if v.tool_capabilities and v.tool_capabilities.groupcaps then
|
||||
for gn, gv in pairs(v.tool_capabilities.groupcaps) do
|
||||
for gt in pairs(gv.times or {}) do
|
||||
db["toolcap:" .. gn .. ":" .. gt] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
for gn, gv in pairs(v.groups or {}) do
|
||||
db["group:" .. gn] = gv
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local done = {}
|
||||
local found = {}
|
||||
for _, hint in ipairs(nodecore.hints) do
|
||||
if hint.goal(db, pname, player) then
|
||||
done[#done + 1] = hint
|
||||
elseif hint.reqs(db, pname, player) then
|
||||
found[#found + 1] = hint
|
||||
end
|
||||
end
|
||||
|
||||
return found, done
|
||||
end
|
@ -35,11 +35,10 @@ local function playercheck(player, pos, maxdist, check)
|
||||
end
|
||||
|
||||
function nodecore.witness(pos, label, maxdist, check)
|
||||
if not nodecore.player_stat_add then return end
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
if playercheck(player, pos, maxdist or 32, check) then
|
||||
for _, l in pairs(type(label) == "table" and label or {label}) do
|
||||
nodecore.player_stat_add(1, player, "witness", l)
|
||||
nodecore.player_discover(player, "witness:" .. l)
|
||||
end
|
||||
end
|
||||
end
|
@ -54,8 +54,8 @@ function nodecore.register_door(basemod, basenode, desc, pin, lv)
|
||||
local dir = vector.subtract(pointed.above, pointed.under)
|
||||
if vector.equals(dir, fd.t) or vector.equals(dir, fd.b) then
|
||||
node.name = doorname
|
||||
nodecore.player_stat_add(1, clicker, "craft",
|
||||
"door pin " .. basenode:lower())
|
||||
nodecore.player_discover(clicker, "craft:door pin "
|
||||
.. basenode:lower())
|
||||
nodecore.set_loud(pos, node)
|
||||
stack:take_item(1)
|
||||
return stack
|
||||
|
@ -1,96 +0,0 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local ipairs, minetest, nodecore, pairs, string, type
|
||||
= ipairs, minetest, nodecore, pairs, string, type
|
||||
local string_lower
|
||||
= string.lower
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
nodecore.hints = {}
|
||||
|
||||
function nodecore.hints_disabled()
|
||||
return minetest.settings:get_bool(
|
||||
string_lower(nodecore.product) .. "_disable_hints")
|
||||
end
|
||||
|
||||
local function conv(spec)
|
||||
if not spec then
|
||||
return function() return true end
|
||||
end
|
||||
if type(spec) == "function" then return spec end
|
||||
if type(spec) == "table" then
|
||||
local f = spec[1]
|
||||
if f == true then
|
||||
return function(db)
|
||||
for i = 2, #spec do
|
||||
if db[spec[i]] then return true end
|
||||
end
|
||||
end
|
||||
end
|
||||
return function(db)
|
||||
for i = 1, #spec do
|
||||
if not db[spec[i]] then return end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
return function(db) return db[spec] end
|
||||
end
|
||||
|
||||
function nodecore.addhint(text, goal, reqs)
|
||||
local hints = nodecore.hints
|
||||
local t = nodecore.translate(text)
|
||||
local h = {
|
||||
text = t,
|
||||
goal = conv(goal),
|
||||
reqs = conv(reqs)
|
||||
}
|
||||
hints[#hints + 1] = h
|
||||
return h
|
||||
end
|
||||
|
||||
function nodecore.hint_state(player)
|
||||
local pname
|
||||
if type(player) == "string" then
|
||||
pname, player = player, minetest.get_player_by_name(player)
|
||||
else
|
||||
pname = player:get_player_name()
|
||||
end
|
||||
|
||||
if type(player) == "string" then player = minetest.get_player_by_name(pname) end
|
||||
|
||||
local rawdb = nodecore.statsdb[pname] or {}
|
||||
|
||||
local db = {}
|
||||
for _, r in ipairs({"inv", "punch", "dig", "place", "craft", "witness"}) do
|
||||
for k, v in pairs(rawdb[r] or {}) do
|
||||
db[k] = v
|
||||
db[r .. ":" .. k] = v
|
||||
end
|
||||
end
|
||||
for k, v in pairs(minetest.registered_items) do
|
||||
if db[k] then
|
||||
if v.tool_capabilities and v.tool_capabilities.groupcaps then
|
||||
for gn, gv in pairs(v.tool_capabilities.groupcaps) do
|
||||
for gt in pairs(gv.times or {}) do
|
||||
db["toolcap:" .. gn .. ":" .. gt] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
for gn, gv in pairs(v.groups or {}) do
|
||||
db["group:" .. gn] = gv
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local done = {}
|
||||
local found = {}
|
||||
for _, hint in ipairs(nodecore.hints) do
|
||||
if hint.goal(db, pname, player) then
|
||||
done[#done + 1] = hint
|
||||
elseif hint.reqs(db, pname, player) then
|
||||
found[#found + 1] = hint
|
||||
end
|
||||
end
|
||||
|
||||
return found, done
|
||||
end
|
@ -3,7 +3,7 @@ local nodecore
|
||||
= nodecore
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local addhint = nodecore.addhint
|
||||
local addhint = nodecore.register_hint
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- SCALING
|
||||
|
@ -5,7 +5,4 @@ local include, nodecore
|
||||
|
||||
nodecore.amcoremod()
|
||||
|
||||
include("api")
|
||||
include("hints")
|
||||
include("invtab")
|
||||
include("alerts")
|
||||
|
@ -1 +1 @@
|
||||
depends = nc_api_all, nc_fire, nc_player_gui, nc_stats
|
||||
depends = nc_api_all
|
@ -38,7 +38,7 @@ local function gethint(player)
|
||||
while #found > 5 do
|
||||
table_remove(found, math_random(1, #found))
|
||||
end
|
||||
while #found < 5 do
|
||||
while #found < 5 and #done > 0 do
|
||||
local j = math_random(1, #done)
|
||||
found[#found + 1] = done[j]
|
||||
table_remove(done, j)
|
@ -8,3 +8,4 @@ nodecore.amcoremod()
|
||||
include("api")
|
||||
include("about")
|
||||
include("guide")
|
||||
include("hints")
|
||||
|
@ -73,10 +73,8 @@ hand.on_place = function(stack, player, pointed, ...)
|
||||
stack, player, pointed, node, ...) then return end
|
||||
|
||||
if nodecore.scaling_apply(pointed, player) then
|
||||
if nodecore.player_stat_add then
|
||||
nodecore.player_stat_add(1, player, "craft",
|
||||
"scaling dy=" .. (pointed.under.y - pointed.above.y))
|
||||
end
|
||||
nodecore.player_discover(player, "craft:scaling dy="
|
||||
.. (pointed.under.y - pointed.above.y))
|
||||
return nodecore.scaling_particles(pointed.above, {
|
||||
time = 0.1,
|
||||
amount = 40,
|
||||
|
@ -28,8 +28,8 @@ nodecore.extend_item(chip, function(copy, orig)
|
||||
nodecore.sound_play(stoned.name, stoned)
|
||||
itemstack:set_count(itemstack:get_count() - 1)
|
||||
if placer then
|
||||
nodecore.player_stat_add(1, placer, "craft",
|
||||
"assemble " .. v.to)
|
||||
nodecore.player_discover(placer,
|
||||
"craft:assemble " .. v.to)
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
|
@ -33,9 +33,7 @@ minetest.register_node(modname .. ":eggcorn", {
|
||||
|
||||
nodecore.set_loud(pos, {name = epname, param2 = 16})
|
||||
|
||||
if nodecore.player_stat_add then
|
||||
nodecore.player_stat_add(1, whom, "craft", "eggcorn planting")
|
||||
end
|
||||
nodecore.player_discover(whom, "craft:eggcorn planting")
|
||||
nodecore.log("action", (whom and whom:get_player_name() or "unknown")
|
||||
.. " planted an eggcorn at " .. minetest.pos_to_string(pos))
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user