Merge branch 'skins'

master
Wuzzy 2021-08-03 18:38:42 +02:00
commit fe5965d7ad
34 changed files with 554 additions and 1 deletions

View File

@ -768,9 +768,18 @@ minetest.register_node("hades_core:diamondblock", {
minetest.register_node("hades_core:bookshelf", {
description = S("Bookshelf"),
tiles = {"default_wood.png", "default_wood.png", "default_bookshelf.png"},
paramtype2 = "facedir",
tiles = {
{name="default_wood.png", align_style="world"},
{name="default_wood.png", align_style="world"},
{name="default_wood.png", align_style="world"},
{name="default_wood.png", align_style="world"},
"default_bookshelf.png",
"default_bookshelf.png",
},
is_ground_content = false,
groups = {choppy=3,oddly_breakable_by_hand=2,flammable=3},
sounds = hades_sounds.node_sound_wood_defaults(),
on_rotate = "simple",
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 459 B

After

Width:  |  Height:  |  Size: 560 B

View File

@ -0,0 +1,9 @@
Mesh hand mod for Hades Revisited
This mod uses a better-looking mesh for the wieldhand and applies the player skin color to it.
== Credits ==
Based on 3D Hand [newhand] mod by jordan4ibanez.
https://forum.minetest.net/viewtopic.php?t=16435
License: CC0

View File

@ -0,0 +1,41 @@
hades_meshhand = {}
local handdef = minetest.registered_items[""]
-- This is a fake node that should never be placed in the world
minetest.register_node("hades_meshhand:hand", {
description = "",
tiles = {"hades_skins_skin_base.png"},
use_texture_alpha = "opaque",
visual_scale = 1,
wield_scale = {x=1,y=1,z=1},
paramtype = "light",
drawtype = "mesh",
mesh = "hades_meshhand.b3d",
-- Prevent construction
node_placement_prediction = "",
on_construct = function(pos)
minetest.log("error", "[hades_meshhand] Trying to construct hades_meshhand:hand at "..minetest.pos_to_string(pos))
minetest.remove_node(pos)
end,
drop = "",
on_drop = function()
return ""
end,
-- Allow to get rid of the node if it somehow ended up in world
buildable_to = true,
groups = { dig_immediate = 3, not_in_creative_inventory = 1 },
range = handdef.range,
})
minetest.register_on_joinplayer(function(player)
player:get_inventory():set_size("hand", 1)
end)
function hades_meshhand.set_skin_color(player, colorstring)
local hand = ItemStack("hades_meshhand:hand")
local handmeta = hand:get_meta()
handmeta:set_string("color", colorstring)
player:get_inventory():set_stack("hand", 1, hand)
end

View File

@ -0,0 +1,3 @@
name = hades_meshhand
author = jordan4ibanez
description = Applies the player skin texture to the hand.

Binary file not shown.

Binary file not shown.

View File

@ -77,6 +77,12 @@ function hades_player.player_set_textures(player, textures)
player:set_properties({textures = textures,})
end
function hades_player.player_get_textures(player)
local name = player:get_player_name()
local props = player:get_properties()
return props.textures
end
function hades_player.player_set_animation(player, anim_name, speed)
local name = player:get_player_name()
if player_anim[name] == anim_name then

View File

@ -0,0 +1,40 @@
License and credits:
The overall license of the media is CC BY-SA 3.0.
In the list below, there's a list of all authors and indivudual file licenses.
Note: Files marked with an asterisk were modified from the original.
Wuzzy (CC0 1.0):
- hades_skins_eyes_base.png
- hades_skins_eyes_pupils.png
- hades_skins_mouth.png
- hades_skins_pupils.png
- hades_skins_pants_shorts.png
- hades_skins_pants_hotpants.png
- hades_skins_shirt_top.png
- hades_skins_shirt_tanktop.png
- hades_skins_accessory_head_flowers.png
Kosanaya (CC BY-SA 3.0):
* hades_skins_accessory_head_ribbon.png (original skin: Bikutoria_by_Kosanaya.png)
Minetestian (CC BY-SA 3.0):
* hades_skins_shirt_t-shirt.png (original skin: Minetestian_by_Minetestian.png)
nelly (CC BY-SA 3.0):
* hades_skins_hair_long.png (original skin: Emma_by_nelly.png)
QoiOui (CC BY-SA 3.0):
* hades_skins_hair_beard.png (original skin: QoiOui_by_QoiOui.png)
Geopbyte (CC BY-SA 3.0):
* character.png (original skin: Geopbyte_by_Geopbyte.png)
* hades_skins_belt_simple.png (original skin: Geopbyte_by_Geopbyte.png)
* hades_skins_hair_medium.png (original skin: Geopbyte_by_Geopbyte.png)
* hades_skins_pants_long.png (original skin: Geopbyte_by_Geopbyte.png)
* hades_skins_shirt_shirt.png (original skin: Geopbyte_by_Geopbyte.png)
* hades_skins_shoes_simple.png (original skin: Geopbyte_by_Geopbyte.png)
* hades_skins_skin_base.png (original skin: Geopbyte_by_Geopbyte.png)

397
mods/hades_skins/init.lua Normal file
View File

@ -0,0 +1,397 @@
local S = minetest.get_translator("hades_skins")
local F = minetest.formspec_escape
hades_skins = {}
local editor_color_states = {} -- current skin/clothing colors per-player
local editor_cloth_states = {} -- current clothing IDs per-player
local editor_current_color = {} -- current value of color widgets in color editor
local editor_current_color_cloth = {} -- clothing type ID that the player currently edits the color of
local get_color = function(r, g, b)
if not r then
r = math.random(0,255)
end
if not g then
g = math.random(0,255)
end
if not b then
b = math.random(0,255)
end
local cspec = {r=r, g=g, b=b, a=255}
local cstr = string.format("#%.2X%.2X%.2X", r, g, b)
return cstr, cspec
end
local styles = {
hair = {
{ name = "medium", desc = S("Medium hair") },
{ name = "long", desc = S("Long hair") },
{ name = "beard", desc = S("Hair with beard") },
},
accessory_head = {
{ name = "blank", desc = S("No accessory") },
{ name = "ribbon", desc = S("Ribbon") },
{ name = "headband", desc = S("Headband") },
{ name = "flowers", desc = S("Head flowers") },
},
shirt = {
{ name = "shirt", desc = S("Shirt") },
{ name = "t-shirt", desc = S("T-Shirt") },
{ name = "tanktop", desc = S("Tanktop") },
{ name = "top", desc = S("Top") },
},
belt = {
{ name = "blank", desc = S("No belt") },
{ name = "simple", desc = S("Belt") },
},
pants = {
{ name = "long", desc = S("Long pants") },
{ name = "shorts", desc = S("Shorts") },
{ name = "hotpants", desc = S("Hotpants") },
},
shoes = {
{ name = "simple", desc = S("Shoes") },
},
skin = {
{ name = "base", desc = S("Skin") },
},
eyes = {
{ name = "pupils", desc = S("Eyes") },
},
}
-- Also styles by ID for reverse lookup
local style_ids = {}
for k,v in pairs(styles) do
local style = styles[k]
style_ids[k] = {}
for q,r in pairs(style) do
style_ids[k][r.name] = q
end
end
-- Sort styles by the rough position on the body (from top to bottom)
local styles_sorted = {
"skin", "accessory_head", "hair", "eyes", "shirt", "belt", "pants", "shoes"
}
local load_skin = function(player)
local meta = player:get_meta()
local bases_meta = meta:get_string("hades_skins_bases")
local colors_meta = meta:get_string("hades_skins_colors")
if bases_meta == "" or colors_meta == "" then
-- If skin could not loaded, select a random one
hades_skins.player_set_random_textures(player)
return
end
local bases = string.split(bases_meta, ",")
local colors = string.split(colors_meta, ",")
local name = player:get_player_name()
for b=1, #bases do
local kv = string.split(bases[b], "=")
local k = kv[1]
local v = kv[2]
if style_ids[k] and style_ids[k][v] then
editor_cloth_states[name][k] = style_ids[k][v]
else
-- Fallback if no corresponding ID found
editor_cloth_states[name][k] = 1
end
end
for c=1, #colors do
local kv = string.split(colors[c], "=")
local k = kv[1]
local v = kv[2]
editor_color_states[name][k] = tonumber(string.sub(v, 2), 16)
end
end
local save_skin = function(player)
local name = player:get_player_name()
local cells = {}
for k,v in pairs(styles) do
local cloth_state = editor_cloth_states[name][k]
local cloth_style = v[cloth_state].name
table.insert(cells, k .. "=" .. cloth_style)
end
local outstr = table.concat(cells, ",")
local meta = player:get_meta()
meta:set_string("hades_skins_bases", outstr)
cells = {}
for k,v in pairs(editor_color_states[name]) do
table.insert(cells, k .. "=" .. string.format("#%.6X", v))
end
outstr = table.concat(cells, ",")
meta:set_string("hades_skins_colors", outstr)
end
function hades_skins.get_random_textures_and_colors()
-- for texture handling
local color = {} -- colorstring
local base = {} -- clothing name
-- for editor states table
local color_state = {} -- color as number
local base_id = {} -- clothing ID
local tex = {}
for s=1, #styles_sorted do
local k = styles_sorted[s]
local cspec
color[k], cspec = get_color()
color_state[k] = cspec.r * 0x10000 + cspec.g * 0x100 + cspec.b
local v = styles[k]
base_id[k] = math.random(1, #v)
base[k] = v[base_id[k]].name
end
return { colors = color, bases = base, base_ids = base_id, color_states = color_state }
end
function hades_skins.build_texture(base, color)
local tex = {}
for k, v in pairs(styles) do
if base[k] ~= "blank" then
tex[k] = "^(hades_skins_"..k.."_"..base[k]..".png"
tex[k] = tex[k] .. "^[multiply:"..color[k]..")"
else
tex[k] = ""
end
end
if not color.skin then
color.skin = get_color()
end
if not color.eyes then
color.eyes = get_color()
end
local eyes = "^(hades_skins_eyes_base.png"
.. "^(hades_skins_eyes_pupils.png^[multiply:"..color.eyes.."))"
local skin = "((hades_skins_skin_base.png^hades_skins_mouth.png)^[multiply:"..color.skin..")"
local texture = skin
.. eyes
.. tex.pants
.. tex.shoes
.. tex.shirt
.. tex.belt
.. tex.hair
.. tex.accessory_head
return { textures = { texture }, colors = color }
end
function hades_skins.editor_state_to_textures(player)
local name = player:get_player_name()
local bases = {}
local colors = {}
for k,v in pairs(editor_cloth_states[name]) do
bases[k] = styles[k][v].name
end
for k,v in pairs(editor_color_states[name]) do
colors[k] = string.format("#%.6X", v)
end
return hades_skins.build_texture(bases, colors)
end
function hades_skins.player_set_textures(player, textures, skin_color)
save_skin(player)
hades_player.player_set_textures(player, textures)
-- Set meshhand
hades_meshhand.set_skin_color(player, skin_color)
end
function hades_skins.player_set_random_textures(player)
local texcol = hades_skins.get_random_textures_and_colors()
local name = player:get_player_name()
for k,v in pairs(texcol.base_ids) do
editor_cloth_states[name][k] = v
end
for k,v in pairs(texcol.color_states) do
editor_color_states[name][k] = v
end
local out = hades_skins.build_texture(texcol.bases, texcol.colors)
hades_skins.player_set_textures(player, out.textures, out.colors.skin)
end
function hades_skins.show_skin_editor(player, texture)
if not texture then
texture = hades_player.player_get_textures(player)
if not texture then
return
end
texture = texture[1]
end
local formspec = [[
formspec_version[4]
size[12,11]
box[0.4,0.4;4.2,8.2;#FFFFFF4F]
box[0.5,0.5;4,8;#000000FF]
model[0.5,0.5;4,8;playerpreview;character.b3d;]]..texture..[[;0,180;false;true;0,79]
button[0.5,9.75;3,0.8;random;]]..F(S("Random skin"))..[[]
button_exit[9.55,9.75;2,0.8;submit;]]..F(S("Close"))..[[]
]]
local name = player:get_player_name()
local y = 0.5
for i=1, #styles_sorted do
local s = styles_sorted[i]
local id = editor_cloth_states[name][s]
local choice = styles[s][id].name
local desc = styles[s][id].desc
formspec = formspec .. "button[5.15,"..y..";1,0.8;"..s.."_prev;<]"
formspec = formspec .. "button[6.15,"..y..";3,0.8;"..s..";"..F(desc).."]"
formspec = formspec .. "button[9.15,"..y..";1,0.8;"..s.."_next;>]"
formspec = formspec .. "button[10.55,"..y..";1,0.8;"..s.."_color;"..F(S("Color")).."]"
y = y + 0.9
end
minetest.show_formspec(player:get_player_name(), "hades_skins:skin_editor", formspec)
end
function hades_skins.show_skin_editor_color(player, texture, color)
local name = player:get_player_name()
if not texture then
texture = hades_player.player_get_textures(player)
if not texture then
return
end
texture = texture[1]
end
if not color then
local cloth = editor_current_color_cloth[name] or "shirt"
local k = editor_color_states[name][cloth] or 0xFFFFFF
local r = math.floor(k / 65536)
local g = math.floor(k / 256) % 256
local b = k % 256
editor_current_color[name].r = r
editor_current_color[name].g = g
editor_current_color[name].b = b
else
editor_current_color[name] = table.copy(color)
end
local form = [[
formspec_version[4]
size[12,11]
box[0.4,0.4;4.2,8.2;#FFFFFF4F]
box[0.5,0.5;4,8;#000000FF]
model[0.5,0.5;4,8;playerpreview;character.b3d;]]..texture..[[;0,180;false;true;0,79]
scrollbaroptions[min=0;max=255;smallstep=8;largestep=64]
scrollbar[5,1.5;5,0.5;horizontal;red;]]..editor_current_color[name].r..[[]
scrollbar[5,3.5;5,0.5;horizontal;green;]]..editor_current_color[name].g..[[]
scrollbar[5,5.5;5,0.5;horizontal;blue;]]..editor_current_color[name].b..[[]
label[5,1.1;]]..F(S("Red"))..[[]
label[5,3.1;]]..F(S("Green"))..[[]
label[5,5.1;]]..F(S("Blue"))..[[]
button[0.5,9.75;3,0.8;random;]]..F(S("Random color"))..[[]
button[5,7.75;3,0.8;update;]]..F(S("Update preview"))..[[]
button_exit[9.55,9.75;2,0.8;submit;]]..F(S("Back"))..[[]
]]
minetest.show_formspec(name, "hades_skins:skin_editor_color", form)
end
minetest.register_on_joinplayer(function(player)
local name = player:get_player_name()
-- Initialize skin states
editor_color_states[name] = {}
editor_cloth_states[name] = {}
editor_current_color[name] = { r = 255, g = 255, b = 255 }
for k,_ in pairs(styles) do
editor_cloth_states[name][k] = 1
editor_color_states[name][k] = math.random(0, 0xFFFFFF)
end
-- Load skin
load_skin(player)
local out = hades_skins.editor_state_to_textures(player)
hades_skins.player_set_textures(player, out.textures, out.colors.skin)
end)
minetest.register_on_leaveplayer(function(player)
local name = player:get_player_name()
save_skin(player)
editor_color_states[name] = nil
editor_cloth_states[name] = nil
editor_current_color[name] = nil
end)
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == "hades_skins:skin_editor" then
local name = player:get_player_name()
local update_skin = function(player)
local out = hades_skins.editor_state_to_textures(player)
hades_skins.player_set_textures(player, out.textures, out.colors.skin)
hades_skins.show_skin_editor(player)
end
for stylename,_ in pairs(styles) do
if fields[stylename] or fields[stylename.."_next"] then
editor_cloth_states[name][stylename] = editor_cloth_states[name][stylename] + 1
if editor_cloth_states[name][stylename] > #styles[stylename] then
editor_cloth_states[name][stylename] = 1
end
update_skin(player)
return
elseif fields[stylename.."_prev"] then
editor_cloth_states[name][stylename] = editor_cloth_states[name][stylename] - 1
if editor_cloth_states[name][stylename] < 1 then
editor_cloth_states[name][stylename] = #styles[stylename]
end
update_skin(player)
return
elseif fields[stylename.."_color"] then
editor_current_color_cloth[name] = stylename
hades_skins.show_skin_editor_color(player)
return
end
end
if fields.random then
hades_skins.player_set_random_textures(player)
hades_skins.show_skin_editor(player)
end
elseif formname == "hades_skins:skin_editor_color" then
local function update_skin(player)
local name = player:get_player_name()
local cloth = editor_current_color_cloth[name] or "shirt"
editor_color_states[name][cloth] =
editor_current_color[name].r * 0x10000 +
editor_current_color[name].g * 0x100 +
editor_current_color[name].b
local out = hades_skins.editor_state_to_textures(player)
hades_skins.player_set_textures(player, out.textures, out.colors.skin)
end
local name = player:get_player_name()
local f = { "red", "green", "blue" }
local fmap = { "r", "g", "b" }
for i=1, #f do
local fname = f[i]
if fields[fname] then
local evnt = minetest.explode_scrollbar_event(fields[fname])
if evnt.type == "CHG" then
editor_current_color[name][fmap[i]] = evnt.value
end
end
end
if fields.update then
update_skin(player)
hades_skins.show_skin_editor_color(player, nil, editor_current_color[name])
return
end
if fields.random then
local color = {}
color.r = math.random(0,255)
color.g = math.random(0,255)
color.b = math.random(0,255)
editor_current_color[name] = table.copy(color)
update_skin(player)
hades_skins.show_skin_editor_color(player, nil, color)
return
end
if fields.submit then
update_skin(player)
hades_skins.show_skin_editor(player)
return
end
end
end)

View File

@ -0,0 +1,2 @@
name = hades_skins
depends = hades_player, hades_meshhand

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 B

View File

@ -0,0 +1,7 @@
Hades Wardrobes
The wardrobe block allows players to change their skin.
License: MIT License
Textures by prestidigitator
Code by Wuzzy

View File

@ -0,0 +1,36 @@
local S = minetest.get_translator("hades_wardrobes")
minetest.register_node("hades_wardrobes:wardrobe", {
description = S("Wardrobe"),
_tt_help = S("Lets you change your clothes and body"),
is_ground_content = false,
paramtype2 = "facedir",
tiles = {
{name="default_wood.png", align_style="world"},
{name="default_wood.png", align_style="world"},
{name="default_wood.png", align_style="world"},
{name="default_wood.png", align_style="world"},
{name="default_wood.png", align_style="world"},
"wardrobe_wardrobe_front.png"
},
sounds = hades_sounds.node_sound_wood_defaults(),
groups = { choppy = 3, oddly_breakable_by_hand = 2, flammable = 3 },
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
hades_skins.show_skin_editor(player)
return itemstack
end,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", S("Wardrobe"))
end,
on_rotate = "simple",
})
minetest.register_craft({
output = "hades_wardrobes:wardrobe",
recipe = {
{"group:wood","group:wood","group:wood"},
{"group:wool","group:wool","group:wool"},
{"group:wood","group:wood","group:wood"},
},
})

View File

@ -0,0 +1,3 @@
name = hades_wardrobes
description = Adds a wardrobe node allowing players to change their skin
depends = hades_skins, hades_sounds

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B