Add folks mod @ v0.2.0...
Forum: https://forum.minetest.net/viewtopic.php?t=26121 Release: https://gitlab.com/SonoMichele/folks/tags/v0.2.0
This commit is contained in:
parent
f950f53351
commit
e7f0dadb0a
@ -84,6 +84,7 @@ The game includes the mods from the default [minetest_game](https://github.com/m
|
|||||||
* [creatures][mob-engine] ([zlib][lic.creatures] / [CC BY-SA][lic.ccbysa3.0]) -- version: [c2bedc3 Git][ver.mob-engine] *2018-04-23* ([patched][patch.mob-engine])
|
* [creatures][mob-engine] ([zlib][lic.creatures] / [CC BY-SA][lic.ccbysa3.0]) -- version: [c2bedc3 Git][ver.mob-engine] *2018-04-23* ([patched][patch.mob-engine])
|
||||||
* [mobkit][] ([MIT][lic.mobkit]) -- version: [ddea141 Git][ver.mobkit] *2021-02-01*
|
* [mobkit][] ([MIT][lic.mobkit]) -- version: [ddea141 Git][ver.mobkit] *2021-02-01*
|
||||||
* [mobs_redo][] ([MIT][lic.mobs_redo] / [CC BY][lic.ccby3.0] / [CC0][lic.cc0]) -- version: [f6e16a5 Git][ver.mobs_redo] *2021-04-11* ([patched][patch.mobs_redo])
|
* [mobs_redo][] ([MIT][lic.mobs_redo] / [CC BY][lic.ccby3.0] / [CC0][lic.cc0]) -- version: [f6e16a5 Git][ver.mobs_redo] *2021-04-11* ([patched][patch.mobs_redo])
|
||||||
|
* [folks][] ([GPL][lic.gpl3.0]) -- version: [0.2.0][ver.folks] *2021-02-23*
|
||||||
* general/
|
* general/
|
||||||
* [mobs_animal][] ([MIT][lic.mobs_animal]) -- version: [80e72a4 Git][ver.mobs_animal] *2021-04-13* ([patched][patch.mobs_animal])
|
* [mobs_animal][] ([MIT][lic.mobs_animal]) -- version: [80e72a4 Git][ver.mobs_animal] *2021-04-13* ([patched][patch.mobs_animal])
|
||||||
* [monsters_aggressive][] (see individual mods for licensing) -- version: [89a8187 Git][ver.monsters_aggressive] *2017-08-30*
|
* [monsters_aggressive][] (see individual mods for licensing) -- version: [89a8187 Git][ver.monsters_aggressive] *2017-08-30*
|
||||||
@ -264,6 +265,7 @@ The game includes the mods from the default [minetest_game](https://github.com/m
|
|||||||
[ethereal]: https://forum.minetest.net/viewtopic.php?t=14638
|
[ethereal]: https://forum.minetest.net/viewtopic.php?t=14638
|
||||||
[farlands]: https://forum.minetest.net/viewtopic.php?t=16921
|
[farlands]: https://forum.minetest.net/viewtopic.php?t=16921
|
||||||
[farming_plus]: https://forum.minetest.net/viewtopic.php?t=2787
|
[farming_plus]: https://forum.minetest.net/viewtopic.php?t=2787
|
||||||
|
[folks]: https://forum.minetest.net/viewtopic.php?t=26121
|
||||||
[fort_spikes]: https://forum.minetest.net/viewtopic.php?t=14574
|
[fort_spikes]: https://forum.minetest.net/viewtopic.php?t=14574
|
||||||
[gems_encrustable]: https://forum.minetest.net/viewtopic.php?t=2596
|
[gems_encrustable]: https://forum.minetest.net/viewtopic.php?t=2596
|
||||||
[gems_tools]: https://forum.minetest.net/viewtopic.php?t=4294
|
[gems_tools]: https://forum.minetest.net/viewtopic.php?t=4294
|
||||||
@ -482,6 +484,7 @@ The game includes the mods from the default [minetest_game](https://github.com/m
|
|||||||
[ver.equip_exam]: https://github.com/AntumMT/mod-equip_exam/releases/tag/v1.0
|
[ver.equip_exam]: https://github.com/AntumMT/mod-equip_exam/releases/tag/v1.0
|
||||||
[ver.ethereal]: https://notabug.org/TenPlus1/ethereal/src/9d6103d9bb2be7b7ff761c85a6e7285bfe7700a0
|
[ver.ethereal]: https://notabug.org/TenPlus1/ethereal/src/9d6103d9bb2be7b7ff761c85a6e7285bfe7700a0
|
||||||
[ver.farming_plus]: https://github.com/PilzAdam/farming_plus/tree/7e0d976
|
[ver.farming_plus]: https://github.com/PilzAdam/farming_plus/tree/7e0d976
|
||||||
|
[ver.folks]: https://gitlab.com/SonoMichele/folks/tags/v0.2.0
|
||||||
[ver.fort_spikes]: https://github.com/xeranas/fort_spikes/tree/3b98b46
|
[ver.fort_spikes]: https://github.com/xeranas/fort_spikes/tree/3b98b46
|
||||||
[ver.gems_encrustable]: https://github.com/wowiamdiamonds/gems/tree/81d513d
|
[ver.gems_encrustable]: https://github.com/wowiamdiamonds/gems/tree/81d513d
|
||||||
[ver.gems_tools]: https://github.com/captainLAD/gems/tree/b375432
|
[ver.gems_tools]: https://github.com/captainLAD/gems/tree/b375432
|
||||||
|
6
mods/mobiles/folks/README.md
Normal file
6
mods/mobiles/folks/README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Folks [folks]
|
||||||
|
|
||||||
|
This mod is still a WIP. Check the [forum thread](https://forum.minetest.net/viewtopic.php?f=9&t=26121&p=389081#p389081) for more info.
|
||||||
|
|
||||||
|
## Texture
|
||||||
|
The folks_default.png was made by [Zughy](https://content.minetest.net/users/Zughy/)
|
100
mods/mobiles/folks/api.lua
Normal file
100
mods/mobiles/folks/api.lua
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
function folks.edit_npc_name(npc_id, new_name)
|
||||||
|
folks.backend.get_npcs()[npc_id]._npc_name = new_name
|
||||||
|
local npc_objs = folks.backend.get_npcs_obj(npc_id)
|
||||||
|
for _, npc_obj in pairs(npc_objs) do
|
||||||
|
if npc_obj then
|
||||||
|
npc_obj:set_properties({
|
||||||
|
nametag = new_name,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function folks.edit_npc_name_color(npc_id, new_color)
|
||||||
|
folks.backend.get_npcs()[npc_id]._npc_name_color = new_color
|
||||||
|
local npc_objs = folks.backend.get_npcs_obj(npc_id)
|
||||||
|
for _, npc_obj in pairs(npc_objs) do
|
||||||
|
if npc_obj then
|
||||||
|
npc_obj:set_properties({
|
||||||
|
nametag_color = new_color,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function folks.edit_npc_texture(npc_id, new_texture)
|
||||||
|
-- add .png if not found in new_texture
|
||||||
|
if string.find(new_texture, ".png", 0, true) == nil then
|
||||||
|
new_texture = new_texture .. ".png"
|
||||||
|
end
|
||||||
|
|
||||||
|
folks.backend.get_npcs()[npc_id]._npc_textures = {new_texture,}
|
||||||
|
local npc_objs = folks.backend.get_npcs_obj(npc_id)
|
||||||
|
for _, npc_obj in pairs(npc_objs) do
|
||||||
|
if npc_obj then
|
||||||
|
npc_obj:set_properties({
|
||||||
|
textures = {new_texture,},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- needs skins_collectible
|
||||||
|
-- returns false if couldn't retrieve player texture (ex. is offline)
|
||||||
|
function folks.bind_npc_to_player(npc_id, bind_to)
|
||||||
|
local new_texture_obj = skins_collectible.get_player_skin(bind_to)
|
||||||
|
if new_texture_obj == nil then return false end
|
||||||
|
|
||||||
|
local new_texture = new_texture_obj.texture
|
||||||
|
folks.backend.get_npcs()[npc_id]._npc_textures = {new_texture,}
|
||||||
|
folks.backend.get_npcs()[npc_id]._npc_name = bind_to
|
||||||
|
folks.backend.get_npcs()[npc_id]._bound_player = bind_to
|
||||||
|
local npc_objs = folks.backend.get_npcs_obj(npc_id)
|
||||||
|
for _, npc_obj in pairs(npc_objs) do
|
||||||
|
if npc_obj then
|
||||||
|
npc_obj:set_properties({
|
||||||
|
nametag = bind_to,
|
||||||
|
textures = {new_texture,},
|
||||||
|
_bound_player = bind_to,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function folks.edit_npc_messages(npc_id, messages)
|
||||||
|
folks.backend.get_npcs()[npc_id]._npc_messages = messages
|
||||||
|
end
|
||||||
|
|
||||||
|
function folks.get_npc_message(npc_id, index)
|
||||||
|
local npc = folks.backend.get_npc(npc_id)
|
||||||
|
|
||||||
|
if npc then
|
||||||
|
if npc._npc_messages[index] == nil then return nil end
|
||||||
|
|
||||||
|
return npc._npc_messages[index]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function folks.spawn_npc(npc_id, position)
|
||||||
|
local npc = folks.backend.get_npc(npc_id)
|
||||||
|
|
||||||
|
if npc then
|
||||||
|
local spawned_npc = minetest.add_entity(position, "folks:npc", minetest.serialize({_npc_id = npc_id}))
|
||||||
|
if spawned_npc then
|
||||||
|
local entity = spawned_npc:get_luaentity()
|
||||||
|
if entity then
|
||||||
|
entity._npc_id = npc_id
|
||||||
|
folks.edit_npc_name(npc_id, npc._npc_name)
|
||||||
|
folks.edit_npc_name_color(npc_id, npc._npc_name_color)
|
||||||
|
folks.edit_npc_texture(npc_id, table.concat(npc._npc_textures))
|
||||||
|
folks.edit_npc_messages(npc_id, npc._npc_messages)
|
||||||
|
folks.backend.set_npc_obj(spawned_npc)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
0
mods/mobiles/folks/backend_sqlite.lua
Normal file
0
mods/mobiles/folks/backend_sqlite.lua
Normal file
136
mods/mobiles/folks/backend_storage.lua
Normal file
136
mods/mobiles/folks/backend_storage.lua
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
local storage = minetest.get_mod_storage()
|
||||||
|
local backend = {}
|
||||||
|
local npcs = {} -- id: obj
|
||||||
|
local npcs_objects = {} -- id: {obj1, obj2}, more objects of the same NPC
|
||||||
|
local msg_for_players = {} -- npc_id: {p_name: msg_index}
|
||||||
|
|
||||||
|
|
||||||
|
function backend.load_npcs()
|
||||||
|
npcs = minetest.deserialize(storage:get_string("npcs")) or {}
|
||||||
|
for npc_id, _ in pairs(npcs) do
|
||||||
|
msg_for_players[npc_id] = {}
|
||||||
|
end
|
||||||
|
return npcs
|
||||||
|
end
|
||||||
|
|
||||||
|
function backend.get_npcs()
|
||||||
|
return npcs
|
||||||
|
end
|
||||||
|
|
||||||
|
function backend.get_npcs_objs()
|
||||||
|
return npcs_objects
|
||||||
|
end
|
||||||
|
|
||||||
|
function backend.get_unique_id()
|
||||||
|
local id
|
||||||
|
repeat
|
||||||
|
id = folks.util.randomString(16)
|
||||||
|
until npcs[id] == nil
|
||||||
|
return id
|
||||||
|
end
|
||||||
|
|
||||||
|
function backend.add_npc(ref)
|
||||||
|
local def = folks.util.deepcopy(minetest.registered_entities[ref:get_luaentity().name])
|
||||||
|
local npc = {}
|
||||||
|
local entity = ref:get_luaentity()
|
||||||
|
npc._npc_pos = ref:get_pos()
|
||||||
|
npc._npc_textures = entity.textures or def.initial_properties.textures
|
||||||
|
npc._npc_name = entity._npc_name or def.initial_properties.nametag
|
||||||
|
npc._npc_name_color = entity._npc_name_color or def.initial_properties.nametag_color
|
||||||
|
npc._npc_id = entity._npc_id
|
||||||
|
npc._npc_type = entity.name
|
||||||
|
npc._bound_player = entity._bound_player
|
||||||
|
npc._npc_messages = entity._npc_messages
|
||||||
|
|
||||||
|
npcs[entity._npc_id] = npc
|
||||||
|
|
||||||
|
msg_for_players[entity._npc_id] = {}
|
||||||
|
|
||||||
|
-- that way I can serialize npcs without problems
|
||||||
|
backend.set_npc_obj(entity._npc_id, entity._npc_object)
|
||||||
|
backend.save_npcs()
|
||||||
|
end
|
||||||
|
|
||||||
|
function backend.remove_npc(npc_id)
|
||||||
|
npcs[npc_id] = nil
|
||||||
|
npcs_objects[npc_id] = nil
|
||||||
|
|
||||||
|
backend.save_npcs()
|
||||||
|
end
|
||||||
|
|
||||||
|
function backend.save_npcs()
|
||||||
|
storage:set_string("npcs", minetest.serialize(npcs))
|
||||||
|
end
|
||||||
|
|
||||||
|
function backend.get_npc(npc_id)
|
||||||
|
return npcs[npc_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
function backend.get_npcs_obj(npc_id)
|
||||||
|
return npcs_objects[npc_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
function backend.set_npc_obj(npc_id, obj)
|
||||||
|
if not npcs_objects[npc_id] then
|
||||||
|
npcs_objects[npc_id] = {obj}
|
||||||
|
else
|
||||||
|
table.insert(npcs_objects[npc_id], obj)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function backend.update_npc_texture(p_name, texture)
|
||||||
|
for npc_id, npc in pairs(npcs) do
|
||||||
|
if npc._bound_player == p_name then
|
||||||
|
if npcs_objects[npc_id] then
|
||||||
|
for _, npc_obj in pairs(npcs_objects[npc_id]) do
|
||||||
|
npc_obj:set_properties({
|
||||||
|
textures = {texture,},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
npcs[npc_id]._npc_textures = {texture}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- custom Messages
|
||||||
|
function backend.get_next_message_index(npc_id, p_name)
|
||||||
|
if msg_for_players[npc_id][p_name] then
|
||||||
|
local id = msg_for_players[npc_id][p_name]
|
||||||
|
if id > #npcs[npc_id]._npc_messages then id = 1 end
|
||||||
|
msg_for_players[npc_id][p_name] = id + 1
|
||||||
|
return id
|
||||||
|
end
|
||||||
|
|
||||||
|
msg_for_players[npc_id][p_name] = 2 -- set the next id
|
||||||
|
return 1 -- if p_name is not found means it's the first message
|
||||||
|
end
|
||||||
|
|
||||||
|
-- function backend.spawn_npc(ref)
|
||||||
|
-- local obj = minetest.add_entity(ref._npc_pos, ref._npc_type)
|
||||||
|
-- local npc = obj:get_properties()
|
||||||
|
-- npc._npc_pos = ref._npc_pos
|
||||||
|
-- npc._npc_textures = ref._npc_textures or npc.initial_properties.textures
|
||||||
|
-- npc._npc_name = ref._npc_name or npc.initial_properties.nametag
|
||||||
|
-- npc._npc_id = ref._npc_id
|
||||||
|
-- npc._npc_type = ref._npc_type
|
||||||
|
-- npc._npc_object = obj
|
||||||
|
--
|
||||||
|
-- npcs[ref._npc_id] = npc
|
||||||
|
--
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- function backend.despawn_npc(ref)
|
||||||
|
-- local npc = npcs[ref._npc_id]
|
||||||
|
-- npc._npc_object:remove()
|
||||||
|
--
|
||||||
|
-- npcs[ref._npc_id]["_npc_object"] = "heyo"
|
||||||
|
-- minetest.log("Despawning: " .. ref._npc_id)
|
||||||
|
-- end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return backend
|
306
mods/mobiles/folks/chatcmdbuilder.lua
Normal file
306
mods/mobiles/folks/chatcmdbuilder.lua
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
ChatCmdBuilder = {}
|
||||||
|
|
||||||
|
function ChatCmdBuilder.new(name, func, def)
|
||||||
|
def = def or {}
|
||||||
|
local cmd = ChatCmdBuilder.build(func)
|
||||||
|
cmd.def = def
|
||||||
|
def.func = cmd.run
|
||||||
|
minetest.register_chatcommand(name, def)
|
||||||
|
return cmd
|
||||||
|
end
|
||||||
|
|
||||||
|
local STATE_READY = 1
|
||||||
|
local STATE_PARAM = 2
|
||||||
|
local STATE_PARAM_TYPE = 3
|
||||||
|
local bad_chars = {}
|
||||||
|
bad_chars["("] = true
|
||||||
|
bad_chars[")"] = true
|
||||||
|
bad_chars["."] = true
|
||||||
|
bad_chars["%"] = true
|
||||||
|
bad_chars["+"] = true
|
||||||
|
bad_chars["-"] = true
|
||||||
|
bad_chars["*"] = true
|
||||||
|
bad_chars["?"] = true
|
||||||
|
bad_chars["["] = true
|
||||||
|
bad_chars["^"] = true
|
||||||
|
bad_chars["$"] = true
|
||||||
|
local function escape(char)
|
||||||
|
if bad_chars[char] then
|
||||||
|
return "%" .. char
|
||||||
|
else
|
||||||
|
return char
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local dprint = function() end
|
||||||
|
|
||||||
|
ChatCmdBuilder.types = {
|
||||||
|
pos = "%(? *(%-?[%d.]+) *, *(%-?[%d.]+) *, *(%-?[%d.]+) *%)?",
|
||||||
|
text = "(.+)",
|
||||||
|
number = "(%-?[%d.]+)",
|
||||||
|
int = "(%-?[%d]+)",
|
||||||
|
word = "([^ ]+)",
|
||||||
|
alpha = "([A-Za-z]+)",
|
||||||
|
modname = "([a-z0-9_]+)",
|
||||||
|
alphascore = "([A-Za-z_]+)",
|
||||||
|
alphanumeric = "([A-Za-z0-9]+)",
|
||||||
|
username = "([A-Za-z0-9-_]+)",
|
||||||
|
}
|
||||||
|
|
||||||
|
function ChatCmdBuilder.build(func)
|
||||||
|
local cmd = {
|
||||||
|
_subs = {}
|
||||||
|
}
|
||||||
|
function cmd:sub(route, func, def)
|
||||||
|
dprint("Parsing " .. route)
|
||||||
|
|
||||||
|
def = def or {}
|
||||||
|
if string.trim then
|
||||||
|
route = string.trim(route)
|
||||||
|
end
|
||||||
|
|
||||||
|
local sub = {
|
||||||
|
pattern = "^",
|
||||||
|
params = {},
|
||||||
|
func = func
|
||||||
|
}
|
||||||
|
|
||||||
|
-- End of param reached: add it to the pattern
|
||||||
|
local param = ""
|
||||||
|
local param_type = ""
|
||||||
|
local should_be_eos = false
|
||||||
|
local function finishParam()
|
||||||
|
if param ~= "" and param_type ~= "" then
|
||||||
|
dprint(" - Found param " .. param .. " type " .. param_type)
|
||||||
|
|
||||||
|
local pattern = ChatCmdBuilder.types[param_type]
|
||||||
|
if not pattern then
|
||||||
|
error("Unrecognised param_type=" .. param_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
sub.pattern = sub.pattern .. pattern
|
||||||
|
|
||||||
|
table.insert(sub.params, param_type)
|
||||||
|
|
||||||
|
param = ""
|
||||||
|
param_type = ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Iterate through the route to find params
|
||||||
|
local state = STATE_READY
|
||||||
|
local catching_space = false
|
||||||
|
local match_space = " " -- change to "%s" to also catch tabs and newlines
|
||||||
|
local catch_space = match_space.."+"
|
||||||
|
for i = 1, #route do
|
||||||
|
local c = route:sub(i, i)
|
||||||
|
if should_be_eos then
|
||||||
|
error("Should be end of string. Nothing is allowed after a param of type text.")
|
||||||
|
end
|
||||||
|
|
||||||
|
if state == STATE_READY then
|
||||||
|
if c == ":" then
|
||||||
|
dprint(" - Found :, entering param")
|
||||||
|
state = STATE_PARAM
|
||||||
|
param_type = "word"
|
||||||
|
catching_space = false
|
||||||
|
elseif c:match(match_space) then
|
||||||
|
print(" - Found space")
|
||||||
|
if not catching_space then
|
||||||
|
catching_space = true
|
||||||
|
sub.pattern = sub.pattern .. catch_space
|
||||||
|
end
|
||||||
|
else
|
||||||
|
catching_space = false
|
||||||
|
sub.pattern = sub.pattern .. escape(c)
|
||||||
|
end
|
||||||
|
elseif state == STATE_PARAM then
|
||||||
|
if c == ":" then
|
||||||
|
dprint(" - Found :, entering param type")
|
||||||
|
state = STATE_PARAM_TYPE
|
||||||
|
param_type = ""
|
||||||
|
elseif c:match(match_space) then
|
||||||
|
print(" - Found whitespace, leaving param")
|
||||||
|
state = STATE_READY
|
||||||
|
finishParam()
|
||||||
|
catching_space = true
|
||||||
|
sub.pattern = sub.pattern .. catch_space
|
||||||
|
elseif c:match("%W") then
|
||||||
|
dprint(" - Found nonalphanum, leaving param")
|
||||||
|
state = STATE_READY
|
||||||
|
finishParam()
|
||||||
|
sub.pattern = sub.pattern .. escape(c)
|
||||||
|
else
|
||||||
|
param = param .. c
|
||||||
|
end
|
||||||
|
elseif state == STATE_PARAM_TYPE then
|
||||||
|
if c:match(match_space) then
|
||||||
|
print(" - Found space, leaving param type")
|
||||||
|
state = STATE_READY
|
||||||
|
finishParam()
|
||||||
|
catching_space = true
|
||||||
|
sub.pattern = sub.pattern .. catch_space
|
||||||
|
elseif c:match("%W") then
|
||||||
|
dprint(" - Found nonalphanum, leaving param type")
|
||||||
|
state = STATE_READY
|
||||||
|
finishParam()
|
||||||
|
sub.pattern = sub.pattern .. escape(c)
|
||||||
|
else
|
||||||
|
param_type = param_type .. c
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
dprint(" - End of route")
|
||||||
|
finishParam()
|
||||||
|
sub.pattern = sub.pattern .. "$"
|
||||||
|
dprint("Pattern: " .. sub.pattern)
|
||||||
|
|
||||||
|
table.insert(self._subs, sub)
|
||||||
|
end
|
||||||
|
|
||||||
|
if func then
|
||||||
|
func(cmd)
|
||||||
|
end
|
||||||
|
|
||||||
|
cmd.run = function(name, param)
|
||||||
|
for i = 1, #cmd._subs do
|
||||||
|
local sub = cmd._subs[i]
|
||||||
|
local res = { string.match(param, sub.pattern) }
|
||||||
|
if #res > 0 then
|
||||||
|
local pointer = 1
|
||||||
|
local params = { name }
|
||||||
|
for j = 1, #sub.params do
|
||||||
|
local param = sub.params[j]
|
||||||
|
if param == "pos" then
|
||||||
|
local pos = {
|
||||||
|
x = tonumber(res[pointer]),
|
||||||
|
y = tonumber(res[pointer + 1]),
|
||||||
|
z = tonumber(res[pointer + 2])
|
||||||
|
}
|
||||||
|
table.insert(params, pos)
|
||||||
|
pointer = pointer + 3
|
||||||
|
elseif param == "number" or param == "int" then
|
||||||
|
table.insert(params, tonumber(res[pointer]))
|
||||||
|
pointer = pointer + 1
|
||||||
|
else
|
||||||
|
table.insert(params, res[pointer])
|
||||||
|
pointer = pointer + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if table.unpack then
|
||||||
|
-- lua 5.2 or later
|
||||||
|
return sub.func(table.unpack(params))
|
||||||
|
else
|
||||||
|
-- lua 5.1 or earlier
|
||||||
|
return sub.func(unpack(params))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false, "Invalid command"
|
||||||
|
end
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
end
|
||||||
|
|
||||||
|
local function run_tests()
|
||||||
|
if not (ChatCmdBuilder.build(function(cmd)
|
||||||
|
cmd:sub("bar :one and :two:word", function(name, one, two)
|
||||||
|
if name == "singleplayer" and one == "abc" and two == "def" then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)).run("singleplayer", "bar abc and def") then
|
||||||
|
error("Test 1 failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
local move = ChatCmdBuilder.build(function(cmd)
|
||||||
|
cmd:sub("move :target to :pos:pos", function(name, target, pos)
|
||||||
|
if name == "singleplayer" and target == "player1" and
|
||||||
|
pos.x == 0 and pos.y == 1 and pos.z == 2 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end).run
|
||||||
|
if not move("singleplayer", "move player1 to 0,1,2") then
|
||||||
|
error("Test 2 failed")
|
||||||
|
end
|
||||||
|
if not move("singleplayer", "move player1 to (0,1,2)") then
|
||||||
|
error("Test 3 failed")
|
||||||
|
end
|
||||||
|
if not move("singleplayer", "move player1 to 0, 1,2") then
|
||||||
|
error("Test 4 failed")
|
||||||
|
end
|
||||||
|
if not move("singleplayer", "move player1 to 0 ,1, 2") then
|
||||||
|
error("Test 5 failed")
|
||||||
|
end
|
||||||
|
if not move("singleplayer", "move player1 to 0, 1, 2") then
|
||||||
|
error("Test 6 failed")
|
||||||
|
end
|
||||||
|
if not move("singleplayer", "move player1 to 0 ,1 ,2") then
|
||||||
|
error("Test 7 failed")
|
||||||
|
end
|
||||||
|
if not move("singleplayer", "move player1 to ( 0 ,1 ,2)") then
|
||||||
|
error("Test 8 failed")
|
||||||
|
end
|
||||||
|
if move("singleplayer", "move player1 to abc,def,sdosd") then
|
||||||
|
error("Test 9 failed")
|
||||||
|
end
|
||||||
|
if move("singleplayer", "move player1 to abc def sdosd") then
|
||||||
|
error("Test 10 failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
if not (ChatCmdBuilder.build(function(cmd)
|
||||||
|
cmd:sub("does :one:int plus :two:int equal :three:int", function(name, one, two, three)
|
||||||
|
if name == "singleplayer" and one + two == three then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)).run("singleplayer", "does 1 plus 2 equal 3") then
|
||||||
|
error("Test 11 failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
local checknegint = ChatCmdBuilder.build(function(cmd)
|
||||||
|
cmd:sub("checknegint :x:int", function(name, x)
|
||||||
|
return x
|
||||||
|
end)
|
||||||
|
end).run
|
||||||
|
if checknegint("checker","checknegint -2") ~= -2 then
|
||||||
|
error("Test 12 failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
local checknegnumber = ChatCmdBuilder.build(function(cmd)
|
||||||
|
cmd:sub("checknegnumber :x:number", function(name, x)
|
||||||
|
return x
|
||||||
|
end)
|
||||||
|
end).run
|
||||||
|
if checknegnumber("checker","checknegnumber -3.3") ~= -3.3 then
|
||||||
|
error("Test 13 failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
local checknegpos = ChatCmdBuilder.build(function(cmd)
|
||||||
|
cmd:sub("checknegpos :pos:pos", function(name, pos)
|
||||||
|
return pos
|
||||||
|
end)
|
||||||
|
end).run
|
||||||
|
local negpos = checknegpos("checker","checknegpos (-13.3,-4.6,-1234.5)")
|
||||||
|
if negpos.x ~= -13.3 or negpos.y ~= -4.6 or negpos.z ~= -1234.5 then
|
||||||
|
error("Test 14 failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
local checktypes = ChatCmdBuilder.build(function(cmd)
|
||||||
|
cmd:sub("checktypes :int:int :number:number :pos:pos :word:word :text:text", function(name, int, number, pos, word, text)
|
||||||
|
return int, number, pos.x, pos.y, pos.z, word, text
|
||||||
|
end)
|
||||||
|
end).run
|
||||||
|
local int, number, posx, posy, posz, word, text
|
||||||
|
int, number, posx, posy, posz, word, text = checktypes("checker","checktypes -1 -2.4 (-3,-5.3,6.12) some text to finish off with")
|
||||||
|
--dprint(int, number, posx, posy, posz, word, text)
|
||||||
|
if int ~= -1 or number ~= -2.4 or posx ~= -3 or posy ~= -5.3 or posz ~= 6.12 or word ~= "some" or text ~= "text to finish off with" then
|
||||||
|
error("Test 15 failed")
|
||||||
|
end
|
||||||
|
dprint("All tests passed")
|
||||||
|
|
||||||
|
end
|
||||||
|
if not minetest then
|
||||||
|
run_tests()
|
||||||
|
end
|
105
mods/mobiles/folks/commands.lua
Normal file
105
mods/mobiles/folks/commands.lua
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
local S = minetest.get_translator("folks")
|
||||||
|
|
||||||
|
ChatCmdBuilder.new("folks", function(cmd)
|
||||||
|
-- command for editing selected npc name
|
||||||
|
cmd:sub("edit name :name:text", function(pname, new_name)
|
||||||
|
local player = minetest.get_player_by_name(pname)
|
||||||
|
if player then
|
||||||
|
local meta = player:get_meta()
|
||||||
|
if meta then
|
||||||
|
local editing_npc = meta:get_string("folks_editing_npc")
|
||||||
|
if editing_npc == "" then
|
||||||
|
minetest.chat_send_player(pname, minetest.colorize("#ff0000", S("You are not editing an NPC. Click the NPC you want to edit with the NPC editor item.")))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local npc = folks.backend.get_npc(editing_npc)
|
||||||
|
if npc then
|
||||||
|
folks.edit_npc_name(editing_npc, new_name)
|
||||||
|
meta:set_string("folks_editing_npc", "")
|
||||||
|
minetest.chat_send_player(pname, minetest.colorize("#00ff00", S("Edited NPC: @1", editing_npc)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
-- command for editing selected npc name color
|
||||||
|
cmd:sub("edit name_color :color:text", function(pname, new_color)
|
||||||
|
local player = minetest.get_player_by_name(pname)
|
||||||
|
if player then
|
||||||
|
local meta = player:get_meta()
|
||||||
|
if meta then
|
||||||
|
local editing_npc = meta:get_string("folks_editing_npc")
|
||||||
|
if editing_npc == "" then
|
||||||
|
minetest.chat_send_player(pname, minetest.colorize("#ff0000", S("You are not editing an NPC. Click the NPC you want to edit with the NPC editor item.")))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local npc = folks.backend.get_npc(editing_npc)
|
||||||
|
if npc then
|
||||||
|
folks.edit_npc_name_color(editing_npc, new_color)
|
||||||
|
meta:set_string("folks_editing_npc", "")
|
||||||
|
minetest.chat_send_player(pname, minetest.colorize("#00ff00", S("Edited NPC: @1", editing_npc)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
-- command for editing selected npc texture
|
||||||
|
cmd:sub("edit texture :name:text", function(pname, new_texture)
|
||||||
|
local player = minetest.get_player_by_name(pname)
|
||||||
|
if player then
|
||||||
|
local meta = player:get_meta()
|
||||||
|
if meta then
|
||||||
|
local editing_npc = meta:get_string("folks_editing_npc")
|
||||||
|
if editing_npc == "" then
|
||||||
|
minetest.chat_send_player(pname, minetest.colorize("#ff0000", S("You are not editing an NPC. Click the NPC you want to edit with the NPC editor item.")))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local npc = folks.backend.get_npc(editing_npc)
|
||||||
|
if npc then
|
||||||
|
folks.edit_npc_texture(editing_npc, new_texture)
|
||||||
|
meta:set_string("folks_editing_npc", "")
|
||||||
|
minetest.chat_send_player(pname, minetest.colorize("#00ff00", S("Edited NPC: @1", editing_npc)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- command to bind name and texture of npc to a player, needs skins_collectible
|
||||||
|
cmd:sub("bind :name:text", function(pname, bind_to)
|
||||||
|
if folks.skins_c then
|
||||||
|
local player = minetest.get_player_by_name(pname)
|
||||||
|
if player then
|
||||||
|
local meta = player:get_meta()
|
||||||
|
if meta then
|
||||||
|
local editing_npc = meta:get_string("folks_editing_npc")
|
||||||
|
if editing_npc == "" then
|
||||||
|
minetest.chat_send_player(pname, minetest.colorize("#ff0000", S("You are not editing an NPC. Click the NPC you want to edit with the NPC editor item.")))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local npc = folks.backend.get_npc(editing_npc)
|
||||||
|
if npc then
|
||||||
|
if folks.bind_npc_to_player(editing_npc, bind_to) then
|
||||||
|
minetest.chat_send_player(pname, minetest.colorize("#00ff00", S("Edited NPC: @1", editing_npc)))
|
||||||
|
else
|
||||||
|
minetest.chat_send_player(pname, minetest.colorize("#ff0000", S("Couldn't retrieve player texture (is it online?)")))
|
||||||
|
end
|
||||||
|
meta:set_string("folks_editing_npc", "")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
minetest.chat_send_player(pname, minetest.colorize("#ff0000", S("You need skins_collectible to use this feature")))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
end, {
|
||||||
|
description = S("Manage folks npcs"),
|
||||||
|
privs = {
|
||||||
|
folks_admin = true
|
||||||
|
}
|
||||||
|
})
|
117
mods/mobiles/folks/formspecs.lua
Normal file
117
mods/mobiles/folks/formspecs.lua
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
local S = minetest.get_translator("folks")
|
||||||
|
|
||||||
|
function folks.get_edit_formspec(npc_id)
|
||||||
|
local npc = folks.backend.get_npc(npc_id)
|
||||||
|
local escape = minetest.formspec_escape
|
||||||
|
local formspec = {}
|
||||||
|
if npc then
|
||||||
|
formspec = {
|
||||||
|
"formspec_version[3]",
|
||||||
|
"size[11,11]",
|
||||||
|
"label[4.85,1;", S("Edit Folk"), "]",
|
||||||
|
"field[2,2;3,0.75;folk_name;", S("Folk name"), ";", escape(npc._npc_name), "]",
|
||||||
|
"field[6,2;3,0.75;folk_name_color;", S("Folk Name Color"), ";", escape(npc._npc_name_color), "]",
|
||||||
|
"field[2,3.5;7,0.75;folk_texture;", S("Folk Texture (with or without .png)"), ";", escape(table.concat(npc._npc_textures)), "]",
|
||||||
|
"textarea[2,5;7,4;folk_messages;", S("Messages (every line is a message)"), ";", escape(table.concat(npc._npc_messages, "\n")), "]",
|
||||||
|
"button_exit[4,9.5;3,0.75;folk_save_edit;", S("Save"), "]",
|
||||||
|
"button_exit[9.5,0.2;1,0.75;folk_close_edit;X]",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return table.concat(formspec)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function folks.get_spawn_formspec()
|
||||||
|
local escape = minetest.formspec_escape
|
||||||
|
local npcs = folks.backend.get_npcs()
|
||||||
|
local dropdown_items = {}
|
||||||
|
|
||||||
|
for npc_id, npc in pairs(npcs) do
|
||||||
|
table.insert(dropdown_items, escape(npc._npc_name .. " - " .. npc_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
local formspec = {
|
||||||
|
"formspec_version[3]",
|
||||||
|
"size[9,8.5]",
|
||||||
|
"label[3.7,1;", S("Spawn NPC"), "]",
|
||||||
|
"button_exit[7.5,0.5;1,0.75;folks_close_spawner;X]",
|
||||||
|
"dropdown[1,3;7,1;folks_select_npc;", table.concat(dropdown_items, ",") ,";1]",
|
||||||
|
"button_exit[3,7;3,0.75;folks_spawn_npc;", S("Spawn"), "]",
|
||||||
|
}
|
||||||
|
|
||||||
|
return table.concat(formspec)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function handle_edit_formspec(player, formname, fields)
|
||||||
|
if fields.folk_save_edit then
|
||||||
|
local p_name = player:get_player_name()
|
||||||
|
if not minetest.check_player_privs(player:get_player_name(), { folks_admin=true }) then return end
|
||||||
|
|
||||||
|
if player then
|
||||||
|
local meta = player:get_meta()
|
||||||
|
if meta then
|
||||||
|
local editing_npc = meta:get_string("folks_editing_npc")
|
||||||
|
if editing_npc == "" then
|
||||||
|
minetest.chat_send_player(p_name, minetest.colorize("#ff0000", S("You are not editing an NPC. Click the NPC you want to edit with the NPC editor item.")))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local npc = folks.backend.get_npc(editing_npc)
|
||||||
|
if npc then
|
||||||
|
local msgs = string.split(fields.folk_messages, "\n")
|
||||||
|
folks.edit_npc_name(editing_npc, fields.folk_name)
|
||||||
|
folks.edit_npc_name_color(editing_npc, fields.folk_name_color)
|
||||||
|
folks.edit_npc_texture(editing_npc, fields.folk_texture)
|
||||||
|
folks.edit_npc_messages(editing_npc, msgs)
|
||||||
|
meta:set_string("folks_editing_npc", "")
|
||||||
|
minetest.chat_send_player(p_name, minetest.colorize("#00ff00", S("Edited NPC: @1", editing_npc)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if fields.folk_close_edit then
|
||||||
|
if player then
|
||||||
|
local meta = player:get_meta()
|
||||||
|
if meta then
|
||||||
|
minetest.chat_send_player(player:get_player_name(), minetest.colorize("#00ff00", S("Exited from NPC: @1", meta:get_string("folks_editing_npc"))))
|
||||||
|
meta:set_string("folks_editing_npc", "")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function handle_spawn_formspec(player, formname, fields)
|
||||||
|
if fields.folks_spawn_npc then
|
||||||
|
local p_name = player:get_player_name()
|
||||||
|
if not minetest.check_player_privs(p_name, { folks_admin=true }) then return end
|
||||||
|
|
||||||
|
if fields.folks_select_npc ~= "" then
|
||||||
|
local npc_id = string.split(fields.folks_select_npc, " - ")[2]
|
||||||
|
if folks.spawn_npc(npc_id, player:get_pos()) then
|
||||||
|
minetest.chat_send_player(p_name, minetest.colorize("#00ff00", S("Spawned NPC: @1", npc_id)))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
else
|
||||||
|
minetest.chat_send_player(p_name, minetest.colorize("#ff0000", S("No NPC selected")))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
if formname == "folks:edit_npc_formspec" then
|
||||||
|
handle_edit_formspec(player, formname, fields)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if formname == "folks:spawn_npc_formspec" then
|
||||||
|
handle_spawn_formspec(player, formname, fields)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
return
|
||||||
|
end)
|
54
mods/mobiles/folks/init.lua
Normal file
54
mods/mobiles/folks/init.lua
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
folks = {}
|
||||||
|
local version = "0.2.0"
|
||||||
|
local modpath = minetest.get_modpath("folks")
|
||||||
|
|
||||||
|
-- check for skins_collectible
|
||||||
|
if minetest.get_modpath("skins_collectible") then
|
||||||
|
folks.skins_c = true
|
||||||
|
else
|
||||||
|
folks.skins_c = false
|
||||||
|
end
|
||||||
|
|
||||||
|
folks.util = dofile(modpath .. "/util.lua")
|
||||||
|
|
||||||
|
dofile(modpath .. "/settings.lua")
|
||||||
|
if folks.backend_type == "storage" then
|
||||||
|
folks.backend = dofile(modpath .. "/backend_storage.lua")
|
||||||
|
elseif folks.backend_type == "sqlite" then
|
||||||
|
folks.backend = dofile(modpath .. "/backend_sqlite.lua")
|
||||||
|
else
|
||||||
|
minetest.log("error", "[FOLKS] Invalid storage type")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
dofile(modpath .. "/api.lua")
|
||||||
|
dofile(modpath .. "/privs.lua")
|
||||||
|
dofile(modpath .. "/chatcmdbuilder.lua")
|
||||||
|
dofile(modpath .. "/commands.lua")
|
||||||
|
dofile(modpath .. "/formspecs.lua")
|
||||||
|
dofile(modpath .. "/items.lua")
|
||||||
|
dofile(modpath .. "/npc.lua")
|
||||||
|
|
||||||
|
minetest.after(0, function()
|
||||||
|
local npcs = folks.backend.load_npcs()
|
||||||
|
-- if npcs then
|
||||||
|
-- for id, npc in pairs(npcs) do
|
||||||
|
-- minetest.log("action", minetest.serialize(npc))
|
||||||
|
-- folks.backend.spawn_npc(npc)
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- callback for skins_collectible
|
||||||
|
if folks.skins_c then
|
||||||
|
skins_collectible.register_on_set_skin(function(p_name, skin_ID)
|
||||||
|
local texture = skins_collectible.get_skin(skin_ID)
|
||||||
|
folks.backend.update_npc_texture(p_name, texture.texture)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_on_shutdown(function()
|
||||||
|
folks.backend.save_npcs()
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.log("action", "[FOLKS] Mod initialised. Running version " .. version)
|
112
mods/mobiles/folks/items.lua
Normal file
112
mods/mobiles/folks/items.lua
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
local S = minetest.get_translator("folks")
|
||||||
|
|
||||||
|
minetest.register_tool("folks:npc_creator", {
|
||||||
|
description = S("Use this to create a new NPC at your position"),
|
||||||
|
inventory_image = "npc_creator.png",
|
||||||
|
groups = {oddly_breakable_by_hand = "2"},
|
||||||
|
on_place = function() end,
|
||||||
|
on_drop = function() end,
|
||||||
|
|
||||||
|
on_use = function(itemstack, player, pointed_thing)
|
||||||
|
if not minetest.check_player_privs(player:get_player_name(), { folks_admin=true }) then return end
|
||||||
|
|
||||||
|
local npc_id = folks.backend.get_unique_id()
|
||||||
|
local new_npc = minetest.add_entity(player:get_pos(), "folks:npc", minetest.serialize({_npc_id = npc_id}))
|
||||||
|
if new_npc then
|
||||||
|
local entity = new_npc:get_luaentity()
|
||||||
|
if entity then
|
||||||
|
entity._npc_id = npc_id
|
||||||
|
folks.backend.add_npc(new_npc)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_tool("folks:npc_editor", {
|
||||||
|
description = S("Use this to edit the NPC you click"),
|
||||||
|
inventory_image = "npc_editor.png",
|
||||||
|
groups = {oddly_breakable_by_hand = "2"},
|
||||||
|
on_place = function() end,
|
||||||
|
on_drop = function() end,
|
||||||
|
|
||||||
|
on_use = function(itemstack, player, pointed_thing)
|
||||||
|
if pointed_thing.type == "nothing" or pointed_thing.type == "node" then return end
|
||||||
|
if not minetest.check_player_privs(player:get_player_name(), { folks_admin=true }) then return end
|
||||||
|
|
||||||
|
local entity = pointed_thing.ref:get_luaentity()
|
||||||
|
if entity._isfolk then
|
||||||
|
if mobkit.is_alive(entity) and not entity._isremoved then
|
||||||
|
-- TODO: show formspec to edit clicked npc
|
||||||
|
local meta = player:get_meta()
|
||||||
|
meta:set_string("folks_editing_npc", entity._npc_id)
|
||||||
|
-- minetest.log(dump(entity._npc_object))
|
||||||
|
minetest.chat_send_player(player:get_player_name(), minetest.colorize("#00ff00", S("You are now editing NPC: @1", entity._npc_id)))
|
||||||
|
-- minetest.log(entity._npc_id or "none")
|
||||||
|
-- formspec
|
||||||
|
minetest.show_formspec(player:get_player_name(), "folks:edit_npc_formspec", folks.get_edit_formspec(entity._npc_id))
|
||||||
|
-- end formspec
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_tool("folks:npc_remover", {
|
||||||
|
description = S("Use this to remove the NPC you click"),
|
||||||
|
inventory_image = "npc_remover.png",
|
||||||
|
groups = {oddly_breakable_by_hand = "2"},
|
||||||
|
on_place = function() end,
|
||||||
|
on_drop = function() end,
|
||||||
|
|
||||||
|
on_use = function(itemstack, player, pointed_thing)
|
||||||
|
if pointed_thing.type == "nothing" or pointed_thing.type == "node" then return end
|
||||||
|
if not minetest.check_player_privs(player:get_player_name(), { folks_admin=true }) then return end
|
||||||
|
|
||||||
|
local entity = pointed_thing.ref:get_luaentity()
|
||||||
|
if entity._isfolk and not entity._isremoved then
|
||||||
|
if folks.backend.get_npc(entity._npc_id) then
|
||||||
|
for _, npc_obj in pairs(folks.backend.get_npcs_obj(entity._npc_id)) do
|
||||||
|
npc_obj:remove()
|
||||||
|
end
|
||||||
|
folks.backend.remove_npc(entity._npc_id)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
else
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_tool("folks:npc_spawner", {
|
||||||
|
description = S("Use this to spawn an NPC that you had already created"),
|
||||||
|
inventory_image = "npc_spawner.png",
|
||||||
|
groups = {oddly_breakable_by_hand = "2"},
|
||||||
|
on_place = function() end,
|
||||||
|
on_drop = function() end,
|
||||||
|
|
||||||
|
on_use = function(itemstack, player, pointed_thing)
|
||||||
|
if not minetest.check_player_privs(player:get_player_name(), { folks_admin=true }) then return end
|
||||||
|
|
||||||
|
minetest.show_formspec(player:get_player_name(), "folks:spawn_npc_formspec", folks.get_spawn_formspec())
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_tool("folks:npc_despawner", {
|
||||||
|
description = S("Use this to despawn without deleting the NPC you click"),
|
||||||
|
inventory_image = "npc_despawner.png",
|
||||||
|
groups = {oddly_breakable_by_hand = "2"},
|
||||||
|
on_place = function() end,
|
||||||
|
on_drop = function() end,
|
||||||
|
|
||||||
|
on_use = function(itemstack, player, pointed_thing)
|
||||||
|
if pointed_thing.type == "nothing" or pointed_thing.type == "node" then return end
|
||||||
|
if not minetest.check_player_privs(player:get_player_name(), { folks_admin=true }) then return end
|
||||||
|
|
||||||
|
pointed_thing.ref:remove()
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
})
|
40
mods/mobiles/folks/locale/folks.it.tr
Normal file
40
mods/mobiles/folks/locale/folks.it.tr
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# textdomain: folks
|
||||||
|
|
||||||
|
|
||||||
|
### commands.lua ###
|
||||||
|
|
||||||
|
Couldn't retrieve player texture (is it online?)=Impossibile ottenere la skin del giocatore (è online?)
|
||||||
|
You need skins_collectible to use this feature=Hai bisogno di skins_collectible per usare questa funzione
|
||||||
|
Manage folks npcs=Gestisci gli npc di folks
|
||||||
|
|
||||||
|
### commands.lua ###
|
||||||
|
### formspecs.lua ###
|
||||||
|
|
||||||
|
You are not editing an NPC. Click the NPC you want to edit with the NPC editor item.=Non stai modificando nessun NPC. Clicca l'NPC che vuoi modificare con l'oggetto NPC editor.
|
||||||
|
Edited NPC: @1=Modificato NPC: @1
|
||||||
|
|
||||||
|
### formspecs.lua ###
|
||||||
|
|
||||||
|
Edit Folk=Modifica Folk
|
||||||
|
Folk name=Nome Folk
|
||||||
|
Folk Name Color=Colore del nome Folk
|
||||||
|
Folk Texture (with or without .png)=Texture del Folk (con o senza .png)
|
||||||
|
Messages (every line is a message)=Messaggi (ogni riga è un messaggio)
|
||||||
|
Save=Salva
|
||||||
|
Spawn NPC=Piazza NPC
|
||||||
|
Spawn=Piazza
|
||||||
|
Exited from NPC: @1=Uscito dall'NPC: @1
|
||||||
|
Spawned NPC: @1=Piazzato NPC: @1
|
||||||
|
No NPC selected=Nessun NPC selezionato
|
||||||
|
|
||||||
|
### items.lua ###
|
||||||
|
|
||||||
|
Use this to create a new NPC at your position=Usa questo per creare un NPC nella tua posizione
|
||||||
|
Use this to edit the NPC you click=Usa questo per modificare l'NPC che clicchi
|
||||||
|
You are now editing NPC: @1=Stai modificando l'NPC: @1
|
||||||
|
Use this to remove the NPC you click=Usa questo per rimuovere l'NPC che clicchi
|
||||||
|
Use this to spawn an NPC that you had already created=Usa questo per piazzare un NPC che hai già creato
|
||||||
|
Use this to despawn without deleting the NPC you click=Usa questo per rimuovere l'NPC che clicchi senza eliminarlo
|
||||||
|
|
||||||
|
### NPC messages ###
|
||||||
|
Hey, I'm a Folk!=Ciao, sono un Folk!
|
40
mods/mobiles/folks/locale/template.txt
Normal file
40
mods/mobiles/folks/locale/template.txt
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# textdomain: folks
|
||||||
|
|
||||||
|
|
||||||
|
### commands.lua ###
|
||||||
|
|
||||||
|
Couldn't retrieve player texture (is it online?)=
|
||||||
|
You need skins_collectible to use this feature=
|
||||||
|
Manage folks npcs=
|
||||||
|
|
||||||
|
### commands.lua ###
|
||||||
|
### formspecs.lua ###
|
||||||
|
|
||||||
|
You are not editing an NPC. Click the NPC you want to edit with the NPC editor item.=
|
||||||
|
Edited NPC: @1=
|
||||||
|
|
||||||
|
### formspecs.lua ###
|
||||||
|
|
||||||
|
Edit Folk=
|
||||||
|
Folk name=
|
||||||
|
Folk Name Color=
|
||||||
|
Folk Texture (with or without .png)=
|
||||||
|
Messages (every line is a message)=
|
||||||
|
Save=
|
||||||
|
Spawn NPC=
|
||||||
|
Spawn=
|
||||||
|
Exited from NPC: @1=
|
||||||
|
Spawned NPC: @1=
|
||||||
|
No NPC selected=
|
||||||
|
|
||||||
|
### items.lua ###
|
||||||
|
|
||||||
|
Use this to create a new NPC at your position=
|
||||||
|
Use this to edit the NPC you click=
|
||||||
|
You are now editing NPC: @1=
|
||||||
|
Use this to remove the NPC you click=
|
||||||
|
Use this to spawn an NPC that you had already created=
|
||||||
|
Use this to despawn without deleting the NPC you click=
|
||||||
|
|
||||||
|
### NPC messages ###
|
||||||
|
Hey, I'm a Folk!=
|
4
mods/mobiles/folks/mod.conf
Normal file
4
mods/mobiles/folks/mod.conf
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
name = folks
|
||||||
|
description = Adds npcs for RPG games
|
||||||
|
depends = mobkit
|
||||||
|
optional_depends = skins_collectible
|
BIN
mods/mobiles/folks/models/npc.b3d
Normal file
BIN
mods/mobiles/folks/models/npc.b3d
Normal file
Binary file not shown.
98
mods/mobiles/folks/npc.lua
Normal file
98
mods/mobiles/folks/npc.lua
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
local S = minetest.get_translator("folks")
|
||||||
|
|
||||||
|
folks.default_npc = {
|
||||||
|
initial_properties = {
|
||||||
|
hp_max = 9999,
|
||||||
|
physical = true,
|
||||||
|
collide_with_objects = false,
|
||||||
|
collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
|
||||||
|
visual_size = {x = 1, y = 1},
|
||||||
|
visual = "mesh",
|
||||||
|
mesh = "npc.b3d",
|
||||||
|
textures = {
|
||||||
|
folks.default_npc_texture,
|
||||||
|
},
|
||||||
|
pushable = false,
|
||||||
|
nametag = "Folk",
|
||||||
|
nametag_color = "#ffffff",
|
||||||
|
},
|
||||||
|
|
||||||
|
-- mobkit properties
|
||||||
|
timeout = 0,
|
||||||
|
max_hp = 9999,
|
||||||
|
buoyancy = -1,
|
||||||
|
lung_capacity = 200,
|
||||||
|
on_step = mobkit.stepfunc,
|
||||||
|
-- on_activate = mobkit.actfunc,
|
||||||
|
on_activate = function(self, staticdata, dtime_s)
|
||||||
|
mobkit.actfunc(self, staticdata, dtime_s)
|
||||||
|
|
||||||
|
self._npc_object = self.object
|
||||||
|
-- minetest.log("ACtivated")
|
||||||
|
-- minetest.log(dump(self._npc_object))
|
||||||
|
-- minetest.log(dump(mobkit.recall(self, "_npc_id")))
|
||||||
|
if staticdata ~= nil then
|
||||||
|
staticdata = minetest.deserialize(staticdata)
|
||||||
|
if mobkit.recall(self, "_npc_id") == nil then -- saves _npc_id to memory so I can get it every time the entity is activated
|
||||||
|
mobkit.remember(self, "_npc_id", staticdata._npc_id)
|
||||||
|
-- minetest.log(dump(mobkit.recall(self, "_npc_id")))
|
||||||
|
-- else
|
||||||
|
-- self.memory = folks.util.deepcopy(staticdata.memory)
|
||||||
|
end
|
||||||
|
local npc_id = mobkit.recall(self, "_npc_id")
|
||||||
|
local npc_data = folks.backend.get_npc(npc_id)
|
||||||
|
if npc_data then -- Here I set all the customizable properties
|
||||||
|
self.object:set_properties({
|
||||||
|
nametag = npc_data._npc_name,
|
||||||
|
nametag_color = npc_data._npc_name_color,
|
||||||
|
textures = npc_data._npc_textures,
|
||||||
|
})
|
||||||
|
self._npc_id = npc_id
|
||||||
|
folks.backend.set_npc_obj(npc_id, self.object)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
get_staticdata = mobkit.statfunc,
|
||||||
|
view_range = 24,
|
||||||
|
max_speed = 10,
|
||||||
|
jump_height = 10,
|
||||||
|
logic = function(self)
|
||||||
|
mobkit.vitals(self)
|
||||||
|
local prty = mobkit.get_queue_priority(self)
|
||||||
|
|
||||||
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
|
if prty < 10 then
|
||||||
|
local plyr = mobkit.get_nearby_player(self)
|
||||||
|
if plyr and vector.distance(pos,plyr:get_pos()) < 8 then
|
||||||
|
mobkit.lq_turn2pos(self, plyr:get_pos())
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
|
||||||
|
on_rightclick = function(self, player)
|
||||||
|
local msg_index = folks.backend.get_next_message_index(self._npc_id, player:get_player_name())
|
||||||
|
local msg = folks.get_npc_message(self._npc_id, msg_index)
|
||||||
|
if msg then
|
||||||
|
local npc_name = folks.backend.get_npc(self._npc_id)._npc_name
|
||||||
|
minetest.chat_send_player(player:get_player_name(), minetest.colorize("#00ff00", npc_name .. ": " .. S(msg)))
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_punch = function(self, puncher, t_from_last, tool_cap, dir, dmg)
|
||||||
|
-- minetest.log("action", minetest.serialize(tool_cap))
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- custom properties
|
||||||
|
_isfolk = true,
|
||||||
|
_isremoved = false,
|
||||||
|
_npc_object = nil,
|
||||||
|
_bound_player = nil, -- nil or player name
|
||||||
|
_npc_messages = {"Hey, I'm a Folk!"} -- contains all npc's messages
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
minetest.register_entity("folks:npc", folks.default_npc)
|
3
mods/mobiles/folks/privs.lua
Normal file
3
mods/mobiles/folks/privs.lua
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
minetest.register_privilege("folks_admin", {
|
||||||
|
descrption = "Allows you to spawn, edit and remove folks npcs"
|
||||||
|
})
|
5
mods/mobiles/folks/settings.lua
Normal file
5
mods/mobiles/folks/settings.lua
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
-- backend type, can be "storage" or "sqlite"
|
||||||
|
folks.backend_type = "storage"
|
||||||
|
|
||||||
|
-- set default texture for your npcs
|
||||||
|
folks.default_npc_texture = "folks_default.png"
|
BIN
mods/mobiles/folks/textures/folks_default.png
Normal file
BIN
mods/mobiles/folks/textures/folks_default.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 874 B |
BIN
mods/mobiles/folks/textures/npc_creator.png
Normal file
BIN
mods/mobiles/folks/textures/npc_creator.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 172 B |
BIN
mods/mobiles/folks/textures/npc_despawner.png
Normal file
BIN
mods/mobiles/folks/textures/npc_despawner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 181 B |
BIN
mods/mobiles/folks/textures/npc_editor.png
Normal file
BIN
mods/mobiles/folks/textures/npc_editor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 496 B |
BIN
mods/mobiles/folks/textures/npc_remover.png
Normal file
BIN
mods/mobiles/folks/textures/npc_remover.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 209 B |
BIN
mods/mobiles/folks/textures/npc_spawner.png
Normal file
BIN
mods/mobiles/folks/textures/npc_spawner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 195 B |
31
mods/mobiles/folks/util.lua
Normal file
31
mods/mobiles/folks/util.lua
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
local util = {}
|
||||||
|
|
||||||
|
local charset = {} do -- [0-9a-zA-Z]
|
||||||
|
for c = 48, 57 do table.insert(charset, string.char(c)) end
|
||||||
|
for c = 65, 90 do table.insert(charset, string.char(c)) end
|
||||||
|
for c = 97, 122 do table.insert(charset, string.char(c)) end
|
||||||
|
end
|
||||||
|
|
||||||
|
function util.randomString(length)
|
||||||
|
if not length or length <= 0 then return '' end
|
||||||
|
math.randomseed(os.clock()^5)
|
||||||
|
return util.randomString(length - 1) .. charset[math.random(1, #charset)]
|
||||||
|
end
|
||||||
|
|
||||||
|
function util.deepcopy(obj, seen)
|
||||||
|
if type(obj) ~= 'table' then
|
||||||
|
return obj
|
||||||
|
end
|
||||||
|
if seen and seen[obj] then
|
||||||
|
return seen[obj]
|
||||||
|
end
|
||||||
|
local s = seen or {}
|
||||||
|
local copy = setmetatable({}, getmetatable(obj))
|
||||||
|
s[obj] = copy
|
||||||
|
for k, v in pairs(obj) do
|
||||||
|
copy[util.deepcopy(k, s)] = util.deepcopy(v, s)
|
||||||
|
end
|
||||||
|
return copy
|
||||||
|
end
|
||||||
|
|
||||||
|
return util
|
Loading…
x
Reference in New Issue
Block a user