268 lines
9.0 KiB
Lua
268 lines
9.0 KiB
Lua
-- 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 = {
|
|
-- 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,
|
|
|
|
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.mobs_on_rightclick(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
|
|
|
|
-- 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()")
|