diff --git a/ability.lua b/ability.lua index 96df13f..55a36ac 100644 --- a/ability.lua +++ b/ability.lua @@ -79,6 +79,10 @@ function magicalities.available_to_player(player_name, unlocked, researchable) return all end +local function no_newline(str) + return str:gsub("\n(.*)", "") +end + -- Learn a recipe or an ability function magicalities.player_learn(player_name, item, recipe, silent) if not magicalities.data[player_name] then @@ -91,7 +95,7 @@ function magicalities.player_learn(player_name, item, recipe, silent) if recipe and not magicalities.player_has_recipe(player_name, item) then local recipe_n = recipes[item] if recipe_n then - recipe_n = recipe_n.description + recipe_n = no_newline(recipe_n.description) table.insert(magicalities.data[player_name].recipes, item) success = true msgname = msgname .. recipe_n @@ -99,7 +103,7 @@ function magicalities.player_learn(player_name, item, recipe, silent) elseif not recipe and not magicalities.player_has_ability(player_name, item) then local ability_n = abilities[item] if ability_n then - ability_n = ability_n.description + ability_n = no_newline(ability_n.description) table.insert(magicalities.data[player_name].abilities, item) success = true msgname = "to " .. ability_n diff --git a/book.lua b/book.lua index 738ee76..39d15d3 100644 --- a/book.lua +++ b/book.lua @@ -1,18 +1,135 @@ -local function book_formspec(user) +local page_cache = {} + +local function book_formspec(user, page, scrollindex) + if page then + return "size[8,8]".. + "button[0,0;2,1;back;Back to index]".. + "hypertext[0.1,0.5;7.9,7.5;text;"..page_cache[page].."]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots + end + local avail_list = magicalities.available_to_player(user, true) - return "size[5,6]".. + return "size[6,5.7]".. default.gui_bg.. default.gui_bg_img.. - default.gui_slots + default.gui_slots.. + magicalities.researching.generate_formspec_list(avail_list, 0, 0, 5, 5.25, scrollindex, false, true) end -local function book_read(itemstack, user, pointed_thing) - local uname = user:get_player_name() - minetest.show_formspec(uname, "magicalities:book", book_formspec(uname)) - return itemstack +local function first_key(list) + local ekey + for key,_ in pairs(list) do + ekey = key + break + end + return ekey end +local function book_read_page(book, user, page, ptype) + local uname = user:get_player_name() + local check = magicalities.player_has_ability + if ptype == 2 then + check = magicalities.player_has_recipe + end + + if not check(uname, page) then return book end + + local chapter = "#"..ptype..""..page + if not page_cache[chapter] then + return + end + + minetest.show_formspec(uname, "magicalities:book", book_formspec(uname, chapter, 0)) +end + +local function book_read(book, user, pointed_thing) + local uname = user:get_player_name() + local meta = book:get_meta() + minetest.show_formspec(uname, "magicalities:book", book_formspec(uname, nil, meta:get_int("scrolli"))) + return book +end + +local function cache_book_pages() + local file = io.open(minetest.get_modpath("magicalities").."/book.txt") + local all = {} + local previous = "" + local since = 0 + + for line in file:lines() do + if line:sub(0,1) == "#" then + all[line] = "" + previous = line + since = 0 + elseif previous ~= "" then + if since > 0 then + line = '\n'..line + end + all[previous] = all[previous] .. line + since = since + 1 + end + end + + page_cache = all +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname ~= "magicalities:book" then return false end + + local book = player:get_wielded_item() + if book:get_name() ~= "magicalities:book" then return true end + + local bmeta = book:get_meta() + + local scrolled = false + local findex = bmeta:get_int("scrolli") + + local page + local page_type + + local fkey = first_key(fields) + if fields["text"] and fields["text"]:sub(0,6) == "action" then + local pact = fields["text"]:sub(8):gsub("\"", "") + if pact then + fkey = pact + end + end + + if fields["dn"] then + scrolled = true + findex = findex + 1 + elseif fields["up"] then + scrolled = true + findex = findex - 1 + if findex < 0 then + findex = 0 + end + elseif fkey and fkey:sub(0,1) == "#" then + page_type = tonumber(fkey:sub(2,2)) + page = fkey:sub(3) + elseif fields["back"] then + book_read(book, player) + return true + end + + if scrolled then + bmeta:set_int("scrolli", findex) + player:set_wielded_item(book) + book_read(book, player) + + return true + end + + if not page or not page_type then return true end + -- Handle page + --print("Open page on topic " .. page .. ", which is of type " .. page_type) + book_read_page(book, player, page, page_type) + + return true +end) + minetest.register_craftitem("magicalities:book", { description = "Magicalities' Guide for Witches and Wizards", inventory_image = "magicalities_book.png", @@ -24,3 +141,13 @@ minetest.register_craftitem("magicalities:book", { end, stack_max = 1 }) + +minetest.register_chatcommand("mgcbookcache", { + privs = {basic_privs = 1}, + func = function () + cache_book_pages() + return true, "Reloaded book cache successfully." + end +}) + +cache_book_pages() diff --git a/book.txt b/book.txt new file mode 100644 index 0000000..d578872 --- /dev/null +++ b/book.txt @@ -0,0 +1,46 @@ +#1magicalities:crystal +Crystals are nodes that you can find in underground - they grow on the ceilings and the floors of caves. +Crystal Tapping is an action in which by right-clicking a crystal with your wand, you can extract elements from it. +#1magicalities:crystal_preserve +The Crystal Preservation ability helps you collect elements from crystals without completely draining them. You learned that when you drain a crystal of it's elements completely, it will not regenerate anything. +#1magicalities:crystal_draining +The Efficient Crystal Draining ability helps you collect elements from crystals 5x faster than normal. +#1magicalities:pickup_jarred +The Crystal Jarring procedure will enable you to collect crystals without removing all of their contents. +When using this method, the crystal will not break into shards, instead it will drop itself. +Procedure +Surround a crystal in a 3x3 thing of glass, except for the top layer, which has to be wood slabs. +When the structure is complete, hit any node of glass with the wand. +
+
+
+#2magicalities:table +The Research Table is used to do research about various topics in the world of magic. +In order to do research, you need to find knowledge around the world. You can find bookshelves in various structures that will give you the knowledge you need to do your research. If you find a bookshelf that is generated in the world, you can extract knowledge from it by right-clicking. +The Research Table will need three items to operate: Your Guide Book (you're reading it right now!), an Ink and Quill and a piece of paper. +Provided you have acquired sufficient knowledge from exploring the world, you can then dwell deeper into topics you have heard about but don't know all the details of. +#2magicalities:arcane_table +Arcane Table is used for magical crafting. You can create an Arcane Table by using your wand on a Table. Make sure that the table is empty first, though! +
+The Arcane Table will also tell you what elements you need inside of your wand to finish crafting your item. +#2magicalities:cauldron +Cauldron is used for magical crafting. It requires a fire source under it and water to accept items. +Right-Click on the Cauldron with a Bucket of Water in order to fill it with water. +#2magicalities:wand_steel +Wands are used to cast spells. The first wand you know of is called the Steel-Capped Wand, which can contain up to 25 of any element. +#2magicalities:wand_gold +The Gold-Capped Wand is an improved version of the Steel-Capped Wand. It can contain up to 50 of each element instead of the Steel Wand's 25. +#2magicalities:transterra +The Transterra is a stone that can be used to create or remove nodes from the world. It is made in the Cauldron. +
+
+
+#2magicalities:tellium +Tellium is a metal that can be used to create magical tools. It is made in the Cauldron. +
+
+
+#2magicalities:element_ring +The Elemental Ring can show you what elements a crystal contains and their quantities. +#2magicalities:focus_blank +The Blank Wand Focus is your gateway to the world of Wand Focuses. diff --git a/crystals.lua b/crystals.lua index ea370cf..30d1261 100644 --- a/crystals.lua +++ b/crystals.lua @@ -86,7 +86,8 @@ local function update_contents(pos, contents) end local function crystal_rightclick(pos, node, clicker, itemstack, pointed_thing) - local meta = minetest.get_meta(pos) + local player = clicker:get_player_name() + local meta = minetest.get_meta(pos) -- Add contents to the crystal local contents = minetest.deserialize(meta:get_string("contents")) @@ -100,13 +101,19 @@ local function crystal_rightclick(pos, node, clicker, itemstack, pointed_thing) return itemstack end + -- Check if the player knows anything about the Element Ring, if not, surprise them! + local element_ring = magicalities.player_has_recipe(player, "magicalities:element_ring") + if not element_ring then + magicalities.player_learn(player, "magicalities:element_ring", true) + end + -- Check if player can preserve this crystal - local preserve = magicalities.player_has_ability(clicker:get_player_name(), "magicalities:crystal_preserve") + local preserve = magicalities.player_has_ability(player, "magicalities:crystal_preserve") local mincheck = 0 if preserve then mincheck = 1 end -- Check if we can take more than one - local draining = magicalities.player_has_ability(clicker:get_player_name(), "magicalities:crystal_draining") + local draining = magicalities.player_has_ability(player, "magicalities:crystal_draining") local maxtake = 1 if draining then maxtake = 5 end @@ -124,13 +131,17 @@ local function crystal_rightclick(pos, node, clicker, itemstack, pointed_thing) end end + local done_did = 0 local can_put = magicalities.wands.wand_insertable_contents(itemstack, one_of_each) for name, count in pairs(can_put) do if count > 0 then + done_did = done_did + count contents[name][1] = contents[name][1] - count end end + if done_did == 0 then return itemstack end + -- Take - Particles local cpls = clicker:get_pos() cpls.y = cpls.y + 1 diff --git a/focuses.lua b/focuses.lua index 1f88c90..ea19414 100644 --- a/focuses.lua +++ b/focuses.lua @@ -1,5 +1,7 @@ -- Wand Focuses +local particles = minetest.settings:get_bool("mgc_particles", true) + -- Constants -- TODO: make settings magicalities.magic_spray_count = 16 @@ -299,6 +301,7 @@ local special_fn = {} -- Particles local randparticles = PcgRandom(os.clock()) local function shoot_particles (user, velocity, color) + if not particles then return end if not color then color = "" else diff --git a/init.lua b/init.lua index 1ef4a83..62d879a 100644 --- a/init.lua +++ b/init.lua @@ -50,5 +50,8 @@ dofile(modpath.."/cauldron.lua") -- Book dofile(modpath.."/book.lua") +-- Map generation +dofile(modpath.."/mapgen.lua") + -- Register dofile(modpath.."/register.lua") diff --git a/mapgen.lua b/mapgen.lua new file mode 100644 index 0000000..49ca8bd --- /dev/null +++ b/mapgen.lua @@ -0,0 +1,16 @@ +local nostructures = minetest.settings:get_bool("mgc_skip_structures", false) + +if not nostructures then + minetest.register_decoration({ + deco_type = "schematic", + place_on = "default:dirt_with_grass", + y_min = 0, + y_max = 31000, + flags = "force_placement, all_floors", + schematic = "schems/magicalities_booktower.mts", + rotation = "random", + place_offset_y = 0, + -- what noise_params should i use instead of this? + fill_ratio = 0.00000001, + }) +end diff --git a/mod.conf b/mod.conf index 5d11338..c5eb9f5 100644 --- a/mod.conf +++ b/mod.conf @@ -1,4 +1,4 @@ name = magicalities description = Magic mod. depends = default -optional_depends = craftguide,fluid_lib,creative,mobs,mobs_animal,dye +optional_depends = craftguide,fluid_lib,creative,mobs,mobs_animal,dye,treasurer diff --git a/nodes.lua b/nodes.lua index 396e137..a115758 100644 --- a/nodes.lua +++ b/nodes.lua @@ -11,6 +11,11 @@ minetest.register_node("magicalities:tree_enchanted", { on_place = minetest.rotate_node }) +-- circumvent a weird issue +local function add_fix(inv, item) + inv:add_item("main", item) +end + -- Researchable bookshelf -- Supposed to be a generated node that gives Research Notes minetest.register_node("magicalities:bookshelf", { @@ -48,8 +53,7 @@ minetest.register_node("magicalities:bookshelf", { local inv = clicker:get_inventory() if inv:room_for_item("main", item) then - -- idk - inv:add_item("main", item) + minetest.after(0.1, add_fix, inv, item) else minetest.item_drop(item, clicker, clicker:get_pos()) end diff --git a/register.lua b/register.lua index bad2a78..ec528e5 100644 --- a/register.lua +++ b/register.lua @@ -45,7 +45,8 @@ local recipes = { ["fire"] = 15, ["dark"] = 15, ["air"] = 15, - } + }, + learnable = true }, { input = { @@ -358,7 +359,47 @@ if minetest.get_modpath("craftguide") ~= nil then end end --- Abilities +-- Treasurer mod, add Research Notes as a form of treasure. +if minetest.get_modpath("treasurer") then + treasurer.register_treasure("magicalities:note", 0.35, 5, {1,3}, nil, "tool") +end + +--------------- +-- Abilities -- +--------------- + +-- Default abilities + +magicalities.register_recipe_learnable({ + name = "magicalities:wand_steel", + description = "Wands", + default = true, +}) + +magicalities.register_ability_learnable({ + name = "magicalities:crystal", + description = "Crystal Tapping\nExtract elements from crystals", + icon = "magicalities_crystal_gui.png", + default = true, +}) + +magicalities.register_recipe_learnable({ + name = "magicalities:table", + description = "Research Table\nDo research about the magic world", + default = true, +}) + +magicalities.register_recipe_learnable({ + name = "magicalities:arcane_table", + description = "Arcane Table\nCraft magical items", + default = true, +}) + +magicalities.register_recipe_learnable({ + name = "magicalities:cauldron", + description = "Cauldron", + default = true +}) magicalities.register_ability_learnable({ name = "magicalities:crystal_preserve", @@ -379,9 +420,3 @@ magicalities.register_ability_learnable({ depends = {"magicalities:crystal_preserve"}, icon = "magicalities_jarred.png" }) - -magicalities.register_recipe_learnable({ - name = "magicalities:cauldron", - description = "Cauldron", - default = true -}) diff --git a/research_table.lua b/research_table.lua index 678e3c4..14b5e75 100644 --- a/research_table.lua +++ b/research_table.lua @@ -1,7 +1,7 @@ magicalities.researching = {} -local function genlist(list, x, y, w, h, index, canlearn) +function magicalities.researching.generate_formspec_list(list, x, y, w, h, index, canlearn, canopen) local i = "" if #list == 0 then return "" end local ty = 0 @@ -9,7 +9,7 @@ local function genlist(list, x, y, w, h, index, canlearn) local visualtotal = math.ceil(y + h) local reallist = {} - for i = index * visualtotal, visualtotal do + for i = index * visualtotal, (index * visualtotal) + visualtotal do if list[i + 1] then table.insert(reallist, list[i + 1]) end @@ -18,6 +18,12 @@ local function genlist(list, x, y, w, h, index, canlearn) for _,v in pairs(reallist) do if ty + 1 > visualtotal then break end local icon = "" + local t = 1 + if v.type == "recipe" then t = 2 end + + if canopen then + i = i .. "button["..x..","..(y+ty)..";"..w..",1;#"..t..""..v.name..";]" + end if v.icon ~= nil then icon = "image["..x..","..(y+ty)..";1,1;"..v.icon.."]" @@ -27,8 +33,6 @@ local function genlist(list, x, y, w, h, index, canlearn) i = i .. icon .. "label["..(x + 1)..","..(y+ty)..";"..v.description.."]" if canlearn then - local t = 1 - if v.type == "recipe" then t = 2 end i = i .. "button["..(x+w-1)..","..(y+ty)..";1,1;@"..t..""..v.name..";Learn]" end ty = ty + 1 @@ -37,7 +41,7 @@ local function genlist(list, x, y, w, h, index, canlearn) if index > 0 then i = i .. "button["..(x+w)..","..y..";1,1;up;Up]" elseif total > visualtotal then - i = i .. "button["..(x+w)..","..(y+h)..";1,1;dn;Down]" + i = i .. "button["..(x+w)..","..(y+h-0.25)..";1,1;dn;Down]" end return i @@ -60,7 +64,7 @@ local function table_formspec(player, research, index, canlearn) "list[context;tools;0.5,1.5;1,1;]".. "image[0.5,2.5;1,1;magicalities_gui_paper_slot.png]".. "list[context;paper;0.5,2.5;3,3;]".. - genlist(list, 1.5, 0.5, 5.5, 2, index, canlearn).. + magicalities.researching.generate_formspec_list(list, 1.5, 0.5, 5.5, 2, index, canlearn).. "list[current_player;main;0,4.25;8,1;]".. "list[current_player;main;0,5.5;8,3;8]".. "listring[current_player;main]".. @@ -254,6 +258,7 @@ end -- Base Table Override minetest.override_item("magicalities:table", { + description = "Research Table", on_construct = function (pos) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() diff --git a/schems/magicalities_booktower.mts b/schems/magicalities_booktower.mts new file mode 100644 index 0000000..13523e4 Binary files /dev/null and b/schems/magicalities_booktower.mts differ diff --git a/settingtypes.txt b/settingtypes.txt new file mode 100644 index 0000000..9d6ac5b --- /dev/null +++ b/settingtypes.txt @@ -0,0 +1,6 @@ + +# Setting this to true will prevent Magicalities' structures from being placed in the world +mgc_skip_structures (Skip generating Magicalities structures) bool false + +# Enable Magicalities' particle effects +mgc_particles (Magicalities particle effects) bool true diff --git a/textures/magicalities_book_plus.png b/textures/magicalities_book_plus.png new file mode 100644 index 0000000..530eb2a Binary files /dev/null and b/textures/magicalities_book_plus.png differ diff --git a/textures/magicalities_crystal_gui.png b/textures/magicalities_crystal_gui.png new file mode 100644 index 0000000..a4f956f Binary files /dev/null and b/textures/magicalities_crystal_gui.png differ diff --git a/wands.lua b/wands.lua index 811e23d..82e6496 100644 --- a/wands.lua +++ b/wands.lua @@ -236,8 +236,10 @@ function magicalities.wands.wand_insertable_contents(stack, to_put) for name, count in pairs(to_put) do if data_table[name] then - if data_table[name] + count < cap + 1 then + if data_table[name] + count <= cap then insertable[name] = count + elseif cap - data_table[name] > 0 then + insertable[name] = cap - data_table[name] end end end