-- based on my mobf_trader mod - but does not require any other mods -- find out the right mesh; if the wrong one is used, the traders become invisible npc_talk.talking_npc_mesh = "character.b3d"; -- 3darmor/wieldview is great if( minetest.get_modpath( '3d_armor' )) then npc_talk.talking_npc_mesh = "3d_armor_character.b3d"; end npc_talk.talking_npc_texture = "character.png" npc_talk.talking_npc_inventory_image = "character.png" -- look at the player npc_talk.look_at_player = function(self, player) if(not(player) or not(self)) then return end -- look at the player local v1 = self.object:get_pos() local v2 = player:get_pos() local dx = v1.x - v2.x local dz = v2.z - v1.z self.object:set_yaw(math.atan2(dx, dz)) end npc_talk.talking_npc_entity_prototype = { initial_properties = { -- so far, this is more or less the redefinition of the standard player model physical = true, collisionbox = {-0.30, 0.0,-0.30, 0.30,1.8,0.30}, visual = "mesh"; visual_size = {x=1, y=1, z=1}, mesh = npc_talk.talking_npc_mesh, textures = {npc_talk.talking_npc_texture}, inventory_image = npc_talk.talking_npc_inventory_image, description = 'Talking NPC (right-click to talk)', -- the NPC needs an owner owner = "", armor_groups = {immortal=1}, hp_max = 100, -- just to be sure -- this mob only has to stand around and talk to players animation = { stand_START = 0, stand_END = 79, sit_START = 81, sit_END = 160, sleep_START = 162, sleep_END = 166, walk_START = 168, walk_END = 187, mine_START = 189, mine_END = 198, walkmine_START = 200, walkmine_END = 219, }, animation_speed = 30, }, -- end of initial_properties get_staticdata = function(self) return npc_talk.talking_npc_get_staticdata(self) end, on_activate = function(self, staticdata, dtime) return npc_talk.talking_npc_on_activate(self, staticdata, dtime) end, -- actually talk to the NPC on_rightclick = function(self, clicker) npc_talk.look_at_player(self, clicker) return yl_speak_up.talk(self, clicker) end, } npc_talk.talking_npc_get_staticdata = function(self) -- taken basicly from mobs_redo local data = {} for _, v in pairs(self) do local t = type(v) if( t ~= "function" and t ~= "nil" and t ~= "userdata" and _ ~= "object" and _ ~= "_cmi_components") then data[_] = self[_] end end return minetest.serialize(data) end npc_talk.talking_npc_on_activate = function(self, staticdata, dtime) -- this is taken from mobs_redo and copies all staticdata to self local tmp = minetest.deserialize(staticdata) if tmp then for _,stat in pairs(tmp) do local t = type(stat) if t ~= "function" and t ~= "nil" and t ~= "userdata" then self[_] = stat end end end if(self.yl_speak_up) then -- set texture if(self.yl_speak_up.skin) then local tex = self.yl_speak_up.skin self.textures = {tex[1]} end -- set animation if(self.yl_speak_up.animation) then self.object:set_animation(self.yl_speak_up.animation) end -- set infotext if(yl_speak_up.infotext) then local i_text = "" if(self.yl_speak_up.npc_name) then i_text = i_text .. self.yl_speak_up.npc_name .. "\n" end if(self.yl_speak_up.npc_description) then i_text = i_text .. self.yl_speak_up.npc_description .. "\n" end i_text = i_text .. yl_speak_up.infotext self.infotext = i_text end end -- set anything changed above self.object:set_properties(self) -- the NPC is subject to gravity but does not move around self.object:set_velocity( {x=0, y= 0, z=0}) self.object:set_acceleration({x=0, y=-10, z=0}) -- show the nametag (or not - depending on the mob's configuration) if(self.yl_speak_up) then yl_speak_up.update_nametag(self) end end -- the mob as entity minetest.register_entity( "npc_talk:talking_npc", npc_talk.talking_npc_entity_prototype) -- the mob as an item - carried in the inventory -- If you want to add mobs with diffrent names/descriptions/inventory images/entities, just add your -- own register_craftitem and use this as an example. minetest.register_craftitem("npc_talk:talking_npc_item", { name = "Talking NPC", description = "Talking NPC. Place somewhere and right-click in order to talk to him.", groups = {}, stack_max = 1, inventory_image = npc_talk.talking_npc_inventory_image, wield_image = npc_talk.talking_npc_inventory_image, drawtype = "mesh", mesh = npc_talk.talking_npc_mesh, textures = {npc_talk.talking_npc_texture}, on_place = function(itemstack, placer, pointed_thing) return npc_talk.talking_npc_on_place(itemstack, placer, pointed_thing) end, }) -- place the craftitem from your inventory to get the NPC entity in the world npc_talk.talking_npc_on_place = function(itemstack, placer, pointed_thing) -- taken from mobs_redo local pos = pointed_thing.above -- does existing on_rightclick function exist? local under = minetest.get_node(pointed_thing.under) local def = minetest.registered_nodes[under.name] if(def and def.on_rightclick)then return def.on_rightclick(pointed_thing.under, under, placer, itemstack, pointed_thing) end if(pos and not minetest.is_protected(pos, placer:get_player_name())) then local mob = "npc_talk:talking_npc" pos.y = pos.y + 1 local data_str = itemstack:get_metadata() local data = minetest.deserialize(data_str) local smob = minetest.add_entity(pos, mob, data) local ent = smob and smob:get_luaentity() if(not(ent)) then return end ent.owner = placer:get_player_name() ent.tamed = true itemstack:take_item() end return itemstack end npc_talk.talking_npc_pick_up = function(self, player) -- taken from/inspired by mobs_redo as well if(not(self) or not(player:is_player()) or not(player:get_inventory())) then return false end local pname = player:get_player_name() if(not(minetest.check_player_privs(pname, "protection_bypass")) and self.owner ~= pname) then minetest.chat_send_player(pname, "This NPC is owned by "..tostring(self.owner or "?")..".") return false end local mobname = "npc_talk:talking_npc_item" if(not(player:get_inventory():room_for_item("main", mobname))) then minetest.chat_send_player(pname, "You have not enough room in your inventory.") return false end local stack = ItemStack(mobname) local data = minetest.serialize(npc_talk.talking_npc_get_staticdata(self)) stack:set_metadata(data) local inv = player:get_inventory() if(inv:room_for_item("main", stack)) then inv:add_item("main", stack) else minetest.add_item(player:get_pos(), stack) end self.object:remove() return stack end -- add the necessary data for skin configuration etc. npc_talk.enable_talk_to_talking_npc = function() -- the following information is needed in order to handle skin changes -- this model is used by mobs_npc yl_speak_up.mesh_data["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, -- textures are applied directly textures_to_skin = false, -- this information needed so that the animation of the mob can be set (i.e. them sitting) animation = { -- {x = start_frame, y = end_frame, collisionbox} stand_still = {x = 0, y = 0, collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3}}, stand = {x = 0, y = 79, collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3}}, sit = {x = 81, y = 160, collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.0, 0.3}}, lay = {x = 162, y = 166, collisionbox = {-0.6, 0.0, -0.6, 0.6, 0.3, 0.6}}, walk = {x = 168, y = 187, collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3}}, mine = {x = 189, y = 198, collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3}}, walk_mine = {x = 200, y = 219, collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3}}, }, } -- list all textures that shall be available as skins for this particular npc: -- the normal NPC (can be fed and tamed with bread) yl_speak_up.mob_skins["npc_talk:talking_npc"] = { npc_talk.talking_npc_texture, -- at least add some variety - even if we have no textures npc_talk.talking_npc_texture.."^[colorizehsl:0", npc_talk.talking_npc_texture.."^[colorizehsl:60", npc_talk.talking_npc_texture.."^[colorizehsl:120", npc_talk.talking_npc_texture.."^[colorizehsl:180", npc_talk.talking_npc_texture.."^[colorizehsl:-60", npc_talk.talking_npc_texture.."^[colorizehsl:-120", npc_talk.talking_npc_texture.."^[colorizehsl:-180", } yl_speak_up.add_on_rightclick_entry["npc_talk:talking_npc"] = { text_if_true = "[Pick this NPC up.]", text_if_false = "[Something wrent wrong. This is for picking the mob up.]", condition = true, execute_function = npc_talk.talking_npc_pick_up, } end if(not(minetest.get_modpath("player_api"))) then minetest.log("warn", "[npc_talk] Optional dependency \"player_api\" not found. ".. "NPC npc_talk:talking_npc will not work if there is no other mod ".. "providing character.b3d and character.png.") end -- make sure the NPC can be configured regarding its skin yl_speak_up.register_on_reload(npc_talk.enable_talk_to_talking_npc, "npc_talk.enable_talk_to_talking_npc()")