608 lines
17 KiB
Lua

-- SYS4 Achievements
-- by Sys4
local S = sys4_achievements.intllib
-- api
local craftmode = true
-- New Waste Node
minetest.register_node("sys4_achievements:waste",
{
description = S("Waste"),
tiles = {"waste.png"},
is_ground_content = false,
groups = {crumbly=2, flammable=2},
})
function sys4_achievements.write_book(items, prizes)
local text = ""
if prizes and prizes ~= nil then
text = text..S("Amazing ! You win :\n")
local tt = ""
for i=1, #prizes do
local itemstack = ItemStack(prizes[i])
tt = tt..itemstack:get_count().." "..itemstack:get_name().."\n"
end
text = text..tt.."\n"
end
if items and items ~= nil then
text = text..S("You unlock these crafts :\n")
local tt = ""
for i=1, #items do
tt = tt..items[i].."\n"
end
text = text..tt.."\n"
end
return text
end
function sys4_achievements.getAchievement(onType, name)
local registeredAchievements
if onType == "dig" then
registeredAchievements = awards.onDig
end
if onType == "place" then
registeredAchievements = awards.onPlace
end
if onType == "craft" then
registeredAchievements = awards.onCraft
end
for i=1, #registeredAchievements do
if type(registeredAchievements[i]) == "table" and
registeredAchievements[i].award == name then
return registeredAchievements[i]
end
end
end
function sys4_achievements.has_achievement(name, award)
local data = awards.players[name]
if not data then
return
end
if not awards.def[award] then
return
end
awards.tbv(data, "unlocked")
if data.unlocked[award] and data.unlocked[award] == award then
return true
else
return false
end
end
-- run a function when a node is crafted
function sys4_achievements.register_onCraft(func)
table.insert(awards.onCraft,func)
end
function sys4_achievements.getItemCount(action_type, mod, items, playern, data)
local count = 0
if action_type == "craft" then
awards.tbv(awards.players[playern].craft, mod)
for i=1, #items do
awards.tbv(awards.players[playern].craft[mod], items[i], 0)
count = count + data.craft[mod][items[i]]
end
else if action_type == "dig" then
awards.tbv(awards.players[playern].count, mod)
for i=1, #items do
awards.tbv(awards.players[playern].count[mod], items[i], 0)
count = count + data.count[mod][items[i]]
end
else if action_type == "place" then
awards.tbv(awards.players[playern].place, mod)
for i=1, #items do
awards.tbv(awards.players[playern].place[mod], items[i], 0)
count = count + data.place[mod][items[i]]
end
else
return
end
end
end
return count
end
-- AWARDS redefinitions
-- add new trigger 'craft'
awards.onCraft = {}
local add_trig = awards._additional_triggers
awards._additional_triggers = function(name, data_table)
if data_table.trigger.type == "craft" then
local tmp = {
award = name,
node = data_table.trigger.node,
target = data_table.trigger.target,
}
table.insert(awards.onCraft, tmp)
else
add_trig(name, data_table)
end
end
awards.assertPlayer = function(playern)
awards.tbv(awards.players, playern)
awards.tbv(awards.players[playern], "name", playern)
awards.tbv(awards.players[playern], "unlocked")
awards.tbv(awards.players[playern], "place")
awards.tbv(awards.players[playern], "craft")
awards.tbv(awards.players[playern], "count")
awards.tbv(awards.players[playern], "deaths", 0)
awards.tbv(awards.players[playern], "joins", 0)
awards.tbv(awards.players[playern], "chats", 0)
end
-- Redefinition of awards.give_achievement for add given book
awards.give_achievement = function (name, award)
-- Access Player Data
local data = awards.players[name]
-- Perform checks
if not data then
return
end
if not awards.def[award] then
return
end
awards.tbv(data,"unlocked")
-- check to see if the player does not already have that achievement
if not data.unlocked[award] or data.unlocked[award]~=award then
-- Set award flag
data.unlocked[award]=award
-- Give Prizes
if awards.def[award] and awards.def[award].prizes then
for i = 1, #awards.def[award].prizes do
local itemstack = ItemStack(awards.def[award].prizes[i])
if itemstack:is_empty() or not itemstack:is_known() then
return
end
local receiverref = core.get_player_by_name(name)
if receiverref == nil then
return
end
receiverref:get_inventory():add_item("main", itemstack)
end
end
-- Sys4
-- Give book
if awards.def[award] and awards.def[award].book and craftmode then
local itemstack = ItemStack('default:book_written')
local book_data = {}
book_data.title = awards.def[award].book.title
book_data.text = awards.def[award].book.text
book_data.owner = name
local data_str = minetest.serialize(book_data)
itemstack:set_metadata(data_str)
local receiverref = core.get_player_by_name(name)
if receiverref == nil then return end
receiverref:get_inventory():add_item("main", itemstack)
end
-- Get data from definition tables
local title = award
local desc = ""
local background = ""
local icon = ""
local custom_announce = ""
if awards.def[award].title then
title = awards.def[award].title
end
if awards.def[award].custom_announce then
custom_announce = awards.def[award].custom_announce
end
if awards.def[award].background then
background = awards.def[award].background
end
if awards.def[award].icon then
icon = awards.def[award].icon
end
if awards.def[award] and awards.def[award].description then
desc = awards.def[award].description
end
-- send the won award message to the player
if awards.show_mode == "formspec" then
-- use a formspec to send it
minetest.show_formspec(name, "achievements:unlocked", "size[4,2]"..
"image_button_exit[0,0;4,2;"..background..";close1; ]"..
"image_button_exit[0.2,0.8;1,1;"..icon..";close2; ]"..
"label[1.1,1;"..title.."]"..
"label[0.3,0.1;"..custom_announce.."]")
elseif awards.show_mode == "chat" then
-- use the chat console to send it
minetest.chat_send_player(name, S("Achievement Unlocked: ")..title)
if desc~="" then
minetest.chat_send_player(name, desc)
end
else
local player = minetest.get_player_by_name(name)
local one = player:hud_add({
hud_elem_type = "image",
name = "award_bg",
scale = {x = 1, y = 1},
text = background,
position = {x = 0.5, y = 0},
offset = {x = 0, y = 138},
alignment = {x = 0, y = -1}
})
local two = player:hud_add({
hud_elem_type = "text",
name = "award_au",
number = 0xFFFFFF,
scale = {x = 100, y = 20},
text = S("Achievement Unlocked!"),
position = {x = 0.5, y = 0},
offset = {x = 0, y = 40},
alignment = {x = 0, y = -1}
})
local three = player:hud_add({
hud_elem_type = "text",
name = "award_title",
number = 0xFFFFFF,
scale = {x = 100, y = 20},
text = title,
position = {x = 0.5, y = 0},
offset = {x = 30, y = 100},
alignment = {x = 0, y = -1}
})
local four = player:hud_add({
hud_elem_type = "image",
name = "award_icon",
scale = {x = 4, y = 4},
text = icon,
position = {x = 0.5, y = 0},
offset = {x = -81.5, y = 126},
alignment = {x = 0, y = -1}
})
minetest.after(3, function()
player:hud_remove(one)
player:hud_remove(two)
player:hud_remove(three)
player:hud_remove(four)
end)
end
-- record this in the log
minetest.log("action", name.." has unlocked award "..title)
-- save playertable
awards.save()
end
end
-- Redefenition of awards.showto for showing crafts to unlock and arrange display
awards.showto = function(name, to, sid, text)
if name == "" or name == nil then
name = to
end
if text then
if not awards.players[name] or not awards.players[name].unlocked then
minetest.chat_send_player(to, "You have not unlocked any awards")
return
end
minetest.chat_send_player(to, name.."'s awards:")
for _, str in pairs(awards.players[name].unlocked) do
local def = awards.def[str]
if def then
if def.title then
if def.description then
minetest.chat_send_player(to, def.title..": "..def.description)
else
minetest.chat_send_player(to, def.title)
end
else
minetest.chat_send_player(to, str)
end
end
end
else
if sid == nil or sid < 1 then
sid = 1
end
local formspec = "size[15,8]"
local listofawards = awards._order_awards(name)
-- Sidebar
if sid then
local item = listofawards[sid+0]
local def = awards.def[item.name]
if def and def.secret and not item.got then
formspec = formspec .. "label[9,2.75;Secret Award]"..
"image[9.75,0;3,3;unknown.png]"
if def and def.description then
formspec = formspec .. "label[9,3.25;Unlock this award to find out what it is]"
end
else
local title = item.name
if def and def.title then
title = def.title
end
local status = ""
if item.got then
status = " (got)"
end
local icon = ""
if def and def.icon then
icon = def.icon
end
formspec = formspec .. "label[9,3.25;"..title..status.."]".."label[9,0;"..item.name.."]"..
"image[9.75,0.5;3,3;"..icon.."]"
if def and def.description then
formspec = formspec .. "label[8,4.25;"..def.description.."]"
end
-- Sys4
-- Crafts to unlock
if def and def.items then
local items = def.items
local y = 5 -- Position y de départ du label
formspec = formspec .. "label[8,"..y..";"..S("Unlock crafts").." :]"
local name = ""
for i=1, #items do
local itemstack = ItemStack(items[i])
if itemstack and itemstack ~= nil and itemstack:is_known() then
name = itemstack:get_name()
else
name = "Unknown Item"
end
y = y + 0.35
formspec = formspec .. "label[8,"..y..";- "..name.."]"
end
end
end
end
-- Create list box
formspec = formspec .. "textlist[0,0;6.75,8;awards;"
local first = true
for _,award in pairs(listofawards) do
local def = awards.def[award.name]
if def then
if not first then
formspec = formspec .. ","
end
first = false
if def.secret and not award.got then
formspec = formspec .. "#ACACACSecret Award"
else
local title = award.name
if def and def.title then
title = def.title
end
if award.got then
formspec = formspec .. minetest.formspec_escape(title)
else
formspec = formspec .. "#ACACAC".. minetest.formspec_escape(title)
end
end
end
end
formspec = formspec .. ";"..sid.."]"
-- Show formspec to user
minetest.show_formspec(to,"awards:awards",formspec)
end
end
-- Register new trigger on "craft"
minetest.register_on_craft(
function(itemstack, player, old_craft_grid, craft_inv)
-- Par défaut tout craft qui doit donner quelque chose retournera des déchets inutilisables.
local wasteItem = "sys4_achievements:waste"
local nodeName = itemstack:get_name()
local nodeCrafted = string.split(nodeName, ":")
if #nodeCrafted ~= 2 then
--minetest.log("error","Awards mod: "..oldnode.name.." is in wrong format!")
return
end
local mod = nodeCrafted[1]
local item = nodeCrafted[2]
local playern = player:get_player_name()
if (not playern or not nodeCrafted or not mod or not item) then
return
end
awards.assertPlayer(playern)
awards.tbv(awards.players[playern].craft, mod)
awards.tbv(awards.players[playern].craft[mod], item, 0)
-- Si des awards ont été débloqués, ont les parcours pour en extraire les items qu'ils débloquent
if awards.player(playern) ~= nil then
local data = awards.players[playern]
for _, str in pairs(data.unlocked) do
local def = awards.def[str]
if def and def.items then
local items = def.items
for i=1, #items do
-- Si un item débloqué correspond à l'item demandé par l'utilisateur alors on le prend en compte et on retournera l'item (en retournant nil)
if items[i] == nodeName then
-- Increment counter
awards.players[playern].craft[mod][item] = awards.players[playern].craft[mod][item] + itemstack:get_count()
-- Run callbacks and triggers
local crafter = player
for j=1, #awards.onCraft do
local res = nil
if type(awards.onCraft[j]) == "function" then
-- Run trigger callback
res = awards.onCraft[j](crafter, data)
elseif type(awards.onCraft[j]) == "table" then
-- Handle table trigger
if not awards.onCraft[j].node or not awards.onCraft[j].target or not awards.onCraft[j].award then
-- table running failed !
print("[ERROR] awards - onCraft trigger "..j.." is invalid !")
else
-- run the table
local tnodeCrafted = string.split(awards.onCraft[j].node, ":")
local tmod = tnodeCrafted[1]
local titem = tnodeCrafted[2]
if tmod == nil or titem == nil or not data.craft[tmod] or not data.craft[tmod][titem] then
-- table running failed
elseif data.craft[tmod][titem] > awards.onCraft[j].target - 1 then
res = awards.onCraft[j].award
end
end
end
if res then
awards.give_achievement(playern,res)
end
end
return nil
end
end
end
end
end
if craftmode then
return wasteItem
else
return nil
end
end)
minetest.register_chatcommand("gawd", {
params = "award name",
description = "gawd: give award to self",
func = function(name, param)
awards.give_achievement(name,param)
end
})
minetest.register_chatcommand("craftmode",
{
params = "on or off",
description = "craftmode : enable or not sys4_achievements locked crafts.",
func = function(name, param)
if param == "on" then
craftmode = true
minetest.chat_send_player(name, "Sys4 craft mode enabled")
else
craftmode = false
minetest.chat_send_player(name, "Sys4 craft mode disabled")
end
end
})
-- Fonction qui se déclenche quand le joueur place un objet dans son environnement.
-- Cette fonction est normalement déjà définie dans 'awards' : minetest.register_on_place = func(...)
-- Mais elle ne se déclenche pas pour certains objets comme les troncs d'arbres.
-- Ces types d'objets possèdent une propriété on_place = minetest.rotate_node
-- qu'il faut redéfinir par cette fonction pour nos besoins.
function sys4_achievements.register_onPlace(itemstack, placer, pointed_thing)
if not placer or not pointed_thing or not itemstack or not placer:get_player_name() or placer:get_player_name()=="" then
return
end
-- Code pour le systeme awards
local nodedug = string.split(itemstack:get_name(), ":")
if #nodedug ~= 2 then
--minetest.log("error","Awards mod: "..node.name.." is in wrong format!")
return
end
local mod=nodedug[1]
local item=nodedug[2]
local playern = placer:get_player_name()
-- Run checks
if (not playern or not nodedug or not mod or not item) then
return
end
awards.assertPlayer(playern)
awards.tbv(awards.players[playern].place, mod)
awards.tbv(awards.players[playern].place[mod], item, 0)
-- Increment counter
awards.players[playern].place[mod][item] = awards.players[playern].place[mod][item] + 1
-- Run callbacks and triggers
local player = placer
local data = awards.players[playern]
for i=1,# awards.onPlace do
local res = nil
if type(awards.onPlace[i]) == "function" then
-- Run trigger callback
res = awards.onPlace[i](player,data)
elseif type(awards.onPlace[i]) == "table" then
-- Handle table trigger
if not awards.onPlace[i].node or not awards.onPlace[i].target or not awards.onPlace[i].award then
print("[ERROR] awards - onPlace trigger "..i.." is invalid!")
else
-- run the table
local tnodedug = string.split(awards.onPlace[i].node, ":")
local tmod = tnodedug[1]
local titem = tnodedug[2]
if tmod==nil or titem==nil or not data.place[tmod] or not data.place[tmod][titem] then
-- table running failed!
elseif data.place[tmod][titem] > awards.onPlace[i].target-1 then
res = awards.onPlace[i].award
end
end
end
if res then
awards.give_achievement(playern,res)
end
end
-- Meme portion de code que dans la fonction core.rotate_node
core.rotate_and_place(itemstack, placer, pointed_thing,
core.setting_getbool("creative_mode"),
{invert_wall = placer:get_player_control().sneak})
return itemstack
end
-- Redéfinition de la propriété on_place de ces nodes
local nodes = {
minetest.registered_nodes["default:tree"],
minetest.registered_nodes["default:jungletree"],
minetest.registered_nodes["default:acacia_tree"],
minetest.registered_nodes["default:pine_tree"],
}
for i=1, #nodes do
nodes[i].on_place = sys4_achievements.register_onPlace
end