-- snippet_npcs/init.lua -- NPCs defined by snippets -- Copyright (C) 2025 1F616EMO -- SPDX-License-Identifier: LGPL-3.0-or-later local S = core.get_translator("snippet_npcs") dialog_redo.register_dialog_tree("snippet_npcs:not_configured", { init = dialog_redo.elements.simple({ name = S("Error"), avatar = "snippet_npcs_spawner.png", text = S("This NPC is not configured. Sneak and right-click as an admin to configure."), next = "", }), }) dialog_redo.register_dialog_tree("snippet_npcs:snippet_not_found", { init = dialog_redo.elements.simple({ name = S("Error"), avatar = "snippet_npcs_spawner.png", text = S("The snippet is not found. Sneak and right-click as an admin to configure."), next = "", }), }) dialog_redo.register_dialog_tree("snippet_npcs:admin_panel", { init = dialog_redo.elements.choices({ name = S("Admin Panel"), avatar = "snippet_npcs_spawner.png", text = S("Choose one operation:"), buttons = { { text = S("Set snippet"), next = "snippet", }, { text = S("Set skin"), next = "skin", }, { text = S("Set nametag"), next = "nametag", }, { text = S("Look at me"), next = function(session) local player = core.get_player_by_name(session.player_name) session.entity:_look_at(player) return "init" end, }, { text = S("Export"), next = function(session) local player = core.get_player_by_name(session.player_name) local inv = player:get_inventory() local export_item = ItemStack("snippet_npcs:spawner") local item_meta = export_item:get_meta() item_meta:set_string("description", S("NPC Spawner (@1)", session.entity._snippet_name or S("Unconfigured"))) item_meta:set_string("staticdata", session.entity:get_staticdata()) inv:add_item("main", export_item) return "init" end, }, { text = S("Remove"), next = "remove", }, { text = S("Exit"), next = "", }, }, allow_exit = true, }), snippet = dialog_redo.elements.textbox({ name = S("Admin Panel"), avatar = "snippet_npcs_spawner.png", text = S("Type the snippet name:"), next = "init", process_text = function(session, text) if string.trim(text) == "" then text = nil end session.entity._snippet_name = text session.entity:_init_appearance() end, }), nametag = dialog_redo.elements.textbox({ name = S("Admin Panel"), avatar = "snippet_npcs_spawner.png", text = S("Type the nametag:"), next = "init", process_text = function(session, text) if string.trim(text) == "" then text = nil end session.entity._nametag = text session.entity:_init_appearance() end, }), skin = dialog_redo.elements.textbox({ name = S("Admin Panel"), avatar = "snippet_npcs_spawner.png", text = S("Type the skin ID:"), next = "init", process_text = function(session, text) if string.trim(text) == "" then text = nil end session.entity._skinid = text session.entity:_init_appearance() end, }), remove = dialog_redo.elements.choices({ name = S("Admin Panel"), avatar = "snippet_npcs_spawner.png", text = S("Are you sure you want to remove this NPC?"), buttons = { { text = S("Confirm"), next = function(session) session.entity.object:remove() return "" end, }, { text = S("Cancel"), next = "init", }, }, }), }) core.register_entity("snippet_npcs:npc", { initial_properties = { physical = true, collide_with_objects = false, pointable = true, visual = "mesh", mesh = "skinsdb_3d_armor_character_5.b3d", textures = { "blank.png", -- v10 "character.1.png", -- v18 "blank.png", -- armor "blank.png", -- wielditem }, visual_size = { x = 1, y = 1 }, collisionbox = { -0.3, 0.0, -0.3, 0.3, 1.7, 0.3 }, }, on_rightclick = function(self, clicker) if not (clicker and clicker.is_player and clicker:is_player()) then return end local name = clicker:get_player_name() local dialog if clicker:get_player_control().sneak then if core.check_player_privs(name, { server = true }) then dialog = "snippet_npcs:admin_panel" end end if not dialog then if not self._snippet_name then dialog = "snippet_npcs:not_configured" elseif not snippets.registered_snippets[self._snippet_name] then dialog = "snippet_npcs:snippet_not_found" else dialog = snippets.run(self._snippet_name) end end dialog_redo.start_dialog(name, dialog, { entity = self, }) end, get_staticdata = function(self) return core.serialize({ _snippet_name = self._snippet_name, _skinid = self._skinid, _nametag = self._nametag, }) end, on_activate = function(self, staticdata_s) local staticdata = staticdata_s and core.deserialize(staticdata_s) or {} self._snippet_name = staticdata._snippet_name self._skinid = staticdata._skinid self._nametag = staticdata._nametag self:_init_appearance() self.object:set_armor_groups({ immortal = 1 }) end, _init_appearance = function(self) local skin = self._skinid and skins.get(self._skinid) or skins.get(skins.default) local textures = { "blank.png", -- v10 "blank.png", -- v18 "blank.png", -- armor "blank.png", -- wielditem } if skin:get_meta("format") == "1.8" then textures[2] = skin:get_texture() else textures[1] = skin:get_texture() end self.object:set_properties({ nametag = self._nametag or "", textures = textures, visual_size = { x = skin:get_meta("visual_size_x") or 1, y = skin:get_meta("visual_size_y") or 1 }, }) end, _look_at = function(self, target) local self_pos = self.object:get_pos() local target_pos = target:get_pos() local yaw = math.atan2(target_pos.z - self_pos.z, target_pos.x - self_pos.x) - (math.pi / 2) self.object:set_yaw(yaw) end, }) core.register_craftitem("snippet_npcs:spawner", { description = S("NPC Spawner"), inventory_image = "snippet_npcs_spawner.png", stack_max = 1, on_place = function(itemstack, player, pointed_thing) if not (player and player.is_player and player:is_player()) then return itemstack end local name = player:get_player_name() if not core.check_player_privs(name, { server = true }) then core.chat_send_player(name, S("Insufficant privilege!")) return itemstack end local meta = itemstack:get_meta() local staticdata = meta:get("staticdata") local pos = vector.add(pointed_thing.above, vector.new(0, -0.5, 0)) local entity = core.add_entity(pos, "snippet_npcs:npc", staticdata) entity:get_luaentity():_look_at(player) return itemstack end, })