diff --git a/api/api_fashion.lua b/api/api_fashion.lua new file mode 100644 index 0000000..30ebcc3 --- /dev/null +++ b/api/api_fashion.lua @@ -0,0 +1,169 @@ + + +-- 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 + -- mobs_redo stores it extra; other mob mods may not + if(not(entity.mesh) and entity.name + and minetest.registered_entities[entity.name]) then + return minetest.registered_entities[entity.name].mesh + end + return entity.mesh +end + + +-- diffrent mobs (distinguished by self.name) may want to wear diffrent skins +-- even if they share the same model; find out which mob we're dealing with +yl_speak_up.get_mob_type = 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.name +end + + + +-- this makes use of the "model" option of formspecs +yl_speak_up.skin_preview_3d = function(mesh, textures, where_front, where_back) + local tstr = "" + for i, t in ipairs(textures) do + tstr = tstr..minetest.formspec_escape(t).."," + end + local backside = "" + if(where_back) then + backside = "".. + "model["..where_back..";skin_show_back;"..mesh..";"..tstr..";0,0;false;true;;]" + end + return "model["..where_front..";skin_show_front;"..mesh..";"..tstr..";0,180;false;true;;]"..--"0,300;9]".. -- ;]".. + backside +end + + +-- TODO: this function is obsolete now +-- this is a suitable version for most models/meshes that use normal player skins +-- (i.e. mobs_redo) with skins in either 64 x 32 or 64 x 64 MC skin format +yl_speak_up.skin_preview_normal = function(skin, with_backside) + local backside = "" + if(with_backside) then + backside = "".. + "image[8,0.7;2,2;[combine:8x8:-24,-8="..skin.."]".. -- back head + "image[7.85,0.55;2.3,2.3;[combine:8x8:-56,-8="..skin.."]".. -- head, beard + "image[8,2.75;2,3;[combine:8x12:-32,-20="..skin..":-32,-36="..skin.."]".. -- body back + "image[8,5.75;1,3;[combine:4x12:-12,-20="..skin.."]".. -- left leg back + "image[8,5.75;1,3;[combine:4x12:-28,-52="..skin..":-12,-52="..skin.."]".. -- r. leg back ov + "image[9,5.75;1,3;[combine:4x12:-12,-20="..skin.."^[transformFX]".. -- right leg back + "image[9,5.75;1,3;[combine:4x12:-12,-36="..skin.."]".. -- right leg back ov + "image[7,2.75;1,3;[combine:4x12:-52,-20="..skin..":-40,-52="..skin..":-60,-52="..skin.."]".. -- l. hand back ov + "image[10,2.75;1,3;[combine:4x12:-52,-20="..skin.."^[transformFX]".. -- right hand back + "image[10,2.75;1,3;[combine:4x12:-52,-20="..skin..":-52,-36="..skin.."]" -- left hand back + end + return "image[3,0.7;2,2;[combine:8x8:-8,-8="..skin.."]".. + "image[2.85,0.55;2.3,2.3;[combine:8x8:-40,-8="..skin.."]".. -- head, beard + "image[3,2.75;2,3;[combine:8x12:-20,-20="..skin..":-20,-36="..skin.."]".. -- body + "image[3,5.75;1,3;[combine:4x12:-4,-20="..skin..":-4,-36="..skin.."]".. -- left leg + ov + "image[4,5.75;1,3;[combine:4x12:-4,-20="..skin.."^[transformFX]".. -- right leg + "image[4,5.75;1,3;[combine:4x12:-20,-52="..skin..":-4,-52="..skin.."]".. -- right leg ov + "image[2.0,2.75;1,3;[combine:4x12:-44,-20="..skin..":-44,-36="..skin.."]".. -- left hand + "image[5.0,2.75;1,3;[combine:4x12:-44,-20="..skin.."^[transformFX]".. -- right hand + "image[5.0,2.75;1,3;[combine:4x12:-36,-52="..skin..":-52,-52="..skin.."]".. -- right hand ov + backside + + --local legs_back = "[combine:4x12:-12,-20="..skins.skins[name]..".png" +end + + + +yl_speak_up.cape2texture = function(t) + return "yl_speak_up_mask_cape.png^[combine:32x64:56,20=" .. t +end + +yl_speak_up.shield2texture = function(t) + return "yl_speak_up_mask_shield.png^[combine:32x64:0,0=(" .. t .. ")" +end + +yl_speak_up.textures2skin = function(textures) + local temp = {} + -- Cape + + local cape = yl_speak_up.cape2texture(textures[1]) + + -- Main + + local main = textures[2] + + -- left (Shield) + + local left = yl_speak_up.shield2texture(textures[3]) + + -- right (Sword) + + local right = textures[4] + + temp = {cape, main, left, right} + + return temp +end + + +yl_speak_up.mesh_update_textures = function(pname, textures) + -- actually make sure that the NPC updates its texture + local obj = yl_speak_up.speak_to[pname].obj + if(not(obj) or not(textures)) then + return + end + -- the skins with wielded items need some conversion, + -- while simpler models may just apply the texture + local mesh = yl_speak_up.get_mesh(pname) + if(mesh and yl_speak_up.mesh_data[mesh].textures_to_skin) then + textures = yl_speak_up.textures2skin(textures) + end + obj:set_properties({ textures = textures }) + yl_speak_up.speak_to[pname].skins = textures + local entity = obj:get_luaentity() + if(entity) then + entity.yl_speak_up.skin = 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 + + +yl_speak_up.update_nametag = function(self) + if(self.yl_speak_up.hide_nametag) then + self.object:set_nametag_attributes({text=nil}) + return + end + if self.yl_speak_up.npc_name then + -- the nametag is normal (cyan by default) + if(self.yl_speak_up.talk) then + self.force_nametag_color = yl_speak_up.nametag_color_when_not_muted + self.object:set_nametag_attributes({color=self.force_nametag_color, text=self.yl_speak_up.npc_name}) + -- the nametag has the addition "[muted]" and is magenta when muted + else + self.force_nametag_color = yl_speak_up.nametag_color_when_muted + self.object:set_nametag_attributes({color=self.force_nametag_color, text=self.yl_speak_up.npc_name.." [muted]"}) + end + end +end + + diff --git a/fs/fs_fashion.lua b/fs/fs_fashion.lua new file mode 100644 index 0000000..f488350 --- /dev/null +++ b/fs/fs_fashion.lua @@ -0,0 +1,253 @@ +-- ### +-- Fashion +-- ### + +-- 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 + + -- which texture from the textures list are we talking about? + -- this depends on the model! + local mesh = yl_speak_up.get_mesh(pname) + local texture_index = yl_speak_up.mesh_data[mesh].texture_index + if(not(texture_index)) then + texture_index = 1 + end + + -- show extra formspec with wielded item configuration and cape setup + if(fields.button_config_wielded_items + and yl_speak_up.mesh_data[mesh].can_show_wielded_items) then + yl_speak_up.show_fs(player, "fashion_extended") + return + end + + -- which skins are available? this depends on mob_type + local mob_type = yl_speak_up.get_mob_type(pname) + local skins = yl_speak_up.mob_skins[mob_type] + + + local textures = yl_speak_up.speak_to[pname].textures + + -- fallback if something went wrong (i.e. unkown NPC) + local skin = (textures[texture_index] or "") + if(not(skins)) then + skins = {skin} + end + local skin_index = table.indexof(skins, skin) + if(skin_index == -1) then + skin_index = 1 + end + local new_skin = skin + -- switch 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 + yl_speak_up.mesh_update_textures(pname, textures) + end + if(fields.set_animation + and yl_speak_up.mesh_data[mesh] + and yl_speak_up.mesh_data[mesh].animation + and yl_speak_up.mesh_data[mesh].animation[fields.set_animation] + and yl_speak_up.speak_to[pname] + and yl_speak_up.speak_to[pname].obj) then + local obj = yl_speak_up.speak_to[pname].obj + obj:set_animation(yl_speak_up.mesh_data[mesh].animation[fields.set_animation]) + -- store the animation so that it can be restored on reload + local entity = obj:get_luaentity() + if(entity) then + entity.yl_speak_up.animation = yl_speak_up.mesh_data[mesh].animation[fields.set_animation] + end + 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 + + +-- 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) + -- which texture from the textures list are we talking about? + -- this depends on the model! + local mesh = yl_speak_up.get_mesh(pname) + if(not(mesh) or not(yl_speak_up.mesh_data[mesh])) then + return "size[9,2]label[0,0;Error: Mesh data missing.]" + end + local texture_index = yl_speak_up.mesh_data[mesh].texture_index + if(not(texture_index)) then + texture_index = 1 + end + + -- which skins are available? this depends on mob_type + local mob_type = yl_speak_up.get_mob_type(pname) + local skins = yl_speak_up.mob_skins[mob_type] + + local textures = yl_speak_up.speak_to[pname].textures + local skin = "" + if(textures and textures[texture_index]) then + skin = (textures[texture_index] or "") + end + -- 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 + -- fallback if something went wrong + if(not(skins)) then + skins = {old_texture} + 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 + + local tmp_textures = textures + if(texture_index ~= 1) then + tmp_textures = textures2skin(textures) + end + local preview = yl_speak_up.skin_preview_3d(mesh, tmp_textures, "2,1;6,12", "8,1;6,12") +-- local preview = yl_speak_up.mesh_data[mesh].skin_preview(skin) + + 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 + } + if(yl_speak_up.mesh_data[mesh].animation + and yl_speak_up.speak_to[pname] + and yl_speak_up.speak_to[pname].obj) then + local anim_list = {} + for k, v in pairs(yl_speak_up.mesh_data[mesh].animation) do + table.insert(anim_list, k) + end + table.sort(anim_list) + -- which animation is the NPC currently running? + local obj = yl_speak_up.speak_to[pname].obj + local curr_anim = obj:get_animation(pname) + local anim = "" + -- does the current animation match any stored one? + for k, v in pairs(yl_speak_up.mesh_data[mesh].animation) do + if(v.x and v.y and curr_anim and curr_anim.x and curr_anim.y + and v.x == curr_anim.x and v.y == curr_anim.y) then + anim = k + end + end + local anim_index = table.indexof(anim_list, anim) + if(anim_index == -1) then + anim_index = "1" + end + table.insert(formspec, "label[0.75,16.4;Do the following animation:]") + table.insert(formspec, "dropdown[0.75,16.9;16.25,1.5;set_animation;") + table.insert(formspec, table.concat(anim_list, ',')) + table.insert(formspec, ";") + table.insert(formspec, tostring(anim_index) or "") + table.insert(formspec, "]") + end + table.insert(formspec, "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) + h = yl_speak_up.add_edit_button_fs_talkdialog(formspec, h, + "button_config_wielded_items", + "What shall the NPC wield, and which cape shall he wear?", + "I'll tell you what you shall wield.", + (yl_speak_up.mesh_data[mesh].can_show_wielded_items), + "You don't know how to show wielded items. Thus, we can't configure them.", + nil, nil) + return yl_speak_up.show_fs_decorated(pname, true, h, + "", + left_window, + table.concat(formspec, ""), + nil, + h) +end diff --git a/fs/fs_fashion_extended.lua b/fs/fs_fashion_extended.lua new file mode 100644 index 0000000..2eac0fd --- /dev/null +++ b/fs/fs_fashion_extended.lua @@ -0,0 +1,193 @@ + +-- inspired/derived from the wieldview mod in 3darmor +yl_speak_up.get_wield_texture = function(item) + if(not(item) or not(minetest.registered_items[ item ])) then + return "3d_armor_trans.png" + end + local def = minetest.registered_items[ item ] + if(def.inventory_image ~= "") then + return def.inventory_image + elseif(def.tiles and type(def.tiles[1]) == "string" and def.tiles[1] ~= "") then + return minetest.inventorycube(def.tiles[1]) + end + return "3d_armor_trans.png" +end + + +yl_speak_up.fashion_wield_give_items_back = function(player, pname) + -- move the item back to the player's inventory (if possible) + local trade_inv = minetest.get_inventory({type="detached", name="yl_speak_up_player_"..pname}) + local player_inv = player:get_inventory() + local left_stack = trade_inv:get_stack("wield", 1) + local right_stack = trade_inv:get_stack("wield", 2) + if(left_stack and not(left_stack:is_empty()) + and player_inv:add_item("main", left_stack)) then + trade_inv:set_stack("wield", 1, "") + end + if(right_stack and not(right_stack:is_empty()) + and player_inv:add_item("main", right_stack)) then + trade_inv:set_stack("wield", 2, "") + end +end + + +-- set what the NPC shall wield and which cape to wear +yl_speak_up.input_fashion_extended = function(player, formname, fields) + if formname ~= "yl_speak_up:fashion_extended" then + return + end + + local pname = player:get_player_name() + local textures = yl_speak_up.speak_to[pname].textures + + 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 or fields.button_save)) then + yl_speak_up.fashion_wield_give_items_back(player, pname) + yl_speak_up.show_fs(player, "fashion") + 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}) + local player_inv = player:get_inventory() + local left_stack = trade_inv:get_stack("wield", 1) + local right_stack = trade_inv:get_stack("wield", 2) + if(left_stack and left_stack:get_name() and fields.button_wield_left) then + textures[4] = yl_speak_up.get_wield_texture(left_stack:get_name()) + yl_speak_up.log_change(pname, n_id, + "(fashion) sword changed to "..tostring(fields.set_sword)..".") + end + if(right_stack and right_stack:get_name() and fields.button_wield_right) then + textures[3] = yl_speak_up.get_wield_texture(right_stack:get_name()) + yl_speak_up.log_change(pname, n_id, + "(fashion) shield changed to "..tostring(fields.set_shield)..".") + end + yl_speak_up.fashion_wield_give_items_back(player, pname) + + -- only change cape if there really is a diffrent one selected + elseif(fields.set_cape and fields.set_cape ~= textures[1]) then + + local mob_type = yl_speak_up.get_mob_type(pname) + local capes = yl_speak_up.mob_capes[mob_type] or {} + -- only set the cape if it is part of the list of allowed capes + if(table.indexof(capes, fields.set_cape) ~= -1) then + textures[1] = fields.set_cape + yl_speak_up.log_change(pname, n_id, + "(fashion) cape changed to "..tostring(fields.set_cape)..".") + end + end + + if(fields.button_wield_left or fields.button_wield_right or fields.set_cape or fields.button_sve) then + yl_speak_up.fashion_wield_give_items_back(player, pname) + yl_speak_up.mesh_update_textures(pname, textures) + yl_speak_up.show_fs(player, "fashion_extended") + return + end + yl_speak_up.show_fs(player, "fashion") +end + + +yl_speak_up.get_fs_fashion_extended = function(pname) + -- which texture from the textures list are we talking about? + -- this depends on the model! + local mesh = yl_speak_up.get_mesh(pname) + local texture_index = yl_speak_up.mesh_data[mesh].texture_index + if(not(texture_index)) then + texture_index = 1 + end + + local textures = yl_speak_up.speak_to[pname].textures + local skin = (textures[texture_index] or "") + + -- which skins are available? this depends on mob_type + local mob_type = yl_speak_up.get_mob_type(pname) + local skins = yl_speak_up.mob_skins[mob_type] or {skin} + local capes = yl_speak_up.mob_capes[mob_type] or {} + local cape = "" -- TODO + + -- is this player editing this particular NPC? then rename the button + if(not(yl_speak_up.edit_mode[pname]) + or yl_speak_up.edit_mode[pname] ~= yl_speak_up.speak_to[pname].n_id) then + return "label[Error. Not in Edit mode!]" + end + + -- make sure the cape can be unset again + if(#capes < 1 or capes[1] ~= "") then + table.insert(capes, 1, "") + end + local cape_list = table.concat(capes, ",") + local cape_index = table.indexof(capes, cape) + if(cape_index == -1) then + cape_index = "" + end + + local tmp_textures = textures + if(texture_index ~= 1) then + tmp_textures = yl_speak_up.textures2skin(textures) + end + local preview = yl_speak_up.skin_preview_3d(mesh, tmp_textures, "4.7,0.5;5,10", nil) + + 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 formspec = { + "size[13.4,15]", + "label[0.3,0.2;Skin: ", + minetest.formspec_escape(skin), + "]", + "label[4.6,0.65;", + yl_speak_up.speak_to[pname].n_id, + "]", + "label[6,0.65;", + (yl_speak_up.speak_to[pname].n_npc or "- nameless -"), + "]", + "dropdown[9.1,0.2;4,0.75;set_cape;", + cape_list, ";", cape_index, "]", + "label[0.3,4.2;Left:]", + "label[9.1,4.2;Right:]", + "field_close_on_enter[set_sword;false]", + "field_close_on_enter[set_shield;false]", + "image[9.1,1;4,2;", + textures[1] or "", + "]", -- Cape + "image[0.3,4.2;4,4;", + textures[4] or "", + "]", -- Sword + "image[9.1,4.2;4,4;", + textures[3] or "", + "]", --textures[3],"]", -- Shield + "tooltip[0.3,4.2;4,4;This is: ", + minetest.formspec_escape(textures[4]), + "]", + "tooltip[9.1,4.2;4,4;This is: ", + minetest.formspec_escape(textures[3]), + "]", + preview or "", + "button[0.3,8.4;3,0.75;button_cancel;"..button_cancel.."]", + "button[10.1,8.4;3,0.75;button_save;Save]", + "list[current_player;main;1.8,10;8,4;]", + -- set wielded items + "label[0.3,9.7;Wield\nleft:]", + "label[12.0,9.7;Wield\nright:]", + "list[detached:yl_speak_up_player_"..tostring(pname)..";wield;0.3,10.5;1,1;]", + "list[detached:yl_speak_up_player_"..tostring(pname)..";wield;12.0,10.5;1,1;1]", + "button[0.3,11.7;1,0.6;button_wield_left;Set]", + "button[12.0,11.7;1,0.6;button_wield_right;Set]", + "tooltip[button_wield_left;Set and store what your NPC shall wield in its left hand.]", + "tooltip[button_wield_right;Set and store what your NPC shall wield in its right hand.]", + } + return table.concat(formspec, "") +end + diff --git a/fs_fashion.lua b/fs_fashion.lua deleted file mode 100644 index dae43c8..0000000 --- a/fs_fashion.lua +++ /dev/null @@ -1,636 +0,0 @@ --- ### --- 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 - -- mobs_redo stores it extra; other mob mods may not - if(not(entity.mesh) and entity.name - and minetest.registered_entities[entity.name]) then - return minetest.registered_entities[entity.name].mesh - end - return entity.mesh -end - - --- diffrent mobs (distinguished by self.name) may want to wear diffrent skins --- even if they share the same model; find out which mob we're dealing with -yl_speak_up.get_mob_type = 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.name -end - - - --- this makes use of the "model" option of formspecs -yl_speak_up.skin_preview_3d = function(mesh, textures, where_front, where_back) - local tstr = "" - for i, t in ipairs(textures) do - tstr = tstr..minetest.formspec_escape(t).."," - end - local backside = "" - if(where_back) then - backside = "".. - "model["..where_back..";skin_show_back;"..mesh..";"..tstr..";0,0;false;true;;]" - end - return "model["..where_front..";skin_show_front;"..mesh..";"..tstr..";0,180;false;true;;]"..--"0,300;9]".. -- ;]".. - backside -end - - --- this is a suitable version for most models/meshes that use normal player skins --- (i.e. mobs_redo) with skins in either 64 x 32 or 64 x 64 MC skin format -yl_speak_up.skin_preview_normal = function(skin, with_backside) - local backside = "" - if(with_backside) then - backside = "".. - "image[8,0.7;2,2;[combine:8x8:-24,-8="..skin.."]".. -- back head - "image[7.85,0.55;2.3,2.3;[combine:8x8:-56,-8="..skin.."]".. -- head, beard - "image[8,2.75;2,3;[combine:8x12:-32,-20="..skin..":-32,-36="..skin.."]".. -- body back - "image[8,5.75;1,3;[combine:4x12:-12,-20="..skin.."]".. -- left leg back - "image[8,5.75;1,3;[combine:4x12:-28,-52="..skin..":-12,-52="..skin.."]".. -- r. leg back ov - "image[9,5.75;1,3;[combine:4x12:-12,-20="..skin.."^[transformFX]".. -- right leg back - "image[9,5.75;1,3;[combine:4x12:-12,-36="..skin.."]".. -- right leg back ov - "image[7,2.75;1,3;[combine:4x12:-52,-20="..skin..":-40,-52="..skin..":-60,-52="..skin.."]".. -- l. hand back ov - "image[10,2.75;1,3;[combine:4x12:-52,-20="..skin.."^[transformFX]".. -- right hand back - "image[10,2.75;1,3;[combine:4x12:-52,-20="..skin..":-52,-36="..skin.."]" -- left hand back - end - return "image[3,0.7;2,2;[combine:8x8:-8,-8="..skin.."]".. - "image[2.85,0.55;2.3,2.3;[combine:8x8:-40,-8="..skin.."]".. -- head, beard - "image[3,2.75;2,3;[combine:8x12:-20,-20="..skin..":-20,-36="..skin.."]".. -- body - "image[3,5.75;1,3;[combine:4x12:-4,-20="..skin..":-4,-36="..skin.."]".. -- left leg + ov - "image[4,5.75;1,3;[combine:4x12:-4,-20="..skin.."^[transformFX]".. -- right leg - "image[4,5.75;1,3;[combine:4x12:-20,-52="..skin..":-4,-52="..skin.."]".. -- right leg ov - "image[2.0,2.75;1,3;[combine:4x12:-44,-20="..skin..":-44,-36="..skin.."]".. -- left hand - "image[5.0,2.75;1,3;[combine:4x12:-44,-20="..skin.."^[transformFX]".. -- right hand - "image[5.0,2.75;1,3;[combine:4x12:-36,-52="..skin..":-52,-52="..skin.."]".. -- right hand ov - backside - - --local legs_back = "[combine:4x12:-12,-20="..skins.skins[name]..".png" -end - - - -local function cape2texture(t) - return "yl_speak_up_mask_cape.png^[combine:32x64:56,20=" .. t -end - -local function shield2texture(t) - return "yl_speak_up_mask_shield.png^[combine:32x64:0,0=(" .. t .. ")" -end - -local function textures2skin(textures) - local temp = {} - -- Cape - - local cape = cape2texture(textures[1]) - - -- Main - - local main = textures[2] - - -- left (Shield) - - local left = shield2texture(textures[3]) - - -- right (Sword) - - local right = textures[4] - - temp = {cape, main, left, right} - - return temp -end - - -yl_speak_up.mesh_update_textures = function(pname, textures) - -- actually make sure that the NPC updates its texture - local obj = yl_speak_up.speak_to[pname].obj - if(not(obj) or not(textures)) then - return - end - -- the skins with wielded items need some conversion, - -- while simpler models may just apply the texture - local mesh = yl_speak_up.get_mesh(pname) - if(mesh and yl_speak_up.mesh_data[mesh].textures_to_skin) then - textures = textures2skin(textures) - end - obj:set_properties({ textures = textures }) - yl_speak_up.speak_to[pname].skins = textures - local entity = obj:get_luaentity() - if(entity) then - entity.yl_speak_up.skin = 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 - - -yl_speak_up.get_fs_fashion_extended = function(pname) - -- which texture from the textures list are we talking about? - -- this depends on the model! - local mesh = yl_speak_up.get_mesh(pname) - local texture_index = yl_speak_up.mesh_data[mesh].texture_index - if(not(texture_index)) then - texture_index = 1 - end - - local textures = yl_speak_up.speak_to[pname].textures - local skin = (textures[texture_index] or "") - - -- which skins are available? this depends on mob_type - local mob_type = yl_speak_up.get_mob_type(pname) - local skins = yl_speak_up.mob_skins[mob_type] or {skin} - local capes = yl_speak_up.mob_capes[mob_type] or {} - local cape = "" -- TODO - - -- is this player editing this particular NPC? then rename the button - if(not(yl_speak_up.edit_mode[pname]) - or yl_speak_up.edit_mode[pname] ~= yl_speak_up.speak_to[pname].n_id) then - return "label[Error. Not in Edit mode!]" - end - - -- make sure the cape can be unset again - if(#capes < 1 or capes[1] ~= "") then - table.insert(capes, 1, "") - end - local cape_list = table.concat(capes, ",") - local cape_index = table.indexof(capes, cape) - if(cape_index == -1) then - cape_index = "" - end - - local tmp_textures = textures - if(texture_index ~= 1) then - tmp_textures = textures2skin(textures) - end - local preview = yl_speak_up.skin_preview_3d(mesh, tmp_textures, "4.7,0.5;5,10", nil) - - 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 formspec = { - "size[13.4,15]", - "label[0.3,0.2;Skin: ", - minetest.formspec_escape(skin), - "]", - "label[4.6,0.65;", - yl_speak_up.speak_to[pname].n_id, - "]", - "label[6,0.65;", - (yl_speak_up.speak_to[pname].n_npc or "- nameless -"), - "]", - "dropdown[9.1,0.2;4,0.75;set_cape;", - cape_list, ";", cape_index, "]", - "label[0.3,4.2;Left:]", - "label[9.1,4.2;Right:]", - "field_close_on_enter[set_sword;false]", - "field_close_on_enter[set_shield;false]", - "image[9.1,1;4,2;", - textures[1] or "", - "]", -- Cape - "image[0.3,4.2;4,4;", - textures[4] or "", - "]", -- Sword - "image[9.1,4.2;4,4;", - textures[3] or "", - "]", --textures[3],"]", -- Shield - "tooltip[0.3,4.2;4,4;This is: ", - minetest.formspec_escape(textures[4]), - "]", - "tooltip[9.1,4.2;4,4;This is: ", - minetest.formspec_escape(textures[3]), - "]", - preview or "", - "button[0.3,8.4;3,0.75;button_cancel;"..button_cancel.."]", - "button[10.1,8.4;3,0.75;button_save;Save]", - "list[current_player;main;1.8,10;8,4;]", - -- set wielded items - "label[0.3,9.7;Wield\nleft:]", - "label[12.0,9.7;Wield\nright:]", - "list[detached:yl_speak_up_player_"..tostring(pname)..";wield;0.3,10.5;1,1;]", - "list[detached:yl_speak_up_player_"..tostring(pname)..";wield;12.0,10.5;1,1;1]", - "button[0.3,11.7;1,0.6;button_wield_left;Set]", - "button[12.0,11.7;1,0.6;button_wield_right;Set]", - "tooltip[button_wield_left;Set and store what your NPC shall wield in its left hand.]", - "tooltip[button_wield_right;Set and store what your NPC shall wield in its right hand.]", - } - return table.concat(formspec, "") -end - - -yl_speak_up.fashion_wield_give_items_back = function(player, pname) - -- move the item back to the player's inventory (if possible) - local trade_inv = minetest.get_inventory({type="detached", name="yl_speak_up_player_"..pname}) - local player_inv = player:get_inventory() - local left_stack = trade_inv:get_stack("wield", 1) - local right_stack = trade_inv:get_stack("wield", 2) - if(left_stack and not(left_stack:is_empty()) - and player_inv:add_item("main", left_stack)) then - trade_inv:set_stack("wield", 1, "") - end - if(right_stack and not(right_stack:is_empty()) - and player_inv:add_item("main", right_stack)) then - trade_inv:set_stack("wield", 2, "") - end -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 - - -- which texture from the textures list are we talking about? - -- this depends on the model! - local mesh = yl_speak_up.get_mesh(pname) - local texture_index = yl_speak_up.mesh_data[mesh].texture_index - if(not(texture_index)) then - texture_index = 1 - end - - -- show extra formspec with wielded item configuration and cape setup - if(fields.button_config_wielded_items - and yl_speak_up.mesh_data[mesh].can_show_wielded_items) then - yl_speak_up.show_fs(player, "fashion_extended") - return - end - - -- which skins are available? this depends on mob_type - local mob_type = yl_speak_up.get_mob_type(pname) - local skins = yl_speak_up.mob_skins[mob_type] - - - local textures = yl_speak_up.speak_to[pname].textures - - -- fallback if something went wrong (i.e. unkown NPC) - local skin = (textures[texture_index] or "") - if(not(skins)) then - skins = {skin} - end - local skin_index = table.indexof(skins, skin) - if(skin_index == -1) then - skin_index = 1 - end - local new_skin = skin - -- switch 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 - yl_speak_up.mesh_update_textures(pname, textures) - end - if(fields.set_animation - and yl_speak_up.mesh_data[mesh] - and yl_speak_up.mesh_data[mesh].animation - and yl_speak_up.mesh_data[mesh].animation[fields.set_animation] - and yl_speak_up.speak_to[pname] - and yl_speak_up.speak_to[pname].obj) then - local obj = yl_speak_up.speak_to[pname].obj - obj:set_animation(yl_speak_up.mesh_data[mesh].animation[fields.set_animation]) - -- store the animation so that it can be restored on reload - local entity = obj:get_luaentity() - if(entity) then - entity.yl_speak_up.animation = yl_speak_up.mesh_data[mesh].animation[fields.set_animation] - end - 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 - - --- set what the NPC shall wield and which cape to wear -yl_speak_up.input_fashion_extended = function(player, formname, fields) - if formname ~= "yl_speak_up:fashion_extended" then - return - end - - local pname = player:get_player_name() - local textures = yl_speak_up.speak_to[pname].textures - - 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 or fields.button_save)) then - yl_speak_up.fashion_wield_give_items_back(player, pname) - yl_speak_up.show_fs(player, "fashion") - 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}) - local player_inv = player:get_inventory() - local left_stack = trade_inv:get_stack("wield", 1) - local right_stack = trade_inv:get_stack("wield", 2) - if(left_stack and left_stack:get_name() and fields.button_wield_left) then - textures[4] = yl_speak_up.get_wield_texture(left_stack:get_name()) - yl_speak_up.log_change(pname, n_id, - "(fashion) sword changed to "..tostring(fields.set_sword)..".") - end - if(right_stack and right_stack:get_name() and fields.button_wield_right) then - textures[3] = yl_speak_up.get_wield_texture(right_stack:get_name()) - yl_speak_up.log_change(pname, n_id, - "(fashion) shield changed to "..tostring(fields.set_shield)..".") - end - yl_speak_up.fashion_wield_give_items_back(player, pname) - - -- only change cape if there really is a diffrent one selected - elseif(fields.set_cape and fields.set_cape ~= textures[1]) then - - local mob_type = yl_speak_up.get_mob_type(pname) - local capes = yl_speak_up.mob_capes[mob_type] or {} - -- only set the cape if it is part of the list of allowed capes - if(table.indexof(capes, fields.set_cape) ~= -1) then - textures[1] = fields.set_cape - yl_speak_up.log_change(pname, n_id, - "(fashion) cape changed to "..tostring(fields.set_cape)..".") - end - end - - if(fields.button_wield_left or fields.button_wield_right or fields.set_cape or fields.button_sve) then - yl_speak_up.fashion_wield_give_items_back(player, pname) - yl_speak_up.mesh_update_textures(pname, textures) - yl_speak_up.show_fs(player, "fashion_extended") - return - end - yl_speak_up.show_fs(player, "fashion") -end - -function yl_speak_up.fashion(player, obj) - local luaentity = obj:get_luaentity() - local pname = player:get_player_name() - local npc_id = luaentity.yl_speak_up.id - local skins = luaentity.yl_speak_up.skins - local n_id = "n_" .. npc_id - local t = luaentity.textures - - yl_speak_up.speak_to[pname] = {} - yl_speak_up.speak_to[pname].n_id = n_id - yl_speak_up.speak_to[pname].obj = obj - yl_speak_up.speak_to[pname].textures = t - yl_speak_up.speak_to[pname].skins = textures2skin(t) - - local dialog = yl_speak_up.load_dialog(n_id, false) - if next(dialog) then - yl_speak_up.speak_to[pname].n_npc = dialog.n_npc - else - yl_speak_up.speak_to[pname].n_npc = "Unknown" - end - - yl_speak_up.show_fs(player, "fashion") -end - - - -yl_speak_up.update_nametag = function(self) - if(self.yl_speak_up.hide_nametag) then - self.object:set_nametag_attributes({text=nil}) - return - end - if self.yl_speak_up.npc_name then - -- the nametag is normal (cyan by default) - if(self.yl_speak_up.talk) then - self.force_nametag_color = yl_speak_up.nametag_color_when_not_muted - self.object:set_nametag_attributes({color=self.force_nametag_color, text=self.yl_speak_up.npc_name}) - -- the nametag has the addition "[muted]" and is magenta when muted - else - self.force_nametag_color = yl_speak_up.nametag_color_when_muted - self.object:set_nametag_attributes({color=self.force_nametag_color, text=self.yl_speak_up.npc_name.." [muted]"}) - end - end -end - --- inspired/derived from the wieldview mod in 3darmor -yl_speak_up.get_wield_texture = function(item) - if(not(item) or not(minetest.registered_items[ item ])) then - return "3d_armor_trans.png" - end - local def = minetest.registered_items[ item ] - if(def.inventory_image ~= "") then - return def.inventory_image - elseif(def.tiles and type(def.tiles[1]) == "string" and def.tiles[1] ~= "") then - return minetest.inventorycube(def.tiles[1]) - 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) - -- which texture from the textures list are we talking about? - -- this depends on the model! - local mesh = yl_speak_up.get_mesh(pname) - if(not(mesh) or not(yl_speak_up.mesh_data[mesh])) then - return "size[9,2]label[0,0;Error: Mesh data missing.]" - end - local texture_index = yl_speak_up.mesh_data[mesh].texture_index - if(not(texture_index)) then - texture_index = 1 - end - - -- which skins are available? this depends on mob_type - local mob_type = yl_speak_up.get_mob_type(pname) - local skins = yl_speak_up.mob_skins[mob_type] - - local textures = yl_speak_up.speak_to[pname].textures - local skin = "" - if(textures and textures[texture_index]) then - skin = (textures[texture_index] or "") - end - -- 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 - -- fallback if something went wrong - if(not(skins)) then - skins = {old_texture} - 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 - - local tmp_textures = textures - if(texture_index ~= 1) then - tmp_textures = textures2skin(textures) - end - local preview = yl_speak_up.skin_preview_3d(mesh, tmp_textures, "2,1;6,12", "8,1;6,12") --- local preview = yl_speak_up.mesh_data[mesh].skin_preview(skin) - - 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 - } - if(yl_speak_up.mesh_data[mesh].animation - and yl_speak_up.speak_to[pname] - and yl_speak_up.speak_to[pname].obj) then - local anim_list = {} - for k, v in pairs(yl_speak_up.mesh_data[mesh].animation) do - table.insert(anim_list, k) - end - table.sort(anim_list) - -- which animation is the NPC currently running? - local obj = yl_speak_up.speak_to[pname].obj - local curr_anim = obj:get_animation(pname) - local anim = "" - -- does the current animation match any stored one? - for k, v in pairs(yl_speak_up.mesh_data[mesh].animation) do - if(v.x and v.y and curr_anim and curr_anim.x and curr_anim.y - and v.x == curr_anim.x and v.y == curr_anim.y) then - anim = k - end - end - local anim_index = table.indexof(anim_list, anim) - if(anim_index == -1) then - anim_index = "1" - end - table.insert(formspec, "label[0.75,16.4;Do the following animation:]") - table.insert(formspec, "dropdown[0.75,16.9;16.25,1.5;set_animation;") - table.insert(formspec, table.concat(anim_list, ',')) - table.insert(formspec, ";") - table.insert(formspec, tostring(anim_index) or "") - table.insert(formspec, "]") - end - table.insert(formspec, "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) - h = yl_speak_up.add_edit_button_fs_talkdialog(formspec, h, - "button_config_wielded_items", - "What shall the NPC wield, and which cape shall he wear?", - "I'll tell you what you shall wield.", - (yl_speak_up.mesh_data[mesh].can_show_wielded_items), - "You don't know how to show wielded items. Thus, we can't configure them.", - nil, nil) - return yl_speak_up.show_fs_decorated(pname, true, h, - "", - left_window, - table.concat(formspec, ""), - nil, - h) -end diff --git a/init.lua b/init.lua index 184f8b3..ad60b93 100644 --- a/init.lua +++ b/init.lua @@ -233,7 +233,10 @@ yl_speak_up.reload = function(modpath, log_entry) -- used by the above dofile(modpath .. "fs/fs_add_quest_steps.lua") -- setting skin, wielded item etc. - dofile(modpath .. "fs_fashion.lua") + dofile(modpath .. "old_staff_tool_compatibility.lua") + dofile(modpath .. "api/api_fashion.lua") + dofile(modpath .. "fs/fs_fashion.lua") + dofile(modpath .. "fs/fs_fashion_extended.lua") -- properties for NPC without specific dialogs that want to make use of -- some generic dialogs dofile(modpath .. "api/api_properties.lua") diff --git a/old_staff_tool_compatibility.lua b/old_staff_tool_compatibility.lua new file mode 100644 index 0000000..a3550a7 --- /dev/null +++ b/old_staff_tool_compatibility.lua @@ -0,0 +1,25 @@ + +function yl_speak_up.fashion(player, obj) + local luaentity = obj:get_luaentity() + local pname = player:get_player_name() + local npc_id = luaentity.yl_speak_up.id + local skins = luaentity.yl_speak_up.skins + local n_id = "n_" .. npc_id + local t = luaentity.textures + + yl_speak_up.speak_to[pname] = {} + yl_speak_up.speak_to[pname].n_id = n_id + yl_speak_up.speak_to[pname].obj = obj + yl_speak_up.speak_to[pname].textures = t + yl_speak_up.speak_to[pname].skins = textures2skin(t) + + local dialog = yl_speak_up.load_dialog(n_id, false) + if next(dialog) then + yl_speak_up.speak_to[pname].n_npc = dialog.n_npc + else + yl_speak_up.speak_to[pname].n_npc = "Unknown" + end + + yl_speak_up.show_fs(player, "fashion") +end +