2021-05-29 14:12:33 +00:00
local modname = minetest.get_current_modname ( )
local modpath = minetest.get_modpath ( modname )
local S = minetest.get_translator ( modname )
2019-03-14 03:47:56 +00:00
local N = function ( s ) return s end
2019-03-07 20:35:02 +00:00
2021-05-29 14:12:33 +00:00
local mod_mcl_core = minetest.get_modpath ( " mcl_core " )
local mod_doc = minetest.get_modpath ( " doc " )
2017-07-27 04:14:42 +00:00
local node_sounds
if minetest.get_modpath ( " mcl_sounds " ) then
node_sounds = mcl_sounds.node_sound_wood_defaults ( )
end
-- Helper function
local function round ( num , idp )
local mult = 10 ^ ( idp or 0 )
return math.floor ( num * mult + 0.5 ) / mult
end
2017-07-28 23:24:52 +00:00
mcl_banners = { }
mcl_banners.colors = {
-- Format:
-- [ID] = { banner description, wool, unified dyes color group, overlay color, dye, color name for emblazonings }
2019-03-14 03:47:56 +00:00
[ " unicolor_white " ] = { " white " , S ( " White Banner " ) , " mcl_wool:white " , " #FFFFFF " , " mcl_dye:white " , N ( " White " ) } ,
[ " unicolor_darkgrey " ] = { " grey " , S ( " Grey Banner " ) , " mcl_wool:grey " , " #303030 " , " mcl_dye:dark_grey " , N ( " Grey " ) } ,
[ " unicolor_grey " ] = { " silver " , S ( " Light Grey Banner " ) , " mcl_wool:silver " , " #5B5B5B " , " mcl_dye:grey " , N ( " Light Grey " ) } ,
[ " unicolor_black " ] = { " black " , S ( " Black Banner " ) , " mcl_wool:black " , " #000000 " , " mcl_dye:black " , N ( " Black " ) } ,
[ " unicolor_red " ] = { " red " , S ( " Red Banner " ) , " mcl_wool:red " , " #BC0000 " , " mcl_dye:red " , N ( " Red " ) } ,
[ " unicolor_yellow " ] = { " yellow " , S ( " Yellow Banner " ) , " mcl_wool:yellow " , " #E6CD00 " , " mcl_dye:yellow " , N ( " Yellow " ) } ,
[ " unicolor_dark_green " ] = { " green " , S ( " Green Banner " ) , " mcl_wool:green " , " #006000 " , " mcl_dye:dark_green " , N ( " Green " ) } ,
[ " unicolor_cyan " ] = { " cyan " , S ( " Cyan Banner " ) , " mcl_wool:cyan " , " #00ACAC " , " mcl_dye:cyan " , N ( " Cyan " ) } ,
[ " unicolor_blue " ] = { " blue " , S ( " Blue Banner " ) , " mcl_wool:blue " , " #0000AC " , " mcl_dye:blue " , N ( " Blue " ) } ,
[ " unicolor_red_violet " ] = { " magenta " , S ( " Magenta Banner " ) , " mcl_wool:magenta " , " #AC007C " , " mcl_dye:magenta " , N ( " Magenta " ) } ,
[ " unicolor_orange " ] = { " orange " , S ( " Orange Banner " ) , " mcl_wool:orange " , " #E67300 " , " mcl_dye:orange " , N ( " Orange " ) } ,
[ " unicolor_violet " ] = { " purple " , S ( " Purple Banner " ) , " mcl_wool:purple " , " #6400AC " , " mcl_dye:violet " , N ( " Violet " ) } ,
[ " unicolor_brown " ] = { " brown " , S ( " Brown Banner " ) , " mcl_wool:brown " , " #603000 " , " mcl_dye:brown " , N ( " Brown " ) } ,
[ " unicolor_pink " ] = { " pink " , S ( " Pink Banner " ) , " mcl_wool:pink " , " #DE557C " , " mcl_dye:pink " , N ( " Pink " ) } ,
[ " unicolor_lime " ] = { " lime " , S ( " Lime Banner " ) , " mcl_wool:lime " , " #30AC00 " , " mcl_dye:green " , N ( " Lime " ) } ,
[ " unicolor_light_blue " ] = { " light_blue " , S ( " Light Blue Banner " ) , " mcl_wool:light_blue " , " #4040CF " , " mcl_dye:lightblue " , N ( " Light Blue " ) } ,
2017-07-28 23:24:52 +00:00
}
2021-03-24 04:44:56 +00:00
local pattern_names = {
" " ,
" border " ,
" bricks " ,
" circle " ,
" creeper " ,
" cross " ,
" curly_border " ,
" diagonal_up_left " ,
" diagonal_up_right " ,
" diagonal_right " ,
" diagonal_left " ,
" flower " ,
" gradient " ,
" gradient_up " ,
" half_horizontal_bottom " ,
" half_horizontal " ,
" half_vertical " ,
" half_vertical_right " ,
" thing " ,
" 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 " ,
" triangle_top " ,
" triangles_bottom " ,
" triangles_top " ,
}
2019-02-18 22:32:18 +00:00
local colors_reverse = { }
for k , v in pairs ( mcl_banners.colors ) do
colors_reverse [ " mcl_banners:banner_item_ " .. v [ 1 ] ] = k
end
2017-07-28 23:24:52 +00:00
-- Add pattern/emblazoning crafting recipes
2021-05-29 14:12:33 +00:00
dofile ( modpath .. " /patterncraft.lua " )
2017-07-28 23:24:52 +00:00
2017-07-28 01:59:22 +00:00
-- Overlay ratios (0-255)
local base_color_ratio = 224
local layer_ratio = 255
2017-07-27 17:13:41 +00:00
2017-07-31 01:51:06 +00:00
local standing_banner_entity_offset = { x = 0 , y =- 0.499 , z = 0 }
local hanging_banner_entity_offset = { x = 0 , y =- 1.7 , z = 0 }
2017-07-29 13:33:39 +00:00
2021-05-27 22:34:58 +00:00
local function rotation_level_to_yaw ( rotation_level )
2019-12-09 17:27:30 +00:00
return ( rotation_level * ( math.pi / 8 ) ) + math.pi
end
2021-05-27 22:34:58 +00:00
local function on_dig_banner ( pos , node , digger )
2019-03-01 16:31:31 +00:00
-- Check protection
local name = digger : get_player_name ( )
if minetest.is_protected ( pos , name ) then
2019-03-04 05:07:44 +00:00
minetest.record_protection_violation ( pos , name )
2019-03-01 16:31:31 +00:00
return
end
-- Drop item
local meta = minetest.get_meta ( pos )
local item = meta : get_inventory ( ) : get_stack ( " banner " , 1 )
if not item : is_empty ( ) then
minetest.handle_node_drops ( pos , { item : to_string ( ) } , digger )
else
2019-12-09 21:34:56 +00:00
minetest.handle_node_drops ( pos , { " mcl_banners:banner_item_white " } , digger )
2019-03-01 16:31:31 +00:00
end
-- Remove node
minetest.remove_node ( pos )
end
2021-05-27 22:34:58 +00:00
local function on_destruct_banner ( pos , hanging )
2019-02-18 22:32:18 +00:00
local offset , nodename
if hanging then
offset = hanging_banner_entity_offset
nodename = " mcl_banners:hanging_banner "
else
offset = standing_banner_entity_offset
nodename = " mcl_banners:standing_banner "
end
2019-03-01 16:31:31 +00:00
-- Find this node's banner entity and remove it
2019-02-18 22:32:18 +00:00
local checkpos = vector.add ( pos , offset )
2017-07-31 01:51:06 +00:00
local objects = minetest.get_objects_inside_radius ( checkpos , 0.5 )
for _ , v in ipairs ( objects ) do
2017-08-18 19:58:20 +00:00
local ent = v : get_luaentity ( )
2019-02-18 22:32:18 +00:00
if ent and ent.name == nodename then
v : remove ( )
2017-07-31 01:51:06 +00:00
end
end
2019-02-18 22:32:18 +00:00
end
2021-05-27 22:34:58 +00:00
local function on_destruct_standing_banner ( pos )
2019-02-18 22:32:18 +00:00
return on_destruct_banner ( pos , false )
2017-07-31 01:51:06 +00:00
end
2021-05-27 22:34:58 +00:00
local function on_destruct_hanging_banner ( pos )
2019-02-18 22:32:18 +00:00
return on_destruct_banner ( pos , true )
2017-07-27 17:13:41 +00:00
end
2017-07-27 04:14:42 +00:00
2021-05-27 22:34:58 +00:00
local function make_banner_texture ( base_color , layers )
2017-07-27 17:13:41 +00:00
local colorize
2017-07-28 15:23:13 +00:00
if mcl_banners.colors [ base_color ] then
colorize = mcl_banners.colors [ base_color ] [ 4 ]
2017-07-27 17:13:41 +00:00
end
if colorize then
2017-07-27 21:09:48 +00:00
-- Base texture with base color
2017-07-28 01:59:22 +00:00
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) "
2017-07-27 21:09:48 +00:00
-- Optional pattern layers
if layers then
local finished_banner = base
for l = 1 , # layers do
local layerinfo = layers [ l ]
2017-07-28 01:41:36 +00:00
local pattern = " mcl_banners_ " .. layerinfo.pattern .. " .png "
2017-07-28 15:23:13 +00:00
local color = mcl_banners.colors [ layerinfo.color ] [ 4 ]
2017-07-27 21:09:48 +00:00
-- Generate layer texture
2017-07-28 01:59:22 +00:00
local layer = " (( " .. pattern .. " ^[colorize: " .. color .. " : " .. layer_ratio .. " )^[mask: " .. pattern .. " ) "
2017-07-27 21:09:48 +00:00
finished_banner = finished_banner .. " ^ " .. layer
end
return { finished_banner }
end
return { base }
2017-07-27 17:13:41 +00:00
else
return { " mcl_banners_banner_base.png " }
end
end
2017-07-27 04:14:42 +00:00
2021-05-27 22:34:58 +00:00
local function spawn_banner_entity ( pos , hanging , itemstack )
2019-02-18 22:32:18 +00:00
local banner
if hanging then
banner = minetest.add_entity ( pos , " mcl_banners:hanging_banner " )
else
banner = minetest.add_entity ( pos , " mcl_banners:standing_banner " )
end
if banner == nil then
return banner
end
local imeta = itemstack : get_meta ( )
local layers_raw = imeta : get_string ( " layers " )
local layers = minetest.deserialize ( layers_raw )
local colorid = colors_reverse [ itemstack : get_name ( ) ]
banner : get_luaentity ( ) : _set_textures ( colorid , layers )
local mname = imeta : get_string ( " name " )
2021-05-29 14:12:33 +00:00
if mname and mname ~= " " then
2019-02-18 22:32:18 +00:00
banner : get_luaentity ( ) . _item_name = mname
banner : get_luaentity ( ) . _item_description = imeta : get_string ( " description " )
end
return banner
end
2021-05-27 22:34:58 +00:00
local function respawn_banner_entity ( pos , node , force )
2019-02-18 22:32:18 +00:00
local hanging = node.name == " mcl_banners:hanging_banner "
local offset
if hanging then
offset = hanging_banner_entity_offset
else
offset = standing_banner_entity_offset
end
-- Check if a banner entity already exists
local bpos = vector.add ( pos , offset )
local objects = minetest.get_objects_inside_radius ( bpos , 0.5 )
for _ , v in ipairs ( objects ) do
local ent = v : get_luaentity ( )
if ent and ( ent.name == " mcl_banners:standing_banner " or ent.name == " mcl_banners:hanging_banner " ) then
2019-12-09 17:27:30 +00:00
if force then
v : remove ( )
else
return
end
2019-02-18 22:32:18 +00:00
end
end
-- Spawn new entity
local meta = minetest.get_meta ( pos )
local banner_item = meta : get_inventory ( ) : get_stack ( " banner " , 1 )
local banner_entity = spawn_banner_entity ( bpos , hanging , banner_item )
-- Set rotation
local rotation_level = meta : get_int ( " rotation_level " )
2019-12-09 17:27:30 +00:00
local final_yaw = rotation_level_to_yaw ( rotation_level )
2019-02-18 22:32:18 +00:00
banner_entity : set_yaw ( final_yaw )
end
2017-07-31 01:51:06 +00:00
-- Banner nodes.
-- These are an invisible nodes which are only used to destroy the banner entity.
2017-07-27 19:48:20 +00:00
-- All the important banner information (such as color) is stored in the entity.
-- It is used only used internally.
2017-07-31 01:51:06 +00:00
-- Standing banner node
-- This one is also used for the help entry to avoid spamming the help with 16 entries.
2017-07-27 19:48:20 +00:00
minetest.register_node ( " mcl_banners:standing_banner " , {
2020-03-08 02:18:47 +00:00
_doc_items_entry_name = S ( " Banner " ) ,
2017-07-29 01:39:03 +00:00
_doc_items_image = " mcl_banners_item_base.png^mcl_banners_item_overlay.png " ,
2019-03-07 20:35:02 +00:00
_doc_items_longdesc = S ( " 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. " ) ,
_doc_items_usagehelp = S ( " 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 12 layers on a banner that way. If the banner includes a gradient, only 3 layers are possible. " ) .. " \n " ..
S ( " 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. " ) ,
2017-07-27 19:48:20 +00:00
walkable = false ,
is_ground_content = false ,
paramtype = " light " ,
sunlight_propagates = true ,
2018-05-12 23:52:38 +00:00
drawtype = " nodebox " ,
-- Nodebox is drawn as fallback when the entity is missing, so that the
-- banner node is never truly invisible.
-- If the entity is drawn, the nodebox disappears within the real banner mesh.
node_box = {
type = " fixed " ,
fixed = { - 1 / 32 , - 0.49 , - 1 / 32 , 1 / 32 , 1.49 , 1 / 32 } ,
} ,
-- This texture is based on the banner base texture
tiles = { " mcl_banners_fallback_wood.png " } ,
2017-07-27 19:48:20 +00:00
inventory_image = " mcl_banners_item_base.png " ,
wield_image = " mcl_banners_item_base.png " ,
2018-05-12 23:52:38 +00:00
2017-07-31 02:14:04 +00:00
selection_box = { type = " fixed " , fixed = { - 0.3 , - 0.5 , - 0.3 , 0.3 , 0.5 , 0.3 } } ,
2020-04-18 21:24:42 +00:00
groups = { axey = 1 , handy = 1 , attached_node = 1 , not_in_creative_inventory = 1 , not_in_craft_guide = 1 , material_wood = 1 , dig_by_piston = 1 , flammable =- 1 } ,
2017-07-27 19:48:20 +00:00
stack_max = 16 ,
sounds = node_sounds ,
drop = " " , -- Item drops are handled in entity code
2019-03-01 16:31:31 +00:00
on_dig = on_dig_banner ,
2017-07-27 19:48:20 +00:00
on_destruct = on_destruct_standing_banner ,
2019-02-18 22:32:18 +00:00
on_punch = function ( pos , node )
respawn_banner_entity ( pos , node )
end ,
2017-07-27 19:48:20 +00:00
_mcl_hardness = 1 ,
2020-04-17 19:40:13 +00:00
_mcl_blast_resistance = 1 ,
2019-12-09 17:27:30 +00:00
on_rotate = function ( pos , node , user , mode , param2 )
if mode == screwdriver.ROTATE_FACE then
local meta = minetest.get_meta ( pos )
local rot = meta : get_int ( " rotation_level " )
rot = ( rot - 1 ) % 16
meta : set_int ( " rotation_level " , rot )
respawn_banner_entity ( pos , node , true )
return true
else
return false
end
end ,
2017-07-27 19:48:20 +00:00
} )
2017-07-31 01:51:06 +00:00
-- Hanging banner node
minetest.register_node ( " mcl_banners:hanging_banner " , {
walkable = false ,
is_ground_content = false ,
paramtype = " light " ,
paramtype2 = " wallmounted " ,
sunlight_propagates = true ,
2018-05-12 23:52:38 +00:00
drawtype = " nodebox " ,
2017-07-31 01:51:06 +00:00
inventory_image = " mcl_banners_item_base.png " ,
wield_image = " mcl_banners_item_base.png " ,
2018-05-12 23:52:38 +00:00
tiles = { " mcl_banners_fallback_wood.png " } ,
node_box = {
type = " wallmounted " ,
wall_side = { - 0.49 , 0.41 , - 0.49 , - 0.41 , 0.49 , 0.49 } ,
wall_top = { - 0.49 , 0.41 , - 0.49 , - 0.41 , 0.49 , 0.49 } ,
wall_bottom = { - 0.49 , - 0.49 , - 0.49 , - 0.41 , - 0.41 , 0.49 } ,
} ,
2017-07-31 01:51:06 +00:00
selection_box = { type = " wallmounted " , wall_side = { - 0.5 , - 0.5 , - 0.5 , - 4 / 16 , 0.5 , 0.5 } } ,
2020-04-18 21:24:42 +00:00
groups = { axey = 1 , handy = 1 , attached_node = 1 , not_in_creative_inventory = 1 , not_in_craft_guide = 1 , material_wood = 1 , flammable =- 1 } ,
2017-07-31 01:51:06 +00:00
stack_max = 16 ,
sounds = node_sounds ,
drop = " " , -- Item drops are handled in entity code
2019-03-01 16:31:31 +00:00
on_dig = on_dig_banner ,
2017-07-31 01:51:06 +00:00
on_destruct = on_destruct_hanging_banner ,
2019-02-18 22:32:18 +00:00
on_punch = function ( pos , node )
respawn_banner_entity ( pos , node )
end ,
2017-07-31 01:51:06 +00:00
_mcl_hardness = 1 ,
2020-04-17 19:40:13 +00:00
_mcl_blast_resistance = 1 ,
2019-12-09 17:27:30 +00:00
on_rotate = function ( pos , node , user , mode , param2 )
if mode == screwdriver.ROTATE_FACE then
local r = screwdriver.rotate . wallmounted ( pos , node , mode )
node.param2 = r
minetest.swap_node ( pos , node )
local meta = minetest.get_meta ( pos )
local rot = 0
if node.param2 == 2 then
rot = 12
elseif node.param2 == 3 then
rot = 4
elseif node.param2 == 4 then
rot = 0
elseif node.param2 == 5 then
rot = 8
end
meta : set_int ( " rotation_level " , rot )
respawn_banner_entity ( pos , node , true )
return true
else
return false
end
end ,
2017-07-31 01:51:06 +00:00
} )
2021-03-24 04:44:56 +00:00
-- for pattern_name, pattern in pairs(patterns) do
2017-07-28 15:23:13 +00:00
for colorid , colortab in pairs ( mcl_banners.colors ) do
2021-03-24 04:44:56 +00:00
for i , pattern_name in ipairs ( pattern_names ) do
2017-07-27 17:13:41 +00:00
local itemid = colortab [ 1 ]
local desc = colortab [ 2 ]
local wool = colortab [ 3 ]
local colorize = colortab [ 4 ]
2021-03-24 04:44:56 +00:00
local itemstring
if pattern_name == " " then
itemstring = " mcl_banners:banner_item_ " .. itemid
else
itemstring = " mcl_banners:banner_preview " .. " _ " .. pattern_name .. " _ " .. itemid
end
2017-07-27 17:13:41 +00:00
local inv
2021-03-24 04:44:56 +00:00
local base
local finished_banner
if pattern_name == " " then
if colorize then
-- Base texture with base color
base = " mcl_banners_item_base.png^(mcl_banners_item_overlay.png^[colorize: " .. colorize .. " )^[resize:32x32 "
else
base = " mcl_banners_item_base.png^mcl_banners_item_overlay.png^[resize:32x32 "
end
finished_banner = base
2017-07-27 17:13:41 +00:00
else
2021-03-24 04:44:56 +00:00
-- Banner item preview background
base = " mcl_banners_item_base.png^(mcl_banners_item_overlay.png^[colorize:#CCCCCC)^[resize:32x32 "
desc = S ( " Preview Banner " )
local pattern = " mcl_banners_ " .. pattern_name .. " .png "
local color = colorize
-- Generate layer texture
-- TODO: The layer texture in the icon is squished
-- weirdly because the width/height aspect ratio of
-- the banner icon is 1:1.5, whereas the aspect ratio
-- of the banner entity is 1:2. A solution would be to
-- redraw the pattern textures as low-resolution pixel
-- art and use that instead.
local layer = " (([combine:20x40:-2,-2= " .. pattern .. " ^[resize:16x24^[colorize: " .. color .. " : " .. layer_ratio .. " )) "
function escape ( text )
return text : gsub ( " %^ " , " \\ %^ " ) : gsub ( " : " , " \\ : " ) -- :gsub("%(", "\\%("):gsub("%)", "\\%)")
end
finished_banner = " [combine:32x32:0,0= " .. escape ( base ) .. " :8,4= " .. escape ( layer )
2017-07-27 17:13:41 +00:00
end
2021-03-24 04:44:56 +00:00
inv = finished_banner
2017-07-27 19:48:20 +00:00
-- Banner items.
2021-03-24 04:44:56 +00:00
-- This is the player-visible banner item. It comes in 16 base colors with a lot of patterns.
2017-07-27 19:48:20 +00:00
-- The multiple items are really only needed for the different item images.
-- TODO: Combine the items into only 1 item.
2021-03-24 04:44:56 +00:00
local groups
if pattern_name == " " then
groups = { banner = 1 , deco_block = 1 , flammable = - 1 }
else
groups = { not_in_creative_inventory = 1 }
end
2017-07-27 19:48:20 +00:00
minetest.register_craftitem ( itemstring , {
2017-07-27 19:18:24 +00:00
description = desc ,
2020-03-08 02:18:47 +00:00
_tt_help = S ( " Paintable decoration " ) ,
2017-07-29 01:39:03 +00:00
_doc_items_create_entry = false ,
2017-07-27 19:18:24 +00:00
inventory_image = inv ,
wield_image = inv ,
2017-07-28 02:52:19 +00:00
-- Banner group groups together the banner items, but not the nodes.
-- Used for crafting.
2021-03-24 04:44:56 +00:00
groups = groups ,
2017-07-27 19:18:24 +00:00
stack_max = 16 ,
on_place = function ( itemstack , placer , pointed_thing )
local above = pointed_thing.above
local under = pointed_thing.under
local node_under = minetest.get_node ( under )
if placer and not placer : get_player_control ( ) . sneak then
2017-07-28 22:47:47 +00:00
-- Use pointed node's on_rightclick function first, if present
2017-07-27 19:18:24 +00:00
if minetest.registered_nodes [ node_under.name ] and minetest.registered_nodes [ node_under.name ] . on_rightclick then
return minetest.registered_nodes [ node_under.name ] . on_rightclick ( under , node_under , placer , itemstack ) or itemstack
end
2017-07-28 22:47:47 +00:00
if minetest.get_modpath ( " mcl_cauldrons " ) then
-- Use banner on cauldron to remove the top-most layer. This reduces the water level by 1.
local new_node
if node_under.name == " mcl_cauldrons:cauldron_3 " then
new_node = " mcl_cauldrons:cauldron_2 "
elseif node_under.name == " mcl_cauldrons:cauldron_2 " then
new_node = " mcl_cauldrons:cauldron_1 "
elseif node_under.name == " mcl_cauldrons:cauldron_1 " then
new_node = " mcl_cauldrons:cauldron "
2017-11-30 18:59:50 +00:00
elseif node_under.name == " mcl_cauldrons:cauldron_3r " then
new_node = " mcl_cauldrons:cauldron_2r "
elseif node_under.name == " mcl_cauldrons:cauldron_2r " then
new_node = " mcl_cauldrons:cauldron_1r "
elseif node_under.name == " mcl_cauldrons:cauldron_1r " then
new_node = " mcl_cauldrons:cauldron "
2017-07-28 22:47:47 +00:00
end
if new_node then
local imeta = itemstack : get_meta ( )
local layers_raw = imeta : get_string ( " layers " )
local layers = minetest.deserialize ( layers_raw )
if type ( layers ) == " table " and # layers > 0 then
table.remove ( layers )
imeta : set_string ( " layers " , minetest.serialize ( layers ) )
local newdesc = mcl_banners.make_advanced_banner_description ( itemstack : get_definition ( ) . description , layers )
2018-02-02 04:07:58 +00:00
local mname = imeta : get_string ( " name " )
-- Don't change description if item has a name
if mname == " " then
imeta : set_string ( " description " , newdesc )
end
2017-07-28 22:47:47 +00:00
end
-- Washing off reduces the water level by 1.
-- (It is possible to waste water if the banner had 0 layers.)
minetest.set_node ( pointed_thing.under , { name = new_node } )
2017-07-29 00:00:07 +00:00
-- Play sound (from mcl_potions mod)
2020-04-06 22:55:45 +00:00
minetest.sound_play ( " mcl_potions_bottle_pour " , { pos = pointed_thing.under , gain = 0.5 , max_hear_range = 16 } , true )
2017-07-29 00:00:07 +00:00
2017-07-28 22:47:47 +00:00
return itemstack
end
end
2017-07-27 19:18:24 +00:00
end
-- Place the node!
2017-07-31 01:51:06 +00:00
local hanging = false
2017-07-31 02:07:17 +00:00
-- Standing or hanging banner. The placement rules are enforced by the node definitions
2017-07-27 19:48:20 +00:00
local _ , success = minetest.item_place_node ( ItemStack ( " mcl_banners:standing_banner " ) , placer , pointed_thing )
2017-07-27 19:18:24 +00:00
if not success then
2017-07-31 02:07:17 +00:00
-- Forbidden on ceiling
if pointed_thing.under . y ~= pointed_thing.above . y then
return itemstack
end
2017-07-31 01:51:06 +00:00
_ , success = minetest.item_place_node ( ItemStack ( " mcl_banners:hanging_banner " ) , placer , pointed_thing )
if not success then
return itemstack
end
hanging = true
2017-07-27 19:18:24 +00:00
end
local place_pos
if minetest.registered_nodes [ node_under.name ] . buildable_to then
place_pos = under
else
place_pos = above
end
2019-02-18 22:32:18 +00:00
local bnode = minetest.get_node ( place_pos )
if bnode.name ~= " mcl_banners:standing_banner " and bnode.name ~= " mcl_banners:hanging_banner " then
minetest.log ( " error " , " [mcl_banners] The placed banner node is not what the mod expected! " )
return itemstack
2017-07-31 01:51:06 +00:00
end
2019-02-18 22:32:18 +00:00
local meta = minetest.get_meta ( place_pos )
local inv = meta : get_inventory ( )
inv : set_size ( " banner " , 1 )
local store_stack = ItemStack ( itemstack )
store_stack : set_count ( 1 )
inv : set_stack ( " banner " , 1 , store_stack )
-- Spawn entity
local entity_place_pos
2017-07-31 01:51:06 +00:00
if hanging then
2019-02-18 22:32:18 +00:00
entity_place_pos = vector.add ( place_pos , hanging_banner_entity_offset )
2017-07-31 01:59:43 +00:00
else
2019-02-18 22:32:18 +00:00
entity_place_pos = vector.add ( place_pos , standing_banner_entity_offset )
2017-07-31 01:51:06 +00:00
end
2019-02-18 22:32:18 +00:00
local banner_entity = spawn_banner_entity ( entity_place_pos , hanging , itemstack )
2017-07-31 01:51:06 +00:00
-- Set rotation
2019-02-18 22:32:18 +00:00
local final_yaw , rotation_level
2017-07-31 01:51:06 +00:00
if hanging then
local pdir = vector.direction ( pointed_thing.under , pointed_thing.above )
final_yaw = minetest.dir_to_yaw ( pdir )
2019-02-18 22:32:18 +00:00
if pdir.x > 0 then
rotation_level = 4
elseif pdir.z > 0 then
rotation_level = 8
elseif pdir.x < 0 then
rotation_level = 12
else
rotation_level = 0
end
2017-07-31 01:51:06 +00:00
else
-- Determine the rotation based on player's yaw
local yaw = placer : get_look_horizontal ( )
-- Select one of 16 possible rotations (0-15)
2019-02-18 22:32:18 +00:00
rotation_level = round ( ( yaw / ( math.pi * 2 ) ) * 16 )
if rotation_level >= 16 then
rotation_level = 0
end
2019-12-09 17:27:30 +00:00
final_yaw = rotation_level_to_yaw ( rotation_level )
2017-07-31 01:51:06 +00:00
end
2019-02-18 22:32:18 +00:00
meta : set_int ( " rotation_level " , rotation_level )
2021-05-29 14:12:33 +00:00
if banner_entity then
2019-02-18 22:32:18 +00:00
banner_entity : set_yaw ( final_yaw )
end
2017-07-27 19:18:24 +00:00
2020-07-10 14:08:40 +00:00
if not minetest.is_creative_enabled ( placer : get_player_name ( ) ) then
2017-07-27 19:18:24 +00:00
itemstack : take_item ( )
end
2020-04-06 22:55:45 +00:00
minetest.sound_play ( { name = " default_place_node_hard " , gain = 1.0 } , { pos = place_pos } , true )
2017-07-27 19:18:24 +00:00
return itemstack
end ,
2018-02-04 04:52:10 +00:00
_mcl_generate_description = function ( itemstack )
local meta = itemstack : get_meta ( )
local layers_raw = meta : get_string ( " layers " )
if not layers_raw then
return nil
end
local layers = minetest.deserialize ( layers_raw )
local desc = itemstack : get_definition ( ) . description
local newdesc = mcl_banners.make_advanced_banner_description ( desc , layers )
meta : set_string ( " description " , newdesc )
return newdesc
end ,
2017-07-27 17:13:41 +00:00
} )
2021-05-29 14:12:33 +00:00
if mod_mcl_core and minetest.get_modpath ( " mcl_wool " ) then
2017-07-27 17:13:41 +00:00
minetest.register_craft ( {
2017-07-27 19:48:20 +00:00
output = itemstring ,
2017-07-27 17:13:41 +00:00
recipe = {
{ wool , wool , wool } ,
{ wool , wool , wool } ,
{ " " , " mcl_core:stick " , " " } ,
}
} )
end
2017-07-29 01:39:03 +00:00
2021-05-29 14:12:33 +00:00
if mod_doc then
2017-07-29 01:39:03 +00:00
-- Add item to node alias
doc.add_entry_alias ( " nodes " , " mcl_banners:standing_banner " , " craftitems " , itemstring )
end
2021-03-24 04:44:56 +00:00
end
2017-07-27 17:13:41 +00:00
end
2017-07-27 04:14:42 +00:00
2021-05-29 14:12:33 +00:00
if mod_doc then
2017-08-28 16:09:30 +00:00
-- Add item to node alias
doc.add_entry_alias ( " nodes " , " mcl_banners:standing_banner " , " nodes " , " mcl_banners:hanging_banner " )
end
2017-07-31 01:59:43 +00:00
-- Banner entities.
local entity_standing = {
2017-07-27 04:14:42 +00:00
physical = false ,
collide_with_objects = false ,
visual = " mesh " ,
mesh = " amc_banner.b3d " ,
2017-07-27 17:13:41 +00:00
visual_size = { x = 2.499 , y = 2.499 } ,
textures = make_banner_texture ( ) ,
2019-03-07 02:53:06 +00:00
pointable = false ,
2017-07-27 04:14:42 +00:00
2017-07-28 01:41:36 +00:00
_base_color = nil , -- base color of banner
_layers = nil , -- table of layers painted over the base color.
-- This is a table of tables with each table having the following fields:
-- color: layer color ID (see colors table above)
-- pattern: name of pattern (see list above)
2017-07-27 04:14:42 +00:00
get_staticdata = function ( self )
2018-02-02 04:07:58 +00:00
local out = { _base_color = self._base_color , _layers = self._layers , _name = self._name }
2017-07-27 04:14:42 +00:00
return minetest.serialize ( out )
end ,
on_activate = function ( self , staticdata )
if staticdata and staticdata ~= " " then
local inp = minetest.deserialize ( staticdata )
self._base_color = inp._base_color
2017-07-28 01:41:36 +00:00
self._layers = inp._layers
2018-02-02 04:07:58 +00:00
self._name = inp._name
2017-07-31 01:51:06 +00:00
self.object : set_properties ( {
textures = make_banner_texture ( self._base_color , self._layers ) ,
} )
2017-07-27 04:14:42 +00:00
end
2017-07-31 01:51:06 +00:00
-- Make banner slowly swing
self.object : set_animation ( { x = 0 , y = 80 } , 25 )
2017-07-27 04:14:42 +00:00
self.object : set_armor_groups ( { immortal = 1 } )
end ,
2017-07-27 19:48:20 +00:00
2017-07-28 01:41:36 +00:00
-- Set the banner textures. This function can be used by external mods.
-- Meaning of parameters:
-- * self: Lua entity reference to entity.
-- * other parameters: Same meaning as in make_banner_texture
_set_textures = function ( self , base_color , layers )
2017-07-28 01:47:21 +00:00
if base_color then
self._base_color = base_color
2017-07-28 01:41:36 +00:00
end
2017-07-28 01:47:21 +00:00
if layers then
2017-07-28 01:41:36 +00:00
self._layers = layers
end
2017-07-28 01:47:21 +00:00
self.object : set_properties ( { textures = make_banner_texture ( self._base_color , self._layers ) } )
2017-07-28 01:41:36 +00:00
end ,
2017-07-31 01:59:43 +00:00
}
minetest.register_entity ( " mcl_banners:standing_banner " , entity_standing )
local entity_hanging = table.copy ( entity_standing )
entity_hanging.mesh = " amc_banner_hanging.b3d "
minetest.register_entity ( " mcl_banners:hanging_banner " , entity_hanging )
2017-07-27 04:14:42 +00:00
2019-02-18 22:32:18 +00:00
-- FIXME: Prevent entity destruction by /clearobjects
minetest.register_lbm ( {
label = " Respawn banner entities " ,
name = " mcl_banners:respawn_entities " ,
run_at_every_load = true ,
nodenames = { " mcl_banners:standing_banner " , " mcl_banners:hanging_banner " } ,
action = function ( pos , node )
respawn_banner_entity ( pos , node )
end ,
} )
2017-07-27 04:14:42 +00:00
minetest.register_craft ( {
type = " fuel " ,
2017-07-27 17:13:41 +00:00
recipe = " group:banner " ,
2017-07-27 04:14:42 +00:00
burntime = 15 ,
} )