More work being done. And... bugs.
All checks were successful
Error Check / luacheck_errcheck (push) Successful in 37s
Unit Tests / busted_unit_test (push) Successful in 48s

This commit is contained in:
DesertMermaid 2024-12-11 14:47:15 -08:00
parent 0242488c9e
commit a260c4a33a
20 changed files with 1102 additions and 80 deletions

View file

@ -0,0 +1,152 @@
# Vox Coloring Mod
The `vox_coloring` mod is a dynamic and robust system for adding colorable items, blocks, and decorations to your Minetest game. It enables automatic registration of dyeable variants, recipes for applying and removing dyes, and integration with other mods.
---
## Features
- **Dynamic Dye Registration**:
- Automatically generates colorable variants of nodes and items.
- Uses a neutral "template" texture for consistent colorization.
- **Custom Recipes**:
- Recipes for dyeing nodes and items.
- Recipes for reverting dyed objects to their original state.
- **Spraygun Tool**:
- Dye objects directly in the world with a spraygun.
- **Cleaning Station**:
- Revert dyed objects in bulk using the cleaning station.
- **Mod Integration**:
- Other mods can easily register their own dyeable items.
---
## How to Use
### Registering Dyeable Items/Blocks
To register a dyeable item or block, call the `register_dyeable` function in your mod:
```lua
-- List of dyeable things
local dyeable_blocks = {"sand", "terracotta", "marble", "cobblestone", "sandstone"}
-- Register base things their dyeable variants
for _, base_block in ipairs(dyeable_blocks) do
vox_coloring.register_dyeable("vox_worldblocks", base_block)
end
```
Parameters:
```plaintext
modname: The name of your mod (e.g., vox_worldblocks).
base_item: The name of the base item/block to make dyeable.
```
Example:
```lua
vox_coloring.register_dyeable("vox_worldblocks", "sand")
```
### Objects Added
#### Cleaning Solvent
```plaintext
Soap | Bucket of Water | Salt
Ash
```
#### Cleaning Station
```plaintext
Iron Ingot | Bucket of Water | Iron Ingot
Stone | Soap | Stone
Stone | Empty | Stone
```
Our recipe expects these to exist, but you can edit things to suit your game.
```lua
-- Ash
minetest.register_craftitem("vox_mats:ash", {
description = "Ash",
inventory_image = "ash.png",
groups = {crumbly = 3},
})
-- Salt
minetest.register_craftitem("vox_mats:salt", {
description = "Salt",
inventory_image = "salt.png",
})
-- Lye
minetest.register_craftitem("vox_mats:lye", {
description = "Lye",
inventory_image = "lye.png",
})
minetest.register_craft({
output = "vox_mats:lye",
recipe = {
{"vox_mats:ash", "bucket:water_bucket"},
},
replacements = {{"bucket:water_bucket", "bucket:bucket"}},
})
-- Soap
minetest.register_craftitem("vox_mats:soap", {
description = "Soap",
inventory_image = "soap.png",
})
minetest.register_craft({
output = "vox_mats:soap",
recipe = {
{"vox_mobdrops:fat", "vox_mats:lye", "vox_mats:salt"},
},
})
```
We also expect colors to be registered somewhere. Our personal example:
Not full file, but vox_colors contains this part vox_coloring needs...
```lua
vox_colors = {
WHITE = "#FFFFFF",
LIGHTGREY = "#D3D3D3",
SILVER = "#C0C0C0",
GREY = "#808080",
BLACK = "#000000",
RED = "#FF0000",
DARK_RED = "#8B0000",
YELLOW = "#FFFF00",
GOLD = "#FFD700",
ORANGE = "#FFA500",
PUMPKIN = "#FF7518",
CREAM = "#FFFDD0",
TAN = "#D2B48C",
BROWN = "#A52A2A",
DARK_BROWN = "#8B4513",
LIME = "#00FF00",
MINT = "#98FF98",
EMERALD = "#50C878",
DARK_GREEN = "#006400",
TURQUOISE = "#40E0D0",
TEAL = "#008080",
CYAN = "#00FFFF",
BLUE = "#0000FF",
NAVY = "#000080",
MAGENTA = "#FF00FF",
VIOLET = "#EE82EE",
PURPLE = "#800080",
INDIGO = "#4B0082",
PINK = "#FF69B4",
FLAMINGO = "#FC8EAC",
}
```

View file

@ -0,0 +1,212 @@
-- Vox Coloring System
-- Register dyes dynamically based on vox_colors
for color_name, color_hex in pairs(vox_colors) do
if type(color_hex) == "string" and vox_colors.validate(color_hex) then
minetest.register_craftitem("vox_coloring:dye_" .. color_name:lower(), {
description = color_name .. " Dye",
inventory_image = "dye_template.png^[multiply:" .. color_hex,
groups = {dye = 1},
})
end
end
-- Table to hold registered dyeable items
local dyeable_registry = {}
-- Function for other mods to register colorable items or blocks
function vox_coloring.register_dyeable(modname, base_item)
dyeable_registry[modname] = dyeable_registry[modname] or {}
table.insert(dyeable_registry[modname], base_item)
-- Get the original node definition
local base_item_full = modname .. ":" .. base_item
local base_def = minetest.registered_nodes[base_item_full]
if not base_def then
minetest.log("error", "[vox_coloring] Failed to register dyeable item: " .. base_item_full .. " does not exist.")
return
end
-- Derive the template texture by appending `_colorize` to the base texture filename
local base_texture = base_def.tiles and base_def.tiles[1]
if not base_texture then
minetest.log("error", "[vox_coloring] No texture found for " .. base_item_full)
return
end
local colorize_texture = base_texture:gsub("%.png$", "_colorize.png")
-- Iterate over all colors and register dyeable variants
for color_name, color_hex in pairs(vox_colors) do
if type(color_hex) == "string" then
local colored_item = modname .. ":" .. base_item .. "_" .. color_name:lower()
-- Register the colored version of the item/block
minetest.register_node(colored_item, {
description = base_def.description .. " (" .. color_name .. ")",
tiles = {colorize_texture .. "^[multiply:" .. color_hex},
groups = base_def.groups or {},
})
-- Register recipe to dye the item/block
minetest.register_craft({
output = colored_item,
recipe = {
{base_item_full, "vox_coloring:dye_" .. color_name:lower()},
},
})
-- Register recipe to undye the item/block
minetest.register_craft({
output = base_item_full,
recipe = {
{colored_item, "vox_coloring:cleaning_solvent"},
},
replacements = {{"vox_coloring:cleaning_solvent", "bucket:bucket"}},
})
end
end
end
-- Function to unregister a dyeable item or block
function vox_coloring.unregister_dyeable(modname, base_item)
if not dyeable_registry[modname] then return end
for i, item in ipairs(dyeable_registry[modname]) do
if item == base_item then
table.remove(dyeable_registry[modname], i)
break
end
end
-- Remove all colored variants and recipes
for color_name, _ in pairs(vox_colors) do
local colored_item = modname .. ":" .. base_item .. "_" .. color_name:lower()
minetest.unregister_item(colored_item)
end
end
-- Spraygun Tool
minetest.register_tool("vox_coloring:spraygun", {
description = "Spraygun",
inventory_image = "spraygun.png",
on_use = function(itemstack, user, pointed_thing)
if pointed_thing.type == "node" then
local node = minetest.get_node(pointed_thing.under)
local meta = itemstack:get_meta()
local dye_color = meta:get_string("dye_color")
if dye_color and vox_colors[dye_color:upper()] then
local modname, item_base = node.name:match("^(.-):(.*)")
if modname and item_base then
local colored_item = modname .. ":" .. item_base .. "_" .. dye_color:lower()
if minetest.registered_nodes[colored_item] then
minetest.swap_node(pointed_thing.under, {name = colored_item})
itemstack:add_wear(65535 / 100) -- Simulate durability loss
minetest.chat_send_player(user:get_player_name(), "Dyed with " .. dye_color .. "!")
else
minetest.chat_send_player(user:get_player_name(), "Cannot dye this object.")
end
else
minetest.chat_send_player(user:get_player_name(), "No valid target for dye.")
end
else
minetest.chat_send_player(user:get_player_name(), "No valid dye loaded in the spraygun.")
end
end
return itemstack
end,
})
-- Add dye to the spraygun
minetest.register_craftitem("vox_coloring:dye_cartridge", {
description = "Dye Cartridge",
inventory_image = "dye_cartridge.png",
on_place = function(itemstack, user, pointed_thing)
local wielded = user:get_wielded_item()
if wielded:get_name() == "vox_coloring:spraygun" then
local meta = wielded:get_meta()
local dye_color = itemstack:get_name():match("vox_coloring:dye_(%w+)")
if dye_color then
meta:set_string("dye_color", dye_color)
minetest.chat_send_player(user:get_player_name(), "Spraygun loaded with " .. dye_color .. " dye!")
return itemstack:take_item()
else
minetest.chat_send_player(user:get_player_name(), "Failed to load dye into the spraygun.")
end
end
return itemstack
end,
})
-- Cleaning Solvent
minetest.register_craftitem("vox_coloring:cleaning_solvent", {
description = "Cleaning Solvent",
inventory_image = "cleaning_solvent.png",
on_use = function(itemstack, user, pointed_thing)
if pointed_thing.type == "node" then
local node = minetest.get_node(pointed_thing.under)
local modname, item_base = node.name:match("^(.-):(.*)")
if modname and item_base then
local base_item = item_base:match("^(.-)_")
if base_item then
local original_item = modname .. ":" .. base_item
if minetest.registered_nodes[original_item] then
minetest.swap_node(pointed_thing.under, {name = original_item})
itemstack:take_item()
minetest.chat_send_player(user:get_player_name(), "Reverted to original state.")
else
minetest.chat_send_player(user:get_player_name(), "This block cannot be cleaned.")
end
else
minetest.chat_send_player(user:get_player_name(), "No dye detected on this block.")
end
else
minetest.chat_send_player(user:get_player_name(), "No dye detected on this block.")
end
end
return itemstack
end,
})
-- Recipe for Cleaning Solvent
minetest.register_craft({
output = "vox_coloring:cleaning_solvent",
recipe = {
{"vox_mats:soap", "bucket:water_bucket", "vox_mats:salt"},
{"vox_mats:ash", "", ""},
},
replacements = {{"bucket:water_bucket", "bucket:bucket"}},
})
-- Cleaning Station
minetest.register_node("vox_coloring:cleaning_station", {
description = "Cleaning Station",
tiles = {"cleaning_station_top.png", "cleaning_station_side.png"},
groups = {cracky = 2},
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
local inv = player:get_inventory()
if inv:contains_item("main", "vox_coloring:cleaning_solvent") then
local node_name = minetest.get_node(pointed_thing.under).name
local modname, item_base = node_name:match("^(.-):(.*)")
if modname and item_base then
local base_item = item_base:match("^(.-)_")
if base_item then
local original_item = modname .. ":" .. base_item
if minetest.registered_nodes[original_item] then
minetest.swap_node(pointed_thing.under, {name = original_item})
inv:remove_item("main", "vox_coloring:cleaning_solvent")
minetest.chat_send_player(player:get_player_name(), "Reverted to original state.")
else
minetest.chat_send_player(player:get_player_name(), "This block cannot be cleaned.")
end
else
minetest.chat_send_player(player:get_player_name(), "No dye detected on this block.")
end
else
minetest.chat_send_player(player:get_player_name(), "No dye detected on this block.")
end
else
minetest.chat_send_player(player:get_player_name(), "You need cleaning solvent to clean blocks.")
end
end,
})

View file

@ -0,0 +1,2 @@
name = vox_coloring
description = Voxelis - coloring. Adds dynamic dyes, dynamically adds dyed (fill in the blanks) from mods that call upon the function, adds other things that are helpful.