VoxeLibre/mods/ITEMS/mcl_heads/init.lua
2022-08-11 17:21:23 +08:00

300 lines
10 KiB
Lua
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local S = minetest.get_translator(minetest.get_current_modname())
local minetest = minetest
local mod_doc = minetest.get_modpath("doc")
local mod_screwdriver = minetest.get_modpath("screwdriver")
local equip_armor
if minetest.get_modpath("mcl_armor") then
equip_armor = mcl_armor.equip_on_use
end
mcl_heads = {}
-- rotations of head nodes within a quadrant (0° ≤ θ ≤ 90°)
mcl_heads.FLOOR_DEGREES = { [0]='', '22_5', '45', '67_5', }
-- box of head nodes
mcl_heads.FLOOR_BOX = { -0.25, -0.5, -0.25, 0.25, 0.0, 0.25, }
-- floor head node nodedef template ------------------------------------------------------------------------------------
--- node definition template for floor mod heads
mcl_heads.deftemplate_floor = {
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = mcl_heads.FLOOR_BOX,
},
groups = {
handy = 1,
armor = 1,
armor_head = 1,
non_combat_armor = 1,
non_combat_armor_head = 1,
head = 1,
deco_block = 1,
dig_by_piston = 1,
},
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
paramtype = "light",
paramtype2 = "facedir",
stack_max = 64,
sunlight_propagates = true,
sounds = mcl_sounds.node_sound_defaults{
footstep = {name="default_hard_footstep", gain=0.3},
},
is_ground_content = false,
_mcl_armor_element = "head",
_mcl_blast_resistance = 1,
_mcl_hardness = 1,
on_secondary_use = equip_armor,
}
mcl_heads.deftemplate_floor_angled = {
drawtype = "mesh",
selection_box = {
type = "fixed",
fixed = mcl_heads.FLOOR_BOX,
},
collision_box = {
type = "fixed",
fixed = mcl_heads.FLOOR_BOX,
},
groups = {
handy = 1,
head = 1,
deco_block = 1,
dig_by_piston = 1,
not_in_creative_inventory = 1,
},
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
paramtype = "light",
paramtype2 = "facedir",
stack_max = 64,
sunlight_propagates = true,
sounds = mcl_sounds.node_sound_defaults{
footstep = {name="default_hard_footstep", gain=0.3},
},
is_ground_content = false,
_doc_items_create_entry = false,
_mcl_blast_resistance = 1,
_mcl_hardness = 1,
}
function mcl_heads.deftemplate_floor.on_rotate(pos, node, user, mode, new_param2)
if mode == screwdriver.ROTATE_AXIS then
node.name = node.name .. "_wall"
node.param2 = minetest.dir_to_wallmounted(minetest.facedir_to_dir(node.param2))
minetest.set_node(pos, node)
return true
end
end
function mcl_heads.deftemplate_floor.on_place(itemstack, placer, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
local under = pointed_thing.under
local node = minetest.get_node(under)
local def = minetest.registered_nodes[node.name]
if not def then return itemstack end
-- Allow pointed node's on_rightclick callback to override place.
if placer and not placer:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
return minetest.registered_nodes[node.name].on_rightclick(under, node, placer, itemstack) or itemstack
end
end
local above = pointed_thing.above
local dir = {x = under.x - above.x, y = under.y - above.y, z = under.z - above.z}
local wdir = minetest.dir_to_wallmounted(dir)
local itemstring = itemstack:get_name()
local placestack = ItemStack(itemstack)
-- place wall head node (elsewhere)
if wdir ~= 0 and wdir ~= 1 then
placestack:set_name(itemstring .."_wall")
itemstack = minetest.item_place(placestack, placer, pointed_thing, wdir)
-- place floor head node (floor and ceiling)
else
local fdir = minetest.dir_to_facedir(dir)
-- determine the head node rotation based on player's yaw (in cw direction from North/Z+)
local yaw = math.pi*2 - placer:get_look_horizontal()
local rotation_level = math.min(math.max(math.round((yaw / (math.pi*2)) * 16), 0), 15)
placestack:set_name(itemstring ..mcl_heads.FLOOR_DEGREES[rotation_level % 4])
-- determine the head node face direction based on rotation level
fdir = math.floor(rotation_level / 4)
itemstack = minetest.item_place(placestack, placer, pointed_thing, fdir)
end
-- restore item from angled and wall head nodes
itemstack:set_name(itemstring)
return itemstack
end
-- wall head node nodedef template -------------------------------------------------------------------------------------
--- node definition template for wall mod heads
mcl_heads.deftemplate_wall = {
drawtype = "nodebox",
node_box = {
type = "wallmounted",
wall_bottom = { -0.25, -0.5, -0.25, 0.25, 0.0, 0.25, },
wall_top = { -0.25, 0.0, -0.25, 0.25, 0.5, 0.25, },
wall_side = { -0.5, -0.25, -0.25, 0.0, 0.25, 0.25, },
},
groups = {
handy = 1,
head = 1,
deco_block = 1,
dig_by_piston = 1,
not_in_creative_inventory = 1,
},
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
paramtype = "light",
paramtype2 = "wallmounted",
stack_max = 64,
sunlight_propagates = true,
sounds = mcl_sounds.node_sound_defaults{
footstep = {name="default_hard_footstep", gain=0.3},
},
is_ground_content = false,
_doc_items_create_entry = false,
_mcl_blast_resistance = 1,
_mcl_hardness = 1,
}
function mcl_heads.deftemplate_wall.on_rotate(pos, node, user, mode, new_param2)
if mode == screwdriver.ROTATE_AXIS then
node.name = string.sub(node.name, 1, string.len(node.name)-5)
node.param2 = minetest.dir_to_facedir(minetest.wallmounted_to_dir(node.param2))
minetest.set_node(pos, node)
return true
end
end
-- API functions -------------------------------------------------------------------------------------------------------
--- @class HeadDef
--- @field name string identifier for node
--- @field texture string texture filename for node
--- @field description string translated description
--- @field longdesc string translated doc description
--- @field armor_texture string texture filename for armor
--- @field range_mob string name of mob affected by range reduction
--- @field range_factor number factor of range reduction
--- registers a head
--- @param head_def HeadDef head node definition
function mcl_heads.register_head(head_def)
local name = "mcl_heads:" ..head_def.name
-- register the floor head node
minetest.register_node(name, table.update(table.copy(mcl_heads.deftemplate_floor), {
description = head_def.description,
_doc_items_longdesc = head_def.longdesc,
-- The head textures are based off the textures of an actual mob.
tiles = {
-- Note: bottom texture is overlaid over top texture to get rid of possible transparency.
-- This is required for skeleton skull and wither skeleton skull.
"[combine:16x16:-4,4=" ..head_def.texture, -- top
"([combine:16x16:-4,4=" ..head_def.texture..")^([combine:16x16:-12,4="..head_def.texture..")", -- bottom
"[combine:16x16:-12,0=" ..head_def.texture, -- left
"[combine:16x16:4,0=" ..head_def.texture, -- right
"[combine:16x16:-20,0=" ..head_def.texture, -- back
"[combine:16x16:-4,0=" ..head_def.texture, -- front
},
_mcl_armor_mob_range_mob = head_def.range_mob,
_mcl_armor_mob_range_factor = head_def.range_factor,
_mcl_armor_texture = head_def.armor_texture
}))
-- register the angled floor head nodes
for i, d in ipairs(mcl_heads.FLOOR_DEGREES) do
minetest.register_node(name ..d, table.update(table.copy(mcl_heads.deftemplate_floor_angled), {
mesh = "mcl_heads_floor" ..d ..".obj",
tiles = { head_def.armor_texture },
drop = name,
}))
end
-- register the wall head node
minetest.register_node(name .."_wall", table.update(table.copy(mcl_heads.deftemplate_wall), {
-- The head textures are based off the textures of an actual mob.
tiles = {
{ name = "[combine:16x16:-4,-4=" ..head_def.texture, align_style = "world" }, -- front
{ name = "[combine:16x16:-20,-4="..head_def.texture, align_style = "world" }, -- back
{ name = "[combine:16x16:-8,-4=" ..head_def.texture, align_style = "world" }, -- left
{ name = "[combine:16x16:0,-4=" ..head_def.texture, align_style = "world" }, -- right
{ name = "([combine:16x16:-4,0=" ..head_def.texture ..")^[transformR180", align_style = "node" }, -- top
-- Note: bottom texture is overlaid over top texture to get rid of possible transparency.
-- This is required for skeleton skull and wither skeleton skull.
{ name = "([combine:16x16:-4,8=" ..head_def.texture ..")^([combine:16x16:-12,8=" ..head_def.texture..")", align_style = "node" }, -- bottom
},
drop = name,
}))
end
-- initial heads -------------------------------------------------------------------------------------------------------
mcl_heads.register_head{
name = "zombie",
texture = "mcl_heads_zombie_node.png",
description = S("Zombie Head"),
longdesc = S("A zombie head is a small decorative block which resembles the head of a zombie. It can also be worn as a helmet, which reduces the detection range of zombies by 50%."),
armor_texture = "mcl_heads_zombie.png",
range_mob = "mobs_mc:zombie",
range_factor = 0.5,
}
mcl_heads.register_head{
name = "creeper",
texture = "mcl_heads_creeper_node.png",
description = S("Creeper Head"),
longdesc = S("A creeper head is a small decorative block which resembles the head of a creeper. It can also be worn as a helmet, which reduces the detection range of creepers by 50%."),
armor_texture = "mcl_heads_creeper.png",
range_mob = "mobs_mc:creeper",
range_factor = 0.5,
}
-- Original Minecraft name: “Head”
mcl_heads.register_head{
name = "steve",
texture = "mcl_heads_steve_node.png",
description = S("Human Head"),
longdesc = S("A human head is a small decorative block which resembles the head of a human (i.e. a player character). It can also be worn as a helmet for fun, but does not offer any protection."),
armor_texture = "mcl_heads_steve.png",
}
mcl_heads.register_head{
name = "skeleton",
texture = "mcl_heads_skeleton_node.png",
description = S("Skeleton Skull"),
longdesc = S("A skeleton skull is a small decorative block which resembles the skull of a skeleton. It can also be worn as a helmet, which reduces the detection range of skeletons by 50%."),
armor_texture = "mcl_heads_skeleton.png",
range_mob = "mobs_mc:skeleton",
range_factor = 0.5,
}
mcl_heads.register_head{
name = "wither_skeleton",
texture = "mcl_heads_wither_skeleton_node.png",
description = S("Wither Skeleton Skull"),
longdesc = S("A wither skeleton skull is a small decorative block which resembles the skull of a wither skeleton. It can also be worn as a helmet for fun, but does not offer any protection."),
armor_texture = "mcl_heads_wither_skeleton.png",
}