Add category series.

These can be accessed using enter teleporters where is_series==2.

At that point, the `box` meta value determines the category, not
the box id. Then the next box that is unplayed in that category
is offered for play.

For now, the player is sent a message if there are no more
unplayed boxes in a category.
This commit is contained in:
Auke Kok 2019-01-18 15:32:52 -08:00
parent f819361ac7
commit 06c900120e
2 changed files with 62 additions and 7 deletions

View File

@ -183,7 +183,8 @@ register_teleport("boxes:enter_teleport", {
on_teleport = function(pos, node, player)
local meta = minetest.get_meta(pos)
local id = meta:get_int("box")
if meta:get_int("is_series") == 1 then
local is_series = meta:get_int("is_series")
if is_series == 1 then
local smeta = db.series_get_meta(id)
if not smeta then
return
@ -199,6 +200,37 @@ register_teleport("boxes:enter_teleport", {
end
return
else if is_series == 2 then
if not ranks or not ranks.categories then
minetest.log("error", "ranks mod not found, can't use category teleport")
return true
end
-- get the list of boxes for category (id)
local catboxes = ranks.categories[tostring(id)]
-- first, find first unplayed box in dynamic series
local name = player:get_player_name()
local player_id = db.player_get_id(name)
local playerboxes = db.player_get_completed_boxes(player_id)
for _, catbox in pairs(catboxes) do
if not playerboxes[catbox] then
local bmeta = db.box_get_meta(catbox)
if bmeta.type ~= db.BOX_TYPE then
return true
end
boxes.open_box(player, {0, catbox, 1})
return
end
end
-- fallback to a random one ?
-- FIXME implement
minetest.chat_send_player(name, "You've completed every " ..
"box in this category! Come back later to see if " ..
"there are new boxes in it.")
return
end
local bmeta = db.box_get_meta(id)
if bmeta.type ~= db.BOX_TYPE then
@ -212,15 +244,24 @@ register_teleport("boxes:enter_teleport", {
end
local meta = minetest.get_meta(pos)
if puncher:get_player_control().sneak then
local is_series = meta:get_int("is_series")
meta:set_int("is_series", 1 - is_series)
minetest.chat_send_player(puncher:get_player_name(), "Destination is" ..
((is_series == 0) and " " or " not ") .. "a series")
-- 0: a box portal
-- 1: a numbered series portal
-- 2: a category portal
local is_series = meta:get_int("is_series") + 1
if is_series > 2 then
is_series = 0
end
meta:set_int("is_series", is_series)
minetest.chat_send_player(puncher:get_player_name(), "Teleporter is a" ..
((is_series == 0) and " box " or
(is_series == 1) and " numbered series " or
" category ") .. "portal")
return
end
local id = meta:get_int("box")
local newid = id + 1
if not db.box_exists(newid) then
local is_series = meta:get_int("is_series")
if is_series == 1 and not db.box_exists(newid) then
newid = 0
end
meta:set_int("box", newid)
@ -233,7 +274,8 @@ register_teleport("boxes:enter_teleport", {
local meta = minetest.get_meta(pos)
local id = meta:get_int("box")
local newid = id - 1
if not db.box_exists(newid) then
local is_series = meta:get_int("is_series")
if is_series == 1 and not db.box_exists(newid) then
newid = db.get_last_box_id()
end
meta:set_int("box", newid)

View File

@ -204,6 +204,19 @@ function db.player_points(player_id, box_id, type, values, limit)
return true
end
function db.player_get_completed_boxes(player_id)
local stmt = itb_db:prepare[[
SELECT DISTINCT box_id FROM points WHERE type='time' AND player_id = :player_id
]]
stmt:bind_names{player_id = player_id}
local boxes = {}
for row in stmt:nrows() do
boxes[row.box_id] = 1
end
return boxes
end
function db.player_get_points(filtertbl)
if not filtertbl then
filtertbl = {}