Spawner: Moved all spawning code to spawner.lua.
Started progress on node timer-based NPC spawning (WIP)
This commit is contained in:
parent
3649d5bc6a
commit
e937cc4ce4
489
npc.lua
489
npc.lua
@ -69,15 +69,6 @@ function npc.get_item_count(item_string)
|
|||||||
return ItemStack(item_string):get_count()
|
return ItemStack(item_string):get_count()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function initialize_inventory()
|
|
||||||
return {
|
|
||||||
[1] = "", [2] = "", [3] = "", [4] = "",
|
|
||||||
[5] = "", [6] = "", [7] = "", [8] = "",
|
|
||||||
[9] = "", [10] = "", [11] = "", [12] = "",
|
|
||||||
[13] = "", [14] = "", [15] = "", [16] = "",
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add an item to inventory. Returns true if add successful
|
-- Add an item to inventory. Returns true if add successful
|
||||||
-- These function can be used to give items to other NPCs
|
-- These function can be used to give items to other NPCs
|
||||||
-- given that the "self" variable can be any NPC
|
-- given that the "self" variable can be any NPC
|
||||||
@ -463,287 +454,6 @@ function npc.delete_schedule_entry(self, schedule_type, date, time)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---------------------------------------------------------------------------------------
|
|
||||||
-- Spawning functions
|
|
||||||
---------------------------------------------------------------------------------------
|
|
||||||
-- These functions are used at spawn time to determine several
|
|
||||||
-- random attributes for the NPC in case they are not already
|
|
||||||
-- defined. On a later phase, pre-defining many of the NPC values
|
|
||||||
-- will be allowed.
|
|
||||||
|
|
||||||
-- This function checks for "female" text on the texture name
|
|
||||||
local function is_female_texture(textures)
|
|
||||||
for i = 1, #textures do
|
|
||||||
if string.find(textures[i], "female") ~= nil then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Choose whether NPC can have relationships. Only 30% of NPCs cannot have relationships
|
|
||||||
local function can_have_relationships()
|
|
||||||
local chance = math.random(1,10)
|
|
||||||
return chance > 3
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Choose a maximum of two items that the NPC will have at spawn time
|
|
||||||
-- These items are chosen from the favorite items list.
|
|
||||||
local function choose_spawn_items(self)
|
|
||||||
local number_of_items_to_add = math.random(1, 2)
|
|
||||||
local number_of_items = #npc.FAVORITE_ITEMS[self.sex].phase1
|
|
||||||
|
|
||||||
for i = 1, number_of_items_to_add do
|
|
||||||
npc.add_item_to_inventory(
|
|
||||||
self,
|
|
||||||
npc.FAVORITE_ITEMS[self.sex].phase1[math.random(1, number_of_items)].item,
|
|
||||||
math.random(1,5)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
-- Add currency to the items spawned with. Will add 5-10 tier 3
|
|
||||||
-- currency items
|
|
||||||
local currency_item_count = math.random(5, 10)
|
|
||||||
npc.add_item_to_inventory(self, npc.trade.prices.currency.tier3.string, currency_item_count)
|
|
||||||
|
|
||||||
-- For test
|
|
||||||
npc.add_item_to_inventory(self, "default:tree", 10)
|
|
||||||
npc.add_item_to_inventory(self, "default:cobble", 10)
|
|
||||||
npc.add_item_to_inventory(self, "default:diamond", 2)
|
|
||||||
npc.add_item_to_inventory(self, "default:mese_crystal", 2)
|
|
||||||
npc.add_item_to_inventory(self, "flowers:rose", 2)
|
|
||||||
npc.add_item_to_inventory(self, "advanced_npc:marriage_ring", 2)
|
|
||||||
npc.add_item_to_inventory(self, "flowers:geranium", 2)
|
|
||||||
npc.add_item_to_inventory(self, "mobs:meat", 2)
|
|
||||||
npc.add_item_to_inventory(self, "mobs:leather", 2)
|
|
||||||
npc.add_item_to_inventory(self, "default:sword_stone", 2)
|
|
||||||
npc.add_item_to_inventory(self, "default:shovel_stone", 2)
|
|
||||||
npc.add_item_to_inventory(self, "default:axe_stone", 2)
|
|
||||||
|
|
||||||
minetest.log("Initial inventory: "..dump(self.inventory))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Spawn function. Initializes all variables that the
|
|
||||||
-- NPC will have and choose random, starting values
|
|
||||||
local function npc_spawn(self, pos)
|
|
||||||
minetest.log("Spawning new NPC:")
|
|
||||||
|
|
||||||
-- Get Lua Entity
|
|
||||||
local ent = self:get_luaentity()
|
|
||||||
|
|
||||||
-- Avoid NPC to be removed by mobs_redo API
|
|
||||||
ent.remove_ok = false
|
|
||||||
|
|
||||||
-- Set name
|
|
||||||
ent.nametag = "Kio"
|
|
||||||
|
|
||||||
-- Set ID
|
|
||||||
ent.npc_id = tostring(math.random(1000, 9999))..":"..ent.nametag
|
|
||||||
|
|
||||||
-- Determine sex based on textures
|
|
||||||
if (is_female_texture(ent.base_texture)) then
|
|
||||||
ent.sex = npc.FEMALE
|
|
||||||
else
|
|
||||||
ent.sex = npc.MALE
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Initialize all gift data
|
|
||||||
ent.gift_data = {
|
|
||||||
-- Choose favorite items. Choose phase1 per default
|
|
||||||
favorite_items = npc.relationships.select_random_favorite_items(ent.sex, "phase1"),
|
|
||||||
-- Choose disliked items. Choose phase1 per default
|
|
||||||
disliked_items = npc.relationships.select_random_disliked_items(ent.sex),
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Flag that determines if NPC can have a relationship
|
|
||||||
ent.can_have_relationship = can_have_relationships()
|
|
||||||
|
|
||||||
-- Initialize relationships object
|
|
||||||
ent.relationships = {}
|
|
||||||
|
|
||||||
-- Determines if NPC is married or not
|
|
||||||
ent.is_married_to = nil
|
|
||||||
|
|
||||||
-- Initialize dialogues
|
|
||||||
ent.dialogues = npc.dialogue.select_random_dialogues_for_npc(ent.sex,
|
|
||||||
"phase1",
|
|
||||||
ent.gift_data.favorite_items,
|
|
||||||
ent.gift_data.disliked_items)
|
|
||||||
|
|
||||||
-- Declare NPC inventory
|
|
||||||
ent.inventory = initialize_inventory()
|
|
||||||
|
|
||||||
-- Choose items to spawn with
|
|
||||||
choose_spawn_items(ent)
|
|
||||||
|
|
||||||
-- Flags: generic booleans or functions that help drive functionality
|
|
||||||
ent.flags = {}
|
|
||||||
|
|
||||||
-- Declare trade data
|
|
||||||
ent.trader_data = {
|
|
||||||
-- Type of trader
|
|
||||||
trader_status = npc.trade.get_random_trade_status(),
|
|
||||||
-- Current buy offers
|
|
||||||
buy_offers = {},
|
|
||||||
-- Current sell offers
|
|
||||||
sell_offers = {},
|
|
||||||
-- Items to buy change timer
|
|
||||||
change_offers_timer = 0,
|
|
||||||
-- Items to buy change timer interval
|
|
||||||
change_offers_timer_interval = 60,
|
|
||||||
-- Trading list: a list of item names the trader is expected to trade in.
|
|
||||||
-- It is mostly related to its occupation.
|
|
||||||
-- If empty, the NPC will revert to casual trading
|
|
||||||
-- If not, it will try to sell those that it have, and buy the ones it not.
|
|
||||||
trade_list = {
|
|
||||||
sell = {},
|
|
||||||
buy = {},
|
|
||||||
both = {}
|
|
||||||
},
|
|
||||||
-- Custom trade allows to specify more than one payment
|
|
||||||
-- and a custom prompt (instead of the usual buy or sell prompts)
|
|
||||||
custom_trades = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Initialize trading offers for NPC
|
|
||||||
--npc.trade.generate_trade_offers_by_status(ent)
|
|
||||||
-- if ent.trader_data.trader_status == npc.trade.CASUAL then
|
|
||||||
-- select_casual_trade_offers(ent)
|
|
||||||
-- end
|
|
||||||
|
|
||||||
-- Actions data
|
|
||||||
ent.actions = {
|
|
||||||
-- The queue is a queue of actions to be performed on each interval
|
|
||||||
queue = {},
|
|
||||||
-- Current value of the action timer
|
|
||||||
action_timer = 0,
|
|
||||||
-- Determines the interval for each action in the action queue
|
|
||||||
-- Default is 1. This can be changed via actions
|
|
||||||
action_interval = 1,
|
|
||||||
-- Avoid the execution of the action timer
|
|
||||||
action_timer_lock = false,
|
|
||||||
-- Defines the state of the current action
|
|
||||||
current_action_state = npc.action_state.none,
|
|
||||||
-- Store information about action on state before lock
|
|
||||||
state_before_lock = {
|
|
||||||
-- State of the mobs_redo API
|
|
||||||
freeze = false,
|
|
||||||
-- State of execution
|
|
||||||
action_state = npc.action_state.none,
|
|
||||||
-- Action executed while on lock
|
|
||||||
interrupted_action = {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- This flag is checked on every step. If it is true, the rest of
|
|
||||||
-- Mobs Redo API is not executed
|
|
||||||
ent.freeze = nil
|
|
||||||
|
|
||||||
-- This map will hold all the places for the NPC
|
|
||||||
-- Map entries should be like: "bed" = {x=1, y=1, z=1}
|
|
||||||
ent.places_map = {}
|
|
||||||
|
|
||||||
-- Schedule data
|
|
||||||
ent.schedules = {
|
|
||||||
-- Flag to enable or disable the schedules functionality
|
|
||||||
enabled = true,
|
|
||||||
-- Lock for when executing a schedule
|
|
||||||
lock = false,
|
|
||||||
-- An array of schedules, meant to be one per day at some point
|
|
||||||
-- when calendars are implemented. Allows for only 7 schedules,
|
|
||||||
-- one for each day of the week
|
|
||||||
generic = {},
|
|
||||||
-- An array of schedules, meant to be for specific dates in the
|
|
||||||
-- year. Can contain as many as possible. The keys will be strings
|
|
||||||
-- in the format MM:DD
|
|
||||||
date_based = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Temporary initialization of actions for testing
|
|
||||||
local nodes = npc.places.find_node_nearby(ent.object:getpos(), {"cottages:bench"}, 20)
|
|
||||||
minetest.log("Found nodes: "..dump(nodes))
|
|
||||||
|
|
||||||
--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
|
|
||||||
ent.trader_data.trade_list.both = {
|
|
||||||
["default:tree"] = {},
|
|
||||||
["default:cobble"] = {},
|
|
||||||
["default:wood"] = {},
|
|
||||||
["default:diamond"] = {},
|
|
||||||
["default:mese_crystal"] = {},
|
|
||||||
["flowers:rose"] = {},
|
|
||||||
["advanced_npc:marriage_ring"] = {},
|
|
||||||
["flowers:geranium"] = {},
|
|
||||||
["mobs:meat"] = {},
|
|
||||||
["mobs:leather"] = {},
|
|
||||||
["default:sword_stone"] = {},
|
|
||||||
["default:shovel_stone"] = {},
|
|
||||||
["default:axe_stone"] = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
npc.trade.generate_trade_offers_by_status(ent)
|
|
||||||
|
|
||||||
-- Add a custom trade offer
|
|
||||||
local offer1 = npc.trade.create_custom_sell_trade_offer("Do you want me to fix your steel sword?", "Fix steel sword", "Fix steel sword", "default:sword_steel", {"default:sword_steel", "default:iron_lump 5"})
|
|
||||||
table.insert(ent.trader_data.custom_trades, offer1)
|
|
||||||
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)
|
|
||||||
|
|
||||||
-- Add a simple schedule for testing
|
|
||||||
npc.create_schedule(ent, npc.schedule_types.generic, 0)
|
|
||||||
-- Add schedule entries
|
|
||||||
local morning_actions = {
|
|
||||||
[1] = {task = npc.actions.walk_to_pos, args = {end_pos=nodes[1], walkable={}} } ,
|
|
||||||
[2] = {task = npc.actions.use_sittable, args = {pos=nodes[1], action=npc.actions.const.sittable.SIT} },
|
|
||||||
[3] = {action = npc.actions.freeze, args = {freeze = true}}
|
|
||||||
}
|
|
||||||
npc.add_schedule_entry(ent, npc.schedule_types.generic, 0, 7, nil, morning_actions)
|
|
||||||
local afternoon_actions = { [1] = {action = npc.actions.stand, args = {}} }
|
|
||||||
npc.add_schedule_entry(ent, npc.schedule_types.generic, 0, 9, nil, afternoon_actions)
|
|
||||||
-- local night_actions = {action: npc.action, args: {}}
|
|
||||||
-- npc.add_schedule_entry(self, npc.schedule_type.generic, 0, 19, check, actions)
|
|
||||||
|
|
||||||
-- npc.add_action(ent, npc.action.stand, {self = ent})
|
|
||||||
-- npc.add_action(ent, npc.action.stand, {self = ent})
|
|
||||||
-- npc.add_action(ent, npc.action.walk_step, {self = ent, dir = npc.direction.east})
|
|
||||||
-- npc.add_action(ent, npc.action.walk_step, {self = ent, dir = npc.direction.east})
|
|
||||||
-- npc.add_action(ent, npc.action.walk_step, {self = ent, dir = npc.direction.east})
|
|
||||||
-- npc.add_action(ent, npc.action.walk_step, {self = ent, dir = npc.direction.east})
|
|
||||||
-- npc.add_action(ent, npc.action.walk_step, {self = ent, dir = npc.direction.east})
|
|
||||||
-- npc.add_action(ent, npc.action.walk_step, {self = ent, dir = npc.direction.east})
|
|
||||||
-- npc.add_action(ent, npc.action.sit, {self = ent})
|
|
||||||
-- npc.add_action(ent, npc.action.rotate, {self = ent, dir = npc.direction.south})
|
|
||||||
-- npc.add_action(ent, npc.action.lay, {self = ent})
|
|
||||||
|
|
||||||
-- 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))
|
|
||||||
|
|
||||||
-- Refreshes entity
|
|
||||||
ent.object:set_properties(ent)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------
|
||||||
-- NPC Definition
|
-- NPC Definition
|
||||||
---------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------
|
||||||
@ -846,132 +556,139 @@ mobs:register_mob("advanced_npc:npc", {
|
|||||||
end,
|
end,
|
||||||
do_custom = function(self, dtime)
|
do_custom = function(self, dtime)
|
||||||
|
|
||||||
-- Timer function for casual traders to reset their trade offers
|
if self.trader_data ~= nil then
|
||||||
self.trader_data.change_offers_timer = self.trader_data.change_offers_timer + dtime
|
-- Timer function for casual traders to reset their trade offers
|
||||||
-- Check if time has come to change offers
|
self.trader_data.change_offers_timer = self.trader_data.change_offers_timer + dtime
|
||||||
if self.trader_data.trader_status == npc.trade.CASUAL and
|
-- Check if time has come to change offers
|
||||||
self.trader_data.change_offers_timer >= self.trader_data.change_offers_timer_interval then
|
if self.trader_data.trader_status == npc.trade.CASUAL and
|
||||||
-- Reset timer
|
self.trader_data.change_offers_timer >= self.trader_data.change_offers_timer_interval then
|
||||||
self.trader_data.change_offers_timer = 0
|
-- Reset timer
|
||||||
-- Re-select casual trade offers
|
self.trader_data.change_offers_timer = 0
|
||||||
npc.trade.generate_trade_offers_by_status(self)
|
-- Re-select casual trade offers
|
||||||
|
npc.trade.generate_trade_offers_by_status(self)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Timer function for gifts
|
if self.relationships ~= nil then
|
||||||
for i = 1, #self.relationships do
|
-- Timer function for gifts
|
||||||
local relationship = self.relationships[i]
|
for i = 1, #self.relationships do
|
||||||
-- Gift timer check
|
local relationship = self.relationships[i]
|
||||||
if relationship.gift_timer_value < relationship.gift_interval then
|
-- Gift timer check
|
||||||
relationship.gift_timer_value = relationship.gift_timer_value + dtime
|
if relationship.gift_timer_value < relationship.gift_interval then
|
||||||
elseif relationship.talk_timer_value < relationship.gift_interval then
|
relationship.gift_timer_value = relationship.gift_timer_value + dtime
|
||||||
-- Relationship talk timer - only allows players to increase relationship
|
elseif relationship.talk_timer_value < relationship.gift_interval then
|
||||||
-- by talking on the same intervals as gifts
|
-- Relationship talk timer - only allows players to increase relationship
|
||||||
relationship.talk_timer_value = relationship.talk_timer_value + dtime
|
-- by talking on the same intervals as gifts
|
||||||
else
|
relationship.talk_timer_value = relationship.talk_timer_value + dtime
|
||||||
-- Relationship decrease timer
|
|
||||||
if relationship.relationship_decrease_timer_value
|
|
||||||
< relationship.relationship_decrease_interval then
|
|
||||||
relationship.relationship_decrease_timer_value =
|
|
||||||
relationship.relationship_decrease_timer_value + dtime
|
|
||||||
else
|
else
|
||||||
-- Check if married to decrease half
|
-- Relationship decrease timer
|
||||||
if relationship.phase == "phase6" then
|
if relationship.relationship_decrease_timer_value
|
||||||
-- Avoid going below the marriage phase limit
|
< relationship.relationship_decrease_interval then
|
||||||
if (relationship.points - 0.5) >=
|
relationship.relationship_decrease_timer_value =
|
||||||
npc.relationships.RELATIONSHIP_PHASE["phase5"].limit then
|
relationship.relationship_decrease_timer_value + dtime
|
||||||
relationship.points = relationship.points - 0.5
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
relationship.points = relationship.points - 1
|
-- Check if married to decrease half
|
||||||
|
if relationship.phase == "phase6" then
|
||||||
|
-- Avoid going below the marriage phase limit
|
||||||
|
if (relationship.points - 0.5) >=
|
||||||
|
npc.relationships.RELATIONSHIP_PHASE["phase5"].limit then
|
||||||
|
relationship.points = relationship.points - 0.5
|
||||||
|
end
|
||||||
|
else
|
||||||
|
relationship.points = relationship.points - 1
|
||||||
|
end
|
||||||
|
relationship.relationship_decrease_timer_value = 0
|
||||||
|
--minetest.log(dump(self))
|
||||||
end
|
end
|
||||||
relationship.relationship_decrease_timer_value = 0
|
|
||||||
--minetest.log(dump(self))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Action queue timer
|
-- Action queue timer
|
||||||
-- Check if actions and timers aren't locked
|
-- Check if actions and timers aren't locked
|
||||||
if self.actions.action_timer_lock == false then
|
if self.actions ~= nil then
|
||||||
-- Increment action timer
|
if self.actions.action_timer_lock == false then
|
||||||
self.actions.action_timer = self.actions.action_timer + dtime
|
-- Increment action timer
|
||||||
if self.actions.action_timer >= self.actions.action_interval then
|
self.actions.action_timer = self.actions.action_timer + dtime
|
||||||
-- Reset action timer
|
if self.actions.action_timer >= self.actions.action_interval then
|
||||||
self.actions.action_timer = 0
|
-- Reset action timer
|
||||||
-- Execute action
|
self.actions.action_timer = 0
|
||||||
self.freeze = npc.execute_action(self)
|
-- Execute action
|
||||||
-- Check if there are still remaining actions in the queue
|
self.freeze = npc.execute_action(self)
|
||||||
if self.freeze == nil and table.getn(self.actions.queue) > 0 then
|
-- Check if there are still remaining actions in the queue
|
||||||
self.freeze = false
|
if self.freeze == nil and table.getn(self.actions.queue) > 0 then
|
||||||
|
self.freeze = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
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 ~= nil then
|
||||||
-- Get time of day
|
if self.schedules.enabled == true then
|
||||||
local time = get_time_in_hours()
|
-- Get time of day
|
||||||
-- Check if time is an hour
|
local time = get_time_in_hours()
|
||||||
if time % 1 < 0.1 and self.schedules.lock == false then
|
-- Check if time is an hour
|
||||||
-- Activate lock to avoid more than one entry to this code
|
if time % 1 < 0.1 and self.schedules.lock == false then
|
||||||
self.schedules.lock = true
|
-- Activate lock to avoid more than one entry to this code
|
||||||
-- Get integer part of time
|
self.schedules.lock = true
|
||||||
time = (time) - (time % 1)
|
-- Get integer part of time
|
||||||
-- Check if there is a schedule entry for this time
|
time = (time) - (time % 1)
|
||||||
-- Note: Currently only one schedule is supported, for day 0
|
-- Check if there is a schedule entry for this time
|
||||||
minetest.log("Time: "..dump(time))
|
-- Note: Currently only one schedule is supported, for day 0
|
||||||
local schedule = self.schedules.generic[0]
|
minetest.log("Time: "..dump(time))
|
||||||
if schedule ~= nil then
|
local schedule = self.schedules.generic[0]
|
||||||
-- Check if schedule for this time exists
|
if schedule ~= nil then
|
||||||
minetest.log("Found default schedule")
|
-- Check if schedule for this time exists
|
||||||
if schedule[time] ~= nil then
|
minetest.log("Found default schedule")
|
||||||
-- Check if schedule has a check function
|
if schedule[time] ~= nil then
|
||||||
if schedule[time].check ~= nil then
|
-- Check if schedule has a check function
|
||||||
-- Execute check function and then add corresponding action
|
if schedule[time].check ~= nil then
|
||||||
-- to action queue. This is for jobs.
|
-- Execute check function and then add corresponding action
|
||||||
-- TODO: Need to implement
|
-- to action queue. This is for jobs.
|
||||||
else
|
-- TODO: Need to implement
|
||||||
minetest.log("Adding actions to action queue")
|
else
|
||||||
-- Add to action queue all actions on schedule
|
minetest.log("Adding actions to action queue")
|
||||||
for i = 1, #schedule[time] do
|
-- Add to action queue all actions on schedule
|
||||||
if schedule[time][i].action == nil then
|
for i = 1, #schedule[time] do
|
||||||
-- Add task
|
if schedule[time][i].action == nil then
|
||||||
npc.add_task(self, schedule[time][i].task, schedule[time][i].args)
|
-- Add task
|
||||||
else
|
npc.add_task(self, schedule[time][i].task, schedule[time][i].args)
|
||||||
-- Add action
|
else
|
||||||
npc.add_action(self, schedule[time][i].action, schedule[time][i].args)
|
-- Add action
|
||||||
|
npc.add_action(self, schedule[time][i].action, schedule[time][i].args)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
minetest.log("New action queue: "..dump(self.actions))
|
||||||
end
|
end
|
||||||
minetest.log("New action queue: "..dump(self.actions))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
else
|
||||||
else
|
-- Check if lock can be released
|
||||||
-- Check if lock can be released
|
if time % 1 > 0.1 then
|
||||||
if time % 1 > 0.1 then
|
-- Release lock
|
||||||
-- Release lock
|
self.schedules.lock = false
|
||||||
self.schedules.lock = false
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
return self.freeze
|
return self.freeze
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
-- Spawn
|
-- Spawn
|
||||||
mobs:spawn({
|
-- mobs:spawn({
|
||||||
name = "advanced_npc:npc",
|
-- name = "advanced_npc:npc",
|
||||||
nodes = {"mg_villages:plotmarker"},
|
-- nodes = {"mg_villages:plotmarker"},
|
||||||
min_light = 3,
|
-- min_light = 3,
|
||||||
active_object_count = 1,
|
-- active_object_count = 1,
|
||||||
interval = 5,
|
-- interval = 5,
|
||||||
chance = 1,
|
-- chance = 1,
|
||||||
--max_height = 0,
|
-- --max_height = 0,
|
||||||
on_spawn = npc_spawn,
|
-- on_spawn = npc_spawn,
|
||||||
})
|
-- })
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
-- Item definitions
|
-- Item definitions
|
||||||
|
417
spawner.lua
417
spawner.lua
@ -53,9 +53,300 @@ npc.spawner.mg_villages_supported_building_types = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
npc.spawner.replace_activated = true
|
npc.spawner.replace_activated = true
|
||||||
|
npc.spawn_delay = 5
|
||||||
-- npc.spawner.max_replace_count = 1
|
-- npc.spawner.max_replace_count = 1
|
||||||
-- spawner.replace_count = 0
|
-- spawner.replace_count = 0
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------------------
|
||||||
|
-- Spawning functions
|
||||||
|
---------------------------------------------------------------------------------------
|
||||||
|
-- These functions are used at spawn time to determine several
|
||||||
|
-- random attributes for the NPC in case they are not already
|
||||||
|
-- defined. On a later phase, pre-defining many of the NPC values
|
||||||
|
-- will be allowed.
|
||||||
|
|
||||||
|
local function initialize_inventory()
|
||||||
|
return {
|
||||||
|
[1] = "", [2] = "", [3] = "", [4] = "",
|
||||||
|
[5] = "", [6] = "", [7] = "", [8] = "",
|
||||||
|
[9] = "", [10] = "", [11] = "", [12] = "",
|
||||||
|
[13] = "", [14] = "", [15] = "", [16] = "",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- This function checks for "female" text on the texture name
|
||||||
|
local function is_female_texture(textures)
|
||||||
|
for i = 1, #textures do
|
||||||
|
if string.find(textures[i], "female") ~= nil then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Choose whether NPC can have relationships. Only 30% of NPCs cannot have relationships
|
||||||
|
local function can_have_relationships()
|
||||||
|
local chance = math.random(1,10)
|
||||||
|
return chance > 3
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Choose a maximum of two items that the NPC will have at spawn time
|
||||||
|
-- These items are chosen from the favorite items list.
|
||||||
|
local function choose_spawn_items(self)
|
||||||
|
local number_of_items_to_add = math.random(1, 2)
|
||||||
|
local number_of_items = #npc.FAVORITE_ITEMS[self.sex].phase1
|
||||||
|
|
||||||
|
for i = 1, number_of_items_to_add do
|
||||||
|
npc.add_item_to_inventory(
|
||||||
|
self,
|
||||||
|
npc.FAVORITE_ITEMS[self.sex].phase1[math.random(1, number_of_items)].item,
|
||||||
|
math.random(1,5)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
-- Add currency to the items spawned with. Will add 5-10 tier 3
|
||||||
|
-- currency items
|
||||||
|
local currency_item_count = math.random(5, 10)
|
||||||
|
npc.add_item_to_inventory(self, npc.trade.prices.currency.tier3.string, currency_item_count)
|
||||||
|
|
||||||
|
-- For test
|
||||||
|
npc.add_item_to_inventory(self, "default:tree", 10)
|
||||||
|
npc.add_item_to_inventory(self, "default:cobble", 10)
|
||||||
|
npc.add_item_to_inventory(self, "default:diamond", 2)
|
||||||
|
npc.add_item_to_inventory(self, "default:mese_crystal", 2)
|
||||||
|
npc.add_item_to_inventory(self, "flowers:rose", 2)
|
||||||
|
npc.add_item_to_inventory(self, "advanced_npc:marriage_ring", 2)
|
||||||
|
npc.add_item_to_inventory(self, "flowers:geranium", 2)
|
||||||
|
npc.add_item_to_inventory(self, "mobs:meat", 2)
|
||||||
|
npc.add_item_to_inventory(self, "mobs:leather", 2)
|
||||||
|
npc.add_item_to_inventory(self, "default:sword_stone", 2)
|
||||||
|
npc.add_item_to_inventory(self, "default:shovel_stone", 2)
|
||||||
|
npc.add_item_to_inventory(self, "default:axe_stone", 2)
|
||||||
|
|
||||||
|
minetest.log("Initial inventory: "..dump(self.inventory))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Spawn function. Initializes all variables that the
|
||||||
|
-- NPC will have and choose random, starting values
|
||||||
|
local function spawn(entity, pos)
|
||||||
|
minetest.log("Spawning new NPC: "..dump(entity))
|
||||||
|
|
||||||
|
-- Get Lua Entity
|
||||||
|
local ent = entity:get_luaentity()
|
||||||
|
|
||||||
|
-- Avoid NPC to be removed by mobs_redo API
|
||||||
|
ent.remove_ok = false
|
||||||
|
|
||||||
|
-- Set name
|
||||||
|
ent.nametag = "Kio"
|
||||||
|
|
||||||
|
-- Set ID
|
||||||
|
ent.npc_id = tostring(math.random(1000, 9999))..":"..ent.nametag
|
||||||
|
|
||||||
|
-- Determine sex based on textures
|
||||||
|
if (is_female_texture(ent.base_texture)) then
|
||||||
|
ent.sex = npc.FEMALE
|
||||||
|
else
|
||||||
|
ent.sex = npc.MALE
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Initialize all gift data
|
||||||
|
ent.gift_data = {
|
||||||
|
-- Choose favorite items. Choose phase1 per default
|
||||||
|
favorite_items = npc.relationships.select_random_favorite_items(ent.sex, "phase1"),
|
||||||
|
-- Choose disliked items. Choose phase1 per default
|
||||||
|
disliked_items = npc.relationships.select_random_disliked_items(ent.sex),
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Flag that determines if NPC can have a relationship
|
||||||
|
ent.can_have_relationship = can_have_relationships()
|
||||||
|
|
||||||
|
-- Initialize relationships object
|
||||||
|
ent.relationships = {}
|
||||||
|
|
||||||
|
-- Determines if NPC is married or not
|
||||||
|
ent.is_married_to = nil
|
||||||
|
|
||||||
|
-- Initialize dialogues
|
||||||
|
ent.dialogues = npc.dialogue.select_random_dialogues_for_npc(ent.sex,
|
||||||
|
"phase1",
|
||||||
|
ent.gift_data.favorite_items,
|
||||||
|
ent.gift_data.disliked_items)
|
||||||
|
|
||||||
|
-- Declare NPC inventory
|
||||||
|
ent.inventory = initialize_inventory()
|
||||||
|
|
||||||
|
-- Choose items to spawn with
|
||||||
|
choose_spawn_items(ent)
|
||||||
|
|
||||||
|
-- Flags: generic booleans or functions that help drive functionality
|
||||||
|
ent.flags = {}
|
||||||
|
|
||||||
|
-- Declare trade data
|
||||||
|
ent.trader_data = {
|
||||||
|
-- Type of trader
|
||||||
|
trader_status = npc.trade.get_random_trade_status(),
|
||||||
|
-- Current buy offers
|
||||||
|
buy_offers = {},
|
||||||
|
-- Current sell offers
|
||||||
|
sell_offers = {},
|
||||||
|
-- Items to buy change timer
|
||||||
|
change_offers_timer = 0,
|
||||||
|
-- Items to buy change timer interval
|
||||||
|
change_offers_timer_interval = 60,
|
||||||
|
-- Trading list: a list of item names the trader is expected to trade in.
|
||||||
|
-- It is mostly related to its occupation.
|
||||||
|
-- If empty, the NPC will revert to casual trading
|
||||||
|
-- If not, it will try to sell those that it have, and buy the ones it not.
|
||||||
|
trade_list = {
|
||||||
|
sell = {},
|
||||||
|
buy = {},
|
||||||
|
both = {}
|
||||||
|
},
|
||||||
|
-- Custom trade allows to specify more than one payment
|
||||||
|
-- and a custom prompt (instead of the usual buy or sell prompts)
|
||||||
|
custom_trades = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Initialize trading offers for NPC
|
||||||
|
--npc.trade.generate_trade_offers_by_status(ent)
|
||||||
|
-- if ent.trader_data.trader_status == npc.trade.CASUAL then
|
||||||
|
-- select_casual_trade_offers(ent)
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- Actions data
|
||||||
|
ent.actions = {
|
||||||
|
-- The queue is a queue of actions to be performed on each interval
|
||||||
|
queue = {},
|
||||||
|
-- Current value of the action timer
|
||||||
|
action_timer = 0,
|
||||||
|
-- Determines the interval for each action in the action queue
|
||||||
|
-- Default is 1. This can be changed via actions
|
||||||
|
action_interval = 1,
|
||||||
|
-- Avoid the execution of the action timer
|
||||||
|
action_timer_lock = false,
|
||||||
|
-- Defines the state of the current action
|
||||||
|
current_action_state = npc.action_state.none,
|
||||||
|
-- Store information about action on state before lock
|
||||||
|
state_before_lock = {
|
||||||
|
-- State of the mobs_redo API
|
||||||
|
freeze = false,
|
||||||
|
-- State of execution
|
||||||
|
action_state = npc.action_state.none,
|
||||||
|
-- Action executed while on lock
|
||||||
|
interrupted_action = {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- This flag is checked on every step. If it is true, the rest of
|
||||||
|
-- Mobs Redo API is not executed
|
||||||
|
ent.freeze = nil
|
||||||
|
|
||||||
|
-- This map will hold all the places for the NPC
|
||||||
|
-- Map entries should be like: "bed" = {x=1, y=1, z=1}
|
||||||
|
ent.places_map = {}
|
||||||
|
|
||||||
|
-- Schedule data
|
||||||
|
ent.schedules = {
|
||||||
|
-- Flag to enable or disable the schedules functionality
|
||||||
|
enabled = true,
|
||||||
|
-- Lock for when executing a schedule
|
||||||
|
lock = false,
|
||||||
|
-- An array of schedules, meant to be one per day at some point
|
||||||
|
-- when calendars are implemented. Allows for only 7 schedules,
|
||||||
|
-- one for each day of the week
|
||||||
|
generic = {},
|
||||||
|
-- An array of schedules, meant to be for specific dates in the
|
||||||
|
-- year. Can contain as many as possible. The keys will be strings
|
||||||
|
-- in the format MM:DD
|
||||||
|
date_based = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Temporary initialization of actions for testing
|
||||||
|
local nodes = npc.places.find_node_nearby(ent.object:getpos(), {"cottages:bench"}, 20)
|
||||||
|
minetest.log("Found nodes: "..dump(nodes))
|
||||||
|
|
||||||
|
--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
|
||||||
|
ent.trader_data.trade_list.both = {
|
||||||
|
["default:tree"] = {},
|
||||||
|
["default:cobble"] = {},
|
||||||
|
["default:wood"] = {},
|
||||||
|
["default:diamond"] = {},
|
||||||
|
["default:mese_crystal"] = {},
|
||||||
|
["flowers:rose"] = {},
|
||||||
|
["advanced_npc:marriage_ring"] = {},
|
||||||
|
["flowers:geranium"] = {},
|
||||||
|
["mobs:meat"] = {},
|
||||||
|
["mobs:leather"] = {},
|
||||||
|
["default:sword_stone"] = {},
|
||||||
|
["default:shovel_stone"] = {},
|
||||||
|
["default:axe_stone"] = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
npc.trade.generate_trade_offers_by_status(ent)
|
||||||
|
|
||||||
|
-- Add a custom trade offer
|
||||||
|
local offer1 = npc.trade.create_custom_sell_trade_offer("Do you want me to fix your steel sword?", "Fix steel sword", "Fix steel sword", "default:sword_steel", {"default:sword_steel", "default:iron_lump 5"})
|
||||||
|
table.insert(ent.trader_data.custom_trades, offer1)
|
||||||
|
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)
|
||||||
|
|
||||||
|
-- Add a simple schedule for testing
|
||||||
|
npc.create_schedule(ent, npc.schedule_types.generic, 0)
|
||||||
|
-- Add schedule entries
|
||||||
|
local morning_actions = {
|
||||||
|
[1] = {task = npc.actions.walk_to_pos, args = {end_pos=nodes[1], walkable={}} } ,
|
||||||
|
[2] = {task = npc.actions.use_sittable, args = {pos=nodes[1], action=npc.actions.const.sittable.SIT} },
|
||||||
|
[3] = {action = npc.actions.freeze, args = {freeze = true}}
|
||||||
|
}
|
||||||
|
npc.add_schedule_entry(ent, npc.schedule_types.generic, 0, 7, nil, morning_actions)
|
||||||
|
local afternoon_actions = { [1] = {action = npc.actions.stand, args = {}} }
|
||||||
|
npc.add_schedule_entry(ent, npc.schedule_types.generic, 0, 9, nil, afternoon_actions)
|
||||||
|
-- local night_actions = {action: npc.action, args: {}}
|
||||||
|
-- npc.add_schedule_entry(self, npc.schedule_type.generic, 0, 19, check, actions)
|
||||||
|
|
||||||
|
-- npc.add_action(ent, npc.action.stand, {self = ent})
|
||||||
|
-- npc.add_action(ent, npc.action.stand, {self = ent})
|
||||||
|
-- npc.add_action(ent, npc.action.walk_step, {self = ent, dir = npc.direction.east})
|
||||||
|
-- npc.add_action(ent, npc.action.walk_step, {self = ent, dir = npc.direction.east})
|
||||||
|
-- npc.add_action(ent, npc.action.walk_step, {self = ent, dir = npc.direction.east})
|
||||||
|
-- npc.add_action(ent, npc.action.walk_step, {self = ent, dir = npc.direction.east})
|
||||||
|
-- npc.add_action(ent, npc.action.walk_step, {self = ent, dir = npc.direction.east})
|
||||||
|
-- npc.add_action(ent, npc.action.walk_step, {self = ent, dir = npc.direction.east})
|
||||||
|
-- npc.add_action(ent, npc.action.sit, {self = ent})
|
||||||
|
-- npc.add_action(ent, npc.action.rotate, {self = ent, dir = npc.direction.south})
|
||||||
|
-- npc.add_action(ent, npc.action.lay, {self = ent})
|
||||||
|
|
||||||
|
-- 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))
|
||||||
|
|
||||||
|
-- Refreshes entity
|
||||||
|
ent.object:set_properties(ent)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------
|
||||||
-- Scanning functions
|
-- Scanning functions
|
||||||
---------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------
|
||||||
@ -85,11 +376,70 @@ function spawner.scan_area(start_pos, end_pos)
|
|||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- This function is called when the node timer for spawning NPC
|
||||||
|
-- is expired
|
||||||
|
function npc.spawner.spawn_npc(pos)
|
||||||
|
-- Get timer
|
||||||
|
local timer = minetest.get_node_timer(pos)
|
||||||
|
-- Get metadata
|
||||||
|
local meta = minetest.get_meta(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("Currently spawned "..dump(spawned_npc_count).." of "..dump(npc_count).." NPCs")
|
||||||
|
if spawned_npc_count < npc_count then
|
||||||
|
-- Spawn a NPC
|
||||||
|
local npc = minetest.add_entity(pos, "advanced_npc:npc")
|
||||||
|
if npc and npc:get_luaentity() then
|
||||||
|
spawn(npc, pos)
|
||||||
|
-- Increase NPC spawned count
|
||||||
|
spawned_npc_count = spawned_npc_count + 1
|
||||||
|
-- Store count into node
|
||||||
|
meta:set_int("spawned_npc_count", spawned_npc_count)
|
||||||
|
-- Check if there are more NPCs to spawn
|
||||||
|
if spawned_npc_count >= npc_count then
|
||||||
|
-- Stop timer
|
||||||
|
timer:stop()
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
npc:remove()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
-- This function takes care of calculating how many NPCs will be spawn
|
-- This function takes care of calculating how many NPCs will be spawn
|
||||||
function spawner.calculate_npc_spawning(pos)
|
function spawner.calculate_npc_spawning(pos)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
-- Get nodes for this building
|
||||||
|
local node_data = minetest.deserialize(meta:get_string("node_data"))
|
||||||
|
if node_data == nil then
|
||||||
|
minetest.log("ERROR: Mis-configured advanced_npc:plotmarker_auto_spawner at position: "..dump(pos))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- Check number of beds
|
||||||
|
local beds_count = #node_data.bed_type
|
||||||
|
minetest.log("Number of beds: "..dump(beds_count))
|
||||||
|
local npc_count = 0
|
||||||
|
-- If number of beds is zero or beds/2 is less than one, spawn
|
||||||
|
-- a single NPC.
|
||||||
|
if beds_count == 0 or (beds_count > 0 and beds_count / 2 < 1) then
|
||||||
|
-- Spawn a single NPC
|
||||||
|
npc_count = 1
|
||||||
|
else
|
||||||
|
-- Spawn beds_count/2 NPCs
|
||||||
|
npc_count = ((beds_count / 2) - ((beds_count / 2) % 1))
|
||||||
|
end
|
||||||
|
minetest.log("Will spawn "..dump(npc_count).." NPCs at "..dump(pos))
|
||||||
|
-- Store amount of NPCs to spawn
|
||||||
|
meta:set_int("npc_count", npc_count)
|
||||||
|
-- Store amount of NPCs spawned
|
||||||
|
meta:set_int("spawned_npc_count", 0)
|
||||||
|
-- Start timer
|
||||||
|
local timer = minetest.get_node_timer(pos)
|
||||||
|
timer:start(npc.spawn_delay)
|
||||||
end
|
end
|
||||||
|
|
||||||
---------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------
|
||||||
@ -144,7 +494,7 @@ function spawner.replace_mg_villages_plotmarker(pos)
|
|||||||
-- Scan building for nodes
|
-- Scan building for nodes
|
||||||
local nodedata = spawner.scan_mg_villages_building(pos, building_data)
|
local nodedata = spawner.scan_mg_villages_building(pos, building_data)
|
||||||
-- Store nodedata into the spawner's metadata
|
-- Store nodedata into the spawner's metadata
|
||||||
meta:set_string("nodedata", minetest.serialize(nodedata))
|
meta:set_string("node_data", minetest.serialize(nodedata))
|
||||||
-- Stop searching for building type
|
-- Stop searching for building type
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -155,8 +505,10 @@ end
|
|||||||
-- Only register the node, the ABM and the LBM if mg_villages mod
|
-- Only register the node, the ABM and the LBM if mg_villages mod
|
||||||
-- is present
|
-- is present
|
||||||
if minetest.get_modpath("mg_villages") ~= nil then
|
if minetest.get_modpath("mg_villages") ~= nil then
|
||||||
|
|
||||||
-- Node registration
|
-- Node registration
|
||||||
-- This node is currently a slightly modified mg_villages:plotmarker
|
-- 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", {
|
minetest.register_node("advanced_npc:plotmarker_auto_spawner", {
|
||||||
description = "Automatic NPC Spawner",
|
description = "Automatic NPC Spawner",
|
||||||
drawtype = "nodebox",
|
drawtype = "nodebox",
|
||||||
@ -179,6 +531,11 @@ if minetest.get_modpath("mg_villages") ~= nil then
|
|||||||
return mg_villages.plotmarker_formspec( pos, formname, fields, sender );
|
return mg_villages.plotmarker_formspec( pos, formname, fields, sender );
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
on_timer = function(pos, elapsed)
|
||||||
|
minetest.log("Calling spawning function...")
|
||||||
|
npc.spawner.spawn_npc(pos)
|
||||||
|
end,
|
||||||
|
|
||||||
-- protect against digging
|
-- protect against digging
|
||||||
can_dig = function(pos, player)
|
can_dig = function(pos, player)
|
||||||
local meta = minetest.get_meta(pos);
|
local meta = minetest.get_meta(pos);
|
||||||
@ -195,12 +552,14 @@ if minetest.get_modpath("mg_villages") ~= nil then
|
|||||||
label = "Replace mg_villages:plotmarker with Advanced NPC auto spawners",
|
label = "Replace mg_villages:plotmarker with Advanced NPC auto spawners",
|
||||||
name = "advanced_npc:mg_villages_plotmarker_replacer",
|
name = "advanced_npc:mg_villages_plotmarker_replacer",
|
||||||
nodenames = {"mg_villages:plotmarker"},
|
nodenames = {"mg_villages:plotmarker"},
|
||||||
run_at_every_load = true,
|
run_at_every_load = false,
|
||||||
action = function(pos, node)
|
action = function(pos, node)
|
||||||
-- Check if replacement is activated
|
-- Check if replacement is activated
|
||||||
if npc.spawner.replace_activated then
|
if npc.spawner.replace_activated then
|
||||||
-- Replace mg_villages:plotmarker
|
-- Replace mg_villages:plotmarker
|
||||||
spawner.replace_mg_villages_plotmarker(pos)
|
spawner.replace_mg_villages_plotmarker(pos)
|
||||||
|
-- Set NPCs to spawn
|
||||||
|
spawner.calculate_npc_spawning(pos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
@ -209,7 +568,7 @@ if minetest.get_modpath("mg_villages") ~= nil then
|
|||||||
minetest.register_abm({
|
minetest.register_abm({
|
||||||
label = "Replace mg_villages:plotmarker with Advanced NPC auto spawners",
|
label = "Replace mg_villages:plotmarker with Advanced NPC auto spawners",
|
||||||
nodenames = {"mg_villages:plotmarker"},
|
nodenames = {"mg_villages:plotmarker"},
|
||||||
interval = 1.0,
|
interval = 60,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
catch_up = true,
|
catch_up = true,
|
||||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||||
@ -217,8 +576,58 @@ if minetest.get_modpath("mg_villages") ~= nil then
|
|||||||
if npc.spawner.replace_activated then
|
if npc.spawner.replace_activated then
|
||||||
-- Replace mg_villages:plotmarker
|
-- Replace mg_villages:plotmarker
|
||||||
spawner.replace_mg_villages_plotmarker(pos)
|
spawner.replace_mg_villages_plotmarker(pos)
|
||||||
|
-- Set NPCs to spawn
|
||||||
|
spawner.calculate_npc_spawning(pos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- 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.",
|
||||||
|
privs = {server=true},
|
||||||
|
func = function(name, param)
|
||||||
|
-- Check if radius is null
|
||||||
|
if param == nil then
|
||||||
|
minetest.chat_send_player(name, "Need to enter a radius as an integer number. Ex. /restore_plotmarkers 10 for a radius of 10")
|
||||||
|
end
|
||||||
|
-- Get player position
|
||||||
|
local pos = {}
|
||||||
|
for _,player in pairs(minetest.get_connected_players()) do
|
||||||
|
if player:get_player_name() == name then
|
||||||
|
pos = player:get_pos()
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Search for nodes
|
||||||
|
local radius = tonumber(param)
|
||||||
|
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"})
|
||||||
|
-- Check if we have nodes to replace
|
||||||
|
minetest.chat_send_player(name, "Found "..dump(#nodes).." nodes to replace...")
|
||||||
|
if #nodes == 0 then
|
||||||
|
return
|
||||||
|
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)
|
||||||
|
meta:set_int("plot_nr", plot_nr)
|
||||||
|
meta:set_string("infotext", infotext)
|
||||||
|
end
|
||||||
|
minetest.chat_send_player(name, "Finished "..dump(#nodes).." replacement successfully")
|
||||||
|
end
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user