diff --git a/actions/actions.lua b/actions/actions.lua index 8c375c4..c88eda2 100644 --- a/actions/actions.lua +++ b/actions/actions.lua @@ -141,8 +141,8 @@ end -- and the NPC is allowed to roam freely. function npc.actions.freeze(self, args) local freeze_mobs_api = args.freeze - minetest.log("Received: "..dump(freeze_mobs_api)) - minetest.log("Returning: "..dump(not(freeze_mobs_api))) + --minetest.log("Received: "..dump(freeze_mobs_api)) + --minetest.log("Returning: "..dump(not(freeze_mobs_api))) return not(freeze_mobs_api) end @@ -333,7 +333,7 @@ function npc.actions.take_item_from_external_inventory(self, args) else inv = minetest.get_inventory({type="node", pos=pos}) end - -- Create ItemSTack to take from external inventory + -- Create ItemStack to take from external inventory local item = ItemStack(item_name.." "..count) -- Check if there is enough of the item to take if inv:contains_item(inv_list, item) then @@ -369,7 +369,7 @@ end -- TODO: Refactor this function so that it uses a table to check -- for doors instead of having separate logic for each door type function npc.actions.get_openable_node_state(node, npc_dir) - minetest.log("Node name: "..dump(node.name)) + --minetest.log("Node name: "..dump(node.name)) local state = npc.actions.const.doors.state.CLOSED -- Check for default doors and gates local a_i1, a_i2 = string.find(node.name, "_a") @@ -383,7 +383,7 @@ function npc.actions.get_openable_node_state(node, npc_dir) if a_i1 == nil and open_i1 == nil and not half_door_is_closed then state = npc.actions.const.doors.state.OPEN end - minetest.log("Door state: "..dump(state)) + --minetest.log("Door state: "..dump(state)) return state end @@ -412,10 +412,10 @@ end -- items from a chest, are provided here. local function get_pos_argument(self, pos) - minetest.log("Type of pos: "..dump(type(pos))) + --minetest.log("Type of pos: "..dump(type(pos))) -- Check which type of position argument we received if type(pos) == "table" then - minetest.log("Received table pos: "..dump(pos)) + --minetest.log("Received table pos: "..dump(pos)) -- Check if table is position if pos.x ~= nil and pos.y ~= nil and pos.z ~= nil then -- Position received, return position @@ -468,7 +468,7 @@ end function npc.actions.use_furnace(self, args) local pos = get_pos_argument(self, args.pos) if pos == nil then - minetest.log("[advanced_npc] WARNING Got nil position in 'use_furnace' using args.pos: "..dump(args.pos)) + npc.log("WARNING", "Got nil position in 'use_furnace' using args.pos: "..dump(args.pos)) return end @@ -478,14 +478,14 @@ function npc.actions.use_furnace(self, args) -- will mainly use this as fuels to avoid getting useful -- items (such as coal lumps) for burning local fuels = {"default:leaves", - "default:pine_needles", - "default:tree", - "default:acacia_tree", - "default:aspen_tree", - "default:jungletree", - "default:pine_tree", - "default:coalblock", - "farming:straw"} + "default:pine_needles", + "default:tree", + "default:acacia_tree", + "default:aspen_tree", + "default:jungletree", + "default:pine_tree", + "default:coalblock", + "farming:straw"} -- Check if NPC has item to cook local src_item = npc.inventory_contains(self, npc.get_item_name(item)) @@ -503,15 +503,15 @@ function npc.actions.use_furnace(self, args) local fuel_time = minetest.get_craft_result({method="fuel", width=1, items={ItemStack(fuel_item.item_string)}}).time local total_fuel_time = fuel_time * npc.get_item_count(fuel_item.item_string) - minetest.log("Fuel time: "..dump(fuel_time)) + npc.log("DEBUG", "Fuel time: "..dump(fuel_time)) -- Get item to cook's cooking time local cook_result = minetest.get_craft_result({method="cooking", width=1, items={ItemStack(src_item.item_string)}}) local total_cook_time = cook_result.time * npc.get_item_count(item) - minetest.log("Cook: "..dump(cook_result)) + npc.log("DEBUG", "Cook: "..dump(cook_result)) - minetest.log("Total cook time: "..total_cook_time + npc.log("DEBUG", "Total cook time: "..total_cook_time ..", total fuel burn time: "..dump(total_fuel_time)) -- Check if there is enough fuel to cook all items @@ -531,7 +531,7 @@ function npc.actions.use_furnace(self, args) fuel_amount = 1 end - minetest.log("Amount of fuel needed: "..fuel_amount) + npc.log("DEBUG", "Amount of fuel needed: "..fuel_amount) -- Put this item on the fuel inventory list of the furnace local args = { @@ -554,7 +554,7 @@ function npc.actions.use_furnace(self, args) npc.add_action(self, npc.actions.cmd.PUT_ITEM, args) -- Now, set NPC to wait until furnace is done. - minetest.log("Setting wait action for "..dump(total_cook_time)) + npc.log("DEBUG", "Setting wait action for "..dump(total_cook_time)) npc.add_action(self, npc.actions.cmd.SET_INTERVAL, {interval=total_cook_time, freeze=freeze}) -- Reset timer @@ -563,7 +563,7 @@ function npc.actions.use_furnace(self, args) -- If freeze is false, then we will have to find the way back to the furnace -- once cooking is done. if freeze == false then - minetest.log("Adding walk to position to wandering: "..dump(pos)) + npc.log("DEBUG", "Adding walk to position to wandering: "..dump(pos)) npc.add_task(self, npc.actions.cmd.WALK_TO_POS, {end_pos=pos, walkable={}}) end @@ -577,10 +577,10 @@ function npc.actions.use_furnace(self, args) count = npc.get_item_count(item), is_furnace = false } - minetest.log("Taking item back: "..minetest.pos_to_string(pos)) + npc.log("DEBUG", "Taking item back: "..minetest.pos_to_string(pos)) npc.add_action(self, npc.actions.cmd.TAKE_ITEM, args) - minetest.log("Inventory: "..dump(self.inventory)) + npc.log("DEBUG", "Inventory: "..dump(self.inventory)) return true end @@ -594,7 +594,7 @@ end function npc.actions.use_bed(self, args) local pos = get_pos_argument(self, args.pos) if pos == nil then - minetest.log("[advanced_npc] WARNING Got nil position in 'use_bed' using args.pos: "..dump(args.pos)) + npc.log("WARNING", "Got nil position in 'use_bed' using args.pos: "..dump(args.pos)) return end local action = args.action @@ -654,7 +654,7 @@ end function npc.actions.use_sittable(self, args) local pos = get_pos_argument(self, args.pos) if pos == nil then - minetest.log("[advanced_npc] WARNING Got nil position in 'use_sittable' using args.pos: "..dump(args.pos)) + npc.log("WARNING", "Got nil position in 'use_sittable' using args.pos: "..dump(args.pos)) return end local action = args.action @@ -727,7 +727,7 @@ function npc.actions.walk_to_pos(self, args) -- Get arguments for this task local end_pos = get_pos_argument(self, args.end_pos) if end_pos == nil then - minetest.log("[advanced_npc] WARNING Got nil position in 'walk_to_pos' using args.pos: "..dump(args.end_pos)) + npc.log("WARNING", "Got nil position in 'walk_to_pos' using args.pos: "..dump(args.end_pos)) return end local enforce_move = args.enforce_move or true @@ -737,8 +737,8 @@ function npc.actions.walk_to_pos(self, args) local start_pos = vector.round(self.object:getpos()) -- Use y of end_pos (this can only be done assuming flat terrain) --start_pos.y = self.object:getpos().y - minetest.log("[advanced_npc] INFO walk_to_pos: Start pos: "..minetest.pos_to_string(start_pos)) - minetest.log("[advanced_npc] INFO walk_to_pos: End pos: "..minetest.pos_to_string(end_pos)) + npc.log("DEBUG", "walk_to_pos: Start pos: "..minetest.pos_to_string(start_pos)) + npc.log("DEBUG", "walk_to_pos: End pos: "..minetest.pos_to_string(end_pos)) -- Set walkable nodes to empty if the parameter hasn't been used if walkable_nodes == nil then @@ -759,11 +759,8 @@ function npc.actions.walk_to_pos(self, args) end path = path_detail - --minetest.log("Found path: "..dump(path)) - - --minetest.log("Path detail: "..dump(path_detail)) - --minetest.log("New path: "..dump(path)) - minetest.log("[advanced_npc] INFO walk_to_pos Found path to node: "..minetest.pos_to_string(end_pos)) + npc.log("DEBUG", "Detailed path: "..dump(path)) + npc.log("INFO", "walk_to_pos Found path to node: "..minetest.pos_to_string(end_pos)) -- Store path self.actions.walking.path = path @@ -784,6 +781,8 @@ function npc.actions.walk_to_pos(self, args) if (i+1) == #path then -- Add direction to last node local dir = npc.actions.get_direction(path[i].pos, end_pos) + -- Add the last step + npc.add_action(self, npc.actions.cmd.WALK_STEP, {dir = dir, speed = speed, target_pos = path[i+1].pos}) -- Add stand animation at end npc.add_action(self, npc.actions.cmd.STAND, {dir = dir}) break @@ -823,7 +822,7 @@ function npc.actions.walk_to_pos(self, args) -- end -- local pos_on_close = {x=path[i+1].pos.x + x_adj, y=path[i+1].pos.y + 1, z=path[i+1].pos.z + z_adj} -- Add extra walk step to ensure that one is standing at other side of openable node - npc.add_action(self, npc.actions.cmd.WALK_STEP, {dir = dir, speed = speed, target_pos = path[i+2].pos}) + -- npc.add_action(self, npc.actions.cmd.WALK_STEP, {dir = dir, speed = speed, target_pos = path[i+2].pos}) -- Stop to close the door npc.add_action(self, npc.actions.cmd.STAND, {dir=(dir + 2) % 4 })--, pos=pos_on_close}) -- Close door @@ -840,7 +839,7 @@ function npc.actions.walk_to_pos(self, args) else -- Unable to find path - minetest.log("[advanced_npc] INFO walk_to_pos Unable to find path. Teleporting to: "..minetest.pos_to_string(end_pos)) + npc.log("WARNING", "walk_to_pos Unable to find path. Teleporting to: "..minetest.pos_to_string(end_pos)) -- Check if movement is enforced if enforce_move then -- Move to end pos diff --git a/actions/places.lua b/actions/places.lua index e6eb7ef..bc198ed 100644 --- a/actions/places.lua +++ b/actions/places.lua @@ -124,7 +124,7 @@ function npc.places.find_node_orthogonally(pos, nodes, y_adjustment) local result = {} for _,point in pairs(points) do local node = minetest.get_node(point) - minetest.log("Found node: "..dump(node)..", at pos: "..dump(point)) + --minetest.log("Found node: "..dump(node)..", at pos: "..dump(point)) for _,node_name in pairs(nodes) do if node.name == node_name then table.insert(result, {name=node.name, pos=point, param2=node.param2}) @@ -194,8 +194,8 @@ function npc.places.find_entrance_from_openable_nodes(all_openable_nodes, marker --local path = pathfinder.find_path(start_pos, end_pos, 20, {}) local entity = {} entity.collisionbox = {-0.20,-1.0,-0.20, 0.20,0.8,0.20} - minetest.log("Start pos: "..minetest.pos_to_string(start_pos)) - minetest.log("End pos: "..minetest.pos_to_string(end_pos)) + --minetest.log("Start pos: "..minetest.pos_to_string(start_pos)) + --minetest.log("End pos: "..minetest.pos_to_string(end_pos)) local path = pathfinder.find_path(start_pos, end_pos, entity) --minetest.log("Found path: "..dump(path)) if path ~= nil then @@ -217,13 +217,13 @@ function npc.places.find_entrance_from_openable_nodes(all_openable_nodes, marker -- Check if min-distance door is a cottages door -- while we have a MTG door if min_node_name == "cottages:half_door" and doors_st ~= nil then - minetest.log("Assigned new door...") + --minetest.log("Assigned new door...") min = #path result = openable_nodes[i] end end else - minetest.log("Path not found to marker from "..minetest.pos_to_string(start_pos)) + npc.log("ERROR", "Path not found to marker from "..minetest.pos_to_string(start_pos)) end end end @@ -302,7 +302,7 @@ function npc.places.is_in_staircase(pos) -- Get next node local upper_node = minetest.get_node(upper_pos) local lower_node = minetest.get_node(lower_pos) - minetest.log("Next node: "..dump(upper_pos)) + --minetest.log("Next node: "..dump(upper_pos)) -- Check if next node is also a stairs node local up_p1, up_p2 = string.find(upper_node.name, "stairs:") local lo_p1, lo_p2 = string.find(lower_node.name, "stairs:") @@ -351,7 +351,7 @@ end -- front of a door. Used to make NPCs exit buildings. function npc.places.find_node_in_front_of_door(door_pos) local door = minetest.get_node(door_pos) - minetest.log("Param2 of door: "..dump(door.param2)) + --minetest.log("Param2 of door: "..dump(door.param2)) if door.param2 == 0 then -- Looking south return {x=door_pos.x, y=door_pos.y, z=door_pos.z - 1} diff --git a/dialogue.lua b/dialogue.lua index bc60dcf..d604404 100644 --- a/dialogue.lua +++ b/dialogue.lua @@ -296,7 +296,7 @@ function npc.dialogue.process_dialogue(self, dialogue, player_name) -- Send dialogue line if dialogue.text then - minetest.chat_send_player(player_name, self.npc_name..": "..dialogue.text) + npc.chat(self.npc_name, player_name, dialogue.text) end -- Check if dialogue has responses. If it doesn't, unlock the actions diff --git a/init.lua b/init.lua index d50b9de..0c007f5 100755 --- a/init.lua +++ b/init.lua @@ -23,7 +23,6 @@ else end mobs.intllib = S --- NPC dofile(path .. "/npc.lua") dofile(path .. "/spawner.lua") dofile(path .. "/relationships.lua") diff --git a/npc.lua b/npc.lua index b5ad09b..3bd13ed 100755 --- a/npc.lua +++ b/npc.lua @@ -42,9 +42,27 @@ npc.action_state = { interrupted = 2 } +npc.log_level = { + INFO = true, + WARNING = false, + ERROR = true, + DEBUG = false +} + --------------------------------------------------------------------------------------- -- General functions --------------------------------------------------------------------------------------- +-- Logging +function npc.log(level, message) + if npc.log_level[level] then + minetest.log("[advanced_npc] "..type..": "..message) + end +end + +-- NPC chat +function npc.chat(npc_name, player_name, message) + minetest.chat_send_player(player_name, npc_name..": "..message) + -- Gets name of player or NPC function npc.get_entity_name(entity) if entity:is_player() then @@ -176,7 +194,7 @@ end -- Spawn function. Initializes all variables that the -- NPC will have and choose random, starting values function npc.initialize(entity, pos, is_lua_entity, npc_stats) - minetest.log("[advanced_npc] INFO: Initializing NPC at "..minetest.pos_to_string(pos)) + npc.log("INFO", "Initializing NPC at "..minetest.pos_to_string(pos)) -- Get variables local ent = entity @@ -426,7 +444,7 @@ function npc.initialize(entity, pos, is_lua_entity, npc_stats) table.insert(ent.trader_data.custom_trades, offer2) --minetest.log(dump(ent)) - minetest.log("[advanced_npc] INFO Successfully initialized NPC with name "..dump(ent.npc_name)) + npc.log("INFO", "Successfully initialized NPC with name "..dump(ent.npc_name)) -- Refreshes entity ent.object:set_properties(ent) end @@ -596,7 +614,7 @@ end function npc.execute_action(self) -- Check if an action was interrupted if self.actions.current_action_state == npc.action_state.interrupted then - minetest.log("[advanced_npc] DEBUG Re-inserting interrupted action for NPC: '"..dump(self.npc_name).."': "..dump(self.actions.state_before_lock.interrupted_action)) + npc.log("DEBUG", "Re-inserting interrupted action for NPC: '"..dump(self.npc_name).."': "..dump(self.actions.state_before_lock.interrupted_action)) -- Insert into queue the interrupted action table.insert(self.actions.queue, 1, self.actions.state_before_lock.interrupted_action) -- Clear the action @@ -618,7 +636,7 @@ function npc.execute_action(self) -- If the entry is a task, then push all this new operations in -- stack fashion if action_obj.is_task == true then - minetest.log("[advanced_npc] DEBUG Executing task for NPC '"..dump(self.npc_name).."': "..dump(action_obj)) + npc.log("DEBUG", "Executing task for NPC '"..dump(self.npc_name).."': "..dump(action_obj)) -- Backup current queue local backup_queue = self.actions.queue -- Remove this "task" action from queue @@ -634,7 +652,7 @@ function npc.execute_action(self) table.insert(self.actions.queue, backup_queue[i]) end else - minetest.log("[advanced_npc] DEBUG Executing action for NPC '"..dump(self.npc_name).."': "..dump(action_obj)) + npc.log("DEBUG", "Executing action for NPC '"..dump(self.npc_name).."': "..dump(action_obj)) -- Store the action that is being executed self.actions.state_before_lock.interrupted_action = action_obj -- Store current position @@ -689,7 +707,7 @@ function npc.lock_actions(self) -- Freeze mobs_redo API self.freeze = false - minetest.log("Locking") + npc.log("DEBUG", "Locking NPC "..dump(self.npc_id).." actions") end function npc.unlock_actions(self) @@ -703,7 +721,7 @@ function npc.unlock_actions(self) self.freeze = true end - minetest.log("Unlocked") + npc.log("DEBUG", "Unlocked NPC "..dump(self.npc_id).." actions") end --------------------------------------------------------------------------------------- @@ -863,7 +881,7 @@ mobs:register_mob("advanced_npc:npc", { {"npc_female1.png"}, -- female by nuttmeg20 }, child_texture = { - {"npc_baby_male1.png"}, -- derpy baby by AmirDerAssassine + {"npc_baby_male1.png"}, {"npc_baby_female1.png"}, }, makes_footstep_sound = true, @@ -915,12 +933,8 @@ mobs:register_mob("advanced_npc:npc", { --self.base_texture = "mobs_npc_child_male1.png" --self.object:set_properties(self) - minetest.log(dump(self)) + npc.log("DEBUG", "Right-clicked NPC: "..dump(self)) - minetest.log("Child: "..dump(self.is_child)) - minetest.log("Sex: "..dump(self.sex)) - minetest.log("Textures: "..dump(self.textures)) - -- Receive gift or start chat. If player has no item in hand -- then it is going to start chat directly if self.can_have_relationship and item:to_table() ~= nil then @@ -952,7 +966,7 @@ mobs:register_mob("advanced_npc:npc", { -- Initialize NPC if spawned using the spawn egg built in from -- mobs_redo. This functionality will be removed in the future in -- favor of a better manual spawning method with customization - minetest.log("[advanced_npc] WARNING: Initializing NPC from entity step. This message should only be appearing if an NPC is being spawned from inventory with egg!") + npc.log("WARNING", "Initializing NPC from entity step. This message should only be appearing if an NPC is being spawned from inventory with egg!") npc.initialize(self, self.object:getpos(), true) else self.tamed = false @@ -1049,7 +1063,7 @@ mobs:register_mob("advanced_npc:npc", { -- to action queue. This is for jobs. -- TODO: Need to implement else - minetest.log("Adding actions to action queue") + npc.log("DEBUG", "Adding actions to action queue") -- Add to action queue all actions on schedule for i = 1, #schedule[time] do if schedule[time][i].action == nil then @@ -1060,7 +1074,7 @@ mobs:register_mob("advanced_npc:npc", { npc.add_action(self, schedule[time][i].action, schedule[time][i].args) end end - minetest.log("New action queue: "..dump(self.actions)) + npc.log("DEBUG", "New action queue: "..dump(self.actions)) end end end diff --git a/spawner.lua b/spawner.lua index c860f06..f6a4ae3 100644 --- a/spawner.lua +++ b/spawner.lua @@ -209,7 +209,7 @@ function spawner.assign_places(self, pos) -- Find unowned bed for i = 1, #node_data.bed_type do -- Check if bed has owner - minetest.log("Node: "..dump(node_data.bed_type[i])) + --minetest.log("Node: "..dump(node_data.bed_type[i])) if node_data.bed_type[i].owner == "" then -- If bed has no owner, check if it is accessible local empty_nodes = npc.places.find_node_orthogonally( @@ -223,7 +223,7 @@ function spawner.assign_places(self, pos) npc.places.PLACE_TYPE.BED.PRIMARY, node_data.bed_type[i].node_pos, empty_nodes[1].pos) -- Store changes to node_data meta:set_string("node_data", minetest.serialize(node_data)) - minetest.log("Added bed at "..minetest.pos_to_string(node_data.bed_type[i].node_pos) + npc.log("DEBUG", "Added bed at "..minetest.pos_to_string(node_data.bed_type[i].node_pos) .." to NPC "..dump(self.npc_name)) break end @@ -233,7 +233,7 @@ function spawner.assign_places(self, pos) --local plot_info = minetest.deserialize(meta:get_string("plot_info")) --minetest.log("Plot info:"..dump(plot_info)) - minetest.log("places: "..dump(self.places_map)) + npc.log("DEBUG", "Places for NPC "..self.npc_name..": "..dump(self.places_map)) -- Make NPC go into their house npc.add_task(self, @@ -274,9 +274,9 @@ function npc.spawner.spawn_npc(pos) -- Check amount of NPCs that should be spawned local npc_count = meta:get_int("npc_count") local spawned_npc_count = meta:get_int("spawned_npc_count") - minetest.log("[advanced_npc] INFO Currently spawned "..dump(spawned_npc_count).." of "..dump(npc_count).." NPCs") + npc.log("INFO", "Currently spawned "..dump(spawned_npc_count).." of "..dump(npc_count).." NPCs") if spawned_npc_count < npc_count then - minetest.log("[advanced_npc] INFO Spawning NPC at "..minetest.pos_to_string(pos)) + npc.log("INFO", "Spawning NPC at "..minetest.pos_to_string(pos)) -- Spawn a NPC local ent = minetest.add_entity({x=pos.x, y=pos.y+1, z=pos.z}, "advanced_npc:npc") if ent and ent:get_luaentity() then @@ -324,21 +324,21 @@ function npc.spawner.spawn_npc(pos) meta:set_string("npc_stats", minetest.serialize(npc_stats)) -- Temp --meta:set_string("infotext", meta:get_string("infotext")..", "..spawned_npc_count) - minetest.log("[advanced_npc] INFO Spawning successful!") + npc.log("INFO", "Spawning successful!") -- Check if there are more NPCs to spawn if spawned_npc_count >= npc_count then -- Stop timer - minetest.log("[advanced_npc] INFO No more NPCs to spawn at this location") + npc.log("INFO", "No more NPCs to spawn at this location") timer:stop() else -- Start another timer to spawn more NPC local new_delay = math.random(npc.spawner.spawn_delay) - minetest.log("[advanced_npc] INFO Spawning one more NPC in "..dump(npc.spawner.spawn_delay).."s") + npc.log("INFO", "Spawning one more NPC in "..dump(npc.spawner.spawn_delay).."s") timer:start(new_delay) end return true else - minetest.log("[advanced_npc] Spawning failed!") + npc.log("ERROR", "Spawning failed!") ent:remove() return false end @@ -358,13 +358,13 @@ function spawner.calculate_npc_spawning(pos) -- Get nodes for this building local node_data = minetest.deserialize(meta:get_string("node_data")) if node_data == nil then - minetest.log("[advanced_npc] ERROR: Mis-configured advanced_npc:plotmarker_auto_spawner at position: "..minetest.pos_to_string(pos)) + npc.log("ERROR", "Mis-configured advanced_npc:plotmarker_auto_spawner at position: "..minetest.pos_to_string(pos)) return end -- Check number of beds local beds_count = #node_data.bed_type--#spawner.filter_first_floor_nodes(node_data.bed_type, pos) - minetest.log("[advanced_npc] INFO: Found "..dump(beds_count).." beds in the building at "..minetest.pos_to_string(pos)) + npc.log("DEBUG", "Found "..dump(beds_count).." beds in the building at "..minetest.pos_to_string(pos)) local npc_count = 0 -- If number of beds is zero or beds/2 is less than one, spawn -- a single NPC. @@ -375,7 +375,7 @@ function spawner.calculate_npc_spawning(pos) -- Spawn (beds_count/2) NPCs npc_count = ((beds_count / 2) - ((beds_count / 2) % 1)) end - minetest.log("[advanced_npc] INFO: Will spawn "..dump(npc_count).." NPCs at "..minetest.pos_to_string(pos)) + npc.log("INFO", "Will spawn "..dump(npc_count).." NPCs at "..minetest.pos_to_string(pos)) -- Store amount of NPCs to spawn meta:set_int("npc_count", npc_count) -- Store amount of NPCs spawned @@ -435,14 +435,14 @@ function spawner.scan_mg_villages_building(pos, building_data) --minetest.set_node({x=pos.x,y=pos.y,z=pos.z + (z_sign * z_size)}, {name = "wool:blue"}) --minetest.get_meta({x=pos.x,y=pos.y,z=pos.z + (z_sign * z_size)}):set_string("infotext", minetest.get_meta(pos):get_string("infotext")..", Axis: z, Sign: "..dump(z_sign)) - minetest.log("Start pos: "..minetest.pos_to_string(start_pos)) - minetest.log("Plot: "..dump(minetest.get_meta(start_pos):get_string("infotext"))) + npc.log("DEBUG", "Start pos: "..minetest.pos_to_string(start_pos)) + npc.log("DEBUG", "Plot: "..dump(minetest.get_meta(start_pos):get_string("infotext"))) - minetest.log("Brotate: "..dump(brotate)) - minetest.log("X_sign: "..dump(x_sign)) - minetest.log("X_adj: "..dump(x_sign*x_size)) - minetest.log("Z_sign: "..dump(z_sign)) - minetest.log("Z_adj: "..dump(z_sign*z_size)) + npc.log("DEBUG", "Brotate: "..dump(brotate)) + npc.log("DEBUG", "X_sign: "..dump(x_sign)) + npc.log("DEBUG", "X_adj: "..dump(x_sign*x_size)) + npc.log("DEBUG", "Z_sign: "..dump(z_sign)) + npc.log("DEBUG", "Z_adj: "..dump(z_sign*z_size)) local end_pos = {x=pos.x + (x_sign * x_size), y=pos.y + y_size, z=pos.z + (z_sign * z_size)} @@ -451,7 +451,7 @@ function spawner.scan_mg_villages_building(pos, building_data) --minetest.set_node(end_pos, {name="default:mese_block"}) --minetest.get_meta(end_pos):set_string("infotext", minetest.get_meta(start_pos):get_string("infotext")) - minetest.log("Calculated end pos: "..minetest.pos_to_string(end_pos)) + npc.log("DEBUG", "Calculated end pos: "..minetest.pos_to_string(end_pos)) return spawner.scan_area(start_pos, end_pos) end @@ -477,7 +477,7 @@ function spawner.replace_mg_villages_plotmarker(pos) if building_type == value then - minetest.log("Replacing mg_villages:plotmarker at "..minetest.pos_to_string(pos)) + npc.log("INFO", "Replacing mg_villages:plotmarker at "..minetest.pos_to_string(pos)) -- Replace the plotmarker for auto-spawner minetest.set_node(pos, {name="advanced_npc:plotmarker_auto_spawner"}) -- Store old plotmarker metadata again @@ -498,9 +498,9 @@ function spawner.replace_mg_villages_plotmarker(pos) --minetest.log("Found "..dump(#doors).." openable nodes") local entrance = npc.places.find_entrance_from_openable_nodes(doors, pos) if entrance then - minetest.log("Found building entrance at: "..minetest.pos_to_string(entrance.node_pos)) + npc.log("INFO", "Found building entrance at: "..minetest.pos_to_string(entrance.node_pos)) else - minetest.log("Unable to find building entrance!") + npc.log("ERROR", "Unable to find building entrance!") end -- Store building entrance meta:set_string("entrance", minetest.serialize(entrance)) @@ -569,7 +569,7 @@ if minetest.get_modpath("mg_villages") ~= nil then -- end -- minetest.get_meta(pos):set_string("node_data", minetest.serialize(nodedata)) -- minetest.log("Cleared bed owners") - minetest.log("NPC stats: "..dump(minetest.deserialize(minetest.get_meta(pos):get_string("npc_stats")))) + --minetest.log("NPC stats: "..dump(minetest.deserialize(minetest.get_meta(pos):get_string("npc_stats")))) return mg_villages.plotmarker_formspec( pos, nil, {}, clicker ) end, @@ -610,7 +610,7 @@ if minetest.get_modpath("mg_villages") ~= nil then -- end -- }) - -- ABM Registration... for when LBM fails. + -- ABM Registration minetest.register_abm({ label = "Replace mg_villages:plotmarker with Advanced NPC auto spawners", nodenames = {"mg_villages:plotmarker"}, diff --git a/trade/trade.lua b/trade/trade.lua index 6008eed..c4d7f75 100644 --- a/trade/trade.lua +++ b/trade/trade.lua @@ -415,8 +415,8 @@ function npc.trade.get_dedicated_trade_offers(self) -- If item found, create a buy offer for this item -- Again, offers are created for one item only. Buy offers should be removed -- after the NPC has bought a certain quantity, say, 5 items. - minetest.log("Item: "..item_name) - minetest.log("Trade info: "..dump(trade_info)) + --minetest.log("Item: "..item_name) + --minetest.log("Trade info: "..dump(trade_info)) --minetest.log("Logic: "..dump(trade_info.item_bought_count == nil -- or (trade_info.item_bought_count ~= nil and trade_info.item_bought_count <= npc.trade.DEDICATED_MAX_BUY_AMOUNT))) if trade_info.item_bought_count == nil @@ -537,16 +537,17 @@ function npc.trade.perform_trade(self, player_name, offer) inv:add_item("main", price_stacks[j]) end -- Send message to player - minetest.chat_send_player(player_name, "Thank you!") + npc.chat(self.npc_name, player_name, "Thank you!") return true else - minetest.chat_send_player(player_name, + npc.chat(self.npc_name, player_name, "Looks like you can't get what I'm giving you for payment!") return false end end else - minetest.chat_send_player(player_name, "Looks like you don't have what I want to buy...") + npc.chat(self.npc_name, player_name, + "Looks like you don't have what I want to buy...") return false end else @@ -570,14 +571,16 @@ function npc.trade.perform_trade(self, player_name, offer) -- Add item items to player inv:add_item("main", item_stack) -- Send message to player - minetest.chat_send_player(player_name, "Thank you!") + npc.chat(self.npc_name, player_name, "Thank you!") return true else - minetest.chat_send_player(player_name, "Looks like you can't carry anything else...") + npc.chat(self.npc_name, player_name, + "Looks like you can't carry anything else...") return false end else - minetest.chat_send_player(player_name, "Looks like you don't have what I'm asking for!") + npc.chat(self.npc_name, player_name, + "Looks like you don't have what I'm asking for!") return false end end @@ -624,8 +627,8 @@ minetest.register_on_player_receive_fields(function (player, formname, fields) if player_response.offers_type == npc.trade.OFFER_BUY then -- Increase the item bought count local offer_item_name = npc.get_item_name(trade_offers[i].item) - minetest.log("Bought item name: "..dump(offer_item_name)) - minetest.log(dump(player_response.npc.trader_data.trade_list.both[offer_item_name])) + --minetest.log("Bought item name: "..dump(offer_item_name)) + --minetest.log(dump(player_response.npc.trader_data.trade_list.both[offer_item_name])) -- Check if this item has been bought before if player_response.npc.trader_data.trade_list.both[offer_item_name].item_bought_count == nil then -- Set first count to 1 diff --git a/trader.lua b/trader.lua deleted file mode 100755 index f7ed2e8..0000000 --- a/trader.lua +++ /dev/null @@ -1,355 +0,0 @@ - -local S = mobs.intllib - -mobs.human = { - items = { - --{item for sale, price, chance of appearing in trader's inventory} - {"default:apple 10", "default:gold_ingot 2", 10}, - {"farming:bread 10", "default:gold_ingot 4", 5}, - {"default:clay 10", "default:gold_ingot 2", 12}, - {"default:brick 10", "default:gold_ingot 4", 17}, - {"default:glass 10", "default:gold_ingot 4", 17}, - {"default:obsidian 10", "default:gold_ingot 15", 50}, - {"default:diamond 1", "default:gold_ingot 5", 40}, - {"farming:wheat 10", "default:gold_ingot 2", 17}, - {"default:tree 5", "default:gold_ingot 4", 20}, - {"default:stone 10", "default:gold_ingot 8", 17}, - {"default:desert_stone 10", "default:gold_ingot 8", 27}, - {"default:sapling 1", "default:gold_ingot 1", 7}, - {"default:pick_steel 1", "default:gold_ingot 2", 7}, - {"default:sword_steel 1", "default:gold_ingot 2", 17}, - {"default:shovel_steel 1", "default:gold_ingot 1", 17}, - }, - names = { - "Bob", "Duncan", "Bill", "Tom", "James", "Ian", "Lenny" - } -} - --- Trader ( same as NPC but with right-click shop ) - -mobs:register_mob("mobs_npc:trader", { - type = "npc", - passive = false, - damage = 3, - attack_type = "dogfight", - attacks_monsters = true, - pathfinding = false, - hp_min = 10, - hp_max = 20, - armor = 100, - collisionbox = {-0.35,-1.0,-0.35, 0.35,0.8,0.35}, - visual = "mesh", - mesh = "character.b3d", - textures = { - {"mobs_trader.png"}, -- by Frerin - }, - makes_footstep_sound = true, - sounds = {}, - walk_velocity = 2, - run_velocity = 3, - jump = false, - drops = {}, - water_damage = 0, - lava_damage = 4, - light_damage = 0, - follow = {"default:diamond"}, - view_range = 15, - owner = "", - order = "stand", - fear_height = 3, - animation = { - speed_normal = 30, - speed_run = 30, - stand_start = 0, - stand_end = 79, - walk_start = 168, - walk_end = 187, - run_start = 168, - run_end = 187, - punch_start = 200, - punch_end = 219, - }, - on_rightclick = function(self, clicker) - mobs_trader(self, clicker, entity, mobs.human) - end, -}) - ---This code comes almost exclusively from the trader and inventory of mobf, by Sapier. ---The copyright notice below is from mobf: -------------------------------------------------------------------------------- --- Mob Framework Mod by Sapier --- --- You may copy, use, modify or do nearly anything except removing this --- copyright notice. --- And of course you are NOT allow to pretend you have written it. --- ---! @file inventory.lua ---! @brief component containing mob inventory related functions ---! @copyright Sapier ---! @author Sapier ---! @date 2013-01-02 --- ---! @defgroup Inventory Inventory subcomponent ---! @brief Component handling mob inventory ---! @ingroup framework_int ---! @{ --- --- Contact sapier a t gmx net -------------------------------------------------------------------------------- - -function mobs.allow_move(inv, from_list, from_index, to_list, to_index, count, player) - - if to_list ~= "selection" - or from_list == "price" - or from_list == "payment" - or from_list == "takeaway" - or from_list == "identifier" then - - return 0 - end - - -- forbid moving split stacks - local old_stack = inv.get_stack(inv, from_list, from_index) - - if count ~= old_stack.get_count(old_stack) then - return 0 - end - - return count -end - -function mobs.allow_put(inv, listname, index, stack, player) - - if listname == "payment" then - return 99 - end - - return 0 -end - -function mobs.allow_take(inv, listname, index, stack, player) - - if listname == "takeaway" - or listname == "payment" then - - return 99 - else - return 0 - end -end - -function mobs.on_put(inv, listname, index, stack) - - if listname == "payment" then - mobs.update_takeaway(inv) - end -end - -function mobs.on_take(inv, listname, count, index, stack, player) - - if listname == "takeaway" then - - local amount = inv:get_stack("payment", 1):get_count() - local price = inv:get_stack("price", 1):get_count() - local thing = inv:get_stack("payment", 1):get_name() - - inv.set_stack(inv,"selection", 1, nil) - inv.set_stack(inv,"price", 1, nil) - inv.set_stack(inv,"takeaway", 1, nil) - inv.set_stack(inv,"payment", 1, thing .. " " .. amount - price) - end - - if listname == "payment" then - - if mobs.check_pay(inv, false) then - - local selection = inv.get_stack(inv, "selection", 1) - - if selection ~= nil then - inv.set_stack(inv,"takeaway", 1, selection) - end - else - inv.set_stack(inv, "takeaway", 1, nil) - end - end -end - -function mobs.update_takeaway(inv) - - if mobs.check_pay(inv,false) then - - local selection = inv.get_stack(inv,"selection", 1) - - if selection ~= nil then - inv.set_stack(inv,"takeaway", 1, selection) - end - else - inv.set_stack(inv,"takeaway", 1, nil) - end -end - -function mobs.check_pay(inv, paynow) - - local now_at_pay = inv.get_stack(inv,"payment", 1) - local count = now_at_pay.get_count(now_at_pay) - local name = now_at_pay.get_name(now_at_pay) - local price = inv.get_stack(inv, "price", 1) - - if price:get_name() == name then - - local price = price:get_count() - - if price > 0 - and price <= count then - - if paynow then - - now_at_pay.take_item(now_at_pay, price) - - inv.set_stack(inv,"payment", 1, now_at_pay) - - return true - else - return true - end - else - if paynow then - inv.set_stack(inv, "payment", 1, nil) - end - end - end - - return false -end - -mobs.trader_inventories = {} - -function mobs.add_goods(entity, race) - - local goods_to_add = nil - - for i = 1, 15 do - - if math.random(0, 100) > race.items[i][3] then - mobs.trader_inventory.set_stack(mobs.trader_inventory, - "goods", i, race.items[i][1]) - end - end -end - -function mobs_trader(self, clicker, entity, race) - - local player = clicker:get_player_name() - - if not self.id then - self.id = (math.random(1, 1000) * math.random(1, 10000)) - .. self.npc_name .. (math.random(1, 1000) ^ 2) - end - - if not self.game_name then - - self.game_name = tostring(race.names[math.random(1, #race.names)]) - self.npc_nametag = S("Trader @1", self.game_name) - - self.object:set_properties({ - nametag = self.npc_nametag, - nametag_color = "#00FF00" - }) - - end - - local unique_entity_id = self.id - local is_inventory = minetest.get_inventory({ - type = "detached", name = unique_entity_id}) - - local move_put_take = { - - allow_move = mobs.allow_move, - allow_put = mobs.allow_put, - allow_take = mobs.allow_take, - - on_move = function(inventory, from_list, from_index, to_list, to_index, count, player) - - if from_list == "goods" - and to_list == "selection" then - - local inv = inventory - local moved = inv.get_stack(inv,to_list, to_index) - local goodname = moved.get_name(moved) - local elements = moved.get_count(moved) - - if elements > count then - - -- remove the surplus parts - inv.set_stack(inv,"selection", 1, - goodname .. " " .. tostring(count)) - - -- the slot we took from is now free - inv.set_stack(inv,"goods",from_index, - goodname .. " " .. tostring(elements - count)) - - -- update the real amount of items in the slot now - elements = count - end - - local good = nil - - for i = 1, #race.items, 1 do - - local stackstring = goodname .." " .. count - - if race.items[i][1] == stackstring then - good = race.items[i] - end - end - - if good ~= nil then - inventory.set_stack(inventory,"price", 1, good[2]) - else - inventory.set_stack(inventory,"price", 1, nil) - end - - mobs.update_takeaway(inv) - - end - end, - - on_put = mobs.on_put, - on_take = mobs.on_take - } - - if is_inventory == nil then - - mobs.trader_inventory = minetest.create_detached_inventory(unique_entity_id, move_put_take) - mobs.trader_inventory.set_size(mobs.trader_inventory,"goods", 15) - mobs.trader_inventory.set_size(mobs.trader_inventory,"takeaway", 1) - mobs.trader_inventory.set_size(mobs.trader_inventory,"selection", 1) - mobs.trader_inventory.set_size(mobs.trader_inventory,"price", 1) - mobs.trader_inventory.set_size(mobs.trader_inventory,"payment", 1) - mobs.add_goods(entity, race) - end - - minetest.chat_send_player(player, S("[NPC] Hello, @2, have a look at my wares.", - self.game_name, player)) - - minetest.show_formspec(player, "trade", "size[8,10;]" - .. default.gui_bg_img - .. default.gui_slots - .. "label[0,0;" .. S("Trader @1's stock:", self.game_name) .. "]" - .. "list[detached:" .. unique_entity_id .. ";goods;.5,.5;3,5;]" - .. "label[4.5,0.5;" .. S("Selection") .. "]" - .. "list[detached:" .. unique_entity_id .. ";selection;4.5,1;5.5,2;]" - .. "label[6,0.5;" .. S("Price") .. "]" - .. "list[detached:" .. unique_entity_id .. ";price;6,1;7,2;]" - .. "label[4.5,3.5;" .. S("Payment") .. "]" - .. "list[detached:" .. unique_entity_id .. ";payment;4.5,4;5.5,5;]" - .. "label[6,3.5;" .. S("Bought items") .. "]" - .. "list[detached:" .. unique_entity_id .. ";takeaway;6,4;7.5,5.5;]" - .. "list[current_player;main;0,6;8,4;]" - ) -end - -mobs:register_egg("mobs_npc:trader", S("Trader"), "default_sandstone.png", 1) - --- compatibility -mobs:alias_mob("mobs:trader", "mobs_npc:trader") diff --git a/trader_test.lua b/trader_test.lua deleted file mode 100755 index 9ab48db..0000000 --- a/trader_test.lua +++ /dev/null @@ -1,264 +0,0 @@ - -if not minetest.get_modpath("shop") then - minetest.register_alias("shop:coin", "default:gold_ingot") -end - -local S = mobs.intllib - -mobs.human = { - items = { - -- item, price, chance - {"default:apple 10", "shop:coin 2", 40}, - {"farming:bread 10", "shop:coin 4", 50}, - {"default:clay 10", "shop:coin 2", 14}, - {"default:brick 10", "shop:coin 4", 17}, - {"default:glass 10", "shop:coin 4", 17}, - {"default:obsidian 10", "shop:coin 15", 50}, - {"default:diamond 1", "default:goldblock 1", 7}, - {"default:goldblock 1", "default:diamond 1", 7}, - {"farming:wheat 10", "shop:coin 2", 17}, - {"default:tree 5", "shop:coin 4", 20}, - {"default:stone 10", "shop:coin 8", 17}, - {"default:desert_stone 10", "shop:coin 8", 27}, - {"default:sapling 1", "shop:coin 1", 7}, - {"default:pick_steel 1", "shop:coin 2", 7}, - {"default:sword_steel 1", "shop:coin 2", 17}, - {"default:shovel_steel 1", "shop:coin 1", 17}, - }, - names = { - "Bob", "Duncan", "Bill", "Tom", "James", "Ian", "Lenny" - } -} - --- Trader ( same as NPC but with right-click shop ) - -mobs:register_mob("mobs_npc:trader", { - type = "npc", - passive = false, - damage = 3, - attack_type = "dogfight", - attacks_monsters = true, - pathfinding = false, - hp_min = 10, - hp_max = 20, - armor = 100, - collisionbox = {-0.35,-1.0,-0.35, 0.35,0.8,0.35}, - visual = "mesh", - mesh = "character.b3d", - textures = { - {"mobs_trader.png"}, -- by Frerin - {"mobs_trader2.png"}, -- re-coloured by amhadinger - {"mobs_trader3.png"}, -- re-coloured by amhadinger - }, - makes_footstep_sound = true, - sounds = {}, - walk_velocity = 2, - run_velocity = 3, - jump = false, - drops = {}, - water_damage = 0, - lava_damage = 4, - light_damage = 0, - follow = {"default:diamond"}, - view_range = 15, - owner = "", - order = "stand", - fear_height = 3, - animation = { - speed_normal = 30, - speed_run = 30, - stand_start = 0, - stand_end = 79, - walk_start = 168, - walk_end = 187, - run_start = 168, - run_end = 187, - punch_start = 200, - punch_end = 219, - }, - on_rightclick = function(self, clicker) - mobs_trader(self, clicker, mobs.human) - end, -}) - ---This code comes almost exclusively from the trader and inventory of mobf, by Sapier. ---The copyright notice below is from mobf: -------------------------------------------------------------------------------- --- Mob Framework Mod by Sapier --- --- You may copy, use, modify or do nearly anything except removing this --- copyright notice. --- And of course you are NOT allow to pretend you have written it. --- ---! @file inventory.lua ---! @brief component containing mob inventory related functions ---! @copyright Sapier ---! @author Sapier ---! @date 2013-01-02 --- ---! @defgroup Inventory Inventory subcomponent ---! @brief Component handling mob inventory ---! @ingroup framework_int ---! @{ --- --- Contact sapier a t gmx net -------------------------------------------------------------------------------- - --- Modifications Copyright 2016 by James Stevenson - -local trader_inventory = {} - -local function add_goods(race) - local goods_to_add = nil - for i = 1, 16 do - if math.random(0, 100) > race.items[i][3] then - trader_inventory.set_stack(trader_inventory, - "goods", i, race.items[i][1]) - end - end -end - -function mobs_trader(self, clicker, race) - local player = clicker:get_player_name() - - if not self.id then - self.id = (math.random(1, 1000) * math.random(1, 10000)) - .. self.npc_name .. (math.random(1, 1000) ^ 2) - end - - if not self.game_name then - self.game_name = tostring(race.names[math.random(1, #race.names)]) - self.npc_nametag = S("Trader @1", self.game_name) - self.object:set_properties({ - nametag = self.npc_nametag, - nametag_color = "#00FF00" - }) - end - - local unique_entity_id = self.id - local is_inventory = minetest.get_inventory({ - type = "detached", name = unique_entity_id}) - - local move_put_take = { - allow_move = function(inv, from_list, from_index, to_list, to_index, count, player) - if (from_list == "goods" and - to_list == "selection") or - (from_list == "selection" and - to_list == "goods") then - return count - else - return 0 - end - end, - allow_put = function(inv, listname, index, stack, player) - return 0 - end, - allow_take = function(inv, listname, index, stack, player) - return 0 - end, - on_move = function(inv, from_list, from_index, to_list, to_index, count, player) - if from_list == "goods" and - to_list == "selection" then - local moved = inv.get_stack(inv, to_list, to_index) - local goodname = moved.get_name(moved) - local elements = moved.get_count(moved) - if elements > count then - -- Remove the surplus parts - inv.set_stack(inv, "selection", 1, - goodname .. " " .. tostring(count)) - - -- The slot we took from is now free. - inv.set_stack(inv, "goods", from_index, - goodname .. " " .. tostring(elements - count)) - - -- Update the real amount of items in the slot now. - elements = count - end - local good = nil - for i = 1, #race.items, 1 do - local stackstring = goodname .. " " .. count - if race.items[i][1] == stackstring then - good = race.items[i] - end - end - if good ~= nil then - inv.set_stack(inv, "price", 1, good[2]) - else - inv.set_stack(inv, "price", 1, nil) - end - elseif from_list == "selection" and - to_list == "goods" then - inv.set_stack(inv, "price", 1, nil) - end - end, - on_put = function(inv, listname, index, stack, player) - end, - on_take = function(inv, listname, index, stack, player) - end, - } - - if is_inventory == nil then - trader_inventory = minetest.create_detached_inventory(unique_entity_id, move_put_take) - trader_inventory.set_size(trader_inventory, "goods", 16) - trader_inventory.set_size(trader_inventory, "selection", 1) - trader_inventory.set_size(trader_inventory, "price", 1) - add_goods(race) - --print("added stuff") - end - - minetest.chat_send_player(player, S("[NPC] Hello, @2, have a look at my wares.", - self.game_name, player)) - - minetest.show_formspec(player, "mobs_npc:trader", "size[8,9]" .. - default.gui_bg .. - default.gui_bg_img .. - default.gui_slots .. - "list[detached:" .. unique_entity_id .. ";goods;0,0;8,2]" .. - "label[0,3;Selection]" .. - "list[detached:" .. unique_entity_id .. ";selection;2,3;1,1]" .. - "label[4,3;Price]" .. - "list[detached:" .. unique_entity_id .. ";price;6,3;1,1]" .. - "button[4,4;2,1;purchase;Purchase]" .. - "list[current_player;main;0,5;8,1;]" .. - "list[current_player;main;0,6.25;8,3;8]" .. - default.get_hotbar_bg(0, 5)) -end - -minetest.register_on_player_receive_fields(function(player, formname, fields) - if formname ~= "mobs_npc:trader" then - return - end - - --print(dump(trader_inventory:get_lists())) - - local selection_name = trader_inventory:get_stack("selection", 1):get_name() - local selection_count = trader_inventory:get_stack("selection", 1):get_count() - local selection_string = selection_name .. " " .. tostring(selection_count) - - local price_name = trader_inventory:get_stack("price", 1):get_name() - local price_count = trader_inventory:get_stack("price", 1):get_count() - local price_string = price_name .. " " .. tostring(price_count) - - --print(selection_string .. "\nfor:\n" .. price_string) - - if player:get_inventory():contains_item("main", price_string) then - --print("you got it!") - trader_inventory:set_stack("selection", 1, nil) - trader_inventory:set_stack("price", 1, nil) - - player:get_inventory():remove_item("main", price_string) - local adder = player:get_inventory():add_item("main", selection_string) - if adder then - minetest.add_item(player:getpos(), adder) - end - else - minetest.chat_send_player(player:get_player_name(), - "Not enough credits!") - end - -end) - -mobs:register_egg("mobs_npc:trader", S("Trader"), "default_sandstone.png", 1) - --- compatibility -mobs:alias_mob("mobs:trader", "mobs_npc:trader")