Spawner: Large code refactor to remove dependency on plotmarkers.
Most spawner functions can now be called without giving a plotmarker. Move scanning functions to places.lua. Places: Cleanup and add more area-scanning functions. Schedules: Bugfix where schedules weren't being executed due to wrong "end" order in the do_custom() function. Data: Moved random data to "data" folder. Textures: Add 14 male textures and 10 female textures. Occupations: Small tweaks to "default_basic" occupation.
@ -155,6 +155,12 @@ function npc.places.get_by_type(self, place_type)
|
|||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------------------
|
||||||
|
-- Utility functions
|
||||||
|
---------------------------------------------------------------------------------------
|
||||||
|
-- The following are utility functions that are used to operate on nodes for
|
||||||
|
-- specific conditions
|
||||||
|
|
||||||
-- This function searches on a squared are of the given radius
|
-- This function searches on a squared are of the given radius
|
||||||
-- for nodes of the given type. The type should be npc.places.nodes
|
-- for nodes of the given type. The type should be npc.places.nodes
|
||||||
function npc.places.find_node_nearby(pos, type, radius)
|
function npc.places.find_node_nearby(pos, type, radius)
|
||||||
@ -188,11 +194,64 @@ function npc.places.find_node_orthogonally(pos, nodes, y_adjustment)
|
|||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Wrapper around minetest.find_nodes_in_area()
|
||||||
|
-- TODO: Verify if this wrapper is actually needed
|
||||||
function npc.places.find_node_in_area(start_pos, end_pos, type)
|
function npc.places.find_node_in_area(start_pos, end_pos, type)
|
||||||
local nodes = minetest.find_nodes_in_area(start_pos, end_pos, type)
|
local nodes = minetest.find_nodes_in_area(start_pos, end_pos, type)
|
||||||
return nodes
|
return nodes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Function used to filter all nodes in the first floor of a building
|
||||||
|
-- If floor height isn't given, it will assume 2
|
||||||
|
-- Notice that nodes is an array of entries {node_pos={}, type={}}
|
||||||
|
function npc.places.filter_first_floor_nodes(nodes, ground_pos, floor_height)
|
||||||
|
local height = floor_height or 2
|
||||||
|
local result = {}
|
||||||
|
for _,node in pairs(nodes) do
|
||||||
|
if node.node_pos.y <= ground_pos.y + height then
|
||||||
|
table.insert(result, node)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Creates an array of {pos=<node_pos>, owner=''} for managing
|
||||||
|
-- which NPC owns what
|
||||||
|
function npc.places.get_nodes_by_type(start_pos, end_pos, type)
|
||||||
|
local result = {}
|
||||||
|
local nodes = npc.places.find_node_in_area(start_pos, end_pos, type)
|
||||||
|
--minetest.log("Found "..dump(#nodes).." nodes of type: "..dump(type))
|
||||||
|
for _,node_pos in pairs(nodes) do
|
||||||
|
local entry = {}
|
||||||
|
entry["node_pos"] = node_pos
|
||||||
|
entry["owner"] = ''
|
||||||
|
table.insert(result, entry)
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Scans an area for the supported nodes: beds, benches,
|
||||||
|
-- furnaces, storage (e.g. chests) and openable (e.g. doors).
|
||||||
|
-- Returns a table with these classifications
|
||||||
|
function npc.places.scan_area_for_usable_nodes(pos1, pos2)
|
||||||
|
local result = {
|
||||||
|
bed_type = {},
|
||||||
|
sittable_type = {},
|
||||||
|
furnace_type = {},
|
||||||
|
storage_type = {},
|
||||||
|
openable_type = {}
|
||||||
|
}
|
||||||
|
local start_pos, end_pos = vector.sort(pos1, pos2)
|
||||||
|
|
||||||
|
result.bed_type = npc.places.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.BED_TYPE)
|
||||||
|
result.sittable_type = npc.places.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.SITTABLE_TYPE)
|
||||||
|
result.furnace_type = npc.places.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.FURNACE_TYPE)
|
||||||
|
result.storage_type = npc.places.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.STORAGE_TYPE)
|
||||||
|
result.openable_type = npc.places.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.OPENABLE_TYPE)
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
-- Specialized function to find doors that are an entrance to a building.
|
-- Specialized function to find doors that are an entrance to a building.
|
||||||
-- The definition of an entrance is:
|
-- The definition of an entrance is:
|
||||||
-- The openable node with the shortest path to the plotmarker node
|
-- The openable node with the shortest path to the plotmarker node
|
||||||
@ -231,18 +290,8 @@ function npc.places.find_entrance_from_openable_nodes(all_openable_nodes, marker
|
|||||||
local start_pos = {x=open_pos.x, y=open_pos.y, z=open_pos.z}
|
local start_pos = {x=open_pos.x, y=open_pos.y, z=open_pos.z}
|
||||||
local end_pos = {x=marker_pos.x, y=marker_pos.y, z=marker_pos.z}
|
local end_pos = {x=marker_pos.x, y=marker_pos.y, z=marker_pos.z}
|
||||||
|
|
||||||
-- Check if there's any difference in vertical position
|
|
||||||
-- minetest.log("Openable node pos: "..minetest.pos_to_string(open_pos))
|
-- minetest.log("Openable node pos: "..minetest.pos_to_string(open_pos))
|
||||||
-- minetest.log("Plotmarker node pos: "..minetest.pos_to_string(marker_pos))
|
-- minetest.log("Plotmarker node pos: "..minetest.pos_to_string(marker_pos))
|
||||||
-- NOTE: Commented out while testing MarkBu's pathfinder
|
|
||||||
--if start_pos.y ~= end_pos.y then
|
|
||||||
-- Adjust to make pathfinder find nodes one node above
|
|
||||||
-- end_pos.y = start_pos.y
|
|
||||||
--end
|
|
||||||
|
|
||||||
-- This adjustment allows the map to be created correctly
|
|
||||||
--start_pos.y = start_pos.y + 1
|
|
||||||
--end_pos.y = end_pos.y + 1
|
|
||||||
|
|
||||||
-- Find path from the openable node to the plotmarker
|
-- Find path from the openable node to the plotmarker
|
||||||
--local path = pathfinder.find_path(start_pos, end_pos, 20, {})
|
--local path = pathfinder.find_path(start_pos, end_pos, 20, {})
|
||||||
|
8
init.lua
@ -37,9 +37,9 @@ dofile(path .. "/actions/node_registry.lua")
|
|||||||
dofile(path .. "/occupations/occupations.lua")
|
dofile(path .. "/occupations/occupations.lua")
|
||||||
-- Load random data definitions
|
-- Load random data definitions
|
||||||
dofile(path .. "/random_data.lua")
|
dofile(path .. "/random_data.lua")
|
||||||
dofile(path .. "/random_data/dialogues_data.lua")
|
dofile(path .. "/data/dialogues_data.lua")
|
||||||
dofile(path .. "/random_data/gift_items_data.lua")
|
dofile(path .. "/data/gift_items_data.lua")
|
||||||
dofile(path .. "/random_data/names_data.lua")
|
dofile(path .. "/data/names_data.lua")
|
||||||
dofile(path .. "/random_data/occupations_data.lua")
|
dofile(path .. "/data/occupations_data.lua")
|
||||||
|
|
||||||
print (S("[Mod] Advanced NPC loaded"))
|
print (S("[Mod] Advanced NPC loaded"))
|
||||||
|
225
npc.lua
@ -474,7 +474,8 @@ function npc.initialize(entity, pos, is_lua_entity, npc_stats, occupation_name)
|
|||||||
|
|
||||||
-- If occupation name given, override properties with
|
-- If occupation name given, override properties with
|
||||||
-- occupation values and initialize schedules
|
-- occupation values and initialize schedules
|
||||||
minetest.log("Entity age: "..dump(ent.age)..", afult? "..dump(ent.age==npc.age.adult))
|
--minetest.log("Entity age: "..dump(ent.age)..", afult? "..dump(ent.age==npc.age.adult))
|
||||||
|
npc.log("INFO", "Overriding NPC values with occupation: "..dump(occupation_name))
|
||||||
if occupation_name and occupation_name ~= "" and ent.age == npc.age.adult then
|
if occupation_name and occupation_name ~= "" and ent.age == npc.age.adult then
|
||||||
npc.occupations.initialize_occupation_values(ent, occupation_name)
|
npc.occupations.initialize_occupation_values(ent, occupation_name)
|
||||||
end
|
end
|
||||||
@ -508,7 +509,7 @@ function npc.initialize(entity, pos, is_lua_entity, npc_stats, occupation_name)
|
|||||||
|
|
||||||
-- Set initialized flag on
|
-- Set initialized flag on
|
||||||
ent.initialized = true
|
ent.initialized = true
|
||||||
npc.log("WARNING", "Spawned entity: "..dump(ent))
|
--npc.log("WARNING", "Spawned entity: "..dump(ent))
|
||||||
npc.log("INFO", "Successfully initialized NPC with name "..dump(ent.npc_name)
|
npc.log("INFO", "Successfully initialized NPC with name "..dump(ent.npc_name)
|
||||||
..", sex: "..ent.sex..", is child: "..dump(ent.is_child)
|
..", sex: "..ent.sex..", is child: "..dump(ent.is_child)
|
||||||
..", texture: "..dump(ent.textures))
|
..", texture: "..dump(ent.textures))
|
||||||
@ -1156,7 +1157,26 @@ mobs:register_mob("advanced_npc:npc", {
|
|||||||
{"npc_male4.png"},
|
{"npc_male4.png"},
|
||||||
{"npc_male5.png"},
|
{"npc_male5.png"},
|
||||||
{"npc_male6.png"},
|
{"npc_male6.png"},
|
||||||
|
{"npc_male7.png"},
|
||||||
|
{"npc_male8.png"},
|
||||||
|
{"npc_male9.png"},
|
||||||
|
{"npc_male10.png"},
|
||||||
|
{"npc_male11.png"},
|
||||||
|
{"npc_male12.png"},
|
||||||
|
{"npc_male13.png"},
|
||||||
|
{"npc_male14.png"},
|
||||||
|
{"npc_male15.png"},
|
||||||
{"npc_female1.png"}, -- female by nuttmeg20
|
{"npc_female1.png"}, -- female by nuttmeg20
|
||||||
|
{"npc_female2.png"},
|
||||||
|
{"npc_female3.png"},
|
||||||
|
{"npc_female4.png"},
|
||||||
|
{"npc_female5.png"},
|
||||||
|
{"npc_female6.png"},
|
||||||
|
{"npc_female7.png"},
|
||||||
|
{"npc_female8.png"},
|
||||||
|
{"npc_female9.png"},
|
||||||
|
{"npc_female10.png"},
|
||||||
|
{"npc_female11.png"},
|
||||||
},
|
},
|
||||||
child_texture = {
|
child_texture = {
|
||||||
{"npc_child_male1.png"},
|
{"npc_child_male1.png"},
|
||||||
@ -1206,7 +1226,7 @@ mobs:register_mob("advanced_npc:npc", {
|
|||||||
local item = clicker:get_wielded_item()
|
local item = clicker:get_wielded_item()
|
||||||
local name = clicker:get_player_name()
|
local name = clicker:get_player_name()
|
||||||
|
|
||||||
npc.log("DEBUG", "Right-clicked NPC: "..dump(self))
|
npc.log("INFO", "Right-clicked NPC: "..dump(self))
|
||||||
|
|
||||||
-- Receive gift or start chat. If player has no item in hand
|
-- Receive gift or start chat. If player has no item in hand
|
||||||
-- then it is going to start chat directly
|
-- then it is going to start chat directly
|
||||||
@ -1232,11 +1252,10 @@ mobs:register_mob("advanced_npc:npc", {
|
|||||||
end,
|
end,
|
||||||
name
|
name
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
npc.start_dialogue(self, clicker, true)
|
npc.start_dialogue(self, clicker, true)
|
||||||
end
|
end
|
||||||
|
end,
|
||||||
end,
|
|
||||||
do_custom = function(self, dtime)
|
do_custom = function(self, dtime)
|
||||||
if self.initialized == nil then
|
if self.initialized == nil then
|
||||||
-- Initialize NPC if spawned using the spawn egg built in from
|
-- Initialize NPC if spawned using the spawn egg built in from
|
||||||
@ -1266,7 +1285,8 @@ mobs:register_mob("advanced_npc:npc", {
|
|||||||
-- Set interval to large interval so this code isn't called frequently
|
-- Set interval to large interval so this code isn't called frequently
|
||||||
npc.texture_check.interval = 60
|
npc.texture_check.interval = 60
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Timer function for casual traders to reset their trade offers
|
-- Timer function for casual traders to reset their trade offers
|
||||||
self.trader_data.change_offers_timer = self.trader_data.change_offers_timer + dtime
|
self.trader_data.change_offers_timer = self.trader_data.change_offers_timer + dtime
|
||||||
@ -1335,103 +1355,102 @@ mobs:register_mob("advanced_npc:npc", {
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Schedule timer
|
-- Schedule timer
|
||||||
-- Check if schedules are enabled
|
-- Check if schedules are enabled
|
||||||
if self.schedules.enabled == true then
|
if self.schedules.enabled == true then
|
||||||
-- Get time of day
|
-- Get time of day
|
||||||
local time = get_time_in_hours()
|
local time = get_time_in_hours()
|
||||||
-- Check if time is an hour
|
-- Check if time is an hour
|
||||||
if time % 1 < 0.1 and self.schedules.lock == false then
|
if ((time % 1) < dtime) and self.schedules.lock == false then
|
||||||
-- Activate lock to avoid more than one entry to this code
|
-- Activate lock to avoid more than one entry to this code
|
||||||
self.schedules.lock = true
|
self.schedules.lock = true
|
||||||
-- Get integer part of time
|
-- Get integer part of time
|
||||||
time = (time) - (time % 1)
|
time = (time) - (time % 1)
|
||||||
-- Check if there is a schedule entry for this time
|
-- Check if there is a schedule entry for this time
|
||||||
-- Note: Currently only one schedule is supported, for day 0
|
-- Note: Currently only one schedule is supported, for day 0
|
||||||
--minetest.log("Time: "..dump(time))
|
minetest.log("Time: "..dump(time))
|
||||||
local schedule = self.schedules.generic[0]
|
local schedule = self.schedules.generic[0]
|
||||||
if schedule ~= nil then
|
if schedule ~= nil then
|
||||||
-- Check if schedule for this time exists
|
-- Check if schedule for this time exists
|
||||||
--minetest.log("Found default schedule")
|
if schedule[time] ~= nil then
|
||||||
if schedule[time] ~= nil then
|
npc.log("WARNING", "Found schedule for time "..dump(time)..": "..dump(schedule[time]))
|
||||||
npc.log("WARNING", "Found schedule for time "..dump(time)..": "..dump(schedule[time]))
|
npc.log("DEBUG", "Adding actions to action queue")
|
||||||
npc.log("DEBUG", "Adding actions to action queue")
|
-- Add to action queue all actions on schedule
|
||||||
-- Add to action queue all actions on schedule
|
for i = 1, #schedule[time] do
|
||||||
for i = 1, #schedule[time] do
|
-- Check if schedule has a check function
|
||||||
-- Check if schedule has a check function
|
if schedule[time][i].check then
|
||||||
if not schedule[time][i].check then
|
-- Add parameters for check function and run for first time
|
||||||
-- Add parameters for check function and run for first time
|
npc.log("INFO", "NPC "..dump(self.npc_name).." is starting check on "..minetest.pos_to_string(self.object:getpos()))
|
||||||
npc.log("INFO", "NPC "..dump(self.npc_name).." is starting check on "..minetest.pos_to_string(self.object:getpos()))
|
local check_params = schedule[time][i]
|
||||||
local check_params = schedule[time][i]
|
-- Calculates how many times check will be executed
|
||||||
-- Calculates how many times check will be executed
|
local execution_times = check_params.count
|
||||||
local execution_times = check_params.count
|
if check_params.random_execution_times then
|
||||||
if check_params.random_execution_times then
|
execution_times = math.random(check_params.min_count, check_params.max_count)
|
||||||
execution_times = math.random(check_params.min_count, check_params.max_count)
|
end
|
||||||
end
|
-- Set current parameters
|
||||||
-- Set current parameters
|
self.schedules.current_check_params = {
|
||||||
self.schedules.current_check_params = {
|
range = check_params.range,
|
||||||
range = check_params.range,
|
nodes = check_params.nodes,
|
||||||
nodes = check_params.nodes,
|
actions = check_params.actions,
|
||||||
actions = check_params.actions,
|
none_actions = check_params.none_actions,
|
||||||
none_actions = check_params.none_actions,
|
execution_count = 0,
|
||||||
execution_count = 0,
|
execution_times = execution_times
|
||||||
execution_times = execution_times
|
}
|
||||||
}
|
-- Execute check for the first time
|
||||||
-- Execute check for the first time
|
npc.schedule_check(self)
|
||||||
npc.schedule_check(self)
|
else
|
||||||
else
|
npc.log("INFO", "Executing schedule entry: "..dump(schedule[time][i]))
|
||||||
-- Run usual schedule entry
|
-- Run usual schedule entry
|
||||||
-- Check chance
|
-- Check chance
|
||||||
local execution_chance = math.random(1, 100)
|
local execution_chance = math.random(1, 100)
|
||||||
if not schedule[time][i].chance or
|
if not schedule[time][i].chance or
|
||||||
(schedule[time][i].chance and execution_chance <= schedule[time][i].chance) then
|
(schedule[time][i].chance and execution_chance <= schedule[time][i].chance) then
|
||||||
-- Check if entry has dependency on other entry
|
-- Check if entry has dependency on other entry
|
||||||
local dependencies_met = nil
|
local dependencies_met = nil
|
||||||
if schedule[time][i].depends then
|
if schedule[time][i].depends then
|
||||||
dependencies_met = npc.utils.array_is_subset_of_array(
|
dependencies_met = npc.utils.array_is_subset_of_array(
|
||||||
self.schedules.temp_executed_queue,
|
self.schedules.temp_executed_queue,
|
||||||
schedule[time][i].depends)
|
schedule[time][i].depends)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check for dependencies being met
|
-- Check for dependencies being met
|
||||||
if dependencies_met == nil or dependencies_met == true then
|
if dependencies_met == nil or dependencies_met == true then
|
||||||
-- Add tasks
|
-- Add tasks
|
||||||
if schedule[time][i].task ~= nil then
|
if schedule[time][i].task ~= nil then
|
||||||
-- Add task
|
-- Add task
|
||||||
npc.add_task(self, schedule[time][i].task, schedule[time][i].args)
|
npc.add_task(self, schedule[time][i].task, schedule[time][i].args)
|
||||||
elseif schedule[time][i].action ~= nil then
|
elseif schedule[time][i].action ~= nil then
|
||||||
-- Add action
|
-- Add action
|
||||||
npc.add_action(self, schedule[time][i].action, schedule[time][i].args)
|
npc.add_action(self, schedule[time][i].action, schedule[time][i].args)
|
||||||
elseif schedule[time][i].property ~= nil then
|
elseif schedule[time][i].property ~= nil then
|
||||||
-- Change NPC property
|
-- Change NPC property
|
||||||
npc.schedule_change_property(self, schedule[time][i].property, schedule[time][i].args)
|
npc.schedule_change_property(self, schedule[time][i].property, schedule[time][i].args)
|
||||||
end
|
end
|
||||||
-- Backward compatibility check
|
-- Backward compatibility check
|
||||||
if self.schedules.temp_executed_queue then
|
if self.schedules.temp_executed_queue then
|
||||||
-- Add into execution queue to meet dependency
|
-- Add into execution queue to meet dependency
|
||||||
table.insert(self.schedules.temp_executed_queue, i)
|
table.insert(self.schedules.temp_executed_queue, i)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else
|
|
||||||
-- TODO: Change to debug
|
|
||||||
npc.log("WARNING", "Skipping schedule entry for time "..dump(time)..": "..dump(schedule[time][i]))
|
|
||||||
end
|
end
|
||||||
end
|
else
|
||||||
end
|
-- TODO: Change to debug
|
||||||
-- Clear execution queue
|
npc.log("WARNING", "Skipping schedule entry for time "..dump(time)..": "..dump(schedule[time][i]))
|
||||||
self.schedules.temp_executed_queue = {}
|
end
|
||||||
npc.log("WARNING", "New action queue: "..dump(self.actions))
|
end
|
||||||
end
|
end
|
||||||
end
|
-- Clear execution queue
|
||||||
end
|
self.schedules.temp_executed_queue = {}
|
||||||
else
|
npc.log("WARNING", "New action queue: "..dump(self.actions))
|
||||||
-- Check if lock can be released
|
end
|
||||||
if time % 1 > 0.1 then
|
end
|
||||||
-- Release lock
|
else
|
||||||
self.schedules.lock = false
|
-- Check if lock can be released
|
||||||
end
|
if (time % 1) > dtime then
|
||||||
end
|
-- Release lock
|
||||||
end
|
self.schedules.lock = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return self.freeze
|
return self.freeze
|
||||||
end
|
end
|
||||||
|
@ -95,10 +95,7 @@ npc.occupations.registered_occupations = {}
|
|||||||
-- don't have a specific occupation. It serves as an example.
|
-- don't have a specific occupation. It serves as an example.
|
||||||
npc.occupations.basic_def = {
|
npc.occupations.basic_def = {
|
||||||
-- Use random textures
|
-- Use random textures
|
||||||
textures = {
|
textures = {},
|
||||||
{"npc_male1.png"},
|
|
||||||
{"npc_child_male1.png"}
|
|
||||||
},
|
|
||||||
-- Use random dialogues
|
-- Use random dialogues
|
||||||
dialogues = {},
|
dialogues = {},
|
||||||
-- Initialize inventory with random items
|
-- Initialize inventory with random items
|
||||||
@ -240,6 +237,7 @@ npc.occupations.basic_def = {
|
|||||||
-- This function registers an occupation
|
-- This function registers an occupation
|
||||||
function npc.occupations.register_occupation(name, def)
|
function npc.occupations.register_occupation(name, def)
|
||||||
npc.occupations.registered_occupations[name] = def
|
npc.occupations.registered_occupations[name] = def
|
||||||
|
npc.log("INFO", "Successfully registered occupation with name: "..dump(name))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- This function scans all registered occupations and filter them by
|
-- This function scans all registered occupations and filter them by
|
||||||
|
1064
spawner.lua
3
spawner_marker.lua
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-- Spawner markers
|
||||||
|
-- Specialized functionality to allow players do NPC spawning
|
||||||
|
-- on their own custom buildings.
|
BIN
textures/npc_female10.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
textures/npc_female11.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
textures/npc_female2.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
textures/npc_female3.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
textures/npc_female4.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
textures/npc_female5.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
textures/npc_female6.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
textures/npc_female7.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
textures/npc_female8.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
textures/npc_female9.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
textures/npc_male10.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
textures/npc_male11.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
textures/npc_male12.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
textures/npc_male13.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
textures/npc_male14.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
textures/npc_male15.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
textures/npc_male8.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
textures/npc_male9.png
Normal file
After Width: | Height: | Size: 2.4 KiB |