446 lines
11 KiB
Lua
446 lines
11 KiB
Lua
--
|
|
-- Achivements mod
|
|
-- By Kaadmy, for Pixture
|
|
--
|
|
|
|
local COLOR_GOTTEN = "#00FF00"
|
|
|
|
local S = minetest.get_translator("achievements")
|
|
|
|
achievements = {}
|
|
|
|
achievements.achievements = {}
|
|
achievements.registered_achievements = {}
|
|
achievements.registered_achievements_list = {}
|
|
|
|
local achievements_file = minetest.get_worldpath() .. "/achievements.dat"
|
|
local saving = false
|
|
|
|
local function save_achievements()
|
|
local f = io.open(achievements_file, "w")
|
|
|
|
f:write(minetest.serialize(achievements.achievements))
|
|
|
|
io.close(f)
|
|
|
|
saving = false
|
|
end
|
|
|
|
local function delayed_save()
|
|
if not saving then
|
|
saving = true
|
|
|
|
minetest.after(40, save_achievements)
|
|
end
|
|
end
|
|
|
|
local function load_achievements()
|
|
local f = io.open(achievements_file, "r")
|
|
|
|
if f then
|
|
achievements.achievements = minetest.deserialize(f:read("*all"))
|
|
|
|
io.close(f)
|
|
else
|
|
save_achievements()
|
|
end
|
|
end
|
|
|
|
function achievements.register_achievement(name, def)
|
|
local rd = {
|
|
title = def.title or name, -- good-looking name of the achievement
|
|
description = def.description or "The " .. name .. " achievement", -- description of what the achievement is, and how to get it
|
|
times = def.times or 1, -- how many times to trigger before getting the achievement
|
|
dignode = def.dignode or nil, -- digging this node also triggers the achievement
|
|
placenode = def.placenode or nil, -- placing this node also triggers the achievement
|
|
craftitem = def.craftitem or nil, -- crafting this item also triggers the achievement
|
|
}
|
|
|
|
achievements.registered_achievements[name] = def
|
|
|
|
table.insert(achievements.registered_achievements_list, name)
|
|
end
|
|
|
|
function achievements.trigger_achievement(player, aname, times)
|
|
local name = player:get_player_name()
|
|
|
|
times = times or 1
|
|
|
|
if achievements.achievements[name][aname] == nil then
|
|
achievements.achievements[name][aname] = 0
|
|
end
|
|
|
|
if achievements.achievements[name][aname] == -1 then
|
|
return
|
|
end
|
|
|
|
achievements.achievements[name][aname] = achievements.achievements[name][aname] + times
|
|
|
|
if not achievements.registered_achievements[aname] then
|
|
default.log("[mod:achievements] Cannot find registered achievement "
|
|
.. aname, "error")
|
|
return
|
|
end
|
|
|
|
if achievements.achievements[name][aname]
|
|
>= achievements.registered_achievements[aname].times then
|
|
achievements.achievements[name][aname] = -1
|
|
minetest.after(
|
|
2.0,
|
|
function(name, aname)
|
|
minetest.chat_send_all(
|
|
minetest.colorize(
|
|
"#0f0",
|
|
"*** " .. S("@1 has earned the achievement “@2”.",
|
|
name,
|
|
achievements.registered_achievements[aname].title)))
|
|
end, name, aname)
|
|
end
|
|
|
|
if default.ui.current_page[name] == "achievements:achievements" then
|
|
local form = achievements.get_formspec(name)
|
|
player:set_inventory_formspec(form)
|
|
end
|
|
|
|
delayed_save()
|
|
end
|
|
|
|
-- Load achievements table
|
|
|
|
local function on_load()
|
|
load_achievements()
|
|
end
|
|
|
|
-- Save achievements table
|
|
|
|
local function on_shutdown()
|
|
save_achievements()
|
|
end
|
|
|
|
-- Joining player
|
|
|
|
local function on_joinplayer(player)
|
|
local name = player:get_player_name()
|
|
|
|
if not achievements.achievements[name] then
|
|
achievements.achievements[name] = {}
|
|
end
|
|
end
|
|
|
|
-- Interaction callbacks
|
|
|
|
local function on_craft(itemstack, player)
|
|
for aname, def in pairs(achievements.registered_achievements) do
|
|
if def.craftitem ~= nil then
|
|
if def.craftitem == itemstack:get_name() then
|
|
achievements.trigger_achievement(player, aname)
|
|
else
|
|
local group = string.match(def.craftitem, "group:(.*)")
|
|
|
|
if group and minetest.get_item_group(itemstack:get_name(), group) ~= 0 then
|
|
achievements.trigger_achievement(player, aname)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function on_dig(pos, oldnode, player)
|
|
for aname, def in pairs(achievements.registered_achievements) do
|
|
if def.dignode ~= nil then
|
|
|
|
if def.dignode == oldnode.name then
|
|
achievements.trigger_achievement(player, aname)
|
|
else
|
|
local group = string.match(def.dignode, "group:(.*)")
|
|
|
|
if group and minetest.get_item_group(oldnode.name, group) ~= 0 then
|
|
achievements.trigger_achievement(player, aname)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function on_place(pos, newnode, player, oldnode, itemstack, pointed_thing)
|
|
for aname, def in pairs(achievements.registered_achievements) do
|
|
if def.placenode ~= nil then
|
|
if def.placenode == newnode.name then
|
|
achievements.trigger_achievement(player, aname)
|
|
else
|
|
local group = string.match(def.placenode, "group:(.*)")
|
|
|
|
if group and minetest.get_item_group(newnode.name, group) ~= 0 then
|
|
achievements.trigger_achievement(player, aname)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Add callback functions
|
|
|
|
minetest.register_on_mods_loaded(on_load)
|
|
|
|
minetest.register_on_shutdown(on_shutdown)
|
|
|
|
minetest.register_on_joinplayer(on_joinplayer)
|
|
|
|
minetest.register_on_dignode(on_dig)
|
|
minetest.register_on_placenode(on_place)
|
|
|
|
crafting.register_on_craft(on_craft)
|
|
|
|
-- Formspecs
|
|
|
|
local form = default.ui.get_page("default:default")
|
|
|
|
form = form .. "tableoptions[background=#DDDDDD30]"
|
|
form = form .. "tablecolumns[color;text,align=left,width=11;text,align=left,width=28;"
|
|
.. "text,align=left,width=5]"
|
|
|
|
default.ui.register_page("achievements:achievements", form)
|
|
|
|
function achievements.get_formspec(name, row)
|
|
row = row or 1
|
|
|
|
if not achievements.achievements[name] then
|
|
achievements.achievements[name] = {}
|
|
end
|
|
|
|
local achievement_list = ""
|
|
|
|
local amt_gotten = 0
|
|
local amt_progress = 0
|
|
|
|
for _, aname in ipairs(achievements.registered_achievements_list) do
|
|
local def = achievements.registered_achievements[aname]
|
|
|
|
local progress = ""
|
|
local color = ""
|
|
if achievements.achievements[name][aname] then
|
|
if achievements.achievements[name][aname] == -1 then
|
|
progress = S("Gotten")
|
|
color = COLOR_GOTTEN
|
|
amt_gotten = amt_gotten + 1
|
|
else
|
|
progress = S("@1/@2", achievements.achievements[name][aname], def.times)
|
|
amt_progress = amt_progress + 1
|
|
end
|
|
else
|
|
progress = S("Missing")
|
|
end
|
|
|
|
if achievement_list ~= "" then
|
|
achievement_list = achievement_list .. ","
|
|
end
|
|
|
|
achievement_list = achievement_list .. color .. ","
|
|
achievement_list = achievement_list .. minetest.formspec_escape(def.title) .. ","
|
|
achievement_list = achievement_list .. minetest.formspec_escape(def.description)
|
|
.. ","
|
|
achievement_list = achievement_list .. minetest.formspec_escape(progress)
|
|
end
|
|
|
|
local form = default.ui.get_page("achievements:achievements")
|
|
|
|
form = form .. "table[0.25,2.5;7.9,5.5;achievement_list;" .. achievement_list
|
|
.. ";" .. row .. "]"
|
|
|
|
local aname = achievements.registered_achievements_list[row]
|
|
local def = achievements.registered_achievements[aname]
|
|
|
|
local progress = ""
|
|
local title = def.title
|
|
local description = def.description
|
|
if achievements.achievements[name][aname] then
|
|
if achievements.achievements[name][aname] == -1 then
|
|
progress = minetest.colorize(COLOR_GOTTEN, S("Gotten"))
|
|
title = minetest.colorize(COLOR_GOTTEN, title)
|
|
description = minetest.colorize(COLOR_GOTTEN, description)
|
|
else
|
|
progress = S("@1/@2", achievements.achievements[name][aname], def.times)
|
|
end
|
|
else
|
|
progress = S("Missing")
|
|
end
|
|
|
|
local progress_total =
|
|
S("@1 of @2 achievements gotten, @3 in progress",
|
|
amt_gotten,
|
|
#achievements.registered_achievements_list,
|
|
amt_progress)
|
|
if amt_gotten == #achievements.registered_achievements_list then
|
|
progress_total = minetest.colorize(COLOR_GOTTEN, progress_total)
|
|
end
|
|
form = form .. "label[0.25,8.15;"
|
|
.. minetest.formspec_escape(progress_total)
|
|
.. "]"
|
|
|
|
form = form .. "label[0.25,0.25;" .. minetest.formspec_escape(title) .. "]"
|
|
form = form .. "label[7.25,0.25;" .. minetest.formspec_escape(progress) .. "]"
|
|
|
|
-- TODO: Revert this back to a label
|
|
-- Currently a textarea as a workaround for a bug in Minetest that makes labels too short when translated.
|
|
form = form .. "textarea[0.75,0.75;7.75,2;;;" .. minetest.formspec_escape(description) .. "]"
|
|
|
|
return form
|
|
end
|
|
|
|
local function receive_fields(player, form_name, fields)
|
|
local name = player:get_player_name()
|
|
|
|
local in_achievements_menu = false
|
|
if form_name == "achievements:achievements" then
|
|
in_achievements_menu = true
|
|
elseif form_name ~= "" then
|
|
return
|
|
end
|
|
if fields.quit then
|
|
return
|
|
end
|
|
|
|
local selected = 1
|
|
|
|
if fields.tab_achievements then
|
|
in_achievements_menu = true
|
|
end
|
|
if fields.achievement_list then
|
|
in_achievements_menu = true
|
|
local selection = minetest.explode_table_event(fields.achievement_list)
|
|
|
|
if selection.type == "CHG" or selection.type == "DCL" then
|
|
selected = selection.row
|
|
end
|
|
|
|
end
|
|
if in_achievements_menu then
|
|
local form = achievements.get_formspec(name, selected)
|
|
minetest.show_formspec(
|
|
name,
|
|
"achievements:achievements",
|
|
form
|
|
)
|
|
player:set_inventory_formspec(form)
|
|
end
|
|
end
|
|
|
|
minetest.register_on_player_receive_fields(receive_fields)
|
|
|
|
--
|
|
-- Below are the default achievements
|
|
--
|
|
|
|
-- Digging wood
|
|
|
|
achievements.register_achievement(
|
|
"timber",
|
|
{
|
|
title = S("Timber"),
|
|
description = S("Dig a tree trunk."),
|
|
times = 1,
|
|
dignode = "group:tree",
|
|
})
|
|
|
|
-- Tools
|
|
|
|
achievements.register_achievement(
|
|
"first_pickaxe",
|
|
{
|
|
title = S("My First Pickaxe"),
|
|
description = S("Craft a pickaxe."),
|
|
times = 1,
|
|
craftitem = "group:pickaxe",
|
|
})
|
|
|
|
achievements.register_achievement(
|
|
"hardened_miner",
|
|
{
|
|
title = S("Hardened Miner"),
|
|
description = S("Craft a carbon steel pickaxe."),
|
|
times = 1,
|
|
craftitem = "default:pick_carbon_steel",
|
|
})
|
|
|
|
achievements.register_achievement(
|
|
"off_to_battle",
|
|
{
|
|
title = S("Off to Battle"),
|
|
description = S("Craft a broadsword."),
|
|
times = 1,
|
|
craftitem = "default:broadsword",
|
|
})
|
|
|
|
-- Stone
|
|
|
|
achievements.register_achievement(
|
|
"mineority",
|
|
{
|
|
title = S("Mineority"),
|
|
description = S("Mine a stone."),
|
|
times = 1,
|
|
dignode = "default:stone",
|
|
})
|
|
|
|
achievements.register_achievement(
|
|
"smelting_room",
|
|
{
|
|
title = S("Smelting Room"),
|
|
description = S("Craft a furnace."),
|
|
times = 1,
|
|
craftitem = "default:furnace",
|
|
})
|
|
|
|
-- Biomes
|
|
|
|
achievements.register_achievement(
|
|
"gardener",
|
|
{
|
|
title = S("Gardener"),
|
|
description = S("Plant a flower."),
|
|
times = 1,
|
|
placenode = "default:flower",
|
|
})
|
|
|
|
achievements.register_achievement(
|
|
"welcome_to_the_mountains",
|
|
{
|
|
title = S("Dry Lands"),
|
|
description = S("Collect dry grass."),
|
|
times = 1,
|
|
dignode = "default:dry_grass",
|
|
})
|
|
|
|
achievements.register_achievement(
|
|
"drain_the_swamp",
|
|
{
|
|
title = S("Drain the Swamp"),
|
|
description = S("Dig some swamp dirt."),
|
|
times = 1,
|
|
dignode = "default:swamp_dirt",
|
|
})
|
|
|
|
-- Farming
|
|
|
|
achievements.register_achievement(
|
|
"fertile",
|
|
{
|
|
title = S("Fertile"),
|
|
description = S("Craft a bag of fertilizer."),
|
|
times = 1,
|
|
craftitem = "default:fertilizer",
|
|
})
|
|
|
|
-- Literature
|
|
|
|
achievements.register_achievement(
|
|
"librarian",
|
|
{
|
|
title = S("Librarian"),
|
|
description = S("Craft a bookshelf."),
|
|
times = 1,
|
|
craftitem = "default:bookshelf",
|
|
})
|
|
|
|
default.log("mod:achievements", "loaded")
|