Compare commits
11 Commits
1.0.0-alph
...
1.0.0-alph
Author | SHA1 | Date | |
---|---|---|---|
4c0e2b574a | |||
bf935fd091 | |||
6141af11aa | |||
e70888c3e5 | |||
cc56446206 | |||
7110c49b42 | |||
fd4cec0d63 | |||
3df43ab580 | |||
c19ea70242 | |||
a3b428fe14 | |||
4814c16ba0 |
@ -27,7 +27,7 @@ License
|
||||
|
||||
__advanced_npc__ is Copyright (C) 2016-2017 Hector Franqui (zorman2000), licensed under the GPLv3 license. See `license.txt` for details.
|
||||
|
||||
The `pathfinder.lua` file contains code slighlty modified from the [pathfinder mod](https://github.com/Yonaba/Jumper) by MarkBu, which is licensed as WTFPL. See `actions/pathfinder.lua` for details.
|
||||
The `pathfinder.lua` file contains code slighlty modified from the [pathfinder mod](https://github.com/MarkuBu/pathfinder) by MarkBu, which is licensed as WTFPL. See `actions/pathfinder.lua` for details.
|
||||
|
||||
Current NPC textures are from mobs_redo mod.
|
||||
The following textures are by Zorman2000:
|
||||
|
@ -604,6 +604,10 @@ function npc.actions.use_bed(self, args)
|
||||
|
||||
if action == npc.actions.const.beds.LAY then
|
||||
-- Get position
|
||||
-- Error here due to ignore. Need to come up with better solution
|
||||
if node.name == "ignore" then
|
||||
return
|
||||
end
|
||||
local bed_pos = npc.actions.nodes.beds[node.name].get_lay_pos(pos, dir)
|
||||
-- Sit down on bed, rotate to correct direction
|
||||
npc.add_action(self, npc.actions.cmd.SIT, {pos=bed_pos, dir=(node.param2 + 2) % 4})
|
||||
@ -611,6 +615,10 @@ function npc.actions.use_bed(self, args)
|
||||
npc.add_action(self, npc.actions.cmd.LAY, {})
|
||||
else
|
||||
-- Calculate position to get up
|
||||
-- Error here due to ignore. Need to come up with better solution
|
||||
if node.name == "ignore" then
|
||||
return
|
||||
end
|
||||
local bed_pos_y = npc.actions.nodes.beds[node.name].get_lay_pos(pos, dir).y
|
||||
local bed_pos = {x = pos.x, y = bed_pos_y, z = pos.z}
|
||||
-- Sit up
|
||||
@ -662,6 +670,10 @@ function npc.actions.use_sittable(self, args)
|
||||
|
||||
if action == npc.actions.const.sittable.SIT then
|
||||
-- Calculate position depending on bench
|
||||
-- Error here due to ignore. Need to come up with better solution
|
||||
if node.name == "ignore" then
|
||||
return
|
||||
end
|
||||
local sit_pos = npc.actions.nodes.sittable[node.name].get_sit_pos(pos, node.param2)
|
||||
-- Sit down on bench/chair/stairs
|
||||
npc.add_action(self, npc.actions.cmd.SIT, {pos=sit_pos, dir=(node.param2 + 2) % 4})
|
||||
|
@ -153,7 +153,11 @@ local function walkable(node, exceptions)
|
||||
if node.name == "cottages:wood_flat" then
|
||||
is_mg_villages_ceiling = true
|
||||
end
|
||||
if node ~= nil and node.name ~= nil and not minetest.registered_nodes[node.name].walkable then
|
||||
if node ~= nil
|
||||
and node.name ~= nil
|
||||
and node.name ~= "ignore"
|
||||
and minetest.registered_nodes[node.name]
|
||||
and not minetest.registered_nodes[node.name].walkable then
|
||||
return false
|
||||
elseif is_openable then
|
||||
return false
|
||||
|
@ -22,8 +22,10 @@ npc.places.nodes = {
|
||||
},
|
||||
SITTABLE_TYPE = {
|
||||
"cottages:bench",
|
||||
-- Currently commented out since some NPCs
|
||||
-- were sitting at stairs that are actually staircases
|
||||
-- TODO: Register other stair types
|
||||
"stairs:stair_wood"
|
||||
--"stairs:stair_wood"
|
||||
},
|
||||
STORAGE_TYPE = {
|
||||
"default:chest",
|
||||
@ -56,7 +58,16 @@ npc.places.PLACE_TYPE = {
|
||||
PRIMARY = "bed_primary"
|
||||
},
|
||||
SITTABLE = {
|
||||
PRIMARY = "sit_primary"
|
||||
PRIMARY = "sit_primary",
|
||||
SHARED = "sit_shared"
|
||||
},
|
||||
FURNACE = {
|
||||
PRIMARY = "furnace_primary",
|
||||
SHARED = "furnace_shared"
|
||||
},
|
||||
STORAGE = {
|
||||
PRIMARY = "storage_primary",
|
||||
SHARED = "storage_shared"
|
||||
},
|
||||
OPENABLE = {
|
||||
HOME_ENTRANCE_DOOR = "home_entrance_door"
|
||||
@ -68,27 +79,51 @@ npc.places.PLACE_TYPE = {
|
||||
}
|
||||
}
|
||||
|
||||
function npc.places.add_public(self, place_name, place_type, pos, access_node)
|
||||
--minetest.log("Place name: "..dump(place_name)..", type: "..dump(place_type))
|
||||
function npc.places.add_shared(self, place_name, place_type, pos, access_node)
|
||||
self.places_map[place_name] = {type=place_type, pos=pos, access_node=access_node or pos, status="shared"}
|
||||
end
|
||||
|
||||
-- Adds a specific node to the NPC places, and modifies the
|
||||
-- node metadata to identify the NPC as the owner. This allows
|
||||
-- other NPCs to avoid to take this as their own.
|
||||
function npc.places.add_owned(self, place_name, place_type, pos, access_node)
|
||||
-- Get node metadata
|
||||
--local meta = minetest.get_meta(pos)
|
||||
-- Check if it is owned by an NPC?
|
||||
--if meta:get_string("npc_owner") == "" then
|
||||
-- Set owned by NPC
|
||||
--meta:set_string("npc_owner", self.npc_id)
|
||||
-- Add place to list
|
||||
self.places_map[place_name] = {type=place_type, pos=pos, access_node=access_node or pos, status="owned"}
|
||||
--npc.places.add_public(self, place_name, place_type, pos)
|
||||
return true
|
||||
--end
|
||||
--return false
|
||||
end
|
||||
|
||||
function npc.places.add_unowned_accessible_place(self, nodes, place_type)
|
||||
for i = 1, #nodes do
|
||||
-- Check if node has owner
|
||||
if nodes[i].owner == "" then
|
||||
-- If node has no owner, check if it is accessible
|
||||
local empty_nodes = npc.places.find_node_orthogonally(
|
||||
nodes[i].node_pos, {"air"}, 0)
|
||||
-- Check if node is accessible
|
||||
if #empty_nodes > 0 then
|
||||
-- Set owner to this NPC
|
||||
nodes[i].owner = self.npc_id
|
||||
-- Assign node to NPC
|
||||
npc.places.add_owned(self, place_type, place_type,
|
||||
nodes[i].node_pos, empty_nodes[1].pos)
|
||||
npc.log("DEBUG", "Added node at "..minetest.pos_to_string(nodes[i].node_pos)
|
||||
.." to NPC "..dump(self.npc_name))
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function npc.places.add_shared_accessible_place(self, nodes, place_type)
|
||||
for i = 1, #nodes do
|
||||
-- Check of not adding same owned sit
|
||||
if nodes[i].owner ~= self.npc_id then
|
||||
-- Check if it is accessible
|
||||
local empty_nodes = npc.places.find_node_orthogonally(
|
||||
nodes[i].node_pos, {"air"}, 0)
|
||||
-- Check if bed is accessible
|
||||
if #empty_nodes > 0 then
|
||||
-- Assign node to NPC
|
||||
npc.places.add_shared(self, place_type..dump(i),
|
||||
place_type, nodes[i].node_pos, empty_nodes[1].pos)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function npc.places.get_by_type(self, place_type)
|
||||
|
@ -437,8 +437,8 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
|
||||
-- Get player response
|
||||
local player_response = npc.dialogue.dialogue_results.options_dialogue[player_name]
|
||||
|
||||
-- Check if the player hit the negative option
|
||||
if fields["exit"] then
|
||||
-- Check if the player hit the negative option or esc button
|
||||
if fields["exit"] or fields["quit"] == "true" then
|
||||
-- Unlock queue, reset action timer and unfreeze NPC.
|
||||
npc.unlock_actions(player_response.npc)
|
||||
end
|
||||
|
107
npc.lua
107
npc.lua
@ -44,14 +44,14 @@ npc.action_state = {
|
||||
|
||||
npc.log_level = {
|
||||
INFO = true,
|
||||
WARNING = false,
|
||||
WARNING = true,
|
||||
ERROR = true,
|
||||
DEBUG = false
|
||||
}
|
||||
|
||||
npc.texture_check = {
|
||||
timer = 0,
|
||||
interval = 0
|
||||
interval = 2
|
||||
}
|
||||
|
||||
---------------------------------------------------------------------------------------
|
||||
@ -149,9 +149,9 @@ local function get_random_texture(sex, age)
|
||||
end
|
||||
|
||||
-- Choose whether NPC can have relationships. Only 30% of NPCs cannot have relationships
|
||||
local function can_have_relationships(age)
|
||||
local function can_have_relationships(is_child)
|
||||
-- Children can't have relationships
|
||||
if not age then
|
||||
if is_child then
|
||||
return false
|
||||
end
|
||||
local chance = math.random(1,10)
|
||||
@ -264,8 +264,8 @@ function npc.initialize(entity, pos, is_lua_entity, npc_stats)
|
||||
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
|
||||
x = 0.75,
|
||||
y = 0.75
|
||||
}
|
||||
ent.collisionbox = {-0.10,-0.50,-0.10, 0.10,0.40,0.10}
|
||||
ent.is_child = true
|
||||
@ -310,6 +310,11 @@ function npc.initialize(entity, pos, is_lua_entity, npc_stats)
|
||||
-- Flag that determines if NPC can have a relationship
|
||||
ent.can_have_relationship = can_have_relationships(ent.is_child)
|
||||
|
||||
ent.infotext = "Interested in relationships: "..dump(ent.can_have_relationship)
|
||||
|
||||
-- Flag to determine if NPC can receive gifts
|
||||
ent.can_receive_gifts = ent.can_have_relationship
|
||||
|
||||
-- Initialize relationships object
|
||||
ent.relationships = {}
|
||||
|
||||
@ -455,6 +460,24 @@ function npc.initialize(entity, pos, is_lua_entity, npc_stats)
|
||||
ent.object:set_properties(ent)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------------------
|
||||
-- Trading functions
|
||||
---------------------------------------------------------------------------------------
|
||||
function npc.generate_trade_list_from_inventory(self)
|
||||
local list = {}
|
||||
for i = 1, #self.inventory do
|
||||
list[npc.get_item_name(self.inventory[i])] = {}
|
||||
end
|
||||
self.trader_data.trade_list.both = list
|
||||
end
|
||||
|
||||
function npc.set_trading_status(self, status)
|
||||
-- Set status
|
||||
self.trader_data.trader_status = status
|
||||
-- Re-generate trade offers
|
||||
npc.trade.generate_trade_offers_by_status(self)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------------------
|
||||
-- Inventory functions
|
||||
---------------------------------------------------------------------------------------
|
||||
@ -743,6 +766,14 @@ npc.schedule_types = {
|
||||
["date_based"] = "date_based"
|
||||
}
|
||||
|
||||
npc.schedule_properties = {
|
||||
put_item = "put_item",
|
||||
put_multiple_items = "put_multiple_items",
|
||||
take_item = "take_item",
|
||||
trader_status = "trader_status",
|
||||
can_receive_gifts = "can_receive_gifts"
|
||||
}
|
||||
|
||||
local function get_time_in_hours()
|
||||
return minetest.get_timeofday() * 24
|
||||
end
|
||||
@ -861,6 +892,41 @@ function npc.delete_schedule_entry(self, schedule_type, date, time)
|
||||
end
|
||||
end
|
||||
|
||||
function npc.schedule_change_property(self, property, args)
|
||||
if property == npc.schedule_properties.trader_status then
|
||||
-- Get status from args
|
||||
local status = args.status
|
||||
-- Set status to NPC
|
||||
npc.set_trading_status(self, status)
|
||||
elseif property == npc.schedule_properties.put_item then
|
||||
local itemstring = args.itemstring
|
||||
-- Add item
|
||||
npc.add_item_to_inventory_itemstring(self, itemstring)
|
||||
elseif property == npc.schedule_properties.put_multiple_items then
|
||||
local itemlist = args.itemlist
|
||||
for i = 1, #itemlist do
|
||||
local itemlist_entry = itemlist[i]
|
||||
local current_itemstring = itemlist[i].name
|
||||
if itemlist_entry.random == true then
|
||||
current_itemstring = current_itemstring
|
||||
.." "..dump(math.random(itemlist_entry.min, itemlist_entry.max))
|
||||
else
|
||||
current_itemstring = current_itemstring.." "..tostring(itemlist_entry.count)
|
||||
end
|
||||
-- Add item to inventory
|
||||
npc.add_item_to_inventory_itemstring(self, current_itemstring)
|
||||
end
|
||||
elseif property == npc.schedule_properties.take_item then
|
||||
local itemstring = args.itemstring
|
||||
-- Add item
|
||||
npc.take_item_from_inventory_itemstring(self, itemstring)
|
||||
elseif property == npc.schedule_properties.can_receive_gifts then
|
||||
local value = args.can_receive_gifts
|
||||
-- Set status
|
||||
self.can_receive_gifts = value
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------------------
|
||||
-- NPC Definition
|
||||
---------------------------------------------------------------------------------------
|
||||
@ -884,6 +950,11 @@ mobs:register_mob("advanced_npc:npc", {
|
||||
drawtype = "front",
|
||||
textures = {
|
||||
{"npc_male1.png"},
|
||||
--{"npc_male2.png"},
|
||||
--{"npc_male3.png"},
|
||||
--{"npc_male4.png"},
|
||||
--{"npc_male5.png"},
|
||||
--{"npc_male6.png"},
|
||||
{"npc_female1.png"}, -- female by nuttmeg20
|
||||
},
|
||||
child_texture = {
|
||||
@ -934,16 +1005,14 @@ mobs:register_mob("advanced_npc:npc", {
|
||||
local item = clicker:get_wielded_item()
|
||||
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)
|
||||
|
||||
npc.log("DEBUG", "Right-clicked NPC: "..dump(self))
|
||||
|
||||
-- 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
|
||||
minetest.log("self.can_have_relationship: "..dump(self.can_have_relationship)..", self.can_receive_gifts: "..dump(self.can_receive_gifts)..", table: "..dump(item:to_table()))
|
||||
if self.can_have_relationship
|
||||
and self.can_receive_gifts
|
||||
and item:to_table() ~= nil then
|
||||
-- Get item name
|
||||
local item = minetest.registered_items[item:get_name()]
|
||||
local item_name = item.description
|
||||
@ -980,13 +1049,19 @@ mobs:register_mob("advanced_npc:npc", {
|
||||
-- NPC is initialized, check other variables
|
||||
-- Check child texture issues
|
||||
if self.is_child then
|
||||
-- Check texture
|
||||
npc.texture_check.timer = npc.texture_check.timer + dtime
|
||||
if npc.texture_check.timer > npc.texture_check.interval then
|
||||
-- Reset timer
|
||||
npc.texture_check.timer = 0
|
||||
-- Set hornytimer to zero every 60 seconds so that children
|
||||
-- don't grow automatically
|
||||
self.hornytimer = 0
|
||||
-- Set correct textures
|
||||
self.texture = {self.selected_texture}
|
||||
self.base_texture = {self.selected_texture}
|
||||
self.object:set_properties(self)
|
||||
npc.log("WARNING", "Corrected textures on NPC child "..dump(self.npc_name))
|
||||
-- Set interval to large interval so this code isn't called frequently
|
||||
npc.texture_check.interval = 60
|
||||
end
|
||||
@ -1086,12 +1161,16 @@ mobs:register_mob("advanced_npc:npc", {
|
||||
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
|
||||
--minetest.log("schedule[time]: "..dump(schedule[time]))
|
||||
if schedule[time][i].task ~= nil then
|
||||
-- Add task
|
||||
npc.add_task(self, schedule[time][i].task, schedule[time][i].args)
|
||||
else
|
||||
elseif schedule[time][i].action ~= nil then
|
||||
-- Add action
|
||||
npc.add_action(self, schedule[time][i].action, schedule[time][i].args)
|
||||
elseif schedule[time][i].property ~= nil then
|
||||
-- Change NPC property
|
||||
npc.schedule_change_property(self, schedule[time][i].property, schedule[time][i].args)
|
||||
end
|
||||
end
|
||||
npc.log("DEBUG", "New action queue: "..dump(self.actions))
|
||||
|
@ -27,8 +27,8 @@ npc.relationships = {}
|
||||
npc.relationships.ITEM_GIFT_EFFECT = 2.5
|
||||
|
||||
-- Expected values for these are 720 each respectively
|
||||
npc.relationships.GIFT_TIMER_INTERVAL = 2
|
||||
npc.relationships.RELATIONSHIP_DECREASE_TIMER_INTERVAL = 60
|
||||
npc.relationships.GIFT_TIMER_INTERVAL = 360
|
||||
npc.relationships.RELATIONSHIP_DECREASE_TIMER_INTERVAL = 720
|
||||
|
||||
npc.relationships.RELATIONSHIP_PHASE = {}
|
||||
-- Define phases
|
||||
@ -360,7 +360,7 @@ local function show_receive_gift_reaction(self, item_name, modifier, clicker_nam
|
||||
effect({x = pos.x, y = pos.y + 1, z = pos.z}, 8, "default_item_smoke.png")
|
||||
--minetest.log("Item name: "..item_name..", sex: "..self.sex)
|
||||
local message_to_send = npc.relationships.get_response_for_disliked_item(item_name, self.sex)
|
||||
npc.name(self.npc_name, clicker_name, message_to_send)
|
||||
npc.chat(self.npc_name, clicker_name, message_to_send)
|
||||
end
|
||||
|
||||
end
|
||||
|
237
spawner.lua
237
spawner.lua
@ -88,16 +88,72 @@ local function get_basic_schedule()
|
||||
-- Allow mobs_redo wandering
|
||||
[3] = {action = npc.actions.cmd.FREEZE, args = {freeze = false}}
|
||||
},
|
||||
-- Noon actions: go inside the house
|
||||
-- This will be executed around 12 PM MTG time
|
||||
noon_actions = {
|
||||
-- Walk to a sittable node
|
||||
[1] = {task = npc.actions.cmd.WALK_TO_POS, args = {
|
||||
end_pos = {place_type=npc.places.PLACE_TYPE.SITTABLE.PRIMARY, use_access_node=true},
|
||||
walkable = {"cottages:bench"}
|
||||
}
|
||||
},
|
||||
-- Sit on the node
|
||||
[2] = {task = npc.actions.cmd.USE_SITTABLE, args = {
|
||||
pos = npc.places.PLACE_TYPE.SITTABLE.PRIMARY,
|
||||
action = npc.actions.const.sittable.SIT
|
||||
}
|
||||
},
|
||||
-- Stay put into place
|
||||
[3] = {action = npc.actions.cmd.FREEZE, args = {freeze = true}}
|
||||
},
|
||||
-- Afternoon actions: go inside the house
|
||||
-- This will be executed around 1 PM MTG time
|
||||
afternoon_actions = {
|
||||
-- Get up of the sit
|
||||
[1] = {task = npc.actions.cmd.USE_SITTABLE, args = {
|
||||
pos = npc.places.PLACE_TYPE.SITTABLE.PRIMARY,
|
||||
action = npc.actions.const.sittable.GET_UP
|
||||
}
|
||||
},
|
||||
-- Give NPC money to buy from player
|
||||
[2] = {property = npc.schedule_properties.put_multiple_items, args = {
|
||||
itemlist = {
|
||||
{name="default:iron_lump", random=true, min=2, max=4}
|
||||
}
|
||||
}
|
||||
},
|
||||
-- Change trader status to "trader"
|
||||
[3] = {property = npc.schedule_properties.trader_status, args = {
|
||||
status = npc.trade.TRADER
|
||||
}
|
||||
},
|
||||
[4] = {property = npc.schedule_properties.can_receive_gifts, args = {
|
||||
value = true
|
||||
}
|
||||
},
|
||||
-- Allow mobs_redo wandering
|
||||
[5] = {action = npc.actions.cmd.FREEZE, args = {freeze = false}}
|
||||
},
|
||||
-- Afternoon actions: go inside the house
|
||||
-- This will be executed around 6 PM MTG time
|
||||
afternoon_actions = {
|
||||
late_afternoon_actions = {
|
||||
-- Change trader status to "none"
|
||||
[1] = {property = npc.schedule_properties.trader_status, args = {
|
||||
status = npc.trade.NONE
|
||||
}
|
||||
},
|
||||
-- Enable gift receiving again
|
||||
[2] = {property = npc.schedule_properties.can_receive_gifts, args = {
|
||||
can_receive_gifts = true
|
||||
}
|
||||
},
|
||||
-- Get inside home
|
||||
[1] = {task = npc.actions.cmd.WALK_TO_POS, args = {
|
||||
[3] = {task = npc.actions.cmd.WALK_TO_POS, args = {
|
||||
end_pos = npc.places.PLACE_TYPE.OTHER.HOME_INSIDE,
|
||||
walkable = {}}
|
||||
},
|
||||
-- Allow mobs_redo wandering
|
||||
[2] = {action = npc.actions.cmd.FREEZE, args = {freeze = false}}
|
||||
[4] = {action = npc.actions.cmd.FREEZE, args = {freeze = false}}
|
||||
},
|
||||
-- Evening actions: walk to bed and use it.
|
||||
-- This will be executed around 10 PM MTG time
|
||||
@ -164,6 +220,7 @@ function spawner.scan_area(pos1, pos2)
|
||||
|
||||
result.bed_type = spawner.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.BED_TYPE)
|
||||
result.sittable_type = spawner.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.SITTABLE_TYPE)
|
||||
-- Filter out
|
||||
result.furnace_type = spawner.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.FURNACE_TYPE)
|
||||
result.storage_type = spawner.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.STORAGE_TYPE)
|
||||
result.openable_type = spawner.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.OPENABLE_TYPE)
|
||||
@ -190,49 +247,77 @@ function spawner.assign_places(self, pos)
|
||||
local node_data = minetest.deserialize(meta:get_string("node_data"))
|
||||
|
||||
-- Assign plotmarker
|
||||
npc.places.add_public(self, npc.places.PLACE_TYPE.OTHER.HOME_PLOTMARKER,
|
||||
npc.places.add_shared(self, npc.places.PLACE_TYPE.OTHER.HOME_PLOTMARKER,
|
||||
npc.places.PLACE_TYPE.OTHER.HOME_PLOTMARKER, pos)
|
||||
|
||||
-- Assign entrance door and related locations
|
||||
if entrance ~= nil and entrance.node_pos ~= nil then
|
||||
npc.places.add_public(self, npc.places.PLACE_TYPE.OPENABLE.HOME_ENTRANCE_DOOR, npc.places.PLACE_TYPE.OPENABLE.HOME_ENTRANCE_DOOR, entrance.node_pos)
|
||||
npc.places.add_shared(self, npc.places.PLACE_TYPE.OPENABLE.HOME_ENTRANCE_DOOR, npc.places.PLACE_TYPE.OPENABLE.HOME_ENTRANCE_DOOR, entrance.node_pos)
|
||||
-- Find the position inside and outside the door
|
||||
local entrance_inside = npc.places.find_node_behind_door(entrance.node_pos)
|
||||
local entrance_outside = npc.places.find_node_in_front_of_door(entrance.node_pos)
|
||||
-- Assign these places to NPC
|
||||
npc.places.add_public(self, npc.places.PLACE_TYPE.OTHER.HOME_INSIDE, npc.places.PLACE_TYPE.OTHER.HOME_INSIDE, entrance_inside)
|
||||
npc.places.add_public(self, npc.places.PLACE_TYPE.OTHER.HOME_OUTSIDE, npc.places.PLACE_TYPE.OTHER.HOME_OUTSIDE, entrance_outside)
|
||||
npc.places.add_shared(self, npc.places.PLACE_TYPE.OTHER.HOME_INSIDE, npc.places.PLACE_TYPE.OTHER.HOME_INSIDE, entrance_inside)
|
||||
npc.places.add_shared(self, npc.places.PLACE_TYPE.OTHER.HOME_OUTSIDE, npc.places.PLACE_TYPE.OTHER.HOME_OUTSIDE, entrance_outside)
|
||||
end
|
||||
|
||||
-- Assign beds
|
||||
if #node_data.bed_type > 0 then
|
||||
-- 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]))
|
||||
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(
|
||||
node_data.bed_type[i].node_pos, {"air"}, 0)
|
||||
-- Check if bed is accessible
|
||||
if #empty_nodes > 0 then
|
||||
-- Set owner to this NPC
|
||||
node_data.bed_type[i].owner = self.npc_id
|
||||
-- Assign node to NPC
|
||||
npc.places.add_owned(self, npc.places.PLACE_TYPE.BED.PRIMARY,
|
||||
npc.places.PLACE_TYPE.BED.PRIMARY, node_data.bed_type[i].node_pos, empty_nodes[1].pos)
|
||||
-- Assign a specific sittable node to a NPC.
|
||||
npc.places.add_unowned_accessible_place(self, node_data.bed_type,
|
||||
npc.places.PLACE_TYPE.BED.PRIMARY)
|
||||
-- Store changes to node_data
|
||||
meta:set_string("node_data", minetest.serialize(node_data))
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--local plot_info = minetest.deserialize(meta:get_string("plot_info"))
|
||||
--minetest.log("Plot info:"..dump(plot_info))
|
||||
-- Assign sits
|
||||
if #node_data.sittable_type > 0 then
|
||||
-- Check if there are same or more amount of sits as beds
|
||||
if #node_data.sittable_type >= #node_data.bed_type then
|
||||
-- Assign a specific sittable node to a NPC.
|
||||
npc.places.add_unowned_accessible_place(self, node_data.sittable_type,
|
||||
npc.places.PLACE_TYPE.SITTABLE.PRIMARY)
|
||||
-- Store changes to node_data
|
||||
meta:set_string("node_data", minetest.serialize(node_data))
|
||||
end
|
||||
-- Add all sits to places as shared since NPC should be able to sit
|
||||
-- at any accessible sit
|
||||
npc.places.add_shared_accessible_place(self, node_data.sittable_type,
|
||||
npc.places.PLACE_TYPE.SITTABLE.SHARED)
|
||||
end
|
||||
|
||||
-- Assign furnaces
|
||||
if #node_data.furnace_type > 0 then
|
||||
-- Check if there are same or more amount of furnace as beds
|
||||
if #node_data.furnace_type >= #node_data.bed_type then
|
||||
-- Assign a specific furnace node to a NPC.
|
||||
npc.places.add_unowned_accessible_place(self, node_data.furnace_type,
|
||||
npc.places.PLACE_TYPE.FURNACE.PRIMARY)
|
||||
-- Store changes to node_data
|
||||
meta:set_string("node_data", minetest.serialize(node_data))
|
||||
end
|
||||
-- Add all furnaces to places as shared since NPC should be able to use
|
||||
-- any accessible furnace
|
||||
npc.places.add_shared_accessible_place(self, node_data.furnace_type,
|
||||
npc.places.PLACE_TYPE.FURNACE.SHARED)
|
||||
end
|
||||
|
||||
-- Assign storage nodes
|
||||
if #node_data.storage_type > 0 then
|
||||
-- Check if there are same or more amount of storage as beds
|
||||
if #node_data.storage_type >= #node_data.bed_type then
|
||||
-- Assign a specific storage node to a NPC.
|
||||
npc.places.add_unowned_accessible_place(self, node_data.storage_type,
|
||||
npc.places.PLACE_TYPE.STORAGE.PRIMARY)
|
||||
-- Store changes to node_data
|
||||
meta:set_string("node_data", minetest.serialize(node_data))
|
||||
end
|
||||
-- Add all storage-types to places as shared since NPC should be able
|
||||
-- to use other storage nodes as well.
|
||||
npc.places.add_shared_accessible_place(self, node_data.storage_type,
|
||||
npc.places.PLACE_TYPE.STORAGE.SHARED)
|
||||
end
|
||||
|
||||
npc.log("DEBUG", "Places for NPC "..self.npc_name..": "..dump(self.places_map))
|
||||
|
||||
-- Make NPC go into their house
|
||||
@ -253,8 +338,14 @@ function spawner.assign_schedules(self, pos)
|
||||
-- Add schedule entry for morning actions
|
||||
npc.add_schedule_entry(self, npc.schedule_types.generic, 0, 8, nil, basic_schedule.morning_actions)
|
||||
|
||||
-- Add schedule entry for noon actions
|
||||
npc.add_schedule_entry(self, npc.schedule_types.generic, 0, 12, nil, basic_schedule.noon_actions)
|
||||
|
||||
-- Add schedule entry for afternoon actions
|
||||
npc.add_schedule_entry(self, npc.schedule_types.generic, 0, 18, nil, basic_schedule.afternoon_actions)
|
||||
npc.add_schedule_entry(self, npc.schedule_types.generic, 0, 13, nil, basic_schedule.afternoon_actions)
|
||||
|
||||
-- Add schedule entry for late afternoon actions
|
||||
npc.add_schedule_entry(self, npc.schedule_types.generic, 0, 18, nil, basic_schedule.late_afternoon_actions)
|
||||
|
||||
-- Add schedule entry for evening actions
|
||||
npc.add_schedule_entry(self, npc.schedule_types.generic, 0, 22, nil, basic_schedule.evening_actions)
|
||||
@ -348,17 +439,15 @@ end
|
||||
|
||||
-- This function takes care of calculating how many NPCs will be spawn
|
||||
function spawner.calculate_npc_spawning(pos)
|
||||
-- Check node
|
||||
local node = minetest.get_node(pos)
|
||||
if node.name ~= "advanced_npc:plotmarker_auto_spawner" then
|
||||
return
|
||||
end
|
||||
-- Check node metadata
|
||||
local meta = minetest.get_meta(pos)
|
||||
if meta:get_string("replaced") ~= "true" then
|
||||
return
|
||||
end
|
||||
-- Get nodes for this building
|
||||
local node_data = minetest.deserialize(meta:get_string("node_data"))
|
||||
if node_data == nil then
|
||||
npc.log("ERROR", "Mis-configured advanced_npc:plotmarker_auto_spawner at position: "..minetest.pos_to_string(pos))
|
||||
npc.log("ERROR", "Mis-configured mg_villages:plotmarker at position: "..minetest.pos_to_string(pos))
|
||||
return
|
||||
end
|
||||
-- Check number of beds
|
||||
@ -463,15 +552,16 @@ end
|
||||
-- Also, the building is scanned for NPC-usable nodes and the amount
|
||||
-- of NPCs to spawn and the interval is calculated.
|
||||
function spawner.replace_mg_villages_plotmarker(pos)
|
||||
-- Check if it is already replaced
|
||||
-- if minetest.get_node(pos).name == "advanced_npc:plotmarker_auto_spawner" then
|
||||
-- return
|
||||
-- end
|
||||
-- Get the meta at the current position
|
||||
local meta = minetest.get_meta(pos)
|
||||
local village_id = meta:get_string("village_id")
|
||||
local plot_nr = meta:get_int("plot_nr")
|
||||
local infotext = meta:get_string("infotext")
|
||||
-- Check for nil values above
|
||||
if (not village_id or (village and village == ""))
|
||||
or (not plot_nr or (plot_nr and plot_nr == 0)) then
|
||||
return
|
||||
end
|
||||
-- Following line from mg_villages mod, protection.lua
|
||||
local btype = mg_villages.all_villages[village_id].to_add_data.bpos[plot_nr].btype
|
||||
local building_data = mg_villages.BUILDINGS[btype]
|
||||
@ -483,7 +573,7 @@ function spawner.replace_mg_villages_plotmarker(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"})
|
||||
--minetest.set_node(pos, {name="advanced_npc:plotmarker_auto_spawner"})
|
||||
-- Store old plotmarker metadata again
|
||||
meta:set_string("village_id", village_id)
|
||||
meta:set_int("plot_nr", plot_nr)
|
||||
@ -531,9 +621,10 @@ function spawner.replace_mg_villages_plotmarker(pos)
|
||||
meta:set_string("npc_stats", minetest.serialize(npc_stats))
|
||||
-- Set replaced
|
||||
meta:set_string("replaced", "true")
|
||||
-- Calculate how many NPCs will spawn
|
||||
spawner.calculate_npc_spawning(pos)
|
||||
-- Stop searching for building type
|
||||
break
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -545,19 +636,19 @@ if minetest.get_modpath("mg_villages") ~= nil then
|
||||
-- Node registration
|
||||
-- This node is currently a slightly modified mg_villages:plotmarker
|
||||
-- TODO: Change formspec to a more detailed one.
|
||||
minetest.register_node("advanced_npc:plotmarker_auto_spawner", {
|
||||
description = "Automatic NPC Spawner",
|
||||
drawtype = "nodebox",
|
||||
tiles = {"default_stone.png"},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5+2/16, -0.5, -0.5+2/16, 0.5-2/16, -0.5+2/16, 0.5-2/16},
|
||||
--{-0.5+0/16, -0.5, -0.5+0/16, 0.5-0/16, -0.5+0/16, 0.5-0/16},
|
||||
}
|
||||
},
|
||||
minetest.override_item("mg_villages:plotmarker", {
|
||||
-- description = "Automatic NPC Spawner",
|
||||
-- drawtype = "nodebox",
|
||||
-- tiles = {"default_stone.png"},
|
||||
-- paramtype = "light",
|
||||
-- paramtype2 = "facedir",
|
||||
-- node_box = {
|
||||
-- type = "fixed",
|
||||
-- fixed = {
|
||||
-- {-0.5+2/16, -0.5, -0.5+2/16, 0.5-2/16, -0.5+2/16, 0.5-2/16},
|
||||
-- --{-0.5+0/16, -0.5, -0.5+0/16, 0.5-0/16, -0.5+0/16, 0.5-0/16},
|
||||
-- }
|
||||
-- },
|
||||
walkable = false,
|
||||
groups = {cracky=3,stone=2},
|
||||
|
||||
@ -569,7 +660,7 @@ if minetest.get_modpath("mg_villages") ~= nil then
|
||||
--minetest.log("First-floor beds: "..dump(spawner.filter_first_floor_nodes(nodedata.bed_type, pos)))
|
||||
--local entrance = npc.places.find_entrance_from_openable_nodes(nodedata.openable_type, pos)
|
||||
--minetest.log("Found entrance: "..dump(entrance))
|
||||
|
||||
minetest.log("Replaced: "..dump(minetest.get_meta(pos):get_string("replaced")))
|
||||
-- for i = 1, #nodedata.bed_type do
|
||||
-- nodedata.bed_type[i].owner = ""
|
||||
-- end
|
||||
@ -580,22 +671,22 @@ if minetest.get_modpath("mg_villages") ~= nil then
|
||||
return mg_villages.plotmarker_formspec( pos, nil, {}, clicker )
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, sender)
|
||||
return mg_villages.plotmarker_formspec( pos, formname, fields, sender );
|
||||
end,
|
||||
-- on_receive_fields = function(pos, formname, fields, sender)
|
||||
-- return mg_villages.plotmarker_formspec( pos, formname, fields, sender );
|
||||
-- end,
|
||||
|
||||
on_timer = function(pos, elapsed)
|
||||
npc.spawner.spawn_npc(pos)
|
||||
end,
|
||||
|
||||
-- protect against digging
|
||||
can_dig = function(pos, player)
|
||||
local meta = minetest.get_meta(pos);
|
||||
if (meta and meta:get_string("village_id") ~= "" and meta:get_int("plot_nr") and meta:get_int("plot_nr") > 0 ) then
|
||||
return false;
|
||||
end
|
||||
return true;
|
||||
end
|
||||
-- can_dig = function(pos, player)
|
||||
-- local meta = minetest.get_meta(pos);
|
||||
-- if (meta and meta:get_string("village_id") ~= "" and meta:get_int("plot_nr") and meta:get_int("plot_nr") > 0 ) then
|
||||
-- return false;
|
||||
-- end
|
||||
-- return true;
|
||||
-- end
|
||||
})
|
||||
|
||||
-- LBM Registration
|
||||
@ -621,7 +712,7 @@ if minetest.get_modpath("mg_villages") ~= nil then
|
||||
label = "Replace mg_villages:plotmarker with Advanced NPC auto spawners",
|
||||
nodenames = {"mg_villages:plotmarker"},
|
||||
interval = 10,--npc.spawner.replacement_interval,
|
||||
chance = 1, --5,
|
||||
chance = 1,--5,
|
||||
catch_up = true,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
-- Check if replacement is needed
|
||||
@ -632,14 +723,14 @@ if minetest.get_modpath("mg_villages") ~= nil then
|
||||
if npc.spawner.replace_activated then
|
||||
-- Replace mg_villages:plotmarker
|
||||
spawner.replace_mg_villages_plotmarker(pos)
|
||||
-- Set NPCs to spawn
|
||||
spawner.calculate_npc_spawning(pos)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
--minetest.register_alias_force("mg_villages:plotmarker", )
|
||||
|
||||
-- Chat commands to manage spawners
|
||||
minetest.register_chatcommand("restore_plotmarkers", {
|
||||
description = "Replaces all advanced_npc:plotmarker_auto_spawner with mg_villages:plotmarker in the specified radius.",
|
||||
@ -662,7 +753,7 @@ minetest.register_chatcommand("restore_plotmarkers", {
|
||||
local start_pos = {x=pos.x - radius, y=pos.y - radius, z=pos.z - radius}
|
||||
local end_pos = {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius}
|
||||
local nodes = minetest.find_nodes_in_area_under_air(start_pos, end_pos,
|
||||
{"advanced_npc:plotmarker_auto_spawner"})
|
||||
{"mg_villages:plotmarker"})
|
||||
-- Check if we have nodes to replace
|
||||
minetest.chat_send_player(name, "Found "..dump(#nodes).." nodes to replace...")
|
||||
if #nodes == 0 then
|
||||
@ -670,13 +761,10 @@ minetest.register_chatcommand("restore_plotmarkers", {
|
||||
end
|
||||
-- Replace all nodes
|
||||
for i = 1, #nodes do
|
||||
--minetest.log(dump(nodes[i]))
|
||||
local meta = minetest.get_meta(nodes[i])
|
||||
local village_id = meta:get_string("village_id")
|
||||
local plot_nr = meta:get_int("plot_nr")
|
||||
local infotext = meta:get_string("infotext")
|
||||
-- Replace node
|
||||
minetest.set_node(nodes[i], {name="mg_villages:plotmarker"})
|
||||
-- Set metadata
|
||||
meta = minetest.get_meta(nodes[i])
|
||||
meta:set_string("village_id", village_id)
|
||||
@ -686,6 +774,7 @@ minetest.register_chatcommand("restore_plotmarkers", {
|
||||
meta:set_string("node_data", nil)
|
||||
meta:set_string("npcs", nil)
|
||||
meta:set_string("npc_stats", nil)
|
||||
meta:set_string("replaced", "false")
|
||||
end
|
||||
minetest.chat_send_player(name, "Finished replacement of "..dump(#nodes).." auto-spawners successfully")
|
||||
end
|
||||
|
Reference in New Issue
Block a user