mobs_npcs/npc_custom.lua

618 lines
19 KiB
Lua
Raw Normal View History

2019-05-02 00:01:47 -07:00
-- Basic NPC
--
-- Intllib
local S = mobs.intllib
local vlog = "action" --"info"
-- Mod related infos
local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
local mob_name = "npc_idler"
local icprefix=modname..'_icon_'
mobs.npcs.mob_data = {}
local function find_in_array(needle,stack)
if needle and stack then
for k,v in ipairs(stack) do
if v == needle then
return k
end
end
end
return nil
end
local function get_mob_data(pos)
local key = minetest.pos_to_string(pos)
return mobs.npcs.mob_data[key]
end
local function set_mob_data(pos,data)
local key = minetest.pos_to_string(pos)
mobs.npcs.mob_data[key] = data
end
mobs.npcs.interactions = {
default = {
icon = icprefix..'chat_random.png',
desc = S("Say one of the default random chat message strings"),
on_rightclick = function(self,player,data)
local mobname = mobs.npcs.get_mobname(self)
-- Say something
local playername = player:get_player_name()
local msg = mobs.npcs.messages.get_random()
mobs.npcs.send_chat_message(playername,msg,mobname)
end,
},
say = {
icon = icprefix..'chat.png',
desc = S("Say one of the line below as a chat message"),
formfields = {
{'textarea','message','',3},
},
on_rightclick = function(self, player,data)
local str = S('Hello world')
if not data then data = {} end
if data.action and data.action.message then
str = data.action.message
end
local mobname = mobs.npcs.get_mobname(self)
-- Say something
local playername = player:get_player_name()
local msg = mobs.npcs.messages.get_random_from_string(str)
mobs.npcs.send_chat_message(playername,msg,mobname)
end,
},
dialog = {
icon = icprefix..'dialog.png',
desc = S("Open a dialog menu with a text and a choice of answers"),
disabled = true,
},
ai = {
icon = icprefix..'ai.png',
desc = S("Try to mimic an intercation with the player"),
disabled = true,
},
craft = {
icon = icprefix..'crafter.png',
desc = S("Open a special inventory where the player can give item and received some transformed output"),
disabled = true,
},
heal = {
icon = icprefix..'healer.png',
desc = S("Heal the player"),
disabled = true,
},
give = {
icon = icprefix..'giver.png',
desc = S("Give something to the player"),
disabled = true,
},
alert_owner = {
icon = icprefix..'giver.png',
desc = S("Send an alert to the owner (allowing)"),
hidden = true,
},
}
--
-- Specific mob informations
--
local mob_id = modname..':'..mob_name
local spawner_id = modname..':'..mob_name..'_spawner'
-- Get base defintion
local mob_def = mobs.npcs.base_def
mob_def._spawner_pos = nil
local textures_string
-- Get textures
local textures = mobs.npcs.get_textures_array("character_lambda_",modname)
if textures then
mob_def.textures = textures
-- textures_string =
-- print(dump(textures_string))
-- print(dump(minetest.registered_entities[mob_id].textures))
end
--# Set specific interactions (say something)
mob_def.on_rightclick = function(self, clicker)
--# Look at the player
mobs.npcs.turn_to_player( self, clicker )
local spawner_pos = self._spawner_pos
if spawner_pos then
--# Do custom action
local data = get_mob_data(spawner_pos) or {}
if data.action and data.action.id then
local id = data.action.id
local ref = mobs.npcs.interactions
if ref[id] and ref[id].on_rightclick then
return ref[id].on_rightclick(self, clicker, data)
end
end
end
--# Or at least say something
local mobname = mobs.npcs.get_mobname(self)
local clickername = clicker:get_player_name()
local msg = mobs.npcs.messages.get_random()
mobs.npcs.send_chat_message(clickername,msg,mobname)
end
--
-- Register Spawn condition and egg
--
-- More usable texture array
local ta = {}
for k,v in ipairs(mob_def.textures) do
ta[k] = v[1]
end
local function get_npc_formspec(pos,n)
local spos = pos.x .. "," .. pos.y .. "," .. pos.z
local ww=8 -- window width
local wh=9 -- window height
local fw=4 -- field_width
local iy=0.5 -- index y
-- Texture list as a sring
local ts = table.concat(ta,',')
local data = get_mob_data(pos) or {}
if data.last_tab then n = data.last_tab end
if not n then n = 1 end
local n = tonumber(n)
minetest.log(vlog, '['..modname..'] '..'Showing formspec '..n)
-- print(dump(data))
local ti = 1
-- Get texture index
if data.textures then ti = find_in_array(data.textures[1],ta) or 1 end
local forms = {}
-- Not empty data values
local dv = {
nametag = data.nametag or '',
nametag_color = data.nametag_color or '',
infotext = data.infotext or '',
texture = ts or '',
wield_item = data.wield_item or '',
nametag = data.nametag or '',
}
forms[1] =
-- 'label[0,'.. iy - 0.5 ..';'..S('-- Menu de configuration --')..']' ..
-- 'container[0,0]'..
-- tooltip[<gui_element_name>;<tooltip_text>;<bgcolor>;<fontcolor>]
'field[0.3,'.. iy+1 ..';'..fw..',0.3;nametag;'..S('Nom')..';'..dv.nametag..']' ..
-- 'textarea[0.3,'.. iy+1.6 ..';'..fw..',1.6;infotext;'..S('InfoText')..';'..dv.infotext..']'..
-- 'field[0.3,'.. iy+2.5 ..';'..fw..',0.5;nametag_color;'..S('Nametag Color')..';#61ff0170]' ..
-- 'label[0,'.. iy+1.5 ..';'..S('Nametag Color')..']' ..
-- 'dropdown[0,'.. iy+2 ..';'..fw..';nametag_color;<item 1>,<item 2>,<item n>;1]' ..
'label[0,'.. iy+3 ..';'..S('Texture')..']' ..
'dropdown[0,'.. iy+3.5 ..';'..fw..';texture;'..dv.texture..';'..ti..']' ..
-- 'field[0.3,'.. iy+5 ..';'..fw..',0.3;wield_item;'..S('wield_item')..';'..dv.wield_item..']' ..
--~ 'button[0.1,2;2,1;form01;'..S('Look')..']' ..
--~ 'button[0.1,3;2,1;form01;'..S('Actions')..']' ..
-- 'button[0,'.. iy+5 ..';'..fw..',0.5;action;'..S('configurer les interactions')..']' ..
'button_exit['.. ww - 1 ..','.. wh - 1 ..';1,1;ok;ok]'..
''
forms[2] =
default.gui_slots ..
"list[nodemeta:" .. spos .. ";main;0,0.3;8,4;]" ..
"list[current_player;main;0,4.85;8,1;]" ..
"list[current_player;main;0,6.08;8,3;8]" ..
"listring[nodemeta:" .. spos .. ";main]" ..
"listring[current_player;main]" ..
default.get_hotbar_bg(0,4.85) ..
''
-- local action_buttons=''
-- local l = 0.1
-- for k,v in pairs(mobs.npcs.interactions) do
-- action_buttons = action_buttons..'image_button['..l..',0;1,1;'..v.icon..';'..k..';]'
-- l = l + 1
-- end
local acts={}
for k,v in pairs(mobs.npcs.interactions) do
if not ( v.disabled or v.hidden ) then
acts[#acts+1] = k
end
end
local action = data.action or {}
if not data.action then data.action = {} end
action.id = data.action.id or "default"
action.desc = mobs.npcs.interactions[action.id].desc
local actstr=table.concat(acts,',')
local ai = find_in_array(action.id,acts) or 1
local actionf = ''
local ayi = iy+2
if mobs.npcs.interactions[action.id] and mobs.npcs.interactions[action.id].formfields then
for _,v in ipairs(mobs.npcs.interactions[action.id].formfields) do
if v[1] == 'label' then
actionf = actionf .. 'label[0,'.. ayi ..';'..v[2]..']'
ayi = ayi + 1
elseif v[1] == 'textarea' then
local aname = v[2]
local dstr = action[aname] or 'Foo'
actionf = actionf .. 'textarea[0.3,'.. ayi ..';'..fw..','..v[4]..';action_'..v[2]..';'..v[3]..';'..dstr..']'
ayi = ayi + v[4] + 0.1
end
end
end
forms[3] =
'label[0,'.. iy-0.5 ..';'..S('When a player interact with this character :')..']' ..
'dropdown[0,'.. iy+0.5 ..';'..fw..';action_id;'..actstr..';'..ai..']' ..
'label[0,'.. iy+1.5 ..';'..action.desc..']' ..
actionf..
-- textlist[<X>,<Y>;<W>,<H>;<name>;<listelem 1>,<listelem 2>,...,<listelem n>;<selected idx>;<transparent>]
-- 'textlist[0,0;'..ww - 3*(ww/4)..','.. wh-1 ..';stagelist;action_1,stage_2,stage_3;1;false]'..
-- 'container['..ww - 3*(ww/4)..',0]'..
-- image_button[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]
-- 'image_button[0.1,0;1,1;'..icprefix..'chat.png^'..icprefix..'selected.png'..';act1;]'..
-- action_buttons ..
-- 'container_end[]'..
-- 'button[0,'.. wh-1 ..';1,1;add_stage;+]'..
-- 'button[1,'.. wh-1 ..';1,1;help_stage;?]'..
'button_exit['.. ww - 1 ..','.. wh - 1 ..';1,1;ok;ok]'..
''
forms[4] =
'textarea[0.3,'.. iy+1.6 ..';'..fw..',1.6;infotext;'..S('InfoText')..';'..dv.infotext..']'..
''
local content = forms[n] or ''
local formspec =
'size['..ww..','..wh..']' ..
-- default.gui_bg ..
-- default.gui_bg_img ..
'field[-1,-1;0,0.5;key;;'..minetest.pos_to_string(pos)..']' ..
'tabheader[0,'.. iy - 0.5 ..';tab;Apparence,Inventaire,Action,Misc;'.. n..';false;false]'..
content..
-- tabheader[<X>,<Y>;<name>;<caption 1>,<caption 2>,...,<caption n>;<current_tab>;<transparent>;<draw_border>]
--~ default.get_hotbar_bg(0,4.85)
--~ button[<X>,<Y>;<W>,<H>;<name>;<label>]
--~ field[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]
--~ textarea[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]
--~ label[<X>,<Y>;<label>]
--~ dropdown[<X>,<Y>;<W>;<name>;<item 1>,<item 2>, ...,<item n>;<selected idx>]
-- 'button_exit['.. ww - 1 ..',0;1,1;close;x]'..
''
return formspec
end
-- Function to initialize spawner : add entity and update metadata
-- Call after place node and on rightclick
mobs.npcs.update_cmob_properties = function(pos, player, mob)
minetest.log(vlog, '['..modname..'] '..'Updating mob properties from data at '..minetest.pos_to_string(pos))
local data = get_mob_data(pos) or {}
if not mob and data.obj then mob = data.obj end
local self
if mob then self = mob:get_luaentity() end
if not self then return false end
minetest.log(vlog, '['..modname..'] '..'Mob entity exist')
-- print(dump(data))
-- Set owner
-- TODO: check that node is the correct node
local player_name = player:get_player_name()
-- Set node meta
local meta = minetest.get_meta(pos)
local owner_name = data.owner or player_name
meta:set_string("owner", owner_name)
-- Set mob properties
-- print(dump(self))
if data.nametag then
mob:set_nametag_attributes({
color = data.nametag_color or 'green',
text = data.nametag,
})
end
mob:set_properties({
infotext = data.infotext or nil,
owner = owner_name,
textures = data.textures or self.textures,
infotext = data.infotext or self.infotext,
wield_item = data.wield_item or self.wield_item,
visual_size = data.visual_size or self.visual_size,
})
self._mobname = data.nametag or nil
self._owner = owner_name
self._spawner_pos = pos
data.obj = mob
-- Register to global table
set_mob_data(pos,data)
end
mobs.npcs.update_cmob_data = function(pos)
minetest.log(vlog, '['..modname..'] '..'Updating mob data from current properties at '..minetest.pos_to_string(pos))
local data = get_mob_data(pos)
if data and data.obj then
minetest.log(vlog, '['..modname..'] '..'Mob data exist')
local self = data.obj:get_luaentity()
-- If self is nil, the mob isn't there anymore...
if not self then return false end
minetest.log(vlog, '['..modname..'] '..'Mob entity too')
local prop = data.obj:get_properties() or {}
-- print(dump(prop))
data.nametag = prop.nametag or nil
data.nametag_color = prop.nametag_color or 'green'
data.owner = prop.owner
data.textures = prop.textures or self.textures
data.infotext = prop.infotext or nil
data.spawner_pos = pos
data.wield_item = prop.wield_item or nil
data.visual_size = prop.visual_size or nil
end
set_mob_data(pos,data)
return data
end
mobs.npcs.add_cmob = function(pos, player, _)
-- Place mob
local above = { x=pos.x, y=pos.y+1, z=pos.z }
local mob = minetest.add_entity(above, modname..':'..mob_name,minetest.write_json({_spawner_pos = pos}))
mobs.npcs.update_cmob_properties(pos, player, mob)
mobs.npcs.update_cmob_data(pos)
-- Get Data
--~ local data = {}
--~ data.nametag = meta:get_string('npc_nametag')
--~ data.nametag_color = meta:get_string('npc_nametag_color')
-- Apply it to the mob
--~ local self = mob:get_luaentity()
--~ mob:set_properties({
--~ owner = owner,
--~ _spawner_pos = pos,
--~ })
--~ if data.nametag then
--~ if not data.nametag_color then data.nametag_color = 'green' end
--~ mob:set_nametag_attributes({
--~ color = data.nametag_color,
--~ text = data.nametag,
--~ })
--~ end
end
--
-- Register Npc
--
-- Basic npc don'ts fight
-- mob_def.runaway = true
mob_def.walk_chance = 0
mob_def.jump = false
mob_def.do_custom = function(self, dtime)
-- print(dump(dtime))
-- local spawner_pos = self._spawner_pos
-- if not spawner_pos then self.object:remove()
-- else
local pos = self.object:get_pos()
pos.y = pos.y - 1
-- if ( spawner_pos ~= pos ) or ( minetest.get_node(pos).name ~= spawner_id ) then
if ( minetest.get_node(pos).name ~= spawner_id ) then
self.object:remove()
end
-- end
return false
end
--~ mob_def.on_spawn = function(self,pos)
--~ local data =
--~ end
mobs:register_mob(mob_id, mob_def)
-- This one doesn't spawn naturally, instead it spawn
minetest.register_node(spawner_id, {
description = 'Place this to spawn a configurable npc',
drawtype = "nodebox",
tiles = {"default_stone_block.png"},
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
groups = {oddly_breakable_by_hand = 2},
sounds = default.node_sound_stone_defaults(),
node_box = {
type = "fixed",
fixed = {-0.5, -0.48, -0.5, 0.5, -0.5, 0.5},
},
on_construct = function(pos)
-- minetest.get_node_timer(pos):start(20)
local meta = minetest.get_meta(pos)
-- meta:set_string("infotext", "Chest")
local inv = meta:get_inventory()
inv:set_size("main", 8*3)
end,
after_place_node = mobs.npcs.add_cmob,
--~ after_dig_node = function(pos, node, metadata, digger)
--~ mobs.npcs.remove_custom_mob(pos, placer)
--~ end,
can_dig = function(pos,player)
local meta = minetest.get_meta(pos);
local inv = meta:get_inventory()
return inv:is_empty("main") and
default.can_interact_with_node(player, pos)
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
-- --
-- Check that the npc is still there
-- --
local data = mobs.npcs.update_cmob_data(pos)
local meta = minetest.get_meta(pos)
local owner = meta:get_string('owner')
-- Re-call the after_place_node function if needed
if not ( data and data.obj ) then
-- Get infos about the owner
local powner = minetest.get_player_by_name(owner)
if not powner then powner = clicker end
-- Call the function
--~ local spw_init = minetest.registered_nodes[node.name].after_place_node
--~ if spw_init and player then
--~ spw_init(pos, player, itemstack)
--~ end
mobs.npcs.add_cmob(pos, powner, itemstack)
end
-- --
-- Stop there if not allowed to interact
-- --
if not default.can_interact_with_node(clicker, pos) then
return itemstack
end
-- Show customisation form
-- minetest.show_formspec(playername, formname, formspec)
local tab = 1
if data and data.last_tab then
tab = data.last_tab
end
minetest.after(0.2,
minetest.show_formspec,
clicker:get_player_name(),
modname..':'..mob_name..'_form0'..tab,
get_npc_formspec(pos,tab))
end,
-- on_receive_fields = function(pos, formname, fields, sender)
-- end
})
-- Register egg
mobs:register_egg(mob_id, "npc", "character_lambda_inv.png", 0)
--~ mobs:doc_identifier_compat(mob_id, longdesc, usagehelp)
mobs:alias_mob("mobs:"..mob_name, mob_id) -- compatibility
local on_receive_fields = function(player, formname, fields)
local playername = player:get_player_name()
if not string.match(formname, modname..':'..mob_name..'_form0%d') then
return false
end
-- print('-------- FIELDS ------------')
-- print(dump(fields))
local pos
if fields.key then
pos = minetest.string_to_pos(fields.key)
end
if not pos then return false end
local data = get_mob_data(pos) or {}
-- Update data without overrinding it
if fields.texture then data.textures = { fields.texture } end
if fields.action_id then
-- if fields.action_id and (( not data.action ) or ( fields.action_id ~= data.action.id )) then
data.action = data.action or {}
data.action.id = fields.action_id
data.action.message = fields.action_message or data.action.message
-- data.action = mobs.npcs.interactions[fields.action_id]
-- for k,v in pairs(fields) do
-- for l in string.gmatch(k,"action_(%w+)") do
-- print(dump('action :'))
-- print(dump(l))
-- data.action[l] = v
-- end
-- end
end
local fk = {
'nametag','nametag_color','allowed','infotext','wield_item',
}
for _,v in ipairs(fk) do
if fields[v] then data[v] = fields[v] end
end
data.last_tab = fields.tab or data.last_tab
-- data.visual_size = {x = 1, y = 1.1}
-- print('-------- DATA ------------')
-- print(dump(data))
set_mob_data(pos,data)
mobs.npcs.update_cmob_properties(pos,player, data.obj)
local tb = data.last_tab
if ( fields.tab or fields.action_id ) and not fields.quit then
minetest.after(0.2,
minetest.show_formspec,
playername,
modname..':'..mob_name..'_form0'..tb,
get_npc_formspec(pos,tb))
end
end
minetest.register_on_player_receive_fields(on_receive_fields)