NPC: Changed general issue with names. Now names are a dedicated variable, not anymore a nametag.
NPC names aren't visible anymore. Spawner: Added NPC statistics to plotmarkers. Add statistics-based spawning for a more balanced, family-type spawning of NPCs.
@ -844,7 +844,7 @@ function npc.actions.walk_to_pos(self, args)
|
|||||||
-- Check if movement is enforced
|
-- Check if movement is enforced
|
||||||
if enforce_move then
|
if enforce_move then
|
||||||
-- Move to end pos
|
-- Move to end pos
|
||||||
self.object:moveto(end_pos)
|
self.object:moveto({x=end_pos.x, y=end_pos.y+1, z=end_pos.z})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -296,7 +296,7 @@ function npc.dialogue.process_dialogue(self, dialogue, player_name)
|
|||||||
|
|
||||||
-- Send dialogue line
|
-- Send dialogue line
|
||||||
if dialogue.text then
|
if dialogue.text then
|
||||||
minetest.chat_send_player(player_name, self.name..": "..dialogue.text)
|
minetest.chat_send_player(player_name, self.npc_name..": "..dialogue.text)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if dialogue has responses. If it doesn't, unlock the actions
|
-- Check if dialogue has responses. If it doesn't, unlock the actions
|
||||||
|
192
npc.lua
@ -9,6 +9,11 @@ npc = {}
|
|||||||
npc.FEMALE = "female"
|
npc.FEMALE = "female"
|
||||||
npc.MALE = "male"
|
npc.MALE = "male"
|
||||||
|
|
||||||
|
npc.age = {
|
||||||
|
adult = "adult",
|
||||||
|
child = "child"
|
||||||
|
}
|
||||||
|
|
||||||
npc.INVENTORY_ITEM_MAX_STACK = 99
|
npc.INVENTORY_ITEM_MAX_STACK = 99
|
||||||
|
|
||||||
npc.ANIMATION_STAND_START = 0
|
npc.ANIMATION_STAND_START = 0
|
||||||
@ -89,8 +94,46 @@ local function is_female_texture(textures)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function get_random_texture(sex, age)
|
||||||
|
local textures = {}
|
||||||
|
local filtered_textures = {}
|
||||||
|
-- Find textures by sex and age
|
||||||
|
if age == npc.age.adult then
|
||||||
|
--minetest.log("Registered: "..dump(minetest.registered_entities["advanced_npc:npc"]))
|
||||||
|
textures = minetest.registered_entities["advanced_npc:npc"].texture_list
|
||||||
|
elseif age == npc.age.child then
|
||||||
|
textures = minetest.registered_entities["advanced_npc:npc"].child_texture
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.log("Textures: "..dump(textures))
|
||||||
|
minetest.log("Sex: "..sex)
|
||||||
|
minetest.log("Age: "..age)
|
||||||
|
|
||||||
|
for i = 1, #textures do
|
||||||
|
local current_texture = textures[i][1]
|
||||||
|
if (sex == npc.MALE
|
||||||
|
and string.find(current_texture, sex)
|
||||||
|
and not string.find(current_texture, npc.FEMALE))
|
||||||
|
or (sex == npc.FEMALE
|
||||||
|
and string.find(current_texture, sex)) then
|
||||||
|
table.insert(filtered_textures, current_texture)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if filtered textures is empty
|
||||||
|
if filtered_textures == {} then
|
||||||
|
return textures[1][1]
|
||||||
|
end
|
||||||
|
|
||||||
|
return filtered_textures[math.random(1,#filtered_textures)]
|
||||||
|
end
|
||||||
|
|
||||||
-- Choose whether NPC can have relationships. Only 30% of NPCs cannot have relationships
|
-- Choose whether NPC can have relationships. Only 30% of NPCs cannot have relationships
|
||||||
local function can_have_relationships()
|
local function can_have_relationships(age)
|
||||||
|
-- Children can't have relationships
|
||||||
|
if not age then
|
||||||
|
return false
|
||||||
|
end
|
||||||
local chance = math.random(1,10)
|
local chance = math.random(1,10)
|
||||||
return chance > 3
|
return chance > 3
|
||||||
end
|
end
|
||||||
@ -132,7 +175,7 @@ end
|
|||||||
|
|
||||||
-- Spawn function. Initializes all variables that the
|
-- Spawn function. Initializes all variables that the
|
||||||
-- NPC will have and choose random, starting values
|
-- NPC will have and choose random, starting values
|
||||||
function npc.initialize(entity, pos, is_lua_entity)
|
function npc.initialize(entity, pos, is_lua_entity, npc_stats)
|
||||||
minetest.log("[advanced_npc] INFO: Initializing NPC at "..minetest.pos_to_string(pos))
|
minetest.log("[advanced_npc] INFO: Initializing NPC at "..minetest.pos_to_string(pos))
|
||||||
|
|
||||||
-- Get variables
|
-- Get variables
|
||||||
@ -146,21 +189,93 @@ function npc.initialize(entity, pos, is_lua_entity)
|
|||||||
-- Avoid NPC to be removed by mobs_redo API
|
-- Avoid NPC to be removed by mobs_redo API
|
||||||
ent.remove_ok = false
|
ent.remove_ok = false
|
||||||
|
|
||||||
-- Determine sex based on textures
|
-- Determine sex and age
|
||||||
if (is_female_texture(ent.base_texture)) then
|
-- If there's no previous NPC data, sex and age will be randomly chosen.
|
||||||
ent.sex = npc.FEMALE
|
-- - Sex: Female or male will have each 50% of spawning
|
||||||
|
-- - Age: 90% chance of spawning adults, 10% chance of spawning children.
|
||||||
|
-- If there is previous data then:
|
||||||
|
-- - Sex: The unbalanced sex will get a 75% chance of spawning
|
||||||
|
-- - Example: If there's one male, then female will have 75% spawn chance.
|
||||||
|
-- - If there's male and female, then each have 50% spawn chance.
|
||||||
|
-- - Age: For each two adults, the chance of spawning a child next will be 50%
|
||||||
|
-- If there's a child for two adults, the chance of spawning a child goes to
|
||||||
|
-- 40% and keeps decreasing unless two adults have no child.
|
||||||
|
if npc_stats then
|
||||||
|
-- Default chances
|
||||||
|
local male_s, male_e = 0, 50
|
||||||
|
local female_s, female_e = 51, 100
|
||||||
|
local adult_s, adult_e = 0, 90
|
||||||
|
local child_s, child_e = 91, 100
|
||||||
|
-- Determine sex probabilities
|
||||||
|
if npc_stats[npc.FEMALE].total > npc_stats[npc.MALE].total then
|
||||||
|
male_e = 75
|
||||||
|
female_s, female_e = 76, 100
|
||||||
|
elseif npc_stats[npc.FEMALE].total < npc_stats[npc.MALE].total then
|
||||||
|
male_e = 25
|
||||||
|
female_s, female_e = 26, 100
|
||||||
|
end
|
||||||
|
-- Determine age probabilities
|
||||||
|
if npc_stats["adult_total"] >= 2 then
|
||||||
|
if npc_stats["adult_total"] % 2 == 0
|
||||||
|
and (npc_stats["adult_total"] / 2 > npc_stats["child_total"]) then
|
||||||
|
child_s,child_e = 51, 100
|
||||||
|
adult_e = 50
|
||||||
|
else
|
||||||
|
child_s, child_e = 61, 100
|
||||||
|
adult_e = 60
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Get sex and age based on the probabilities
|
||||||
|
local sex_chance = math.random(1, 100)
|
||||||
|
local age_chance = math.random(1, 100)
|
||||||
|
local selected_sex = ""
|
||||||
|
local selected_age = ""
|
||||||
|
-- Select sex
|
||||||
|
if male_s <= sex_chance and sex_chance <= male_e then
|
||||||
|
selected_sex = npc.MALE
|
||||||
|
elseif female_s <= sex_chance and sex_chance <= female_e then
|
||||||
|
selected_sex = npc.FEMALE
|
||||||
|
end
|
||||||
|
-- Set sex for NPC
|
||||||
|
ent.sex = selected_sex
|
||||||
|
-- Select age
|
||||||
|
if adult_s <= age_chance and age_chance <= adult_e then
|
||||||
|
selected_age = npc.age.adult
|
||||||
|
elseif child_s <= age_chance and age_chance <= child_e then
|
||||||
|
selected_age = npc.age.child
|
||||||
|
ent.visual_size = {
|
||||||
|
x = 0.5,
|
||||||
|
y = 0.5
|
||||||
|
}
|
||||||
|
ent.collisionbox = {-0.10,-0.50,-0.10, 0.10,0.40,0.10}
|
||||||
|
ent.is_child = true
|
||||||
|
end
|
||||||
|
-- Set texture accordingly
|
||||||
|
local selected_texture = get_random_texture(selected_sex, selected_age)
|
||||||
|
--minetest.log("Selected texture: "..dump(selected_texture))
|
||||||
|
ent.textures = {selected_texture}
|
||||||
|
if selected_age == npc.age.child then
|
||||||
|
ent.base_texture = selected_texture
|
||||||
|
end
|
||||||
else
|
else
|
||||||
ent.sex = npc.MALE
|
-- Get sex based on texture. This is a 50% chance for
|
||||||
|
-- each sex as there's same amount of textures for male and female.
|
||||||
|
-- Do not spawn child as first NPC
|
||||||
|
if (is_female_texture(ent.base_texture)) then
|
||||||
|
ent.sex = npc.FEMALE
|
||||||
|
else
|
||||||
|
ent.sex = npc.MALE
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Nametag is initialized to blank
|
-- Nametag is initialized to blank
|
||||||
ent.nametag = ""
|
ent.nametag = ""
|
||||||
|
|
||||||
-- Set name
|
-- Set name
|
||||||
ent.name = get_random_name(ent.sex)
|
ent.npc_name = get_random_name(ent.sex)
|
||||||
|
|
||||||
-- Set ID
|
-- Set ID
|
||||||
ent.npc_id = tostring(math.random(1000, 9999))..":"..ent.name
|
ent.npc_id = tostring(math.random(1000, 9999))..":"..ent.npc_name
|
||||||
|
|
||||||
-- Initialize all gift data
|
-- Initialize all gift data
|
||||||
ent.gift_data = {
|
ent.gift_data = {
|
||||||
@ -171,7 +286,7 @@ function npc.initialize(entity, pos, is_lua_entity)
|
|||||||
}
|
}
|
||||||
|
|
||||||
-- Flag that determines if NPC can have a relationship
|
-- Flag that determines if NPC can have a relationship
|
||||||
ent.can_have_relationship = can_have_relationships()
|
ent.can_have_relationship = can_have_relationships(ent.is_child)
|
||||||
|
|
||||||
-- Initialize relationships object
|
-- Initialize relationships object
|
||||||
ent.relationships = {}
|
ent.relationships = {}
|
||||||
@ -285,28 +400,6 @@ function npc.initialize(entity, pos, is_lua_entity)
|
|||||||
date_based = {}
|
date_based = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Temporary initialization of actions for testing
|
|
||||||
local nodes = npc.places.find_node_nearby(ent.object:getpos(), {"cottages:bench"}, 20)
|
|
||||||
|
|
||||||
--minetest.log("Self destination: "..minetest.pos_to_string(nodes[1]))
|
|
||||||
|
|
||||||
--local path = pathfinder.find_path(ent.object:getpos(), nodes[1], 20, {})
|
|
||||||
--minetest.log("Path to node: "..dump(path))
|
|
||||||
--npc.add_action(ent, npc.actions.use_door, {self = ent, pos = nodes[1], action = npc.actions.door_action.OPEN})
|
|
||||||
--npc.add_action(ent, npc.actions.stand, {self = ent})
|
|
||||||
--npc.add_action(ent, npc.actions.stand, {self = ent})
|
|
||||||
-- if nodes[1] ~= nil then
|
|
||||||
-- npc.add_task(ent, npc.actions.walk_to_pos, {end_pos=nodes[1], walkable={}})
|
|
||||||
-- npc.actions.use_furnace(ent, nodes[1], "default:cobble 5", false)
|
|
||||||
-- --npc.add_action(ent, npc.actions.sit, {self = ent})
|
|
||||||
-- -- npc.add_action(ent, npc.actions.lay, {self = ent})
|
|
||||||
-- -- npc.add_action(ent, npc.actions.lay, {self = ent})
|
|
||||||
-- -- npc.add_action(ent, npc.actions.lay, {self = ent})
|
|
||||||
-- --npc.actions.use_sittable(ent, nodes[1], npc.actions.const.sittable.GET_UP)
|
|
||||||
-- --npc.add_action(ent, npc.actions.set_interval, {self=ent, interval=10, freeze=true})
|
|
||||||
-- npc.add_action(ent, npc.actions.freeze, {freeze = false})
|
|
||||||
--end
|
|
||||||
|
|
||||||
-- Dedicated trade test
|
-- Dedicated trade test
|
||||||
ent.trader_data.trade_list.both = {
|
ent.trader_data.trade_list.both = {
|
||||||
["default:tree"] = {},
|
["default:tree"] = {},
|
||||||
@ -332,15 +425,8 @@ function npc.initialize(entity, pos, is_lua_entity)
|
|||||||
local offer2 = npc.trade.create_custom_sell_trade_offer("Do you want me to fix your mese sword?", "Fix mese sword", "Fix mese sword", "default:sword_mese", {"default:sword_mese", "default:copper_lump 10"})
|
local offer2 = npc.trade.create_custom_sell_trade_offer("Do you want me to fix your mese sword?", "Fix mese sword", "Fix mese sword", "default:sword_mese", {"default:sword_mese", "default:copper_lump 10"})
|
||||||
table.insert(ent.trader_data.custom_trades, offer2)
|
table.insert(ent.trader_data.custom_trades, offer2)
|
||||||
|
|
||||||
-- Temporary initialization of places
|
|
||||||
-- local bed_nodes = npc.places.find_new_nearby(ent, npc.places.nodes.BEDS, 8)
|
|
||||||
-- minetest.log("Number of bed nodes: "..dump(#bed_nodes))
|
|
||||||
-- if #bed_nodes > 0 then
|
|
||||||
-- npc.places.add_owned(ent, "bed1", npc.places.PLACE_TYPE.OWN_BED, bed_nodes[1])
|
|
||||||
-- end
|
|
||||||
|
|
||||||
--minetest.log(dump(ent))
|
--minetest.log(dump(ent))
|
||||||
minetest.log("[advanced_npc] INFO Successfully initialized NPC with name "..dump(ent.name))
|
minetest.log("[advanced_npc] INFO Successfully initialized NPC with name "..dump(ent.npc_name))
|
||||||
-- Refreshes entity
|
-- Refreshes entity
|
||||||
ent.object:set_properties(ent)
|
ent.object:set_properties(ent)
|
||||||
end
|
end
|
||||||
@ -510,7 +596,7 @@ end
|
|||||||
function npc.execute_action(self)
|
function npc.execute_action(self)
|
||||||
-- Check if an action was interrupted
|
-- Check if an action was interrupted
|
||||||
if self.actions.current_action_state == npc.action_state.interrupted then
|
if self.actions.current_action_state == npc.action_state.interrupted then
|
||||||
minetest.log("[advanced_npc] DEBUG Re-inserting interrupted action for NPC: '"..dump(self.name).."': "..dump(self.actions.state_before_lock.interrupted_action))
|
minetest.log("[advanced_npc] 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
|
-- Insert into queue the interrupted action
|
||||||
table.insert(self.actions.queue, 1, self.actions.state_before_lock.interrupted_action)
|
table.insert(self.actions.queue, 1, self.actions.state_before_lock.interrupted_action)
|
||||||
-- Clear the action
|
-- Clear the action
|
||||||
@ -532,7 +618,7 @@ function npc.execute_action(self)
|
|||||||
-- If the entry is a task, then push all this new operations in
|
-- If the entry is a task, then push all this new operations in
|
||||||
-- stack fashion
|
-- stack fashion
|
||||||
if action_obj.is_task == true then
|
if action_obj.is_task == true then
|
||||||
minetest.log("[advanced_npc] DEBUG Executing task for NPC '"..dump(self.name).."': "..dump(action_obj))
|
minetest.log("[advanced_npc] DEBUG Executing task for NPC '"..dump(self.npc_name).."': "..dump(action_obj))
|
||||||
-- Backup current queue
|
-- Backup current queue
|
||||||
local backup_queue = self.actions.queue
|
local backup_queue = self.actions.queue
|
||||||
-- Remove this "task" action from queue
|
-- Remove this "task" action from queue
|
||||||
@ -548,7 +634,7 @@ function npc.execute_action(self)
|
|||||||
table.insert(self.actions.queue, backup_queue[i])
|
table.insert(self.actions.queue, backup_queue[i])
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
minetest.log("[advanced_npc] DEBUG Executing action for NPC '"..dump(self.name).."': "..dump(action_obj))
|
minetest.log("[advanced_npc] DEBUG Executing action for NPC '"..dump(self.npc_name).."': "..dump(action_obj))
|
||||||
-- Store the action that is being executed
|
-- Store the action that is being executed
|
||||||
self.actions.state_before_lock.interrupted_action = action_obj
|
self.actions.state_before_lock.interrupted_action = action_obj
|
||||||
-- Store current position
|
-- Store current position
|
||||||
@ -773,12 +859,13 @@ mobs:register_mob("advanced_npc:npc", {
|
|||||||
mesh = "character.b3d",
|
mesh = "character.b3d",
|
||||||
drawtype = "front",
|
drawtype = "front",
|
||||||
textures = {
|
textures = {
|
||||||
{"mobs_npc_male1.png"},
|
{"npc_male1.png"},
|
||||||
{"mobs_npc_female1.png"}, -- female by nuttmeg20
|
{"npc_female1.png"}, -- female by nuttmeg20
|
||||||
},
|
},
|
||||||
child_texture = {
|
child_texture = {
|
||||||
{"mobs_npc_baby_male1.png"}, -- derpy baby by AmirDerAssassine
|
{"npc_baby_male1.png"}, -- derpy baby by AmirDerAssassine
|
||||||
},
|
{"npc_baby_female1.png"},
|
||||||
|
},
|
||||||
makes_footstep_sound = true,
|
makes_footstep_sound = true,
|
||||||
sounds = {},
|
sounds = {},
|
||||||
-- Added walk chance
|
-- Added walk chance
|
||||||
@ -822,8 +909,17 @@ mobs:register_mob("advanced_npc:npc", {
|
|||||||
-- Get information from clicker
|
-- Get information from clicker
|
||||||
local item = clicker:get_wielded_item()
|
local item = clicker:get_wielded_item()
|
||||||
local name = clicker:get_player_name()
|
local name = clicker:get_player_name()
|
||||||
|
|
||||||
|
--self.child = true
|
||||||
|
--self.textures = {"mobs_npc_child_male1.png"}
|
||||||
|
--self.base_texture = "mobs_npc_child_male1.png"
|
||||||
|
--self.object:set_properties(self)
|
||||||
|
|
||||||
minetest.log(dump(self))
|
minetest.log(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
|
-- 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
|
||||||
@ -835,7 +931,7 @@ mobs:register_mob("advanced_npc:npc", {
|
|||||||
-- Show dialogue to confirm that player is giving item as gift
|
-- Show dialogue to confirm that player is giving item as gift
|
||||||
npc.dialogue.show_yes_no_dialogue(
|
npc.dialogue.show_yes_no_dialogue(
|
||||||
self,
|
self,
|
||||||
"Do you want to give "..item_name.." to "..self.name.."?",
|
"Do you want to give "..item_name.." to "..self.npc_name.."?",
|
||||||
npc.dialogue.POSITIVE_GIFT_ANSWER_PREFIX..item_name,
|
npc.dialogue.POSITIVE_GIFT_ANSWER_PREFIX..item_name,
|
||||||
function()
|
function()
|
||||||
npc.relationships.receive_gift(self, clicker)
|
npc.relationships.receive_gift(self, clicker)
|
||||||
|
90
spawner.lua
@ -57,10 +57,14 @@ npc.spawner.replacement_interval = 60
|
|||||||
npc.spawner.spawn_delay = 10
|
npc.spawner.spawn_delay = 10
|
||||||
|
|
||||||
npc.spawner.spawn_data = {
|
npc.spawner.spawn_data = {
|
||||||
status = {
|
status = {
|
||||||
["dead"] = 0,
|
dead = 0,
|
||||||
["alive"] = 1
|
alive = 1
|
||||||
}
|
},
|
||||||
|
age = {
|
||||||
|
adult = "adult",
|
||||||
|
child = "child"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
local function get_basic_schedule()
|
local function get_basic_schedule()
|
||||||
@ -220,7 +224,7 @@ function spawner.assign_places(self, pos)
|
|||||||
-- Store changes to node_data
|
-- Store changes to node_data
|
||||||
meta:set_string("node_data", minetest.serialize(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)
|
minetest.log("Added bed at "..minetest.pos_to_string(node_data.bed_type[i].node_pos)
|
||||||
.." to NPC "..dump(self.name))
|
.." to NPC "..dump(self.npc_name))
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -241,6 +245,8 @@ end
|
|||||||
|
|
||||||
|
|
||||||
function spawner.assign_schedules(self, pos)
|
function spawner.assign_schedules(self, pos)
|
||||||
|
-- TODO: In the future, this needs to actually take into account
|
||||||
|
-- type of building and different schedules, e.g. farmers, traders, etc.
|
||||||
local basic_schedule = get_basic_schedule()
|
local basic_schedule = get_basic_schedule()
|
||||||
-- Add a simple schedule for testing
|
-- Add a simple schedule for testing
|
||||||
npc.create_schedule(self, npc.schedule_types.generic, 0)
|
npc.create_schedule(self, npc.schedule_types.generic, 0)
|
||||||
@ -252,11 +258,6 @@ function spawner.assign_schedules(self, pos)
|
|||||||
|
|
||||||
-- Add schedule entry for evening actions
|
-- Add schedule entry for evening actions
|
||||||
npc.add_schedule_entry(self, npc.schedule_types.generic, 0, 22, nil, basic_schedule.evening_actions)
|
npc.add_schedule_entry(self, npc.schedule_types.generic, 0, 22, nil, basic_schedule.evening_actions)
|
||||||
|
|
||||||
minetest.log("Schedules: "..dump(self.schedules))
|
|
||||||
--local afternoon_actions = { [1] = {action = npc.actions.stand, args = {}} }
|
|
||||||
--local afternoon_actions = {[1] = {task = npc.actions.cmd.USE_SITTABLE, args = {pos=nodes[1], action=npc.actions.const.sittable.GET_UP} } }
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- This function is called when the node timer for spawning NPC
|
-- This function is called when the node timer for spawning NPC
|
||||||
@ -266,17 +267,27 @@ function npc.spawner.spawn_npc(pos)
|
|||||||
local timer = minetest.get_node_timer(pos)
|
local timer = minetest.get_node_timer(pos)
|
||||||
-- Get metadata
|
-- Get metadata
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
|
-- Get current NPC info
|
||||||
|
local npc_table = minetest.deserialize(meta:get_string("npcs"))
|
||||||
|
-- Get NPC stats
|
||||||
|
local npc_stats = minetest.deserialize(meta:get_string("npc_stats"))
|
||||||
-- Check amount of NPCs that should be spawned
|
-- Check amount of NPCs that should be spawned
|
||||||
local npc_count = meta:get_int("npc_count")
|
local npc_count = meta:get_int("npc_count")
|
||||||
local spawned_npc_count = meta:get_int("spawned_npc_count")
|
local spawned_npc_count = meta:get_int("spawned_npc_count")
|
||||||
minetest.log("Currently spawned "..dump(spawned_npc_count).." of "..dump(npc_count).." NPCs")
|
minetest.log("[advanced_npc] INFO Currently spawned "..dump(spawned_npc_count).." of "..dump(npc_count).." NPCs")
|
||||||
if spawned_npc_count < npc_count then
|
if spawned_npc_count < npc_count then
|
||||||
minetest.log("[advanced_npc] Spawning NPC at "..minetest.pos_to_string(pos))
|
minetest.log("[advanced_npc] INFO Spawning NPC at "..minetest.pos_to_string(pos))
|
||||||
-- Spawn a NPC
|
-- Spawn a NPC
|
||||||
local ent = minetest.add_entity({x=pos.x, y=pos.y+1, z=pos.z}, "advanced_npc: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
|
if ent and ent:get_luaentity() then
|
||||||
ent:get_luaentity().initialized = false
|
ent:get_luaentity().initialized = false
|
||||||
npc.initialize(ent, pos)
|
-- Initialize NPC
|
||||||
|
-- Call with stats if there are NPCs
|
||||||
|
if #npc_table > 0 then
|
||||||
|
npc.initialize(ent, pos, false, npc_stats)
|
||||||
|
else
|
||||||
|
npc.initialize(ent, pos)
|
||||||
|
end
|
||||||
-- Assign nodes
|
-- Assign nodes
|
||||||
spawner.assign_places(ent:get_luaentity(), pos)
|
spawner.assign_places(ent:get_luaentity(), pos)
|
||||||
-- Assign schedules
|
-- Assign schedules
|
||||||
@ -285,22 +296,34 @@ function npc.spawner.spawn_npc(pos)
|
|||||||
spawned_npc_count = spawned_npc_count + 1
|
spawned_npc_count = spawned_npc_count + 1
|
||||||
-- Store count into node
|
-- Store count into node
|
||||||
meta:set_int("spawned_npc_count", spawned_npc_count)
|
meta:set_int("spawned_npc_count", spawned_npc_count)
|
||||||
-- Store spawned NPC data into node
|
-- Store spawned NPC data and stats into node
|
||||||
local npc_table = minetest.deserialize(meta:get_string("npcs"))
|
local age = npc.age.adult
|
||||||
|
if ent:get_luaentity().child then
|
||||||
|
age = npc.age.child
|
||||||
|
end
|
||||||
-- TODO: Add more information here at some time...
|
-- TODO: Add more information here at some time...
|
||||||
local entry = {
|
local entry = {
|
||||||
status = npc.spawner.spawn_data.status.alive,
|
status = npc.spawner.spawn_data.status.alive,
|
||||||
name = ent:get_luaentity().name,
|
name = ent:get_luaentity().name,
|
||||||
id = ent:get_luaentity().npc_id,
|
id = ent:get_luaentity().npc_id,
|
||||||
sex = ent:get_luaentity().sex,
|
sex = ent:get_luaentity().sex,
|
||||||
age = ent:get_luaentity().
|
age = age,
|
||||||
born_day = minetest.get_day_count()
|
born_day = minetest.get_day_count()
|
||||||
}
|
}
|
||||||
table.insert(npc_table, entry)
|
table.insert(npc_table, entry)
|
||||||
-- Store into metadata
|
|
||||||
meta:set_string("npcs", minetest.serialize(npc_table))
|
meta:set_string("npcs", minetest.serialize(npc_table))
|
||||||
|
-- Update and store stats
|
||||||
|
-- Increase total of NPCs for specific sex
|
||||||
|
npc_stats[ent:get_luaentity().sex].total =
|
||||||
|
npc_stats[ent:get_luaentity().sex].total + 1
|
||||||
|
-- Increase total number of NPCs by age
|
||||||
|
npc_stats[age.."_total"] = npc_stats[age.."_total"] + 1
|
||||||
|
-- Increase number of NPCs by age and sex
|
||||||
|
npc_stats[ent:get_luaentity().sex][age] =
|
||||||
|
npc_stats[ent:get_luaentity().sex][age] + 1
|
||||||
|
meta:set_string("npc_stats", minetest.serialize(npc_stats))
|
||||||
-- Temp
|
-- Temp
|
||||||
meta:set_string("infotext", meta:get_string("infotext")..", "..spawned_npc_count)
|
--meta:set_string("infotext", meta:get_string("infotext")..", "..spawned_npc_count)
|
||||||
minetest.log("[advanced_npc] INFO Spawning successful!")
|
minetest.log("[advanced_npc] INFO Spawning successful!")
|
||||||
-- Check if there are more NPCs to spawn
|
-- Check if there are more NPCs to spawn
|
||||||
if spawned_npc_count >= npc_count then
|
if spawned_npc_count >= npc_count then
|
||||||
@ -486,6 +509,22 @@ function spawner.replace_mg_villages_plotmarker(pos)
|
|||||||
-- Initialize NPCs
|
-- Initialize NPCs
|
||||||
local npcs = {}
|
local npcs = {}
|
||||||
meta:set_string("npcs", minetest.serialize(npcs))
|
meta:set_string("npcs", minetest.serialize(npcs))
|
||||||
|
-- Initialize NPC stats
|
||||||
|
local npc_stats = {
|
||||||
|
male = {
|
||||||
|
total = 0,
|
||||||
|
adult = 0,
|
||||||
|
child = 0
|
||||||
|
},
|
||||||
|
female = {
|
||||||
|
total = 0,
|
||||||
|
adult = 0,
|
||||||
|
child = 0
|
||||||
|
},
|
||||||
|
adult_total = 0,
|
||||||
|
child_total = 0
|
||||||
|
}
|
||||||
|
meta:set_string("npc_stats", minetest.serialize(npc_stats))
|
||||||
-- Stop searching for building type
|
-- Stop searching for building type
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -525,11 +564,12 @@ if minetest.get_modpath("mg_villages") ~= nil then
|
|||||||
--local entrance = npc.places.find_entrance_from_openable_nodes(nodedata.openable_type, pos)
|
--local entrance = npc.places.find_entrance_from_openable_nodes(nodedata.openable_type, pos)
|
||||||
--minetest.log("Found entrance: "..dump(entrance))
|
--minetest.log("Found entrance: "..dump(entrance))
|
||||||
|
|
||||||
for i = 1, #nodedata.bed_type do
|
-- for i = 1, #nodedata.bed_type do
|
||||||
nodedata.bed_type[i].owner = ""
|
-- nodedata.bed_type[i].owner = ""
|
||||||
end
|
-- end
|
||||||
minetest.get_meta(pos):set_string("node_data", minetest.serialize(nodedata))
|
-- minetest.get_meta(pos):set_string("node_data", minetest.serialize(nodedata))
|
||||||
minetest.log("Cleared bed owners")
|
-- minetest.log("Cleared bed owners")
|
||||||
|
minetest.log("NPC stats: "..dump(minetest.deserialize(minetest.get_meta(pos):get_string("npc_stats"))))
|
||||||
|
|
||||||
return mg_villages.plotmarker_formspec( pos, nil, {}, clicker )
|
return mg_villages.plotmarker_formspec( pos, nil, {}, clicker )
|
||||||
end,
|
end,
|
||||||
@ -632,6 +672,10 @@ minetest.register_chatcommand("restore_plotmarkers", {
|
|||||||
meta:set_string("village_id", village_id)
|
meta:set_string("village_id", village_id)
|
||||||
meta:set_int("plot_nr", plot_nr)
|
meta:set_int("plot_nr", plot_nr)
|
||||||
meta:set_string("infotext", infotext)
|
meta:set_string("infotext", infotext)
|
||||||
|
-- Clear NPC stats, NPC data and node data
|
||||||
|
meta:set_string("node_data", nil)
|
||||||
|
meta:set_string("npcs", nil)
|
||||||
|
meta:set_string("npc_stats", nil)
|
||||||
end
|
end
|
||||||
minetest.chat_send_player(name, "Finished replacement of "..dump(#nodes).." auto-spawners successfully")
|
minetest.chat_send_player(name, "Finished replacement of "..dump(#nodes).." auto-spawners successfully")
|
||||||
end
|
end
|
||||||
|
Before Width: | Height: | Size: 684 B |
BIN
textures/npc_baby_female1.png
Executable file
After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 901 B After Width: | Height: | Size: 901 B |
Before Width: | Height: | Size: 1018 B After Width: | Height: | Size: 1018 B |
BIN
textures/npc_male1.png
Executable file
After Width: | Height: | Size: 901 B |
@ -112,7 +112,7 @@ function npc.trade.show_trade_offer_formspec(self, player, offer_type)
|
|||||||
default.gui_bg..
|
default.gui_bg..
|
||||||
default.gui_bg_img..
|
default.gui_bg_img..
|
||||||
default.gui_slots..
|
default.gui_slots..
|
||||||
"label[2,0.1;"..self.name..prompt_string.."]"..
|
"label[2,0.1;"..self.npc_name..prompt_string.."]"..
|
||||||
"item_image_button[2,1.3;1.2,1.2;"..trade_offer.item..";item;]"..
|
"item_image_button[2,1.3;1.2,1.2;"..trade_offer.item..";item;]"..
|
||||||
"label[3.75,1.75;"..for_string.."]"..
|
"label[3.75,1.75;"..for_string.."]"..
|
||||||
"item_image_button[4.8,1.3;1.2,1.2;"..trade_offer.price[1]..";price;]"..
|
"item_image_button[4.8,1.3;1.2,1.2;"..trade_offer.price[1]..";price;]"..
|
||||||
@ -221,7 +221,7 @@ function npc.trade.show_custom_trade_offer(self, player, offer)
|
|||||||
default.gui_bg..
|
default.gui_bg..
|
||||||
default.gui_bg_img..
|
default.gui_bg_img..
|
||||||
default.gui_slots..
|
default.gui_slots..
|
||||||
"label[2,0.1;"..self.name..": "..offer.dialogue_prompt.."]"..
|
"label[2,0.1;"..self.npc_name..": "..offer.dialogue_prompt.."]"..
|
||||||
price_grid..
|
price_grid..
|
||||||
"label["..(margin_x + 3.75)..",1.75;"..for_string.."]"..
|
"label["..(margin_x + 3.75)..",1.75;"..for_string.."]"..
|
||||||
"item_image_button["..(margin_x + 4.8)..",1.3;1.2,1.2;"..offer.item..";item;]"..
|
"item_image_button["..(margin_x + 4.8)..",1.3;1.2,1.2;"..offer.item..";item;]"..
|
||||||
|
@ -243,16 +243,16 @@ function mobs_trader(self, clicker, entity, race)
|
|||||||
|
|
||||||
if not self.id then
|
if not self.id then
|
||||||
self.id = (math.random(1, 1000) * math.random(1, 10000))
|
self.id = (math.random(1, 1000) * math.random(1, 10000))
|
||||||
.. self.name .. (math.random(1, 1000) ^ 2)
|
.. self.npc_name .. (math.random(1, 1000) ^ 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.game_name then
|
if not self.game_name then
|
||||||
|
|
||||||
self.game_name = tostring(race.names[math.random(1, #race.names)])
|
self.game_name = tostring(race.names[math.random(1, #race.names)])
|
||||||
self.nametag = S("Trader @1", self.game_name)
|
self.npc_nametag = S("Trader @1", self.game_name)
|
||||||
|
|
||||||
self.object:set_properties({
|
self.object:set_properties({
|
||||||
nametag = self.nametag,
|
nametag = self.npc_nametag,
|
||||||
nametag_color = "#00FF00"
|
nametag_color = "#00FF00"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -123,14 +123,14 @@ function mobs_trader(self, clicker, race)
|
|||||||
|
|
||||||
if not self.id then
|
if not self.id then
|
||||||
self.id = (math.random(1, 1000) * math.random(1, 10000))
|
self.id = (math.random(1, 1000) * math.random(1, 10000))
|
||||||
.. self.name .. (math.random(1, 1000) ^ 2)
|
.. self.npc_name .. (math.random(1, 1000) ^ 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.game_name then
|
if not self.game_name then
|
||||||
self.game_name = tostring(race.names[math.random(1, #race.names)])
|
self.game_name = tostring(race.names[math.random(1, #race.names)])
|
||||||
self.nametag = S("Trader @1", self.game_name)
|
self.npc_nametag = S("Trader @1", self.game_name)
|
||||||
self.object:set_properties({
|
self.object:set_properties({
|
||||||
nametag = self.nametag,
|
nametag = self.npc_nametag,
|
||||||
nametag_color = "#00FF00"
|
nametag_color = "#00FF00"
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|