2 if minetest
.get_modpath("mcl_sounds") then
3 node_sounds
= mcl_sounds
.node_sound_wood_defaults()
7 local function round(num
, idp
)
8 local mult
= 10^
(idp
or 0)
9 return math
.floor(num
* mult
+ 0.5) / mult
14 mcl_banners
.colors
= {
16 -- [ID] = { banner description, wool, unified dyes color group, overlay color, dye, color name for emblazonings }
17 ["unicolor_white"] = {"white", "White Banner", "mcl_wool:white", "#FFFFFF", "mcl_dye:white", "White" },
18 ["unicolor_darkgrey"] = {"grey", "Grey Banner", "mcl_wool:grey", "#303030", "mcl_dye:dark_grey", "Grey" },
19 ["unicolor_grey"] = {"silver", "Light Grey Banner", "mcl_wool:silver", "#5B5B5B", "mcl_dye:grey", "Light Grey" },
20 ["unicolor_black"] = {"black", "Black Banner", "mcl_wool:black", "#000000", "mcl_dye:black", "Black" },
21 ["unicolor_red"] = {"red", "Red Banner", "mcl_wool:red", "#BC0000", "mcl_dye:red", "Red" },
22 ["unicolor_yellow"] = {"yellow", "Yellow Banner", "mcl_wool:yellow", "#E6CD00", "mcl_dye:yellow", "Yellow" },
23 ["unicolor_dark_green"] = {"green", "Green Banner", "mcl_wool:green", "#006000", "mcl_dye:dark_green", "Green" },
24 ["unicolor_cyan"] = {"cyan", "Cyan Banner", "mcl_wool:cyan", "#00ACAC", "mcl_dye:cyan", "Cyan" },
25 ["unicolor_blue"] = {"blue", "Blue Banner", "mcl_wool:blue", "#0000AC", "mcl_dye:blue", "Blue" },
26 ["unicolor_red_violet"] = {"magenta", "Magenta Banner", "mcl_wool:magenta", "#AC007C", "mcl_dye:magenta", "Magenta"},
27 ["unicolor_orange"] = {"orange", "Orange Banner", "mcl_wool:orange", "#E67300", "mcl_dye:orange", "Orange" },
28 ["unicolor_violet"] = {"purple", "Purple Banner", "mcl_wool:purple", "#6400AC", "mcl_dye:violet", "Violet" },
29 ["unicolor_brown"] = {"brown", "Brown Banner", "mcl_wool:brown", "#603000", "mcl_dye:brown", "Brown" },
30 ["unicolor_pink"] = {"pink", "Pink Banner", "mcl_wool:pink", "#DE557C", "mcl_dye:pink", "Pink" },
31 ["unicolor_lime"] = {"lime", "Lime Banner", "mcl_wool:lime", "#30AC00", "mcl_dye:green", "Lime" },
32 ["unicolor_light_blue"] = {"light_blue", "Light Blue Banner", "mcl_wool:light_blue", "#4040CF", "mcl_dye:lightblue", "Light Blue" },
35 -- Add pattern/emblazoning crafting recipes
36 dofile(minetest
.get_modpath("mcl_banners").."/patterncraft.lua")
38 -- Overlay ratios (0-255)
39 local base_color_ratio
= 224
40 local layer_ratio
= 255
42 local standing_banner_entity_offset
= { x
=0, y
=-0.499, z
=0 }
43 local hanging_banner_entity_offset
= { x
=0, y
=-1.7, z
=0 }
45 local on_destruct_standing_banner
= function(pos
)
46 -- Find this node's banner entity and make it drop as an item
47 local checkpos
= vector
.add(pos
, standing_banner_entity_offset
)
48 local objects
= minetest
.get_objects_inside_radius(checkpos
, 0.5)
49 for _
, v
in ipairs(objects
) do
50 local ent
= v
:get_luaentity()
51 if ent
and ent
.name
== "mcl_banners:standing_banner" then
52 v
:get_luaentity():_drop()
57 local on_destruct_hanging_banner
= function(pos
)
58 -- Find this node's banner entity and make it drop as an item
59 local checkpos
= vector
.add(pos
, hanging_banner_entity_offset
)
60 local objects
= minetest
.get_objects_inside_radius(checkpos
, 0.5)
61 for _
, v
in ipairs(objects
) do
62 local ent
= v
:get_luaentity()
63 if ent
and ent
.name
== "mcl_banners:hanging_banner" then
64 v
:get_luaentity():_drop()
69 local make_banner_texture
= function(base_color
, layers
)
71 if mcl_banners
.colors
[base_color
] then
72 colorize
= mcl_banners
.colors
[base_color
][4]
75 -- Base texture with base color
76 local base
= "(mcl_banners_banner_base.png^[mask:mcl_banners_base_inverted.png)^((mcl_banners_banner_base.png^[colorize:"..colorize
..":"..base_color_ratio
..")^[mask:mcl_banners_base.png)"
78 -- Optional pattern layers
80 local finished_banner
= base
82 local layerinfo
= layers
[l
]
83 local pattern
= "mcl_banners_" .. layerinfo
.pattern
.. ".png"
84 local color
= mcl_banners
.colors
[layerinfo
.color
][4]
86 -- Generate layer texture
87 local layer
= "(("..pattern
.."^[colorize:"..color
..":"..layer_ratio
..")^[mask:"..pattern
..")"
89 finished_banner
= finished_banner
.. "^" .. layer
91 return { finished_banner
}
95 return { "mcl_banners_banner_base.png" }
100 if minetest
.get_modpath("screwdriver") then
101 on_rotate
= screwdriver
.disallow
105 -- These are an invisible nodes which are only used to destroy the banner entity.
106 -- All the important banner information (such as color) is stored in the entity.
107 -- It is used only used internally.
109 -- Standing banner node
110 -- This one is also used for the help entry to avoid spamming the help with 16 entries.
111 minetest
.register_node("mcl_banners:standing_banner", {
112 _doc_items_entry_name
= "Banner",
113 _doc_items_image
= "mcl_banners_item_base.png^mcl_banners_item_overlay.png",
114 _doc_items_longdesc
= "Banners are tall colorful decorative blocks. They can be placed on the floor and at walls. Banners can be emblazoned with a variety of patterns using a lot of dye in crafting.",
115 _doc_items_usagehelp
= "Use crafting to draw a pattern on top of the banner. Emblazoned banners can be emblazoned again to combine various patterns. You can draw up to 6 layers on a banner that way. You can copy the pattern of a banner by placing two banners of the same color in the crafting grid—one needs to be emblazoned, the other one must be clean. Finally, you can use a banner on a cauldron with water to wash off its top-most layer.",
117 is_ground_content
= false,
119 sunlight_propagates
= true,
120 drawtype
= "airlike",
121 inventory_image
= "mcl_banners_item_base.png",
122 wield_image
= "mcl_banners_item_base.png",
123 tiles
= { "blank.png" },
124 selection_box
= {type = "fixed", fixed
= {-0.3, -0.5, -0.3, 0.3, 0.5, 0.3} },
125 groups
= {axey
=1,handy
=1, attached_node
= 1, not_in_creative_inventory
= 1, not_in_craft_guide
= 1, material_wood
=1 },
127 sounds
= node_sounds
,
128 drop
= "", -- Item drops are handled in entity code
130 on_destruct
= on_destruct_standing_banner
,
132 _mcl_blast_resistance
= 5,
135 -- Hanging banner node
136 minetest
.register_node("mcl_banners:hanging_banner", {
138 is_ground_content
= false,
140 paramtype2
= "wallmounted",
141 sunlight_propagates
= true,
142 drawtype
= "airlike",
143 inventory_image
= "mcl_banners_item_base.png",
144 wield_image
= "mcl_banners_item_base.png",
145 tiles
= { "blank.png" },
146 selection_box
= {type = "wallmounted", wall_side
= {-0.5, -0.5, -0.5, -4/16, 0.5, 0.5} },
147 groups
= {axey
=1,handy
=1, attached_node
= 1, not_in_creative_inventory
= 1, not_in_craft_guide
= 1, material_wood
=1 },
149 sounds
= node_sounds
,
150 drop
= "", -- Item drops are handled in entity code
152 on_destruct
= on_destruct_hanging_banner
,
154 _mcl_blast_resistance
= 5,
155 on_rotate
= on_rotate
,
158 for colorid
, colortab
in pairs(mcl_banners
.colors
) do
159 local itemid
= colortab
[1]
160 local desc
= colortab
[2]
161 local wool
= colortab
[3]
162 local colorize
= colortab
[4]
164 local itemstring
= "mcl_banners:banner_item_"..itemid
167 inv
= "mcl_banners_item_base.png^(mcl_banners_item_overlay.png^[colorize:"..colorize
..")"
169 inv
= "mcl_banners_item_base.png^mcl_banners_item_overlay.png"
173 -- This is the player-visible banner item. It comes in 16 base colors.
174 -- The multiple items are really only needed for the different item images.
175 -- TODO: Combine the items into only 1 item.
176 minetest
.register_craftitem(itemstring
, {
178 _doc_items_create_entry
= false,
179 inventory_image
= inv
,
181 -- Banner group groups together the banner items, but not the nodes.
182 -- Used for crafting.
183 groups
= { banner
= 1, deco_block
= 1, },
186 on_place
= function(itemstack
, placer
, pointed_thing
)
187 local above
= pointed_thing
.above
188 local under
= pointed_thing
.under
190 local node_under
= minetest
.get_node(under
)
191 if placer
and not placer
:get_player_control().sneak
then
192 -- Use pointed node's on_rightclick function first, if present
193 if minetest
.registered_nodes
[node_under
.name
] and minetest
.registered_nodes
[node_under
.name
].on_rightclick
then
194 return minetest
.registered_nodes
[node_under
.name
].on_rightclick(under
, node_under
, placer
, itemstack
) or itemstack
197 if minetest
.get_modpath("mcl_cauldrons") then
198 -- Use banner on cauldron to remove the top-most layer. This reduces the water level by 1.
200 if node_under
.name
== "mcl_cauldrons:cauldron_3" then
201 new_node
= "mcl_cauldrons:cauldron_2"
202 elseif node_under
.name
== "mcl_cauldrons:cauldron_2" then
203 new_node
= "mcl_cauldrons:cauldron_1"
204 elseif node_under
.name
== "mcl_cauldrons:cauldron_1" then
205 new_node
= "mcl_cauldrons:cauldron"
206 elseif node_under
.name
== "mcl_cauldrons:cauldron_3r" then
207 new_node
= "mcl_cauldrons:cauldron_2r"
208 elseif node_under
.name
== "mcl_cauldrons:cauldron_2r" then
209 new_node
= "mcl_cauldrons:cauldron_1r"
210 elseif node_under
.name
== "mcl_cauldrons:cauldron_1r" then
211 new_node
= "mcl_cauldrons:cauldron"
214 local imeta
= itemstack
:get_meta()
215 local layers_raw
= imeta
:get_string("layers")
216 local layers
= minetest
.deserialize(layers_raw
)
217 if type(layers
) == "table" and #layers
> 0 then
219 imeta
:set_string("layers", minetest
.serialize(layers
))
220 local newdesc
= mcl_banners
.make_advanced_banner_description(itemstack
:get_definition().description
, layers
)
221 imeta
:set_string("description", newdesc
)
224 -- Washing off reduces the water level by 1.
225 -- (It is possible to waste water if the banner had 0 layers.)
226 minetest
.set_node(pointed_thing
.under
, {name
=new_node
})
228 -- Play sound (from mcl_potions mod)
229 minetest
.sound_play("mcl_potions_bottle_pour", {pos
=pointed_thing
.under
, gain
=0.5, max_hear_range
=16})
237 local hanging
= false
239 -- Standing or hanging banner. The placement rules are enforced by the node definitions
240 local _
, success
= minetest
.item_place_node(ItemStack("mcl_banners:standing_banner"), placer
, pointed_thing
)
242 -- Forbidden on ceiling
243 if pointed_thing
.under
.y
~= pointed_thing
.above
.y
then
246 _
, success
= minetest
.item_place_node(ItemStack("mcl_banners:hanging_banner"), placer
, pointed_thing
)
254 if minetest
.registered_nodes
[node_under
.name
].buildable_to
then
260 place_pos
= vector
.add(place_pos
, hanging_banner_entity_offset
)
262 place_pos
= vector
.add(place_pos
, standing_banner_entity_offset
)
267 banner
= minetest
.add_entity(place_pos
, "mcl_banners:hanging_banner")
269 banner
= minetest
.add_entity(place_pos
, "mcl_banners:standing_banner")
271 local imeta
= itemstack
:get_meta()
272 local layers_raw
= imeta
:get_string("layers")
273 local layers
= minetest
.deserialize(layers_raw
)
274 banner
:get_luaentity():_set_textures(colorid
, layers
)
279 local pdir
= vector
.direction(pointed_thing
.under
, pointed_thing
.above
)
280 final_yaw
= minetest
.dir_to_yaw(pdir
)
282 -- Determine the rotation based on player's yaw
283 local yaw
= placer
:get_look_horizontal()
284 -- Select one of 16 possible rotations (0-15)
285 local rotation_level
= round((yaw
/ (math
.pi
*2)) * 16)
286 final_yaw
= (rotation_level
* (math
.pi
/8)) + math
.pi
288 banner
:set_yaw(final_yaw
)
290 if not minetest
.settings
:get_bool("creative_mode") then
291 itemstack
:take_item()
293 minetest
.sound_play({name
="default_place_node_hard", gain
=1.0}, {pos
= place_pos
})
299 if minetest
.get_modpath("mcl_core") and minetest
.get_modpath("mcl_wool") then
300 minetest
.register_craft({
303 { wool
, wool
, wool
},
304 { wool
, wool
, wool
},
305 { "", "mcl_core:stick", "" },
310 if minetest
.get_modpath("doc") then
311 -- Add item to node alias
312 doc
.add_entry_alias("nodes", "mcl_banners:standing_banner", "craftitems", itemstring
)
316 if minetest
.get_modpath("doc") then
317 -- Add item to node alias
318 doc
.add_entry_alias("nodes", "mcl_banners:standing_banner", "nodes", "mcl_banners:hanging_banner")
323 local entity_standing
= {
325 collide_with_objects
= false,
327 mesh
= "amc_banner.b3d",
328 visual_size
= { x
=2.499, y
=2.499 },
329 textures
= make_banner_texture(),
330 collisionbox
= { 0, 0, 0, 0, 0, 0 },
332 _base_color
= nil, -- base color of banner
333 _layers
= nil, -- table of layers painted over the base color.
334 -- This is a table of tables with each table having the following fields:
335 -- color: layer color ID (see colors table above)
336 -- pattern: name of pattern (see list above)
338 get_staticdata
= function(self
)
339 local out
= { _base_color
= self
._base_color
, _layers
= self
._layers
}
340 return minetest
.serialize(out
)
342 on_activate
= function(self
, staticdata
)
343 if staticdata
and staticdata
~= "" then
344 local inp
= minetest
.deserialize(staticdata
)
345 self
._base_color
= inp
._base_color
346 self
._layers
= inp
._layers
347 self
.object
:set_properties({
348 textures
= make_banner_texture(self
._base_color
, self
._layers
),
351 -- Make banner slowly swing
352 self
.object
:set_animation({x
=0, y
=80}, 25)
353 self
.object
:set_armor_groups({immortal
=1})
356 -- This is a custom function which causes the banner to be dropped as item and destroys the entity.
357 _drop
= function(self
)
358 local pos
= self
.object
:getpos()
361 if not minetest
.settings
:get_bool("creative_mode") and self
._base_color
then
363 local banner
= ItemStack("mcl_banners:banner_item_"..mcl_banners
.colors
[self
._base_color
][1])
364 local meta
= banner
:get_meta()
365 meta
:set_string("layers", minetest
.serialize(self
._layers
))
366 meta
:set_string("description", mcl_banners
.make_advanced_banner_description(banner
:get_definition().description
, self
._layers
))
368 minetest
.add_item(pos
, banner
)
375 -- Set the banner textures. This function can be used by external mods.
376 -- Meaning of parameters:
377 -- * self: Lua entity reference to entity.
378 -- * other parameters: Same meaning as in make_banner_texture
379 _set_textures
= function(self
, base_color
, layers
)
381 self
._base_color
= base_color
384 self
._layers
= layers
386 self
.object
:set_properties({textures
= make_banner_texture(self
._base_color
, self
._layers
)})
389 minetest
.register_entity("mcl_banners:standing_banner", entity_standing
)
391 local entity_hanging
= table.copy(entity_standing
)
392 entity_hanging
.mesh
= "amc_banner_hanging.b3d"
393 minetest
.register_entity("mcl_banners:hanging_banner", entity_hanging
)
395 minetest
.register_craft({
397 recipe
= "group:banner",