From 0a5263727174c478aab3ce709ea24288f18258ce Mon Sep 17 00:00:00 2001 From: Sokomine Date: Tue, 19 Jul 2022 21:02:48 +0200 Subject: [PATCH] added improved skin selection depending on model/mesh --- config.lua | 29 ++++++- fs_decorated.lua | 25 +++--- fs_fashion.lua | 214 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 255 insertions(+), 13 deletions(-) diff --git a/config.lua b/config.lua index f8c9aab..87ac7c9 100644 --- a/config.lua +++ b/config.lua @@ -18,10 +18,37 @@ yl_speak_up.enable_staff_based_editing = true yl_speak_up.enable_yl_mobs = true -- Do the NPCs talk right after they spawned? - yl_speak_up.talk_after_spawn = true +-- diffrent NPC may use diffrent models +-- IMPORTANT: If you want to support an NPC with a diffrent model, provide +-- an entry in this array! Else setting its skin will fail horribly. +-- TODO: provide function for preview image +yl_speak_up.mesh_data = {} +yl_speak_up.mesh_data["error"] = { + texture_index = 1, + -- TODO: actually handle that and call the right formspec + can_show_wielded_items = false, + } +-- this model is used by mobs_npc +yl_speak_up.mesh_data["mobs_character.b3d"] = { + -- the first texture is the skin + texture_index = 1, + -- there is no support for capes or wielded items + can_show_wielded_items = false, + } +yl_speak_up.mesh_data["skinsdb_3d_armor_character_5.b3d"] = { + -- the second texture is the skin + texture_index = 2, + -- they can wear and show capes and wield items + can_show_wielded_items = true, +} + + +-- TODO: provide skin texture list for the diffrent NPC (self.name) + + -- some properties from external NPC can be edited and changed (they have the self. prefix), -- and it is possible to react to property changes with handlers; -- key: name of the property (i.e. self.order); diff --git a/fs_decorated.lua b/fs_decorated.lua index 16e6dc9..3458249 100644 --- a/fs_decorated.lua +++ b/fs_decorated.lua @@ -7,18 +7,21 @@ -- helper function for yl_speak_up.show_fs_decorated yl_speak_up.calculate_portrait = function(pname, n_id) - local tex = yl_speak_up.speak_to[pname].textures - local head = "" - - if(tex and tex[2]) then - return head .. "[combine:8x8:-8,-8=" .. tex[2] .. ":-40,-8=" .. tex[2] - end - - if(tex and tex[1]) then - return head .. "[combine:8x8:-8,-8=" .. tex[1] .. ":-40,-8=" .. tex[1] - end - return head + local mesh = yl_speak_up.get_mesh(pname) + -- which texture from the textures list are we talking about? + -- this depends on the model! + if(not(mesh) + or not(yl_speak_up.mesh_data[mesh]) + or not(yl_speak_up.mesh_data[mesh].texture_index)) then + return "" + end + local texture_index = yl_speak_up.mesh_data[mesh].texture_index + local tex = yl_speak_up.speak_to[pname].textures + if(not(tex) or not(tex[texture_index])) then + return "" + end + return "[combine:8x8:-8,-8=" .. tex[texture_index] .. ":-40,-8=" .. tex[texture_index] end diff --git a/fs_fashion.lua b/fs_fashion.lua index 104dfcc..ed35cad 100644 --- a/fs_fashion.lua +++ b/fs_fashion.lua @@ -2,6 +2,24 @@ -- Fashion -- ### +-- some meshes use more than one texture, and which texture is the main skin +-- texture can only be derived from the name of the mesh +yl_speak_up.get_mesh = function(pname) + if(not(pname)) then + return "error" + end + local obj = yl_speak_up.speak_to[pname].obj + if(not(obj)) then + return "error" + end + local entity = obj:get_luaentity() + if(not(entity)) then + return "error" + end + return entity.mesh +end + + local function cape2texture(t) return "yl_speak_up_mask_cape.png^[combine:32x64:56,20=" .. t end @@ -172,7 +190,8 @@ local function create_preview(main_skin) return skin end -yl_speak_up.get_fs_fashion = function(pname) +-- TODO: link that somehow for NPC that support it +yl_speak_up.get_fs_fashion_extended = function(pname) local textures = yl_speak_up.speak_to[pname].textures local maintable, mainlist, mainindex = get_npc_skins(textures[2]) @@ -260,11 +279,103 @@ yl_speak_up.fashion_wield_give_items_back = function(player, pname) end +-- normal skins for NPC - without wielded items or capes etc. yl_speak_up.input_fashion = function(player, formname, fields) if formname ~= "yl_speak_up:fashion" then return end + local pname = player:get_player_name() + local n_id = yl_speak_up.speak_to[pname].n_id + + -- is the player editing this npc? if not: abort + if(not(yl_speak_up.edit_mode[pname]) + or (yl_speak_up.edit_mode[pname] ~= n_id)) then + return "" + end + + -- catch ESC as well + if(not(fields) or (fields.quit or fields.button_cancel or fields.button_exit)) then + yl_speak_up.show_fs(player, "talk", {n_id = yl_speak_up.speak_to[pname].n_id, + d_id = yl_speak_up.speak_to[pname].d_id}) + return + end + + -- TODO: get that list from somewhere + local skins = {"mobs_npc.png", "mobs_npc2.png", "mobs_npc3.png", "mobs_npc4.png", + "mobs_npc_baby.png"} + + local mesh = yl_speak_up.get_mesh(pname) + -- which texture from the textures list are we talking about? + -- this depends on the model! + local texture_index = yl_speak_up.mesh_data[mesh].texture_index + + local textures = yl_speak_up.speak_to[pname].textures + local skin = (textures[texture_index] or "") + local skin_index = table.indexof(skins, skin) + if(skin_index == -1) then + skin_index = 1 + end + local new_skin = skin + -- swithc back to the stored old skin + if(fields.button_old_skin) then + local old_texture = yl_speak_up.speak_to[pname].old_texture + if(old_texture) then + new_skin = old_texture + end + -- store the new skin + elseif(fields.button_store_new_skin) then + yl_speak_up.speak_to[pname].old_texture = skin + -- show previous skin + elseif(fields.button_prev_skin) then + if(skin_index > 1) then + new_skin = skins[skin_index - 1] + else + new_skin = skins[#skins] + end + -- show next skin + elseif(fields.button_next_skin) then + if(skin_index < #skins) then + new_skin = skins[skin_index + 1] + else + new_skin = skins[1] + end + -- set directly via list + elseif(fields.set_skin_normal) then + local new_index = table.indexof(skins, fields.set_skin_normal) + if(new_index ~= -1) then + new_skin = skins[new_index] + end + end + + -- if there is a new skin to consider + if(textures[texture_index] ~= new_skin) then + textures[texture_index] = new_skin + -- actually make sure that the NPC updates its texture + local obj = yl_speak_up.speak_to[pname].obj + if(obj) then + obj:set_properties({ textures = textures }) + end + -- scrolling through the diffrent skins updates the skin; avoid spam in the log +-- yl_speak_up.log_change(pname, n_id, +-- "(fashion) skin changed to "..tostring(new_skin)..".") + end + if(fields.button_old_skin or fields.button_store_new_skin) then + yl_speak_up.speak_to[pname].old_texture = nil + yl_speak_up.show_fs(player, "talk", {n_id = yl_speak_up.speak_to[pname].n_id, + d_id = yl_speak_up.speak_to[pname].d_id}) + return + end + yl_speak_up.show_fs(player, "fashion") +end + + +-- TODO: make use of this somehow +yl_speak_up.input_fashion_extended = function(player, formname, fields) + if formname ~= "yl_speak_up:fashion" then + return + end + local pname = player:get_player_name() local textures = yl_speak_up.speak_to[pname].textures @@ -283,6 +394,12 @@ yl_speak_up.input_fashion = function(player, formname, fields) d_id = yl_speak_up.speak_to[pname].d_id}) return + -- normal skins for NPC - without wielded items or capes etc. + -- TODO add a back button to get back to the normal formspec + elseif(true) then + yl_speak_up.input_fashion_normal(player, formname, fields) + return + elseif(fields.button_wield_left or fields.button_wield_right) then local trade_inv = minetest.get_inventory({type="detached", name="yl_speak_up_player_"..pname}) @@ -393,3 +510,98 @@ yl_speak_up.get_wield_texture = function(item) end return "3d_armor_trans.png" end + + +-- this only sets the *skin*, depending on the mesh of the NPC; +-- capes and wielded items are supported by an extended formspec for those +-- NPC that can handle them +yl_speak_up.get_fs_fashion = function(pname) + + -- TODO: get that list from somewhere (it may depend on the model...) + local skins = {"mobs_npc.png", "mobs_npc2.png", "mobs_npc3.png", "mobs_npc4.png", + "mobs_npc_baby.png"} + + local mesh = yl_speak_up.get_mesh(pname) + -- which texture from the textures list are we talking about? + -- this depends on the model! + local texture_index = yl_speak_up.mesh_data[mesh].texture_index + + local textures = yl_speak_up.speak_to[pname].textures + local skin = (textures[texture_index] or "") + -- store the old texture so that we can go back to it + local old_texture = yl_speak_up.speak_to[pname].old_texture + if(not(old_texture)) then + yl_speak_up.speak_to[pname].old_texture = skin + old_texture = skin + end + + local button_cancel = "Cancel" + -- is this player editing this particular NPC? then rename the button + if( yl_speak_up.edit_mode[pname] + and yl_speak_up.edit_mode[pname] == yl_speak_up.speak_to[pname].n_id) then + button_cancel = "Back" + end + + local skin_list = table.concat(skins, ",") + local skin_index = table.indexof(skins, skin) + if(skin_index == -1) then + skin_index = "" + end + + -- TODO: the preview depends on the model as well + local preview = + "image[4.5,1.8;3,3;[combine:8x9:-8,-9="..skin..":-40,-9="..skin.."]".. -- head, beard + "image[4.5,4.12;3,4.5;[combine:8x12:-20,-20="..skin.."]".. -- body + "image[4.5,8.02;1.5,4.5;[combine:4x12:-4,-20="..skin.."]".. -- left leg + "image[5.73,8.02;1.5,4.5;[combine:4x12:-4,-20="..skin.."^[transformFX]".. -- right leg + "image[3.15,4.12;1.5,4.5;[combine:4x12:-44,-20="..skin.."]".. -- left hand + "image[7.35,4.12;1.5,4.5;[combine:4x12:-44,-20="..skin.."^[transformFX]".. -- right hand + "image[10.5,1.8;3,3;[combine:8x8:-24,-8="..skin.."]".. -- back head + "image[10.5,4.12;3,4.5;[combine:8x12:-32,-20="..skin.."]".. -- body back + "image[10.5,8.02;1.5,4.5;[combine:4x12:-12,-20="..skin.."]".. -- left leg back + "image[11.73,8.02;1.5,4.5;[combine:4x12:-12,-20="..skin.."^[transformFX]".. -- right leg back + "image[9.3,4.12;1.5,4.5;[combine:4x12:-52,-20="..skin.."]".. -- left hand back + "image[12.95,4.12;1.5,4.5;[combine:4x12:-52,-20="..skin.."^[transformFX]" -- right hand back + + local formspec = { + "container[0.5,4.0]", + "dropdown[0.75,14.1;16.25,1.5;set_skin_normal;", + skin_list or "", + ";", + tostring(skin_index) or "", + "]", + "label[0.75,13.6;The name of this skin is:]", + + "button[0.75,0.75;1.2,12;button_prev_skin;<]", + "button[15.75,0.75;1.2,12;button_next_skin;>]", + "tooltip[button_prev_skin;Select previous skin in list.]", + "tooltip[button_next_skin;Select next skin in list.]", + "tooltip[set_skin_normal;Select a skin from the list.]", + preview, + -- we add a special button for setting the skin in the player answer/reply window + "container_end[]", + } + local left_window = table.concat(formspec, "") + formspec = {} + local h = -0.8 + local button_text = "This shall be your new skin. Wear it proudly!" + if(skin == old_texture) then + button_text = "This is your old skin. It is fine. Keep it!" + end + h = yl_speak_up.add_edit_button_fs_talkdialog(formspec, h, + "button_store_new_skin", + "The NPC will wear the currently selected skin.", + button_text, + true, nil, nil, nil) + h = yl_speak_up.add_edit_button_fs_talkdialog(formspec, h, + "button_old_skin", + "The NPC will wear the skin he wore before you started changing it.", + "On a second throught - Keep your old skin. It was fine.", + (skin ~= old_texture), nil, nil, nil) + return yl_speak_up.show_fs_decorated(pname, true, h, + "", + left_window, + table.concat(formspec, ""), + nil, + h) +end