From c50fdcc4d0126b3335d23a43130abb39e99c6d6e Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Sun, 10 Jul 2016 04:02:26 +0100 Subject: [PATCH] Add quest goals --- mods/quests/README.md | 37 ++++++++++++ mods/quests/init.lua | 137 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 149 insertions(+), 25 deletions(-) create mode 100644 mods/quests/README.md diff --git a/mods/quests/README.md b/mods/quests/README.md new file mode 100644 index 0000000..33ebeff --- /dev/null +++ b/mods/quests/README.md @@ -0,0 +1,37 @@ +# Quests + +Mod to manage tasks. + +Todo: + +* Add support for more goals than digging and placing +* Multiple goal.requires +* Call backs on quest completion + +## Creating quests + +Here is a basic quest: + +```lua +local quest = quests.new(name, "Preparing a small feast") +quests.add_dig_goal(quest, "Harvest wheat", "farming:wheat_8", 5) +quests.add_dig_goal(quest, "Harvest apples", "default:apple", 3) +quests.add_quest(name, quest) +``` + +This will show up in the quest menu as: + + -> Preparing a small feast + [ ] Harvest wheat (0/5) + [ ] Harvest apples (0/3) + +For longer quests, certain goals need to be done in an order. +To do this, use goal.require: + +```lua +local quest = quests.new(name, "Breaking Bread") +local g1 = quests.add_dig_goal(quest, "Harvest wheat", "treasure:raregem", 1) +local g2 = quests.add_give_goal(quest, "Return to Bob the Farmer", bob, "treasure:raregem", 1) +g2.requires = g1 +quest.next = quest2 +``` diff --git a/mods/quests/init.lua b/mods/quests/init.lua index 81a4527..b5c907b 100644 --- a/mods/quests/init.lua +++ b/mods/quests/init.lua @@ -42,31 +42,128 @@ function quests.add_quest(player, quest) end function quests.finish_quest(player, quest) - xp.add_xp(digger, quest.xp) + xp.add_xp(minetest.get_player_by_name(player), quest.xp) quest.done = true - quests.callback(player) + if quests.callback then + quests.callback(player) + end +end + +function quests.finish_goal(player, quest, goal) + goal.done = true + if not quest.done then + local all_done = true + for i = 1, #quest.goals do + if not quest.goals[i].done then + all_done = false + break + end + end + if all_done then + quests.finish_quest(player, quest) + end + end + quests.save() +end + +function quests.new(player, title) + local quest = { + title = title, + done = false, + goals = {}, + xp = 0 + } + + return quest +end + +function quests.add_dig_goal(quest, title, node, number) + local goal = { + title = title, + type = "dig", + node = node, + max = number, + progress = 0, + done = false + } + table.insert(quest.goals, goal) + return goal +end + +function quests.add_place_goal(quest, title, node, number) + local goal = { + title = title, + type = "placenode", + node = node, + max = number, + progress = 0, + done = false + } + table.insert(quest.goals, goal) + return goal +end + +function quests.process_node_count_goals(player, type, node) + local player_quests = quests.player_quests[player] + table.foreach(player_quests, function(_, quest) + table.foreach(quest.goals, function(_, goal) + if (not goal.requires or goal.requires.done) and + goal.type == type and goal.node == node then + goal.progress = goal.progress + 1 + if goal.progress >= goal.max then + goal.progress = goal.max + if goal.done then + quests.finish_goal(player, quest, goal) + end + end + quests.save() + end + end) + end) end quests.show_quests_form = "size[8,7.5;]" .. default.gui_colors .. default.gui_bg .. "label[0,0;%s]" +function quests.format_goal(player, quest, goal) + -- TODO: support formatting for more than just digging and placing + if goal.done then + return " [x] " .. goal.title .. " (" .. tostring(goal.progress) .. + "/" .. tostring(goal.max) .. ")\n" + else + return " [ ] " .. goal.title .. " (" .. tostring(goal.progress) .. + "/" .. tostring(goal.max) .. ")\n" + end +end + minetest.register_chatcommand("quests", { params = "", description = "Shows your quests", privs = {}, func = function(name, text) - if not quests.player_quests[name] then + local player_quests = quests.player_quests[name] + if not player_quests or #player_quests == 0 then local s = quests.show_quests_form s = string.format(s, "You have not got any quests yet.") minetest.show_formspec(name, "quests:show_quests", s) return end + local s = quests.show_quests_form local txt = "" - for k, v in pairs(quests.player_quests[name]) do - txt = txt .. " -> " .. v.quest_type .. " " .. v.node .. " (" .. tostring(v.progress) .. "/" .. tostring(v.max) .. ")\n" + for _, quest in pairs(player_quests) do + if quest.done then + txt = txt .. " -> " .. quest.title .. " (Completed)\n" + else + txt = txt .. " -> " .. quest.title .. "\n" + for _, goal in pairs(quest.goals) do + if not goal.requires or goal.requires.done then + txt = txt .. quests.format_goal(name, quest, goal) + end + end + end end - s = string.format(s, txt) + s = string.format(s, minetest.formspec_escape(txt)) minetest.show_formspec(name, "quests:show_quests", s) return true, "" end, @@ -78,16 +175,7 @@ minetest.register_on_dignode(function(pos, oldnode, digger) return end - table.foreach(quests.player_quests[digger:get_player_name()], function(k, v) - print("[quests] run quest " .. v.quest_type .. ", " .. v.node) - if v.quest_type == "dignode" and oldnode.name == v.node then - v.progress = v.progress + 1 - if v.progress > (v.max-1) and not v.done then - quests.finish_quest(digger, v) - end - quests.save() - end - end) + quests.process_node_count_goals(digger:get_player_name(), "dig", oldnode.name) end) minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing) @@ -96,19 +184,18 @@ minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack return end - table.foreach(quests.player_quests[placer:get_player_name()], function(k, v) - if v.quest_type == "placenode" and newnode.name == v.node then - v.progress = v.progress + 1 - if v.progress > (v.max-1) and not v.done then - quests.finish_quest(placer, v) - end - quests.save() - end - end) + quests.process_node_count_goals(placer:get_player_name(), "placenode", newnode.name) end) minetest.register_on_newplayer(function(player) quests.player_quests[player:get_player_name()] = {} + + local name = player:get_player_name() + local quest = quests.new(name, "Quest 1") + local q1 = quests.add_dig_goal(quest, "Harvest dirt", "default:dirt", 5) + local q2 = quests.add_dig_goal(quest, "Harvest sand", "default:sand", 5) + q2.requires = q1 + quests.add_quest(name, quest) end) quests.load()