mirror of
https://git.minetest.land/VoxeLibre/VoxeLibre.git
synced 2024-11-25 12:01:06 +01:00
317 lines
8.2 KiB
Lua
317 lines
8.2 KiB
Lua
mcl_paintings = {}
|
|
|
|
local modname = minetest.get_current_modname()
|
|
dofile(minetest.get_modpath(modname).."/paintings.lua")
|
|
|
|
local S = minetest.get_translator(modname)
|
|
|
|
local math = math
|
|
|
|
local wood = "[combine:16x16:-192,0=mcl_paintings_paintings.png"
|
|
|
|
local function is_protected(pos, name)
|
|
if minetest.is_protected(pos, name) then
|
|
minetest.record_protection_violation(pos, name)
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- Check if there's a painting for provided painting size.
|
|
-- If yes, returns the arguments.
|
|
-- If not, returns the next smaller available painting.
|
|
local function shrink_painting(x, y)
|
|
if x > 4 or y > 4 then
|
|
return nil
|
|
end
|
|
local xstart = x
|
|
local painting
|
|
while not painting do
|
|
painting = mcl_paintings.paintings[y] and mcl_paintings.paintings[y][x]
|
|
if type(painting) == "table" then
|
|
break
|
|
elseif type(painting) == "number" then
|
|
x = painting
|
|
painting = nil
|
|
else
|
|
x = xstart
|
|
y = y - 1
|
|
end
|
|
if y < 1 then
|
|
return nil
|
|
end
|
|
end
|
|
if type(painting) == "table" then
|
|
return x, y
|
|
end
|
|
end
|
|
|
|
local function get_painting(x, y, motive)
|
|
local painting = mcl_paintings.paintings[y] and mcl_paintings.paintings[y][x] and mcl_paintings.paintings[y][x][motive]
|
|
if not painting then
|
|
return nil
|
|
end
|
|
local px, py = -painting.cx, -painting.cy
|
|
local sx, sy = 16*x, 16*y
|
|
return "[combine:"..sx.."x"..sy..":"..px..","..py.."=mcl_paintings_paintings.png"
|
|
end
|
|
|
|
local function get_random_painting(x, y)
|
|
if not mcl_paintings.paintings[y] or not mcl_paintings.paintings[y][x] then
|
|
return nil
|
|
end
|
|
local max = #mcl_paintings.paintings[y][x]
|
|
if max < 1 then
|
|
return nil
|
|
end
|
|
local r = math.random(1, max)
|
|
return get_painting(x, y, r), r
|
|
end
|
|
|
|
--[[local function size_to_minmax(size)
|
|
local min, max
|
|
if size == 2 then
|
|
min = -0.5
|
|
max = 1.5
|
|
elseif size == 3 then
|
|
min = -1.5
|
|
max = 1.5
|
|
elseif size == 4 then
|
|
min = -1.5
|
|
max = 2.5
|
|
else
|
|
min = -0.5
|
|
max = 0.5
|
|
end
|
|
return min, max
|
|
end]]
|
|
|
|
local function size_to_minmax_entity(size)
|
|
return -size/2, size/2
|
|
end
|
|
|
|
local function set_entity(object)
|
|
local ent = object:get_luaentity()
|
|
local wallm = ent._facing
|
|
local xsize = ent._xsize
|
|
local ysize = ent._ysize
|
|
local exmin, exmax = size_to_minmax_entity(xsize)
|
|
local eymin, eymax = size_to_minmax_entity(ysize)
|
|
local visual_size = { x=xsize-0.0001, y=ysize-0.0001, z=1/32 }
|
|
if not ent._xsize or not ent._ysize or not ent._motive then
|
|
minetest.log("error", "[mcl_paintings] Painting loaded with missing painting values!")
|
|
return
|
|
end
|
|
local painting = get_painting(xsize, ysize, ent._motive)
|
|
if not painting then
|
|
minetest.log("error", "[mcl_paintings] No painting found for size "
|
|
..xsize..","..ysize..", motive number "..ent._motive.."!")
|
|
return
|
|
end
|
|
local box
|
|
if wallm == 2 then
|
|
box = { -3/128, eymin, exmin, 1/64, eymax, exmax }
|
|
elseif wallm == 3 then
|
|
box = { -1/64, eymin, exmin, 3/128, eymax, exmax }
|
|
elseif wallm == 4 then
|
|
box = { exmin, eymin, -3/128, exmax, eymax, 1/64 }
|
|
elseif wallm == 5 then
|
|
box = { exmin, eymin, -1/64, exmax, eymax, 3/128 }
|
|
end
|
|
object:set_properties({
|
|
selectionbox = box,
|
|
visual_size = visual_size,
|
|
textures = { wood, wood, wood, wood, painting, wood },
|
|
})
|
|
|
|
local dir = minetest.wallmounted_to_dir(wallm)
|
|
if not dir then
|
|
return
|
|
end
|
|
object:set_yaw(minetest.dir_to_yaw(dir))
|
|
end
|
|
|
|
minetest.register_entity("mcl_paintings:painting", {
|
|
visual = "cube",
|
|
visual_size = { x=0.999, y=0.999, z=1/32 },
|
|
selectionbox = { -1/64, -0.5, -0.5, 1/64, 0.5, 0.5 },
|
|
physical = false,
|
|
collide_with_objects = false,
|
|
textures = { wood, wood, wood, wood, wood, wood },
|
|
hp_max = 1,
|
|
|
|
_motive = 0,
|
|
_pos = nil,
|
|
_facing = 2,
|
|
_xsize = 1,
|
|
_ysize = 1,
|
|
on_activate = function(self, staticdata)
|
|
self.object:set_armor_groups({immortal = 1})
|
|
if staticdata and staticdata ~= "" then
|
|
local data = minetest.deserialize(staticdata)
|
|
if data then
|
|
self._facing = data._facing
|
|
self._pos = data._pos
|
|
self._motive = data._motive
|
|
self._xsize = data._xsize
|
|
self._ysize = data._ysize
|
|
end
|
|
end
|
|
set_entity(self.object)
|
|
end,
|
|
get_staticdata = function(self)
|
|
local data = {
|
|
_facing = self._facing,
|
|
_pos = self._pos,
|
|
_motive = self._motive,
|
|
_xsize = self._xsize,
|
|
_ysize = self._ysize,
|
|
}
|
|
return minetest.serialize(data)
|
|
end,
|
|
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
|
|
-- Drop as item on punch
|
|
if puncher and puncher:is_player() then
|
|
local kname = puncher:get_player_name()
|
|
local pos = self._pos
|
|
if not pos then
|
|
pos = self.object:get_pos()
|
|
end
|
|
if not minetest.is_protected(pos, kname) then
|
|
self.object:remove()
|
|
if not minetest.is_creative_enabled(kname) then
|
|
minetest.add_item(pos, "mcl_paintings:painting")
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
})
|
|
|
|
minetest.register_craftitem("mcl_paintings:painting", {
|
|
description = S("Painting"),
|
|
inventory_image = "mcl_paintings_painting.png",
|
|
on_place = function(itemstack, placer, pointed_thing)
|
|
if pointed_thing.type ~= "node" then
|
|
return itemstack
|
|
end
|
|
|
|
local node = minetest.get_node(pointed_thing.under)
|
|
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(pointed_thing.under, node, placer, itemstack) or itemstack
|
|
end
|
|
end
|
|
|
|
local dir = vector.subtract(pointed_thing.above, pointed_thing.under)
|
|
dir = vector.normalize(dir)
|
|
if dir.y ~= 0 then
|
|
-- Ceiling/floor paintings are not supported
|
|
return itemstack
|
|
end
|
|
local wallm = minetest.dir_to_wallmounted(dir)
|
|
if wallm then
|
|
local ppos = pointed_thing.above
|
|
local xmax
|
|
local ymax = 4
|
|
local xmaxes = {}
|
|
local ymaxed = false
|
|
local negative = dir.x < 0 or dir.z > 0
|
|
-- Check maximum possible painting size
|
|
local t
|
|
for y=0,3 do
|
|
for x=0,3 do
|
|
local k = x
|
|
if negative then
|
|
k = -k
|
|
end
|
|
if dir.z ~= 0 then
|
|
t = {x=k,y=y,z=0}
|
|
else
|
|
t = {x=0,y=y,z=k}
|
|
end
|
|
local unode = minetest.get_node(vector.add(pointed_thing.under, t))
|
|
local anode = minetest.get_node(vector.add(ppos, t))
|
|
local udef = minetest.registered_nodes[unode.name]
|
|
local adef = minetest.registered_nodes[anode.name]
|
|
if (not (udef and udef.walkable)) or (not adef or adef.walkable) then
|
|
xmaxes[y+1] = x
|
|
if x == 0 and not ymaxed then
|
|
ymax = y
|
|
ymaxed = true
|
|
end
|
|
break
|
|
end
|
|
end
|
|
if not xmaxes[y] then
|
|
xmaxes[y] = 4
|
|
end
|
|
end
|
|
xmax = math.max(unpack(xmaxes))
|
|
|
|
local xsize, ysize = xmax, ymax
|
|
xsize, ysize = shrink_painting(xsize, ysize)
|
|
if not xsize then
|
|
return itemstack
|
|
end
|
|
|
|
local _, exmax = size_to_minmax_entity(xsize)
|
|
local _, eymax = size_to_minmax_entity(ysize)
|
|
local pposa = vector.subtract(ppos, vector.multiply(dir, 0.5-5/256))
|
|
local name = placer:get_player_name()
|
|
local pexmax
|
|
local peymax = eymax - 0.5
|
|
local n
|
|
if negative then
|
|
pexmax = -exmax + 0.5
|
|
n = -1
|
|
else
|
|
pexmax = exmax - 0.5
|
|
n = 1
|
|
end
|
|
if is_protected(ppos, name) then return itemstack end
|
|
local ppos2
|
|
if dir.z ~= 0 then
|
|
pposa = vector.add(pposa, {x=pexmax, y=peymax, z=0})
|
|
ppos2 = vector.add(ppos, {x = (xsize-1)*n, y = ysize-1, z = 0})
|
|
else
|
|
pposa = vector.add(pposa, {x=0, y=peymax, z=pexmax})
|
|
ppos2 = vector.add(ppos, {x = 0, y = ysize-1, z = (xsize-1)*n})
|
|
end
|
|
if is_protected(ppos2, name) then return itemstack end
|
|
local painting, pid = get_random_painting(xsize, ysize)
|
|
if not painting then
|
|
minetest.log("error", "[mcl_paintings] No painting found for size "..xsize..","..ysize.."!")
|
|
return itemstack
|
|
end
|
|
local staticdata = {
|
|
_facing = wallm,
|
|
_pos = ppos,
|
|
_motive = pid,
|
|
_xsize = xsize,
|
|
_ysize = ysize,
|
|
}
|
|
local obj = minetest.add_entity(pposa, "mcl_paintings:painting", minetest.serialize(staticdata))
|
|
if not obj then
|
|
return itemstack
|
|
end
|
|
else
|
|
return itemstack
|
|
end
|
|
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
|
itemstack:take_item()
|
|
end
|
|
return itemstack
|
|
end,
|
|
})
|
|
|
|
mcl_wip.register_wip_item("mcl_paintings:painting")
|
|
|
|
minetest.register_craft({
|
|
output = "mcl_paintings:painting",
|
|
recipe = {
|
|
{ "mcl_core:stick", "mcl_core:stick", "mcl_core:stick" },
|
|
{ "mcl_core:stick", "group:wool", "mcl_core:stick" },
|
|
{ "mcl_core:stick", "mcl_core:stick", "mcl_core:stick" },
|
|
}
|
|
})
|
|
|