diff --git a/mods/HELP/mcl_craftguide/init.lua b/mods/HELP/mcl_craftguide/init.lua index d7d07238d..10680426e 100644 --- a/mods/HELP/mcl_craftguide/init.lua +++ b/mods/HELP/mcl_craftguide/init.lua @@ -44,7 +44,7 @@ local min, max, floor, ceil = math.min, math.max, math.floor, math.ceil local group_stereotypes = { wool = "mcl_wool:white", carpet = "mcl_wool:white_carpet", - dye = "mcl_dye:white", + dye = "mcl_dye:red", water_bucket = "bucket:bucket_water", flower = "mcl_flowers:dandelion", mushroom = "mcl_mushrooms:mushroom_brown", @@ -53,7 +53,7 @@ local group_stereotypes = { coal = "mcl_core:coal_lump", shulker_box = "mcl_chests:violet_shulker_box", quartz_block = "mcl_nether:quartz_block", - banner = "mcl_banners:standing_banner_white", + banner = "mcl_banners:banner_item_white", mesecon_conductor_craftable = "mesecons:wire_00000000_off", compass = mcl_compass.stereotype, clock = mcl_clock.sterotype, diff --git a/mods/ITEMS/mcl_banners/init.lua b/mods/ITEMS/mcl_banners/init.lua index 81ecdc0a4..17f1d0a26 100644 --- a/mods/ITEMS/mcl_banners/init.lua +++ b/mods/ITEMS/mcl_banners/init.lua @@ -9,70 +9,36 @@ local function round(num, idp) return math.floor(num * mult + 0.5) / mult end -local colors = { - -- ID, description, wool, unified dyes color group, overlay color, - ["unicolor_white"] = {"white", "White Banner", "mcl_wool:white", "#FFFFFF" }, - ["unicolor_darkgrey"] = {"grey", "Grey Banner", "mcl_wool:grey", "#303030" }, - ["unicolor_grey"] = {"silver", "Light Grey Banner", "mcl_wool:silver", "#5B5B5B" }, - ["unicolor_black"] = {"black", "Black Banner", "mcl_wool:black", "#000000" }, - ["unicolor_red"] = {"red", "Red Banner", "mcl_wool:red", "#BC0000" }, - ["unicolor_yellow"] = {"yellow", "Yellow Banner", "mcl_wool:yellow", "#BCA800" }, - ["unicolor_dark_green"] = {"green", "Green Banner", "mcl_wool:green", "#006000" }, - ["unicolor_cyan"] = {"cyan", "Cyan Banner", "mcl_wool:cyan", "#00ACAC" }, - ["unicolor_blue"] = {"blue", "Blue Banner", "mcl_wool:blue", "#0000AC" }, - ["unicolor_red_violet"] = {"magenta", "Magenta Banner", "mcl_wool:magenta", "#AC007C" }, - ["unicolor_orange"] = {"orange", "Orange Banner", "mcl_wool:orange", "#BC6900" }, - ["unicolor_violet"] = {"purple", "Purple Banner", "mcl_wool:purple", "#6400AC" }, - ["unicolor_brown"] = {"brown", "Brown Banner", "mcl_wool:brown", "#402100" }, - ["unicolor_pink"] = {"pink", "Pink Banner", "mcl_wool:pink", "#DE557C" }, - ["unicolor_lime"] = {"lime", "Lime Banner", "mcl_wool:lime", "#30AC00"}, - ["unicolor_light_blue"] = {"light_blue", "Light Blue Banner", "mcl_wool:light_blue", "#4040CF" }, +mcl_banners = {} + +mcl_banners.colors = { + -- Format: + -- [ID] = { banner description, wool, unified dyes color group, overlay color, dye, color name for emblazonings } + ["unicolor_white"] = {"white", "White Banner", "mcl_wool:white", "#FFFFFF", "mcl_dye:white", "White" }, + ["unicolor_darkgrey"] = {"grey", "Grey Banner", "mcl_wool:grey", "#303030", "mcl_dye:dark_grey", "Grey" }, + ["unicolor_grey"] = {"silver", "Light Grey Banner", "mcl_wool:silver", "#5B5B5B", "mcl_dye:grey", "Light Grey" }, + ["unicolor_black"] = {"black", "Black Banner", "mcl_wool:black", "#000000", "mcl_dye:black", "Black" }, + ["unicolor_red"] = {"red", "Red Banner", "mcl_wool:red", "#BC0000", "mcl_dye:red", "Red" }, + ["unicolor_yellow"] = {"yellow", "Yellow Banner", "mcl_wool:yellow", "#BCA800", "mcl_dye:yellow", "Yellow" }, + ["unicolor_dark_green"] = {"green", "Green Banner", "mcl_wool:green", "#006000", "mcl_dye:dark_green", "Green" }, + ["unicolor_cyan"] = {"cyan", "Cyan Banner", "mcl_wool:cyan", "#00ACAC", "mcl_dye:cyan", "Cyan" }, + ["unicolor_blue"] = {"blue", "Blue Banner", "mcl_wool:blue", "#0000AC", "mcl_dye:blue", "Blue" }, + ["unicolor_red_violet"] = {"magenta", "Magenta Banner", "mcl_wool:magenta", "#AC007C", "mcl_dye:magenta", "Magenta"}, + ["unicolor_orange"] = {"orange", "Orange Banner", "mcl_wool:orange", "#BC6900", "mcl_dye:orange", "Orange" }, + ["unicolor_violet"] = {"purple", "Purple Banner", "mcl_wool:purple", "#6400AC", "mcl_dye:violet", "Violet" }, + ["unicolor_brown"] = {"brown", "Brown Banner", "mcl_wool:brown", "#402100", "mcl_dye:brown", "Brown" }, + ["unicolor_pink"] = {"pink", "Pink Banner", "mcl_wool:pink", "#DE557C", "mcl_dye:pink", "Pink" }, + ["unicolor_lime"] = {"lime", "Lime Banner", "mcl_wool:lime", "#30AC00", "mcl_dye:green", "Lime" }, + ["unicolor_light_blue"] = {"light_blue", "Light Blue Banner", "mcl_wool:light_blue", "#4040CF", "mcl_dye:lightblue", "Light Blue" }, } + +-- Add pattern/emblazoning crafting recipes +dofile(minetest.get_modpath("mcl_banners").."/patterncraft.lua") + -- Overlay ratios (0-255) local base_color_ratio = 224 local layer_ratio = 255 -local patterns = { - "border", - "bricks", - "circle", - "creeper", - "cross", - "curly_border", - "diagonal_left", - "diagonal_right", - "diagonal_up_left", - "diagonal_up_right", - "flower", - "gradient", - "gradient_up", - "half_horizontal_bottom", - "half_horizontal", - "half_vertical", - "half_vertical_right", - "thing", -- Symbol used: U+1F65D ๐Ÿ™ - "rhombus", - "skull", - "small_stripes", - "square_bottom_left", - "square_bottom_right", - "square_top_left", - "square_top_right", - "straight_cross", - "stripe_bottom", - "stripe_center", - "stripe_downleft", - "stripe_downright", - "stripe_left", - "stripe_middle", - "stripe_right", - "stripe_top", - "triangle_bottom", - "triangles_bottom", - "triangles_top", - "triangle_top", -} - -- After destroying the standing banner node local on_destruct_standing_banner = function(pos) -- Find this node's banner entity and make it drop as an item @@ -86,8 +52,8 @@ end local make_banner_texture = function(base_color, layers) local colorize - if colors[base_color] then - colorize = colors[base_color][4] + if mcl_banners.colors[base_color] then + colorize = mcl_banners.colors[base_color][4] end if colorize then -- Base texture with base color @@ -99,7 +65,7 @@ local make_banner_texture = function(base_color, layers) for l=1, #layers do local layerinfo = layers[l] local pattern = "mcl_banners_" .. layerinfo.pattern .. ".png" - local color = colors[layerinfo.color][4] + local color = mcl_banners.colors[layerinfo.color][4] -- Generate layer texture local layer = "(("..pattern.."^[colorize:"..color..":"..layer_ratio..")^[mask:"..pattern..")" @@ -128,7 +94,7 @@ minetest.register_node("mcl_banners:standing_banner", { wield_image = "mcl_banners_item_base.png", tiles = { "blank.png" }, selection_box = {type = "fixed", fixed= {-0.2, -0.5, -0.2, 0.2, 0.5, 0.2} }, - groups = { banner = 1, deco_block = 1, attached_node = 1, not_in_creative_inventory = 1, not_in_craft_guide = 1, }, + groups = { deco_block = 1, attached_node = 1, not_in_creative_inventory = 1, not_in_craft_guide = 1, }, stack_max = 16, sounds = node_sounds, drop = "", -- Item drops are handled in entity code @@ -138,7 +104,7 @@ minetest.register_node("mcl_banners:standing_banner", { _mcl_blast_resistance = 5, }) -for colorid, colortab in pairs(colors) do +for colorid, colortab in pairs(mcl_banners.colors) do local itemid = colortab[1] local desc = colortab[2] local wool = colortab[3] @@ -161,6 +127,8 @@ for colorid, colortab in pairs(colors) do _doc_items_longdesc = "Banners are tall decorative blocks with a solid color. They can be placed on the floor. Banners can not be emblazoned (yet).", inventory_image = inv, wield_image = inv, + -- Banner group groups together the banner items, but not the nodes. + -- Used for crafting. groups = { banner = 1, deco_block = 1, }, stack_max = 16, @@ -191,7 +159,11 @@ for colorid, colortab in pairs(colors) do place_pos.y = place_pos.y - 0.5 local banner = minetest.add_entity(place_pos, "mcl_banners:standing_banner") - banner:get_luaentity():_set_textures(colorid) + local imeta = itemstack:get_meta() + local layers_raw = imeta:get_string("layers") + local layers = minetest.deserialize(layers_raw) + banner:get_luaentity():_set_textures(colorid, layers) + -- Determine the rotation based on player's yaw local yaw = placer:get_look_horizontal() @@ -256,7 +228,7 @@ minetest.register_entity("mcl_banners:standing_banner", { pos.y = pos.y + 1 if not minetest.settings:get_bool("creative_mode") and self._base_color then - minetest.add_item(pos, "mcl_banners:banner_item_"..colors[self._base_color][1]) + minetest.add_item(pos, "mcl_banners:banner_item_"..mcl_banners.colors[self._base_color][1]) end -- Destroy entity diff --git a/mods/ITEMS/mcl_banners/patterncraft.lua b/mods/ITEMS/mcl_banners/patterncraft.lua new file mode 100644 index 000000000..6468adc64 --- /dev/null +++ b/mods/ITEMS/mcl_banners/patterncraft.lua @@ -0,0 +1,410 @@ +-- List of patterns with crafting rules + +local d = "group:dye" -- dye +local e = "" -- empty slot (one of them must contain the banner) +local patterns = { + ["border"] = { + name = "%s Bordure", + { d, d, d }, + { d, e, d }, + { d, d, d }, + }, + ["bricks"] = { + name = "%s Bricks", + type = "shapeless", + { e, "mcl_core:brick_block", d }, + }, + ["circle"] = { + name = "%s Circle", + { e, e, e }, + { e, d, e }, + { e, e, e }, + }, + ["creeper"] = { + name = "%s Creeper Charge", + type = "shapeless", + { e, "mcl_heads:creeper", d }, + }, + ["cross"] = { + name = "%s Saltire", + { d, e, d }, + { e, d, e }, + { d, e, d }, + }, + ["curly_border"] = { + name = "%s Intented Bordure", + type = "shapeless", + { e, "mcl_core:vine", d }, + }, + ["diagonal_left"] = { + name = "%s Inverted Per Bend", + { e, e, e }, + { d, e, e }, + { d, d, e }, + }, + ["diagonal_right"] = { + name = "%s Inverted Per Bend Sinister", + { e, e, e }, + { e, e, d }, + { e, d, d }, + }, + ["diagonal_up_left"] = { + name = "%s Per Bend", + { e, d, d }, + { e, e, d }, + { e, e, e }, + }, + ["diagonal_up_right"] = { + name = "%s Per Bend Sinister", + { d, d, e }, + { d, e, e }, + { e, e, e }, + }, + ["flower"] = { + name = "%s Flower Charge", + type = "shapeless", + { e, "mcl_flowers:oxeye_daisy", d }, + }, + ["gradient"] = { + name = "%s Gradient", + { d, e, d }, + { e, d, e }, + { e, d, e }, + }, + ["gradient_up"] = { + name = "%s Base Gradient", + { e, d, e }, + { e, d, e }, + { d, e, d }, + }, + ["half_horizontal_bottom"] = { + name = "%s Inverted Per Fess", + { e, e, e }, + { d, d, d }, + { d, d, d }, + }, + ["half_horizontal"] = { + name = "%s Per Fess", + { d, d, d }, + { d, d, d }, + { e, e, e }, + }, + ["half_vertical"] = { + name = "%s Per Pale", + { d, d, e }, + { d, d, e }, + { d, d, e }, + }, + ["half_vertical_right"] = { + name = "%s Inverted Per Pale", + { e, d, d }, + { e, d, d }, + { e, d, d }, + }, + ["thing"] = { + -- Symbol used for the โ€œThingโ€: U+1F65D ๐Ÿ™ + + name = "%s Thing", + type = "shapeless", + -- TODO: Replace with enchanted golden apple + { e, "mcl_core:apple_gold", d }, + }, + ["rhombus"] = { + name = "%s Lozenge", + { e, d, e }, + { d, e, d }, + { e, d, e }, + }, + ["skull"] = { + name = "%s Skull Charge", + type = "shapeless", + { e, "mcl_heads:wither_skeleton", d }, + }, + ["small_stripes"] = { + name = "%s Paly", + { d, e, d }, + { d, e, d }, + { e, e, e }, + }, + ["square_bottom_left"] = { + name = "%s Base Dexter Canton", + { e, e, e }, + { e, e, e }, + { d, e, e }, + }, + ["square_bottom_right"] = { + name = "%s Base Sinister Canton", + { e, e, e }, + { e, e, e }, + { e, e, d }, + }, + ["square_top_left"] = { + name = "%s Chief Dexter Canton", + { d, e, e }, + { e, e, e }, + { e, e, e }, + }, + ["square_top_right"] = { + name = "%s Chief Sinister Canton", + { e, e, d }, + { e, e, e }, + { e, e, e }, + }, + ["straight_cross"] = { + name = "%s Cross", + { e, d, e }, + { d, d, d }, + { e, d, e }, + }, + ["stripe_bottom"] = { + name = "%s Base", + { e, e, e }, + { e, e, e }, + { d, d, d }, + }, + ["stripe_center"] = { + name = "%s Fess", + { e, e, e }, + { d, d, d }, + { e, e, e }, + }, + ["stripe_downleft"] = { + name = "%s Bend Sinister", + { e, e, d }, + { e, d, e }, + { d, e, e }, + }, + ["stripe_downright"] = { + name = "%s Bend", + { d, e, e }, + { e, d, e }, + { e, e, d }, + }, + ["stripe_left"] = { + name = "%s Pale Dexter", + { d, e, e }, + { d, e, e }, + { d, e, e }, + }, + ["stripe_middle"] = { + name = "%s Pale", + { e, d, e }, + { e, d, e }, + { e, d, e }, + }, + ["stripe_right"] = { + name = "%s Pale Sinister", + { e, e, d }, + { e, e, d }, + { e, e, d }, + }, + ["stripe_top"] = { + name = "%s Chief", + { d, d, d }, + { e, e, e }, + { e, e, e }, + }, + ["triangle_bottom"] = { + name = "%s Chevron", + { e, e, e }, + { e, d, e }, + { d, e, d }, + }, + ["triangle_top"] = { + name = "%s Inverted Chevron", + { d, e, d }, + { e, d, e }, + { e, e, e }, + }, + ["triangles_bottom"] = { + name = "%s Base Indented", + { e, e, e }, + { d, e, d }, + { e, d, e }, + }, + ["triangles_top"] = { + name = "%s Chief Indented", + { e, d, e }, + { d, e, d }, + { e, e, e }, + }, +} + +-- Number of maximum lines in the descriptions for the banner layers. +-- To avoid huge tooltips. +local max_layer_lines = 6 + +-- Create a banner description containing all the layer names +local make_advanced_banner_description = function(description, layers) + if layers == nil or #layers == 0 then + -- No layers, revert to default + return "" + else + local layerstrings = {} + for l=1, #layers do + -- Prevent excess length description + if l > max_layer_lines then + break + end + -- Layer text line. + local color = mcl_banners.colors[layers[l].color][6] + local pattern_name = patterns[layers[l].pattern].name + -- The pattern name is a format string (e.g. โ€œ%s Baseโ€) + table.insert(layerstrings, string.format(pattern_name, color)) + end + -- Warn about missing information + if #layers == max_layer_lines + 1 then + table.insert(layerstrings, "And one addional layer") + elseif #layers > max_layer_lines + 1 then + table.insert(layerstrings, string.format("And %d addional layers", #layers - max_layer_lines)) + end + + -- Final string concatenations: Just a list of strings + local append = table.concat(layerstrings, "\n") + description = description .. "\n" .. core.colorize("#8F8F8F", append) + return description + end +end + +-- This is for handling all those complex pattern crafting recipes +local banner_pattern_craft = function(itemstack, player, old_craft_grid, craft_inv) + if minetest.get_item_group(itemstack:get_name(), "banner") ~= 1 then + return + end + + local banner, dye + local banner_index + for i = 1, player:get_inventory():get_size("craft") do + local itemname = old_craft_grid[i]:get_name() + if minetest.get_item_group(itemname, "banner") == 1 then + banner = old_craft_grid[i] + banner_index = i + -- Check if all dyes are equal + elseif minetest.get_item_group(itemname, "dye") == 1 then + if dye == nil then + dye = itemname + elseif itemname ~= dye then + return ItemStack("") + end + end + end + if not banner then + return ItemStack("") + end + + -- Get old layers + local ometa = banner:get_meta() + local layers_raw = ometa:get_string("layers") + local layers = minetest.deserialize(layers_raw) + if type(layers) ~= "table" then + layers = {} + end + + local matching_pattern + local max_i = player:get_inventory():get_size("craft") + -- Find the matching pattern + for pattern_name, pattern in pairs(patterns) do + -- Shaped / fixed + if pattern.type == nil then + local pattern_ok = true + local inv_i = 1 + -- This complex code just iterates through the pattern slots one-by-one and compares them with the pattern + for p=1, #pattern do + local row = pattern[p] + if inv_i > max_i then + break + end + for r=1, #row do + local itemname = old_craft_grid[inv_i]:get_name() + local pitem = row[r] + if (pitem == d and minetest.get_item_group(itemname, "dye") == 0) or (pitem == e and itemname ~= e and inv_i ~= banner_index) then + pattern_ok = false + break + else + end + inv_i = inv_i + 1 + end + end + -- Everything matched! We found our pattern! + if pattern_ok then + matching_pattern = pattern_name + break + end + + elseif pattern.type == "shapeless" then + -- TODO + end + + if matching_pattern then + break + end + end + if not matching_pattern then + return ItemStack("") + end + + -- Add the new layer and update other metadata + table.insert(layers, {pattern=matching_pattern, color="unicolor_yellow"}) + + local imeta = itemstack:get_meta() + imeta:set_string("layers", minetest.serialize(layers)) + + local odesc = itemstack:get_definition().description + local description = make_advanced_banner_description(odesc, layers) + imeta:set_string("description", description) + return itemstack +end + +minetest.register_craft_predict(banner_pattern_craft) +minetest.register_on_craft(banner_pattern_craft) + + +-- Register crafting recipes for all the patterns +for pattern_name, pattern in pairs(patterns) do + -- Shaped and fixed recipes + if pattern.type == nil then + for colorid, colortab in pairs(mcl_banners.colors) do + local banner = "mcl_banners:banner_item_"..colortab[1] + local bannered = false + local recipe = {} + for row_id=1, #pattern do + local row = pattern[row_id] + local newrow = {} + for r=1, #row do + if row[r] == e and not bannered then + newrow[r] = banner + bannered = true + else + newrow[r] = row[r] + end + end + table.insert(recipe, newrow) + end + minetest.register_craft({ + output = banner, + recipe = recipe, + }) + end + -- Shapeless recipes + elseif pattern.type == "shapeless" then + for colorid, colortab in pairs(mcl_banners.colors) do + local banner = "mcl_banners:banner_item_"..colortab[1] + local orig = pattern[1] + local recipe = {} + for r=1, #orig do + if orig[r] == e then + recipe[r] = banner + else + recipe[r] = orig[r] + end + end + + minetest.register_craft({ + type = "shapeless", + output = banner, + recipe = recipe, + }) + end + end +end + diff --git a/mods/ITEMS/mcl_banners/textures/mcl_banners_item_base.png b/mods/ITEMS/mcl_banners/textures/mcl_banners_item_base.png index 47f434899..31a75b37b 100644 Binary files a/mods/ITEMS/mcl_banners/textures/mcl_banners_item_base.png and b/mods/ITEMS/mcl_banners/textures/mcl_banners_item_base.png differ