First commit
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
*~
|
||||||
|
_*
|
||||||
|
|
8
README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Display Modpack
|
||||||
|
|
||||||
|
This modpack provides mods with dynamic display. Mods are :
|
||||||
|
|
||||||
|
- **display_lib**: A library for adding display entities to nodes;
|
||||||
|
- **ontime_clocks**: A mod providing clocks which display the ingame time;
|
||||||
|
- **signs**: A mod providing signs and direction signs displaying text;
|
||||||
|
|
77
display_lib/API.md
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
# Display Lib API
|
||||||
|
This document describes Display Lib API. Display Lib allows to add a dynamic display on a node. Node must be wallmounted and Display Lib limits its rotation to vertical positions.
|
||||||
|
## Provided methods
|
||||||
|
### update\_entities
|
||||||
|
**display\_lib.update\_entities(pos)**
|
||||||
|
|
||||||
|
This method triggers entities update for the display node at pos. Actual entity update is made by **on\_display\_update** callback associated to the entity.
|
||||||
|
|
||||||
|
**pos**: Position of the node
|
||||||
|
### register\_display\_entity
|
||||||
|
**display\_lib.register\_display\_entity(entity_name)**
|
||||||
|
|
||||||
|
This is a helper to register entities used for display.
|
||||||
|
|
||||||
|
**entity_name**: Name of the entity to register.
|
||||||
|
## Provided callback implementations
|
||||||
|
### on_place
|
||||||
|
**display\_lib.on\_place(itemstack, placer, pointed\_thing)**
|
||||||
|
|
||||||
|
**On_place** node callback implementation. Display nodes should have this callback (avoid placement of horizontal display node).
|
||||||
|
### on_construct
|
||||||
|
**display\_lib.on\_construct(pos)**
|
||||||
|
|
||||||
|
**On_construct** node callback implementation. Display nodes should have this callback (creates, places and updates display entities on node construction).
|
||||||
|
### on_destruct
|
||||||
|
**display\_lib.on_destruct(pos)**
|
||||||
|
|
||||||
|
**On_destruct** node callback implementation. Display nodes should have this callback (removes display entities on node destruction).
|
||||||
|
### on_rotate
|
||||||
|
**display\_lib.on\_rotate(pos, node, user, mode, new_param2)**
|
||||||
|
|
||||||
|
**On_rotate** node callback implementation. Display nodes should have this callback (restricts rotations and rotates display entities associated with node).
|
||||||
|
### on_activate
|
||||||
|
**display\_lib.on_activate(entity, staticdata)**
|
||||||
|
|
||||||
|
**On_activate** entity callback implementation for display entities. No need of this method if display entities have been registered using **register\_display\_entity** (callback is already set).
|
||||||
|
## Howto register a display node
|
||||||
|
* Register display entities with **register\_display\_entity**
|
||||||
|
* Register node with :
|
||||||
|
- **on\_place**, **on\_construct**, **on\_destruct** and **on\_rotate** callbacks using **display\_lib** callbacks.
|
||||||
|
- a **display\_entities** field in node definition containing a entity name indexed table. For each entity, two fields : **depth** indicates the entity position (-0.5 to 0.5) and **on_display_update** is a callback in charge of setting up entity texture.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
display_lib.register_display_entity("mymod:entity1")
|
||||||
|
display_lib.register_display_entity("mymod:entity2")
|
||||||
|
|
||||||
|
function my_display_update1(pos, objref)
|
||||||
|
objref:set_properties({ textures= {"mytexture1.png"},
|
||||||
|
visual_size = {x=1, y=1} })
|
||||||
|
end
|
||||||
|
|
||||||
|
function my_display_update2(pos, objref)
|
||||||
|
objref:set_properties({ textures= {"mytexture2.png"},
|
||||||
|
visual_size = {x=1, y=1} })
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_node("mymod:test_display_node", {
|
||||||
|
...
|
||||||
|
paramtype2 = "wallmounted",
|
||||||
|
...
|
||||||
|
display_entities = {
|
||||||
|
["mymod:entity1"] = { depth = -0.3,
|
||||||
|
on_display_update = my_display_update1},
|
||||||
|
["mymod:entity1"] = { depth = -0.2,
|
||||||
|
on_display_update = my_display_update2},
|
||||||
|
},
|
||||||
|
...
|
||||||
|
on_place = display_lib.on_place,
|
||||||
|
on_construct = display_lib.on_construct,
|
||||||
|
on_destruct = display_lib.on_destruct,
|
||||||
|
on_rotate = display_lib.on_rotate,
|
||||||
|
...
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
13
display_lib/LICENSE.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
Version 2, December 2004
|
||||||
|
|
||||||
|
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim or modified
|
||||||
|
copies of this license document, and changing it is allowed as long
|
||||||
|
as the name is changed.
|
||||||
|
|
||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. You just DO WHAT THE FUCK YOU WANT TO.
|
11
display_lib/README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Dislpay Lib
|
||||||
|
|
||||||
|
This library's purpose is to ease creation of wallmounted nodes with a display on front side. For example, signs and clocks. Display can be dynamic and/or different for each node instance.
|
||||||
|
|
||||||
|
**Limitations**: This lib uses entities to draw display. This means display has to be vertical. So display nodes are only wallmounted vertically.
|
||||||
|
|
||||||
|
**Dependancies**:default
|
||||||
|
|
||||||
|
**License**: WTFPL
|
||||||
|
|
||||||
|
**API**: See API.md document please.
|
1
display_lib/depends.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
default
|
156
display_lib/init.lua
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
-- Display lib mod by P.Y. Rollo
|
||||||
|
--
|
||||||
|
-- License: WTFPL
|
||||||
|
|
||||||
|
display_lib = {}
|
||||||
|
|
||||||
|
-- Miscelaneous values depending on wallmounted param2
|
||||||
|
local wallmounted_values = {
|
||||||
|
[0]={dx=0, dz=0, lx=0, lz=0, yaw=0, rotate=0}, -- Should never be used
|
||||||
|
{dx=1, dz=0, lx=0, lz=0, yaw=0, rotate=1}, -- Should never be used
|
||||||
|
{dx=1, dz=0, lx=0, lz=-1, yaw=-math.pi/2, rotate=4},
|
||||||
|
{dx=-1, dz=0, lx=0, lz=1, yaw=math.pi/2, rotate=5},
|
||||||
|
{dx=0, dz=1, lx=1, lz=0, yaw=0, rotate=3},
|
||||||
|
{dx=0, dz=-1, lx=-1, lz=0, yaw=math.pi, rotate=2}
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Gets the display entities attached with a node. Removes extra ones
|
||||||
|
local function get_entities(pos)
|
||||||
|
local objrefs = {}
|
||||||
|
local ndef = minetest.registered_nodes[minetest.get_node(pos).name]
|
||||||
|
if ndef and ndef.display_entities then
|
||||||
|
for _, objref in ipairs(minetest.get_objects_inside_radius(pos, 0.5)) do
|
||||||
|
local entity = objref:get_luaentity()
|
||||||
|
if entity and ndef.display_entities[entity.name] then
|
||||||
|
if objrefs[entity.name] then
|
||||||
|
objref:remove()
|
||||||
|
else
|
||||||
|
objrefs[entity.name] = objref
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return objrefs
|
||||||
|
end
|
||||||
|
|
||||||
|
local function clip_pos_prop(posprop)
|
||||||
|
if posprop then
|
||||||
|
return math.max(-0.5, math.min(0.5, posprop))
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (Create and) place display entities according to the node orientation
|
||||||
|
local function place_entities(pos)
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
local ndef = minetest.registered_nodes[node.name]
|
||||||
|
local values = wallmounted_values[node.param2]
|
||||||
|
local objrefs = get_entities(pos)
|
||||||
|
|
||||||
|
if ndef and ndef.display_entities then
|
||||||
|
for entity_name, props in pairs(ndef.display_entities) do
|
||||||
|
local depth = clip_pos_prop(props.depth)
|
||||||
|
local top = clip_pos_prop(props.top)
|
||||||
|
local left = clip_pos_prop(props.left)
|
||||||
|
|
||||||
|
if not objrefs[entity_name] then
|
||||||
|
objrefs[entity_name] = minetest.add_entity(pos, entity_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
objrefs[entity_name]:setpos({
|
||||||
|
x = pos.x - values.dx * depth + values.lx * left,
|
||||||
|
y = pos.y + top,
|
||||||
|
z = pos.z - values.dz * depth + values.lz * left})
|
||||||
|
|
||||||
|
objrefs[entity_name]:setyaw(values.yaw)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return objrefs
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Call on_display_update callback of a node for one of its display entities
|
||||||
|
local function call_node_on_display_update(pos, objref)
|
||||||
|
local ndef = minetest.registered_nodes[minetest.get_node(pos).name]
|
||||||
|
local entity = objref:get_luaentity()
|
||||||
|
if ndef and ndef.display_entities and entity and ndef.display_entities[entity.name] then
|
||||||
|
ndef.display_entities[entity.name].on_display_update(pos, objref)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Force entity update
|
||||||
|
function display_lib.update_entities(pos)
|
||||||
|
local objrefs = place_entities(pos)
|
||||||
|
for _, objref in pairs(objrefs) do
|
||||||
|
call_node_on_display_update(pos, objref)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On_activate callback for display_lib entities. Calls on_display_update callbacks
|
||||||
|
--- of corresponding node for each entity.
|
||||||
|
function display_lib.on_activate(entity, staticdata)
|
||||||
|
if entity then
|
||||||
|
call_node_on_display_update(entity.object:getpos(), entity.object)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On_place callback for display_lib items. Does nothing more than preventing item
|
||||||
|
--- from being placed on ceiling or ground
|
||||||
|
function display_lib.on_place(itemstack, placer, pointed_thing)
|
||||||
|
local above = pointed_thing.above
|
||||||
|
local under = pointed_thing.under
|
||||||
|
local dir = {x = under.x - above.x,
|
||||||
|
y = under.y - above.y,
|
||||||
|
z = under.z - above.z}
|
||||||
|
local wdir = minetest.dir_to_wallmounted(dir)
|
||||||
|
|
||||||
|
if wdir == 0 or wdir == 1 then
|
||||||
|
dir = placer:get_look_dir()
|
||||||
|
dir.y = 0
|
||||||
|
wdir = minetest.dir_to_wallmounted(dir)
|
||||||
|
end
|
||||||
|
return minetest.item_place(itemstack, placer, pointed_thing, wdir)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On_construct callback for display_lib items. Creates entities and update them.
|
||||||
|
function display_lib.on_construct(pos)
|
||||||
|
display_lib.update_entities(pos)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On_destruct callback for display_lib items. Removes entities.
|
||||||
|
function display_lib.on_destruct(pos)
|
||||||
|
local objrefs = get_entities(pos)
|
||||||
|
|
||||||
|
for _, objref in pairs(objrefs) do
|
||||||
|
objref:remove()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- On_rotate (screwdriver) callback for display_lib items. Prevents axis rotation and reorients entities.
|
||||||
|
function display_lib.on_rotate(pos, node, user, mode, new_param2)
|
||||||
|
if mode ~= screwdriver.ROTATE_FACE then return false end
|
||||||
|
|
||||||
|
if wallmounted_values[node.param2] then
|
||||||
|
minetest.swap_node(pos, {name = node.name, param1 = node.param1, param2 = wallmounted_values[node.param2].rotate})
|
||||||
|
place_entities(pos)
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Creates display entity with some fields and the on_activate callback
|
||||||
|
function display_lib.register_display_entity(entity_name)
|
||||||
|
if not minetest.registered_entity then
|
||||||
|
minetest.register_entity(':'..entity_name, {
|
||||||
|
collisionbox = { 0, 0, 0, 0, 0, 0 },
|
||||||
|
visual = "upright_sprite",
|
||||||
|
textures = {},
|
||||||
|
on_activate = display_lib.on_activate,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
0
modpack.txt
Normal file
13
ontime_clocks/LICENSE.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
Version 2, December 2004
|
||||||
|
|
||||||
|
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim or modified
|
||||||
|
copies of this license document, and changing it is allowed as long
|
||||||
|
as the name is changed.
|
||||||
|
|
||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. You just DO WHAT THE FUCK YOU WANT TO.
|
47
ontime_clocks/README.md
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# Ontime Clocks
|
||||||
|
|
||||||
|
This mod provides clocks that display real ingame time.
|
||||||
|
|
||||||
|
**Dependancies**: display_lib, default
|
||||||
|
|
||||||
|
**License**: WTFPL
|
||||||
|
|
||||||
|
## Recipes
|
||||||
|
|
||||||
|
**Green and red digital clocks**
|
||||||
|
|
||||||
|
- D -
|
||||||
|
G M G
|
||||||
|
- - -
|
||||||
|
|
||||||
|
G = Glass, D = Dye, M = Mese Crystal, - = Empty
|
||||||
|
|
||||||
|
Green dye for green clock, red dye for red clock
|
||||||
|
|
||||||
|
**White clock**
|
||||||
|
|
||||||
|
S P S
|
||||||
|
- M -
|
||||||
|
- - -
|
||||||
|
|
||||||
|
P = Paper, S = Steel Ingot, M = Mese Crystal, - = Empty
|
||||||
|
|
||||||
|
|
||||||
|
**Frameless clock**
|
||||||
|
|
||||||
|
S D S
|
||||||
|
- M -
|
||||||
|
- - -
|
||||||
|
|
||||||
|
D = Dye, S = Steel Ingot, M = Mese Crystal, - = Empty
|
||||||
|
|
||||||
|
Black dye for black clock, White dye for white clock
|
||||||
|
|
||||||
|
**Gold frameless clock**
|
||||||
|
|
||||||
|
G - G
|
||||||
|
- M -
|
||||||
|
- - -
|
||||||
|
|
||||||
|
G = Gold Ingot, M = Mese Crystal, - = Empty
|
||||||
|
|
41
ontime_clocks/common.lua
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
-- Entity for time display
|
||||||
|
display_lib.register_display_entity("ontime_clocks:display")
|
||||||
|
|
||||||
|
function ontime_clocks.get_h24()
|
||||||
|
return math.floor(minetest.get_timeofday()*24)%24
|
||||||
|
end
|
||||||
|
|
||||||
|
function ontime_clocks.get_h12()
|
||||||
|
return math.floor(minetest.get_timeofday()*24)%12
|
||||||
|
end
|
||||||
|
|
||||||
|
function ontime_clocks.get_m12()
|
||||||
|
return math.floor(minetest.get_timeofday()*288)%12
|
||||||
|
end
|
||||||
|
|
||||||
|
function ontime_clocks.get_digital_properties(color_off, color_on, hour, minute)
|
||||||
|
return
|
||||||
|
{
|
||||||
|
textures={"ontime_clocks_digital_background.png^[colorize:"..color_off
|
||||||
|
.."^([combine:21x7"
|
||||||
|
..":0,"..(-7*(math.floor(hour/10))).."=ontime_clocks_digital_digit.png"
|
||||||
|
..":5,"..(-7*(hour%10)).."=ontime_clocks_digital_digit.png"
|
||||||
|
..":9,-70=ontime_clocks_digital_digit.png"
|
||||||
|
..":12,"..(-7*(math.floor(minute/2))).."=ontime_clocks_digital_digit.png"
|
||||||
|
..":17,"..(-35*(minute%2)).."=ontime_clocks_digital_digit.png"
|
||||||
|
.."^[colorize:"..color_on..")"},
|
||||||
|
visual_size = {x=21/32, y=7/32}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function ontime_clocks.get_needles_properties(color, size, hour, minute)
|
||||||
|
return
|
||||||
|
{
|
||||||
|
textures={"[combine:"..size.."x"..size
|
||||||
|
..":0,"..(-size*hour).."=ontime_clocks_needle_h"..size..".png"
|
||||||
|
..":0,"..(-size*minute).."=ontime_clocks_needle_m"..size..".png"
|
||||||
|
.."^[colorize:"..color},
|
||||||
|
visual_size = {x=size/64, y=size/64}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
56
ontime_clocks/crafts.lua
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = 'ontime_clocks:green_digital',
|
||||||
|
recipe = {
|
||||||
|
{'', 'dye:green', ''},
|
||||||
|
{'default:glass', 'default:mese_crystal', 'default:glass'},
|
||||||
|
{'', '', ''},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = 'ontime_clocks:red_digital',
|
||||||
|
recipe = {
|
||||||
|
{'', 'dye:red', ''},
|
||||||
|
{'default:glass', 'default:mese_crystal', 'default:glass'},
|
||||||
|
{'', '', ''},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = 'ontime_clocks:white',
|
||||||
|
recipe = {
|
||||||
|
{'default:steel_ingot', 'default:paper', 'default:steel_ingot'},
|
||||||
|
{'', 'default:mese_crystal', ''},
|
||||||
|
{'', '', ''},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = 'ontime_clocks:frameless_black',
|
||||||
|
recipe = {
|
||||||
|
{'default:steel_ingot', 'dye:black', 'default:steel_ingot'},
|
||||||
|
{'', 'default:mese_crystal', ''},
|
||||||
|
{'', '', ''},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = 'ontime_clocks:frameless_gold',
|
||||||
|
recipe = {
|
||||||
|
{'default:gold_ingot', '', 'default:gold_ingot'},
|
||||||
|
{'', 'default:mese_crystal', ''},
|
||||||
|
{'', '', ''},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = 'ontime_clocks:frameless_white',
|
||||||
|
recipe = {
|
||||||
|
{'default:steel_ingot', 'dye:white', 'default:steel_ingot'},
|
||||||
|
{'', 'default:mese_crystal', ''},
|
||||||
|
{'', '', ''},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
3
ontime_clocks/depends.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
default
|
||||||
|
display_lib
|
||||||
|
|
14
ontime_clocks/init.lua
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
-- On time clocks mod by P.Y. Rollo
|
||||||
|
--
|
||||||
|
-- License: WTFPL
|
||||||
|
|
||||||
|
ontime_clocks = {}
|
||||||
|
ontime_clocks.path = minetest.get_modpath("ontime_clocks")
|
||||||
|
|
||||||
|
dofile(ontime_clocks.path.."/common.lua")
|
||||||
|
dofile(ontime_clocks.path.."/nodes.lua")
|
||||||
|
dofile(ontime_clocks.path.."/crafts.lua")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
224
ontime_clocks/nodes.lua
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
-- Green digital clock
|
||||||
|
minetest.register_node("ontime_clocks:green_digital", {
|
||||||
|
description = "Green digital clock",
|
||||||
|
inventory_image = "ontime_clocks_green_digital_inventory.png",
|
||||||
|
wield_image = "ontime_clocks_green_digital_inventory.png",
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "wallmounted",
|
||||||
|
drawtype = "nodebox",
|
||||||
|
node_box = {
|
||||||
|
type = "wallmounted",
|
||||||
|
wall_side = { -0.5, -3/16, -7/16, -13/32, 7/32, 7/16 },
|
||||||
|
wall_bottom = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 },
|
||||||
|
wall_top = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 }
|
||||||
|
},
|
||||||
|
tiles = {"ontime_clocks_digital.png"},
|
||||||
|
groups = {oddly_breakable_by_hand=1},
|
||||||
|
display_entities = {
|
||||||
|
["ontime_clocks:display"] = {
|
||||||
|
depth = -13/32 + 0.01,
|
||||||
|
on_display_update = function(pos, objref)
|
||||||
|
objref:set_properties(
|
||||||
|
ontime_clocks.get_digital_properties(
|
||||||
|
"#040", "#0F0", ontime_clocks.get_h24(), ontime_clocks.get_m12()))
|
||||||
|
end },
|
||||||
|
},
|
||||||
|
on_place = display_lib.on_place,
|
||||||
|
on_construct = display_lib.on_construct,
|
||||||
|
on_destruct = display_lib.on_destruct,
|
||||||
|
on_rotate = display_lib.on_rotate,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_abm({
|
||||||
|
nodenames = {"ontime_clocks:green_digital"},
|
||||||
|
interval = 5,
|
||||||
|
chance = 1,
|
||||||
|
action = display_lib.update_entities,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Red digital clock
|
||||||
|
minetest.register_node("ontime_clocks:red_digital", {
|
||||||
|
description = "Red digital clock",
|
||||||
|
inventory_image = "ontime_clocks_red_digital_inventory.png",
|
||||||
|
wield_image = "ontime_clocks_red_digital_inventory.png",
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "wallmounted",
|
||||||
|
drawtype = "nodebox",
|
||||||
|
node_box = {
|
||||||
|
type = "wallmounted",
|
||||||
|
wall_side = { -0.5, -3/16, -7/16, -13/32, 7/32, 7/16 },
|
||||||
|
wall_bottom = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 },
|
||||||
|
wall_top = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 }
|
||||||
|
},
|
||||||
|
tiles = {"ontime_clocks_digital.png"},
|
||||||
|
groups = {oddly_breakable_by_hand=1},
|
||||||
|
display_entities = {
|
||||||
|
["ontime_clocks:display"] = {
|
||||||
|
depth = -13/32 + 0.01,
|
||||||
|
on_display_update = function(pos, objref)
|
||||||
|
objref:set_properties(
|
||||||
|
ontime_clocks.get_digital_properties(
|
||||||
|
"#400", "#F00", ontime_clocks.get_h24(), ontime_clocks.get_m12()))
|
||||||
|
end },
|
||||||
|
},
|
||||||
|
on_place = display_lib.on_place,
|
||||||
|
on_construct = display_lib.on_construct,
|
||||||
|
on_destruct = display_lib.on_destruct,
|
||||||
|
on_rotate = display_lib.on_rotate,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_abm({
|
||||||
|
nodenames = {"ontime_clocks:red_digital"},
|
||||||
|
interval = 5,
|
||||||
|
chance = 1,
|
||||||
|
action = display_lib.update_entities,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
minetest.register_node("ontime_clocks:white", {
|
||||||
|
description = "White clock",
|
||||||
|
inventory_image = "ontime_clocks_white_inventory.png",
|
||||||
|
wield_image = "ontime_clocks_white_inventory.png",
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "wallmounted",
|
||||||
|
drawtype = "nodebox",
|
||||||
|
node_box = {
|
||||||
|
type = "wallmounted",
|
||||||
|
wall_side = { -0.5, -7/16, -7/16, -6/16, 7/16, 7/16},
|
||||||
|
wall_bottom = { -7/16, -0.5, -7/16, 7/16, -7/16, 7/16},
|
||||||
|
wall_top = { -7/16, 0.5, -7/16, 7/16, 7/16, 7/16},
|
||||||
|
},
|
||||||
|
tiles = {"ontime_clocks_white.png"},
|
||||||
|
groups = {choppy=1,oddly_breakable_by_hand=1},
|
||||||
|
display_entities = {
|
||||||
|
["ontime_clocks:display"] = {
|
||||||
|
depth = -6/16+0.01,
|
||||||
|
on_display_update = function(pos, objref)
|
||||||
|
objref:set_properties(
|
||||||
|
ontime_clocks.get_needles_properties(
|
||||||
|
"#000", 36, ontime_clocks.get_h12(), ontime_clocks.get_m12()))
|
||||||
|
end },
|
||||||
|
},
|
||||||
|
on_place = display_lib.on_place,
|
||||||
|
on_construct = display_lib.on_construct,
|
||||||
|
on_destruct = display_lib.on_destruct,
|
||||||
|
on_rotate = display_lib.on_rotate,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_abm({
|
||||||
|
nodenames = {"ontime_clocks:white"},
|
||||||
|
interval = 5,
|
||||||
|
chance = 1,
|
||||||
|
action = display_lib.update_entities,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_node("ontime_clocks:frameless_black", {
|
||||||
|
description = "Frameless clock",
|
||||||
|
inventory_image = "ontime_clocks_frameless_inventory.png",
|
||||||
|
wield_image = "ontime_clocks_frameless_inventory.png",
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "wallmounted",
|
||||||
|
drawtype = "nodebox",
|
||||||
|
node_box = {
|
||||||
|
type = "wallmounted",
|
||||||
|
wall_side = { -0.5, -7/16, -7/16, -0.45, 7/16, 7/16 },
|
||||||
|
wall_bottom = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 },
|
||||||
|
wall_top = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 }
|
||||||
|
},
|
||||||
|
tiles = {"ontime_clocks_frameless.png"},
|
||||||
|
groups = {choppy=1,oddly_breakable_by_hand=1},
|
||||||
|
display_entities = {
|
||||||
|
["ontime_clocks:display"] = {
|
||||||
|
depth = -7/16,
|
||||||
|
on_display_update = function(pos, objref)
|
||||||
|
objref:set_properties(
|
||||||
|
ontime_clocks.get_needles_properties(
|
||||||
|
"#000", 48, ontime_clocks.get_h12(), ontime_clocks.get_m12()))
|
||||||
|
end },
|
||||||
|
},
|
||||||
|
on_place = display_lib.on_place,
|
||||||
|
on_construct = display_lib.on_construct,
|
||||||
|
on_destruct = display_lib.on_destruct,
|
||||||
|
on_rotate = display_lib.on_rotate,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_abm({
|
||||||
|
nodenames = {"ontime_clocks:frameless_black"},
|
||||||
|
interval = 5,
|
||||||
|
chance = 1,
|
||||||
|
action = display_lib.update_entities,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_node("ontime_clocks:frameless_gold", {
|
||||||
|
description = "Frameless gold clock",
|
||||||
|
inventory_image = "ontime_clocks_frameless_inventory.png^[colorize:#FF0",
|
||||||
|
wield_image = "ontime_clocks_frameless_inventory.png^[colorize:#FF0",
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "wallmounted",
|
||||||
|
drawtype = "nodebox",
|
||||||
|
node_box = {
|
||||||
|
type = "wallmounted",
|
||||||
|
wall_side = { -0.5, -7/16, -7/16, -0.45, 7/16, 7/16 },
|
||||||
|
wall_bottom = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 },
|
||||||
|
wall_top = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 }
|
||||||
|
},
|
||||||
|
tiles = {"ontime_clocks_frameless.png^[colorize:#FF0"},
|
||||||
|
groups = {choppy=1,oddly_breakable_by_hand=1},
|
||||||
|
display_entities = {
|
||||||
|
["ontime_clocks:display"] = {
|
||||||
|
depth = -7/16,
|
||||||
|
on_display_update = function(pos, objref)
|
||||||
|
objref:set_properties(
|
||||||
|
ontime_clocks.get_needles_properties(
|
||||||
|
"#FF0", 48, ontime_clocks.get_h12(), ontime_clocks.get_m12()))
|
||||||
|
end },
|
||||||
|
},
|
||||||
|
on_place = display_lib.on_place,
|
||||||
|
on_construct = display_lib.on_construct,
|
||||||
|
on_destruct = display_lib.on_destruct,
|
||||||
|
on_rotate = display_lib.on_rotate,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_abm({
|
||||||
|
nodenames = {"ontime_clocks:frameless_gold"},
|
||||||
|
interval = 5,
|
||||||
|
chance = 1,
|
||||||
|
action = display_lib.update_entities,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_node("ontime_clocks:frameless_white", {
|
||||||
|
description = "Frameless white clock",
|
||||||
|
inventory_image = "ontime_clocks_frameless_inventory.png^[colorize:#FFF",
|
||||||
|
wield_image = "ontime_clocks_frameless_inventory.png^[colorize:#FFF",
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "wallmounted",
|
||||||
|
drawtype = "nodebox",
|
||||||
|
node_box = {
|
||||||
|
type = "wallmounted",
|
||||||
|
wall_side = { -0.5, -7/16, -7/16, -0.45, 7/16, 7/16 },
|
||||||
|
wall_bottom = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 },
|
||||||
|
wall_top = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 }
|
||||||
|
},
|
||||||
|
tiles = {"ontime_clocks_frameless.png^[colorize:#FFF"},
|
||||||
|
groups = {choppy=1,oddly_breakable_by_hand=1},
|
||||||
|
display_entities = {
|
||||||
|
["ontime_clocks:display"] = {
|
||||||
|
depth = -7/16,
|
||||||
|
on_display_update = function(pos, objref)
|
||||||
|
objref:set_properties(
|
||||||
|
ontime_clocks.get_needles_properties(
|
||||||
|
"#FFF", 48, ontime_clocks.get_h12(), ontime_clocks.get_m12()))
|
||||||
|
end },
|
||||||
|
},
|
||||||
|
on_place = display_lib.on_place,
|
||||||
|
on_construct = display_lib.on_construct,
|
||||||
|
on_destruct = display_lib.on_destruct,
|
||||||
|
on_rotate = display_lib.on_rotate,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_abm({
|
||||||
|
nodenames = {"ontime_clocks:frameless_white"},
|
||||||
|
interval = 5,
|
||||||
|
chance = 1,
|
||||||
|
action = display_lib.update_entities,
|
||||||
|
})
|
BIN
ontime_clocks/textures/ontime_clocks_digital.png
Normal file
After Width: | Height: | Size: 208 B |
BIN
ontime_clocks/textures/ontime_clocks_digital_background.png
Normal file
After Width: | Height: | Size: 197 B |
BIN
ontime_clocks/textures/ontime_clocks_digital_digit.png
Normal file
After Width: | Height: | Size: 223 B |
BIN
ontime_clocks/textures/ontime_clocks_frameless.png
Normal file
After Width: | Height: | Size: 241 B |
BIN
ontime_clocks/textures/ontime_clocks_frameless_inventory.png
Normal file
After Width: | Height: | Size: 426 B |
BIN
ontime_clocks/textures/ontime_clocks_green_digital_inventory.png
Normal file
After Width: | Height: | Size: 300 B |
BIN
ontime_clocks/textures/ontime_clocks_needle_h36.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
ontime_clocks/textures/ontime_clocks_needle_h48.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
ontime_clocks/textures/ontime_clocks_needle_m36.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
ontime_clocks/textures/ontime_clocks_needle_m48.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
ontime_clocks/textures/ontime_clocks_red_digital_inventory.png
Normal file
After Width: | Height: | Size: 315 B |
BIN
ontime_clocks/textures/ontime_clocks_white.png
Normal file
After Width: | Height: | Size: 285 B |
BIN
ontime_clocks/textures/ontime_clocks_white_inventory.png
Normal file
After Width: | Height: | Size: 534 B |
13
signs/LICENSE.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
Version 2, December 2004
|
||||||
|
|
||||||
|
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim or modified
|
||||||
|
copies of this license document, and changing it is allowed as long
|
||||||
|
as the name is changed.
|
||||||
|
|
||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. You just DO WHAT THE FUCK YOU WANT TO.
|
52
signs/README.md
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Signs
|
||||||
|
|
||||||
|
This mod provides various signs with text display. Text is locked if area is protected.
|
||||||
|
|
||||||
|
**Dependancies**: display_lib, default
|
||||||
|
|
||||||
|
**License**: WTFPL
|
||||||
|
|
||||||
|
## Recipes
|
||||||
|
|
||||||
|
**Blue Street Sign**
|
||||||
|
|
||||||
|
B W S
|
||||||
|
S S S
|
||||||
|
- - -
|
||||||
|
|
||||||
|
B = Blue Dye, W = White Dye, S = Steel Ingot
|
||||||
|
|
||||||
|
**Green Street Sign**
|
||||||
|
|
||||||
|
G W S
|
||||||
|
S S S
|
||||||
|
- - -
|
||||||
|
|
||||||
|
G = Green Dye, W = White Dye, S = Steel Ingot
|
||||||
|
|
||||||
|
**Poster**
|
||||||
|
|
||||||
|
P P -
|
||||||
|
P P -
|
||||||
|
P P -
|
||||||
|
|
||||||
|
P = Paper
|
||||||
|
|
||||||
|
Poster displays only title, much more text can be read by right-clicking on it.
|
||||||
|
|
||||||
|
**Wooden direction sigh**
|
||||||
|
|
||||||
|
W W W
|
||||||
|
W W -
|
||||||
|
- - -
|
||||||
|
|
||||||
|
W = Wooden Plank (group)
|
||||||
|
|
||||||
|
**Black direction sign**
|
||||||
|
|
||||||
|
B W S
|
||||||
|
S S -
|
||||||
|
- - -
|
||||||
|
|
||||||
|
B = Black Dye, W = White Dye, S = Steel Ingot
|
||||||
|
|
217
signs/common.lua
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
local font = {}
|
||||||
|
signs.font_height = 10
|
||||||
|
|
||||||
|
-- Get png width, suposing png width is less than 256 (it is the case for all font textures)
|
||||||
|
local function get_png_width(filename)
|
||||||
|
local file=assert(io.open(filename,"rb"))
|
||||||
|
-- All font png are smaller than 256x256 --> read only last byte
|
||||||
|
file:seek("set",19)
|
||||||
|
local w = file:read(1)
|
||||||
|
file:close()
|
||||||
|
return w:byte()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Computes line width for a given font height and text
|
||||||
|
function signs.get_line_width(text)
|
||||||
|
local char
|
||||||
|
local width = 0
|
||||||
|
|
||||||
|
for p=1,#text
|
||||||
|
do
|
||||||
|
char = text:sub(p,p):byte()
|
||||||
|
if font[char] then
|
||||||
|
width = width + font[char].width
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return width
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Builds texture part for a text line
|
||||||
|
-- @param text Text to be rendered
|
||||||
|
-- @param x Starting x position in texture
|
||||||
|
-- @param width Width of the texture (extra text is not rendered)
|
||||||
|
-- @param y Vertical position of the line in texture
|
||||||
|
-- @return Texture string
|
||||||
|
function signs.make_line_texture(text, x, width, y)
|
||||||
|
local char
|
||||||
|
|
||||||
|
local texture = ""
|
||||||
|
|
||||||
|
for p=1,#text
|
||||||
|
do
|
||||||
|
char = text:sub(p,p):byte()
|
||||||
|
if font[char] then
|
||||||
|
-- Add image only if it is visible (at least partly)
|
||||||
|
if x + font[char].width >= 0 and x <= width then
|
||||||
|
texture = texture..string.format(":%d,%d=%s", x, y, font[char].filename)
|
||||||
|
end
|
||||||
|
x = x + font[char].width
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return texture
|
||||||
|
end
|
||||||
|
|
||||||
|
local function split_lines(text, maxlines)
|
||||||
|
local splits = text:split("\n")
|
||||||
|
if maxlines then
|
||||||
|
local lines = {}
|
||||||
|
for num = 1,maxlines do
|
||||||
|
lines[num] = splits[num]
|
||||||
|
end
|
||||||
|
return lines
|
||||||
|
else
|
||||||
|
return splits
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function signs.on_display_update(pos, objref)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local text = meta:get_string("display_text")
|
||||||
|
|
||||||
|
local ndef = minetest.registered_nodes[minetest.get_node(pos).name]
|
||||||
|
if ndef and ndef.sign_model then
|
||||||
|
local model = signs.sign_models[ndef.sign_model]
|
||||||
|
local lines = split_lines(text, model.maxlines)
|
||||||
|
|
||||||
|
local texturew = model.width/model.xscale
|
||||||
|
local textureh = model.height/model.yscale
|
||||||
|
|
||||||
|
local texture = ""
|
||||||
|
|
||||||
|
local y
|
||||||
|
if model.valing == "top" then
|
||||||
|
y = signs.font_height / 2
|
||||||
|
else
|
||||||
|
y = (textureh - signs.font_height * #lines) / 2 + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, line in pairs(lines) do
|
||||||
|
texture = texture..signs.make_line_texture(line,
|
||||||
|
(texturew - signs.get_line_width(line)) / 2,
|
||||||
|
texturew, y)
|
||||||
|
y = y + signs.font_height
|
||||||
|
end
|
||||||
|
|
||||||
|
local texture = string.format("[combine:%dx%d", texturew, textureh)..texture
|
||||||
|
if model.color then texture = texture.."^[colorize:"..model.color end
|
||||||
|
|
||||||
|
objref:set_properties({ textures={texture}, visual_size = {x=model.width, y=model.height}})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function signs.set_formspec(pos)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local ndef = minetest.registered_nodes[minetest.get_node(pos).name]
|
||||||
|
if ndef and ndef.sign_model then
|
||||||
|
local model = signs.sign_models[ndef.sign_model]
|
||||||
|
local formspec
|
||||||
|
|
||||||
|
if model.maxlines == 1 then
|
||||||
|
formspec = "size[6,3]"..
|
||||||
|
"field[0.5,0.7;5.5,1;display_text;Displayed text;${display_text}]"..
|
||||||
|
"button_exit[2,2;2,1;ok;Write]"
|
||||||
|
else
|
||||||
|
local extralabel = ""
|
||||||
|
if model.maxlines then
|
||||||
|
extralabel = " (first "..model.maxlines.." lines only)"
|
||||||
|
end
|
||||||
|
|
||||||
|
formspec = "size[6,4]"..
|
||||||
|
"textarea[0.5,0.7;5.5,2;display_text;Displayed text"..extralabel..";${display_text}]"..
|
||||||
|
"button_exit[2,3;2,1;ok;Write]"
|
||||||
|
end
|
||||||
|
|
||||||
|
meta:set_string("formspec", formspec)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function signs.on_receive_fields(pos, formname, fields, player)
|
||||||
|
if not minetest.is_protected(pos, player:get_player_name()) then
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
if fields and fields.ok then
|
||||||
|
meta:set_string("display_text", fields.display_text)
|
||||||
|
meta:set_string("infotext", "\""..fields.display_text.."\"")
|
||||||
|
display_lib.update_entities(pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- On place callback for direction signs
|
||||||
|
-- (chooses which sign according to look direction)
|
||||||
|
function signs.on_place_direction(itemstack, placer, pointed_thing)
|
||||||
|
local above = pointed_thing.above
|
||||||
|
local under = pointed_thing.under
|
||||||
|
local wdir = minetest.dir_to_wallmounted(
|
||||||
|
{x = under.x - above.x,
|
||||||
|
y = under.y - above.y,
|
||||||
|
z = under.z - above.z})
|
||||||
|
|
||||||
|
local dir = placer:get_look_dir()
|
||||||
|
|
||||||
|
if wdir == 0 or wdir == 1 then
|
||||||
|
wdir = minetest.dir_to_wallmounted({x=dir.x, y=0, z=dir.z})
|
||||||
|
end
|
||||||
|
|
||||||
|
local name = itemstack:get_name()
|
||||||
|
|
||||||
|
-- Only for direction signs (ending with _right)
|
||||||
|
if name:sub(-string.len("_right")) == "_right" then
|
||||||
|
name = name:sub(1, -string.len("_right"))
|
||||||
|
|
||||||
|
local test = {0, dir.z, -dir.z, -dir.x, dir.x}
|
||||||
|
if test[wdir] > 0 then
|
||||||
|
itemstack:set_name(name.."left")
|
||||||
|
end
|
||||||
|
itemstack = minetest.item_place(itemstack, placer, pointed_thing, wdir)
|
||||||
|
itemstack:set_name(name.."right")
|
||||||
|
|
||||||
|
return itemstack
|
||||||
|
else
|
||||||
|
return minetest.item_place(itemstack, placer, pointed_thing, wdir)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- On_rotate (screwdriver) callback for direction signs
|
||||||
|
function signs.on_rotate_direction(pos, node, user, mode, new_param2)
|
||||||
|
if mode == screwdriver.ROTATE_AXIS then
|
||||||
|
local name
|
||||||
|
if node.name:sub(-string.len("_right")) == "_right" then
|
||||||
|
name = node.name:sub(1, -string.len("_right")).."left"
|
||||||
|
end
|
||||||
|
if node.name:sub(-string.len("_left")) == "_left" then
|
||||||
|
name = node.name:sub(1, -string.len("_left")).."right"
|
||||||
|
end
|
||||||
|
|
||||||
|
if name then
|
||||||
|
minetest.swap_node(pos, {name = name, param1 = node.param1, param2 = node.param2})
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
return display_lib.on_rotate(pos, node, user, mode, new_param2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Populate fonts table
|
||||||
|
local w, filename
|
||||||
|
for charnum=32,126 do
|
||||||
|
filename = string.format("signs_%02x.png", charnum)
|
||||||
|
w = get_png_width(signs.path.."/textures/"..filename)
|
||||||
|
font[charnum] = {filename=filename, width=w}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Generic callback for show_formspec displayed formspecs
|
||||||
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
local found, mod, node_name, pos
|
||||||
|
found, _, mod, node_name, pos = formname:find("([%w_]+):([%w_]+)@(.+)")
|
||||||
|
|
||||||
|
if found then
|
||||||
|
if mod ~= 'signs' then return end
|
||||||
|
|
||||||
|
local ndef = minetest.registered_nodes[mod..":"..node_name]
|
||||||
|
|
||||||
|
if ndef and ndef.on_receive_fields then
|
||||||
|
ndef.on_receive_fields(minetest.string_to_pos(pos), formname, fields, player)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
45
signs/crafts.lua
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
minetest.register_craft({
|
||||||
|
output = 'signs:blue_street',
|
||||||
|
recipe = {
|
||||||
|
{'dye:blue', 'dye:white', 'default:steel_ingot'},
|
||||||
|
{'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'},
|
||||||
|
{'', '', ''},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = 'signs:green_street',
|
||||||
|
recipe = {
|
||||||
|
{'dye:green', 'dye:white', 'default:steel_ingot'},
|
||||||
|
{'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'},
|
||||||
|
{'', '', ''},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = 'signs:wooden_right',
|
||||||
|
recipe = {
|
||||||
|
{'group:wood', 'group:wood', 'group:wood'},
|
||||||
|
{'group:wood', 'group:wood', ''},
|
||||||
|
{'', '', ''},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = 'signs:black_right',
|
||||||
|
recipe = {
|
||||||
|
{'dye:black', 'dye:white', 'default:steel_ingot'},
|
||||||
|
{'default:steel_ingot', 'default:steel_ingot', ''},
|
||||||
|
{'', '', ''},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = 'signs:poster',
|
||||||
|
recipe = {
|
||||||
|
{'default:paper', 'default:paper', ''},
|
||||||
|
{'default:paper', 'default:paper', ''},
|
||||||
|
{'default:paper', 'default:paper', ''},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
3
signs/depends.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
default
|
||||||
|
display_lib
|
||||||
|
|
63
signs/font.lua
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
|
||||||
|
local font = {}
|
||||||
|
signs.font_height = 10
|
||||||
|
|
||||||
|
-- Get png width, suposing png width is less than 256 (it is the case for all font textures)
|
||||||
|
local function get_png_width(filename)
|
||||||
|
local file=assert(io.open(filename,"rb"))
|
||||||
|
-- All font png are smaller than 256x256 --> read only last byte
|
||||||
|
file:seek("set",19)
|
||||||
|
local w = file:read(1)
|
||||||
|
file:close()
|
||||||
|
return w:byte()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Computes line width for a given font height and text
|
||||||
|
function signs.get_line_width(text)
|
||||||
|
local char
|
||||||
|
local width = 0
|
||||||
|
|
||||||
|
for p=1,#text
|
||||||
|
do
|
||||||
|
char = text:sub(p,p):byte()
|
||||||
|
if font[char] then
|
||||||
|
width = width + font[char].width
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return width
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Builds texture part for a text line
|
||||||
|
-- @param text Text to be rendered
|
||||||
|
-- @param x Starting x position in texture
|
||||||
|
-- @param width Width of the texture (extra text is not rendered)
|
||||||
|
-- @param y Vertical position of the line in texture
|
||||||
|
-- @return Texture string
|
||||||
|
function signs.make_line_texture(text, x, width, y)
|
||||||
|
local char
|
||||||
|
|
||||||
|
local texture = ""
|
||||||
|
|
||||||
|
for p=1,#text
|
||||||
|
do
|
||||||
|
char = text:sub(p,p):byte()
|
||||||
|
if font[char] then
|
||||||
|
-- Add image only if it is visible (at least partly)
|
||||||
|
if x + font[char].width >= 0 and x <= width then
|
||||||
|
texture = texture..string.format(":%d,%d=%s", x, y, font[char].filename)
|
||||||
|
end
|
||||||
|
x = x + font[char].width
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return texture
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Populate fonts table
|
||||||
|
local w, filename
|
||||||
|
for charnum=32,126 do
|
||||||
|
filename = string.format("signs_%02x.png", charnum)
|
||||||
|
w = get_png_width(signs.path.."/textures/"..filename)
|
||||||
|
font[charnum] = {filename=filename, width=w}
|
||||||
|
end
|
||||||
|
|
15
signs/init.lua
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
-- Signs mod by P.Y. Rollo
|
||||||
|
--
|
||||||
|
-- License: WTFPL
|
||||||
|
|
||||||
|
signs = {}
|
||||||
|
signs.path = minetest.get_modpath("signs")
|
||||||
|
|
||||||
|
dofile(signs.path.."/common.lua")
|
||||||
|
dofile(signs.path.."/nodes.lua")
|
||||||
|
dofile(signs.path.."/crafts.lua")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
203
signs/nodes.lua
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
-- Poster specific formspec
|
||||||
|
local function on_rightclick_poster(pos, node, player)
|
||||||
|
local formspec
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
if not minetest.is_protected(pos, player:get_player_name()) then
|
||||||
|
formspec =
|
||||||
|
"size[6.5,7.5]"..
|
||||||
|
"field[0.5,0.7;6,1;display_text;Title;"..minetest.formspec_escape(meta:get_string("display_text")).."]"..
|
||||||
|
"textarea[0.5,1.7;6,6;text;Text;"..minetest.formspec_escape(meta:get_string("text")).."]"..
|
||||||
|
"button_exit[2,7;2,1;ok;Write]"
|
||||||
|
minetest.show_formspec(player:get_player_name(),
|
||||||
|
"signs:poster@"..minetest.pos_to_string(pos),
|
||||||
|
formspec)
|
||||||
|
else
|
||||||
|
formspec = "size[8,9]"..
|
||||||
|
"size[6.5,7.5]"..
|
||||||
|
"label[0.5,0;"..minetest.formspec_escape(meta:get_string("display_text")).."]"..
|
||||||
|
"textarea[0.5,1;6,7;;"..minetest.formspec_escape(meta:get_string("text"))..";]"..
|
||||||
|
"bgcolor[#111]"..
|
||||||
|
"button_exit[2,7;2,1;ok;Close]"
|
||||||
|
minetest.show_formspec(player:get_player_name(),
|
||||||
|
"",
|
||||||
|
formspec)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Poster specific on_receive_fields callback
|
||||||
|
local function on_receive_fields_poster(pos, formname, fields, player)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
if not minetest.is_protected(pos, player:get_player_name()) then
|
||||||
|
if fields and fields.ok then
|
||||||
|
meta:set_string("display_text", fields.display_text)
|
||||||
|
meta:set_string("text", fields.text)
|
||||||
|
meta:set_string("infotext", "\""..fields.display_text
|
||||||
|
.."\"\n(right-click to read more text)")
|
||||||
|
display_lib.update_entities(pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
signs.sign_models = {
|
||||||
|
blue_street={
|
||||||
|
depth=1/16,
|
||||||
|
width=14/16,
|
||||||
|
height=12/16,
|
||||||
|
color="#fff",
|
||||||
|
maxlines = 3,
|
||||||
|
xscale = 1/144,
|
||||||
|
yscale = 1/64,
|
||||||
|
fields = {
|
||||||
|
description="Blue street sign",
|
||||||
|
tiles={"signs_blue_street.png"},
|
||||||
|
inventory_image="signs_blue_street_inventory.png",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
green_street={
|
||||||
|
depth=1/32,
|
||||||
|
width=1,
|
||||||
|
height=6/16,
|
||||||
|
color="#fff",
|
||||||
|
maxlines = 1,
|
||||||
|
xscale = 1/96,
|
||||||
|
yscale = 1/64,
|
||||||
|
fields = {
|
||||||
|
description="Green street sign",
|
||||||
|
tiles={"signs_green_street.png"},
|
||||||
|
inventory_image="signs_green_street_inventory.png",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wooden_right={
|
||||||
|
depth=1/16,
|
||||||
|
width=14/16,
|
||||||
|
height=7/16,
|
||||||
|
color="#000",
|
||||||
|
maxlines = 2,
|
||||||
|
xscale = 1/112,
|
||||||
|
yscale = 1/64,
|
||||||
|
fields = {
|
||||||
|
description="Wooden direction sign",
|
||||||
|
tiles={"signs_wooden_right.png"},
|
||||||
|
inventory_image="signs_wooden_inventory.png",
|
||||||
|
on_place=signs.on_place_direction,
|
||||||
|
on_rotate=signs.on_rotate_direction,
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wooden_left={
|
||||||
|
depth=1/16,
|
||||||
|
width=14/16,
|
||||||
|
height=7/16,
|
||||||
|
color="#000",
|
||||||
|
maxlines = 2,
|
||||||
|
xscale = 1/112,
|
||||||
|
yscale = 1/64,
|
||||||
|
fields = {
|
||||||
|
description="Wooden direction sign",
|
||||||
|
tiles={"signs_wooden_left.png"},
|
||||||
|
inventory_image="signs_wooden_inventory.png",
|
||||||
|
groups={choppy=1,oddly_breakable_by_hand=1,not_in_creative_inventory=1},
|
||||||
|
drop="signs:wooden_right",
|
||||||
|
on_place=signs.on_place_direction,
|
||||||
|
on_rotate=signs.on_rotate_direction,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
black_right={
|
||||||
|
depth=1/32,
|
||||||
|
width=1,
|
||||||
|
height=0.5,
|
||||||
|
color="#000",
|
||||||
|
maxlines = 1,
|
||||||
|
xscale = 1/96,
|
||||||
|
yscale = 1/64,
|
||||||
|
fields = {
|
||||||
|
description="Black direction sign",
|
||||||
|
tiles={"signs_black_right.png"},
|
||||||
|
inventory_image="signs_black_inventory.png",
|
||||||
|
on_place=signs.on_place_direction,
|
||||||
|
on_rotate=signs.on_rotate_direction,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
black_left={
|
||||||
|
depth=1/32,
|
||||||
|
width=1,
|
||||||
|
height=0.5,
|
||||||
|
color="#000",
|
||||||
|
maxlines = 1,
|
||||||
|
xscale = 1/96,
|
||||||
|
yscale = 1/64,
|
||||||
|
fields = {
|
||||||
|
description="Black direction sign",
|
||||||
|
tiles={"signs_black_left.png"},
|
||||||
|
inventory_image="signs_black_inventory.png",
|
||||||
|
groups={choppy=1,oddly_breakable_by_hand=1,not_in_creative_inventory=1},
|
||||||
|
drop="signs:black_right",
|
||||||
|
on_place=signs.on_place_direction,
|
||||||
|
on_rotate=signs.on_rotate_direction,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
poster={
|
||||||
|
depth=1/32,
|
||||||
|
width=26/32,
|
||||||
|
height=30/32,
|
||||||
|
color="#000",
|
||||||
|
valing="top",
|
||||||
|
maxlines = 1,
|
||||||
|
xscale = 1/144,
|
||||||
|
yscale = 1/64,
|
||||||
|
fields = {
|
||||||
|
description="Poster",
|
||||||
|
tiles={"signs_poster.png"},
|
||||||
|
inventory_image="signs_poster_inventory.png",
|
||||||
|
on_construct=display_lib.on_construct,
|
||||||
|
on_rightclick=on_rightclick_poster,
|
||||||
|
on_receive_fields=on_receive_fields_poster,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
display_lib.register_display_entity("signs:text")
|
||||||
|
|
||||||
|
for model_name, model in pairs(signs.sign_models)
|
||||||
|
do
|
||||||
|
local fields = {
|
||||||
|
sunlight_propagates = true,
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "wallmounted",
|
||||||
|
drawtype = "nodebox",
|
||||||
|
node_box = {
|
||||||
|
type = "wallmounted",
|
||||||
|
wall_side = {-0.5, -model.height/2, -model.width/2,
|
||||||
|
-0.5 + model.depth, model.height/2, model.width/2},
|
||||||
|
wall_bottom = {-model.width/2, -0.5, -model.height/2,
|
||||||
|
model.width/2, -0.5 + model.depth, model.height/2},
|
||||||
|
wall_top = {-model.width/2, 0.5, -model.height/2,
|
||||||
|
model.width/2, 0.5 - model.depth, model.height/2},
|
||||||
|
},
|
||||||
|
groups = {choppy=1,oddly_breakable_by_hand=1},
|
||||||
|
sign_model = model_name,
|
||||||
|
display_entities = {
|
||||||
|
["signs:text"] = {
|
||||||
|
depth = model.depth-0.499,
|
||||||
|
on_display_update = signs.on_display_update },
|
||||||
|
},
|
||||||
|
on_place = display_lib.on_place,
|
||||||
|
on_construct = function(pos)
|
||||||
|
signs.set_formspec(pos)
|
||||||
|
display_lib.on_construct(pos)
|
||||||
|
end,
|
||||||
|
on_destruct = display_lib.on_destruct,
|
||||||
|
on_rotate = display_lib.on_rotate,
|
||||||
|
on_receive_fields = signs.on_receive_fields,
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value in pairs(model.fields) do
|
||||||
|
fields[key] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
if not fields.wield_image then fields.wield_image = fields.inventory_image end
|
||||||
|
|
||||||
|
minetest.register_node("signs:"..model_name, fields)
|
||||||
|
end
|
||||||
|
|
BIN
signs/textures/signs_20.png
Normal file
After Width: | Height: | Size: 232 B |
BIN
signs/textures/signs_21.png
Normal file
After Width: | Height: | Size: 241 B |
BIN
signs/textures/signs_22.png
Normal file
After Width: | Height: | Size: 235 B |
BIN
signs/textures/signs_23.png
Normal file
After Width: | Height: | Size: 244 B |
BIN
signs/textures/signs_24.png
Normal file
After Width: | Height: | Size: 247 B |
BIN
signs/textures/signs_25.png
Normal file
After Width: | Height: | Size: 247 B |
BIN
signs/textures/signs_26.png
Normal file
After Width: | Height: | Size: 246 B |
BIN
signs/textures/signs_27.png
Normal file
After Width: | Height: | Size: 238 B |
BIN
signs/textures/signs_28.png
Normal file
After Width: | Height: | Size: 242 B |
BIN
signs/textures/signs_29.png
Normal file
After Width: | Height: | Size: 241 B |
BIN
signs/textures/signs_2a.png
Normal file
After Width: | Height: | Size: 238 B |
BIN
signs/textures/signs_2b.png
Normal file
After Width: | Height: | Size: 241 B |
BIN
signs/textures/signs_2c.png
Normal file
After Width: | Height: | Size: 238 B |
BIN
signs/textures/signs_2d.png
Normal file
After Width: | Height: | Size: 237 B |
BIN
signs/textures/signs_2e.png
Normal file
After Width: | Height: | Size: 236 B |
BIN
signs/textures/signs_2f.png
Normal file
After Width: | Height: | Size: 244 B |
BIN
signs/textures/signs_30.png
Normal file
After Width: | Height: | Size: 239 B |
BIN
signs/textures/signs_31.png
Normal file
After Width: | Height: | Size: 239 B |
BIN
signs/textures/signs_32.png
Normal file
After Width: | Height: | Size: 247 B |
BIN
signs/textures/signs_33.png
Normal file
After Width: | Height: | Size: 246 B |
BIN
signs/textures/signs_34.png
Normal file
After Width: | Height: | Size: 247 B |
BIN
signs/textures/signs_35.png
Normal file
After Width: | Height: | Size: 247 B |
BIN
signs/textures/signs_36.png
Normal file
After Width: | Height: | Size: 244 B |
BIN
signs/textures/signs_37.png
Normal file
After Width: | Height: | Size: 242 B |
BIN
signs/textures/signs_38.png
Normal file
After Width: | Height: | Size: 240 B |
BIN
signs/textures/signs_39.png
Normal file
After Width: | Height: | Size: 243 B |
BIN
signs/textures/signs_3a.png
Normal file
After Width: | Height: | Size: 237 B |
BIN
signs/textures/signs_3b.png
Normal file
After Width: | Height: | Size: 240 B |
BIN
signs/textures/signs_3c.png
Normal file
After Width: | Height: | Size: 245 B |
BIN
signs/textures/signs_3d.png
Normal file
After Width: | Height: | Size: 236 B |
BIN
signs/textures/signs_3e.png
Normal file
After Width: | Height: | Size: 245 B |
BIN
signs/textures/signs_3f.png
Normal file
After Width: | Height: | Size: 243 B |
BIN
signs/textures/signs_40.png
Normal file
After Width: | Height: | Size: 259 B |
BIN
signs/textures/signs_41.png
Normal file
After Width: | Height: | Size: 243 B |
BIN
signs/textures/signs_42.png
Normal file
After Width: | Height: | Size: 240 B |
BIN
signs/textures/signs_43.png
Normal file
After Width: | Height: | Size: 246 B |
BIN
signs/textures/signs_44.png
Normal file
After Width: | Height: | Size: 242 B |
BIN
signs/textures/signs_45.png
Normal file
After Width: | Height: | Size: 240 B |
BIN
signs/textures/signs_46.png
Normal file
After Width: | Height: | Size: 241 B |
BIN
signs/textures/signs_47.png
Normal file
After Width: | Height: | Size: 247 B |
BIN
signs/textures/signs_48.png
Normal file
After Width: | Height: | Size: 240 B |
BIN
signs/textures/signs_49.png
Normal file
After Width: | Height: | Size: 236 B |
BIN
signs/textures/signs_4a.png
Normal file
After Width: | Height: | Size: 240 B |
BIN
signs/textures/signs_4b.png
Normal file
After Width: | Height: | Size: 246 B |
BIN
signs/textures/signs_4c.png
Normal file
After Width: | Height: | Size: 238 B |
BIN
signs/textures/signs_4d.png
Normal file
After Width: | Height: | Size: 249 B |
BIN
signs/textures/signs_4e.png
Normal file
After Width: | Height: | Size: 243 B |
BIN
signs/textures/signs_4f.png
Normal file
After Width: | Height: | Size: 243 B |
BIN
signs/textures/signs_50.png
Normal file
After Width: | Height: | Size: 241 B |
BIN
signs/textures/signs_51.png
Normal file
After Width: | Height: | Size: 244 B |
BIN
signs/textures/signs_52.png
Normal file
After Width: | Height: | Size: 238 B |
BIN
signs/textures/signs_53.png
Normal file
After Width: | Height: | Size: 247 B |
BIN
signs/textures/signs_54.png
Normal file
After Width: | Height: | Size: 237 B |
BIN
signs/textures/signs_55.png
Normal file
After Width: | Height: | Size: 238 B |
BIN
signs/textures/signs_56.png
Normal file
After Width: | Height: | Size: 243 B |
BIN
signs/textures/signs_57.png
Normal file
After Width: | Height: | Size: 246 B |
BIN
signs/textures/signs_58.png
Normal file
After Width: | Height: | Size: 245 B |
BIN
signs/textures/signs_59.png
Normal file
After Width: | Height: | Size: 244 B |
BIN
signs/textures/signs_5a.png
Normal file
After Width: | Height: | Size: 248 B |
BIN
signs/textures/signs_5b.png
Normal file
After Width: | Height: | Size: 234 B |
BIN
signs/textures/signs_5c.png
Normal file
After Width: | Height: | Size: 244 B |
BIN
signs/textures/signs_5d.png
Normal file
After Width: | Height: | Size: 234 B |
BIN
signs/textures/signs_5e.png
Normal file
After Width: | Height: | Size: 238 B |
BIN
signs/textures/signs_5f.png
Normal file
After Width: | Height: | Size: 233 B |