Aaron Suen 2270f84336 Unique per-player default skin
Colorize player clothes based on a hash of player
name.  This should make it easier to distinguish
players from each other even when you can't see
their names, by remembering clothing colors.

Unfortunately there's no good way currently to
prevent some ugly color combinations, which may
risk incentivizing players to mess with their name
until they get a combination they like, creating a
bunch of junk accounts.  Making colors never
clash (i.e. always matching or complementary
hues) would reduce the variation in colorations,
causing more player color collisions.

Finding a way to ensure colors are "pretty" but
still having enough variation to give each player
name a unique color scheme would be ideal.  Also
there's room for more variations, e.g. adding some
stripes, patterns, emblems, etc. that can be
colorized separately, ideally something visible
from every angle.
2021-02-28 14:09:29 -05:00

126 lines
4.3 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local math, minetest, nodecore, pairs, string, table, tonumber
= math, minetest, nodecore, pairs, string, table, tonumber
local math_ceil, math_floor, math_pi, math_sin, string_format,
string_sub, table_concat
= math.ceil, math.floor, math.pi, math.sin, string.format,
string.sub, table.concat
-- LUALOCALS > ---------------------------------------------------------
local modname = minetest.get_current_modname()
local function addcolor(layers, id, value)
local theta = tonumber(value, 16) / 32768 * math_pi
local r = math_sin(theta + math_pi * 0/3) * 127 + 128
local g = math_sin(theta + math_pi * 2/3) * 127 + 128
local b = math_sin(theta + math_pi * 4/3) * 127 + 128
layers[#layers + 1] = string_format("(%s_color%d.png^[multiply:#%02x%02x%02x)",
modname, id, math_ceil(r), math_ceil(g), math_ceil(b))
end
nodecore.player_skin = nodecore.player_skin or function(player)
local skin = player:get_meta():get_string("custom_skin") or ""
if skin ~= "" then return skin end
local layers = {modname .. "_base.png"}
local name = player:get_player_name()
if name ~= "singleplayer" then
local hash = minetest.sha1(name)
addcolor(layers, 1, string_sub(hash, 1, 4))
addcolor(layers, 2, string_sub(hash, 5, 8))
addcolor(layers, 3, string_sub(hash, 9, 12))
end
local privs = minetest.get_player_privs(player:get_player_name())
if not privs.interact then
layers[#layers + 1] = modname .. "_no_interact.png"
layers[#layers + 1] = "[makealpha:254,0,253"
end
if not privs.shout then
layers[#layers + 1] = modname .. "_no_shout.png"
end
return table_concat(layers, "^"), layers
end
nodecore.player_anim_data = nodecore.player_anim_data or {
stand = {x = 0, y = 0},
sit = {x = 1, y = 1},
lay = {x = 2, y = 2},
walk = {x = 3, y = 27},
walk_mine = {x = 28, y = 52},
mine = {x = 53, y = 77},
swim_mine = {x = 78, y = 108, speed = 0.6},
swim_up = {x = 109, y = 133, speed = 0.6},
swim_down = {x = 134, y = 158, speed = 0.6},
wave = {x = 159, y = 171, speed = 0.8}
}
for k, v in pairs(nodecore.player_anim_data) do
v.name = k
v.speed = 30 * (v.speed or 1)
end
local function walkspeed(player, anim)
if not anim.speed then return anim end
local phys = player:get_physics_override()
local speed = math_floor(phys.speed * 10) / 10
if speed == 1 then return anim end
local t = {}
for k, v in pairs(anim) do
t[k] = (k == "speed") and (speed * v) or v
end
return t
end
nodecore.player_anim = nodecore.player_anim or function(player, data)
local hp = player:get_hp()
if hp <= 0 then
return nodecore.player_anim_data.lay
end
local ctl = player:get_player_control()
local walk = (ctl.up or ctl.down) and not (ctl.up and ctl.down)
or (ctl.right or ctl.left) and not (ctl.right and ctl.left)
local mine = ctl.LMB or ctl.RMB
if data then
if mine then data.animcontrol_mine_exp = nodecore.gametime + 0.25 end
mine = mine or data.animcontrol_mine_exp and data.animcontrol_mine_exp >= nodecore.gametime
end
local aux = ctl.aux1
if data then
if aux then data.animcontrol_aux_exp = nodecore.gametime + 1 end
aux = aux or data.animcontrol_aux_exp and data.animcontrol_aux_exp >= nodecore.gametime
end
if not nodecore.player_swimming(player) then
if walk and mine then return walkspeed(player, nodecore.player_anim_data.walk_mine) end
if walk then return walkspeed(player, nodecore.player_anim_data.walk) end
if mine then return nodecore.player_anim_data.mine end
if aux then return nodecore.player_anim_data.wave end
return nodecore.player_anim_data.stand
end
if mine then return walkspeed(player, nodecore.player_anim_data.swim_mine) end
if not (walk or ctl.jump or ctl.sneak or (ctl.left or ctl.right)
and not (ctl.left and ctl.right)) then
local t = {}
for k, v in pairs(nodecore.player_anim_data.swim_up) do
t[k] = (k == "speed") and (0.1 * v) or v
end
return t
end
local v = player:get_player_velocity()
if v and v.y >= -0.5 then return walkspeed(player, nodecore.player_anim_data.swim_up) end
return walkspeed(player, nodecore.player_anim_data.swim_down)
end
nodecore.player_visuals_base = nodecore.player_visuals_base or function(player)
local mesh = player:get_meta():get_string("custom_mesh") or ""
return {
visual = "mesh",
visual_size = {x = 0.9, y = 0.9, z = 0.9},
mesh = mesh and mesh ~= "" and mesh or modname .. ".b3d"
}
end