Merge pull request 'Villager employment system and mob-api enhancements' (#2209) from villagers_jobsites into master
Reviewed-on: https://git.minetest.land/MineClone2/MineClone2/pulls/2209
@ -1438,7 +1438,8 @@ end
|
||||
|
||||
-- should mob follow what I'm holding ?
|
||||
local follow_holding = function(self, clicker)
|
||||
|
||||
if self.nofollow then return false end
|
||||
|
||||
if mobs.invis[clicker:get_player_name()] then
|
||||
return false
|
||||
end
|
||||
@ -2317,17 +2318,50 @@ local dogswitch = function(self, dtime)
|
||||
return self.dogshoot_switch
|
||||
end
|
||||
|
||||
local function go_to_pos(entity,b)
|
||||
if not entity then return end
|
||||
local s=entity.object:get_pos()
|
||||
if vector.distance(b,s) < 1 then
|
||||
--set_velocity(entity,0)
|
||||
return true
|
||||
end
|
||||
local v = { x = b.x - s.x, z = b.z - s.z }
|
||||
local yaw = (math.atan(v.z / v.x) + math.pi / 2) - entity.rotate
|
||||
if b.x > s.x then yaw = yaw + math.pi end
|
||||
entity.object:set_yaw(yaw)
|
||||
set_velocity(entity,entity.follow_velocity)
|
||||
mobs:set_animation(entity, "walk")
|
||||
end
|
||||
|
||||
local function check_doors(self)
|
||||
local p = self.object:get_pos()
|
||||
local t = minetest.get_timeofday()
|
||||
local dd = minetest.find_nodes_in_area(vector.offset(p,-1,-1,-1),vector.offset(p,1,1,1),{"group:door"})
|
||||
for _,d in pairs(dd) do
|
||||
local n = minetest.get_node(d)
|
||||
if n.name:find("_b_") then
|
||||
local def = minetest.registered_nodes[n.name]
|
||||
local closed = n.name:find("_b_1")
|
||||
if t < 0.3 or t > 0.8 then
|
||||
if not closed then def.on_rightclick(d,n,self) end
|
||||
else
|
||||
if closed then def.on_rightclick(d,n,self) end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- execute current state (stand, walk, run, attacks)
|
||||
-- returns true if mob has died
|
||||
local do_states = function(self, dtime)
|
||||
|
||||
if self.can_open_doors then check_doors(self) end
|
||||
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
|
||||
if self.state == "stand" then
|
||||
|
||||
if random(1, 4) == 1 then
|
||||
|
||||
local lp = nil
|
||||
local s = self.object:get_pos()
|
||||
local objs = minetest.get_objects_inside_radius(s, 3)
|
||||
|
||||
@ -2340,7 +2374,7 @@ local do_states = function(self, dtime)
|
||||
end
|
||||
|
||||
-- look at any players nearby, otherwise turn randomly
|
||||
if lp then
|
||||
if self.look_at_players then
|
||||
|
||||
local vec = {
|
||||
x = lp.x - s.x,
|
||||
@ -2375,8 +2409,35 @@ local do_states = function(self, dtime)
|
||||
end
|
||||
end
|
||||
|
||||
elseif self.state == "walk" then
|
||||
elseif self.state == "gowp" then
|
||||
local p = self.object:get_pos()
|
||||
if not p or not self._target then return end
|
||||
if vector.distance(p,self._target) < 2 or ( self.waypoints and #self.waypoints == 0 ) then
|
||||
self.waypoints = nil
|
||||
self._target = nil
|
||||
self.current_target = nil
|
||||
self.state = "walk"
|
||||
if self.callback_arrived then return self.callback_arrived(self) end
|
||||
return true
|
||||
end
|
||||
if self.waypoints and ( not self.current_target or vector.distance(p,self.current_target) < 1.5 ) then
|
||||
self.current_target = table.remove(self.waypoints, 1)
|
||||
--minetest.log("nextwp:".. tostring(self.current_target) )
|
||||
elseif self.current_target then
|
||||
go_to_pos(self,self.current_target)
|
||||
end
|
||||
|
||||
if self.current_target and not minetest.line_of_sight(self.object:get_pos(),self.current_target) then
|
||||
self.waypoints=minetest.find_path(p,self._target,150,1,4)
|
||||
self.current_target = nil
|
||||
return
|
||||
end
|
||||
if not self.current_target then
|
||||
--minetest.log("no path")
|
||||
self.state = "walk"
|
||||
end
|
||||
|
||||
elseif self.state == "walk" then
|
||||
local s = self.object:get_pos()
|
||||
local lp = nil
|
||||
|
||||
@ -2880,6 +2941,62 @@ local do_states = function(self, dtime)
|
||||
end
|
||||
end
|
||||
|
||||
local plane_adjacents = {
|
||||
vector.new(1,0,0),
|
||||
vector.new(-1,0,0),
|
||||
vector.new(0,0,1),
|
||||
vector.new(0,0,-1),
|
||||
}
|
||||
|
||||
function mobs:gopath(self,target,callback_arrived)
|
||||
local p = self.object:get_pos()
|
||||
local t = vector.offset(target,0,1,0)
|
||||
local wp = minetest.find_path(p,t,150,1,4)
|
||||
if not wp then
|
||||
local d = minetest.find_node_near(target,16,{"group:door"})
|
||||
if d then
|
||||
for _,v in pairs(plane_adjacents) do
|
||||
local pos = vector.add(d,v)
|
||||
local n = minetest.get_node(pos)
|
||||
if n.name == "air" then
|
||||
wp = minetest.find_path(p,pos,150,1,4)
|
||||
if wp then break end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if wp and #wp > 0 then
|
||||
self._target = t
|
||||
self.callback_arrived = callback_arrived
|
||||
self.waypoints = wp
|
||||
self.state = "gowp"
|
||||
return true
|
||||
else
|
||||
--minetest.log("no path found")
|
||||
end
|
||||
end
|
||||
|
||||
local function player_near(pos)
|
||||
for _,o in pairs(minetest.get_objects_inside_radius(pos,2)) do
|
||||
if o:is_player() then return true end
|
||||
end
|
||||
end
|
||||
|
||||
local function check_item_pickup(self)
|
||||
if self.pick_up and #self.pick_up > 0 then
|
||||
local p = self.object:get_pos()
|
||||
for _,o in pairs(minetest.get_objects_inside_radius(p,2)) do
|
||||
local l=o:get_luaentity()
|
||||
if l and l.name == "__builtin:item" then
|
||||
for k,v in pairs(self.pick_up) do
|
||||
if not player_near(p) and self.on_pick_up and l.itemstring:find(v) then
|
||||
if self.on_pick_up(self,l) == nil then o:remove() end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- falling and fall damage
|
||||
-- returns true if mob died
|
||||
@ -3481,7 +3598,7 @@ end
|
||||
|
||||
-- main mob function
|
||||
local mob_step = function(self, dtime)
|
||||
|
||||
check_item_pickup(self)
|
||||
if not self.fire_resistant then
|
||||
mcl_burning.tick(self.object, dtime, self)
|
||||
end
|
||||
@ -3576,8 +3693,7 @@ local mob_step = function(self, dtime)
|
||||
-- attack timer
|
||||
self.timer = self.timer + dtime
|
||||
|
||||
if self.state ~= "attack" then
|
||||
|
||||
if self.state ~= "attack" and self.state ~= "gowp" then
|
||||
if self.timer < 1 then
|
||||
return
|
||||
end
|
||||
@ -3845,6 +3961,8 @@ minetest.register_entity(name, {
|
||||
sounds = def.sounds or {},
|
||||
animation = def.animation,
|
||||
follow = def.follow,
|
||||
nofollow = def.nofollow,
|
||||
can_open_doors = def.can_open_doors,
|
||||
jump = def.jump ~= false,
|
||||
walk_chance = def.walk_chance or 50,
|
||||
attacks_monsters = def.attacks_monsters or false,
|
||||
@ -3910,7 +4028,8 @@ minetest.register_entity(name, {
|
||||
child = def.child or false,
|
||||
texture_mods = {},
|
||||
shoot_arrow = def.shoot_arrow,
|
||||
sounds_child = def.sounds_child,
|
||||
sounds_child = def.sounds_child,
|
||||
pick_up = def.pick_up,
|
||||
explosion_strength = def.explosion_strength,
|
||||
suffocation_timer = 0,
|
||||
follow_velocity = def.follow_velocity or 2.4,
|
||||
@ -3934,6 +4053,8 @@ minetest.register_entity(name, {
|
||||
|
||||
on_grown = def.on_grown,
|
||||
|
||||
on_pick_up = def.on_pick_up,
|
||||
|
||||
on_detach_child = mob_detach_child,
|
||||
|
||||
on_activate = function(self, staticdata, dtime)
|
||||
@ -4250,7 +4371,7 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
|
||||
end
|
||||
|
||||
-- can eat/tame with item in hand
|
||||
if follow_holding(self, clicker) then
|
||||
if self.nofollow or follow_holding(self, clicker) then
|
||||
|
||||
-- if not in creative then take item
|
||||
if not mobs.is_creative(clicker:get_player_name()) then
|
||||
|
@ -169,7 +169,7 @@ mobs_mc.follow = {
|
||||
dog = { mobs_mc.items.rabbit_raw, mobs_mc.items.rabbit_cooked, mobs_mc.items.mutton_raw, mobs_mc.items.mutton_cooked, mobs_mc.items.beef_raw, mobs_mc.items.beef_cooked, mobs_mc.items.chicken_raw, mobs_mc.items.chicken_cooked, mobs_mc.items.rotten_flesh,
|
||||
-- Mobs Redo items
|
||||
"mobs:meat", "mobs:meat_raw" },
|
||||
villager = { "mcl_farming:bread" },
|
||||
villager = { "mcl_farming:bread", "mcl_farming:carrot_item", "mcl_farming:beetroot_item" , "mcl_farming:potato_item" },
|
||||
}
|
||||
|
||||
-- Contents for replace_what
|
||||
|
@ -9,7 +9,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
--################### IRON GOLEM
|
||||
--###################
|
||||
|
||||
|
||||
local etime = 0
|
||||
|
||||
mobs:register_mob("mobs_mc:iron_golem", {
|
||||
description = S("Iron Golem"),
|
||||
@ -41,6 +41,26 @@ mobs:register_mob("mobs_mc:iron_golem", {
|
||||
group_attack = true,
|
||||
attacks_monsters = true,
|
||||
attack_type = "dogfight",
|
||||
_got_poppy = false,
|
||||
pick_up = {"mcl_flowers:poppy"},
|
||||
on_pick_up = function(self,n)
|
||||
if n.itemstring:find("mcl_flowers:poppy") then
|
||||
if not self._got_poppy then
|
||||
self._got_poppy=true
|
||||
return
|
||||
end
|
||||
return true
|
||||
end
|
||||
end,
|
||||
replace_what = {"mcl_flowers:poppy"},
|
||||
replace_with = {"air"},
|
||||
on_replace = function(self, pos, oldnode, newnode)
|
||||
if not self.got_poppy and oldnode.name == "mcl_flowers:poppy" then
|
||||
self._got_poppy=true
|
||||
return
|
||||
end
|
||||
return false
|
||||
end,
|
||||
drops = {
|
||||
{name = mobs_mc.items.iron_ingot,
|
||||
chance = 1,
|
||||
@ -60,6 +80,14 @@ mobs:register_mob("mobs_mc:iron_golem", {
|
||||
punch_start = 40, punch_end = 50,
|
||||
},
|
||||
jump = true,
|
||||
on_step = function(self,dtime)
|
||||
etime = etime + dtime
|
||||
if etime > 10 then
|
||||
if self._home and vector.distance(self._home,self.object:get_pos()) > 50 then
|
||||
mobs:gopath(self,self._home)
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
|
BIN
mods/ENTITIES/mobs_mc/textures/mobs_mc_villager_armorer.png
Normal file
After Width: | Height: | Size: 971 B |
Before Width: | Height: | Size: 866 B After Width: | Height: | Size: 989 B |
BIN
mods/ENTITIES/mobs_mc/textures/mobs_mc_villager_cartographer.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 848 B After Width: | Height: | Size: 1.1 KiB |
BIN
mods/ENTITIES/mobs_mc/textures/mobs_mc_villager_fisherman.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
mods/ENTITIES/mobs_mc/textures/mobs_mc_villager_fletcher.png
Normal file
After Width: | Height: | Size: 950 B |
After Width: | Height: | Size: 933 B |
Before Width: | Height: | Size: 896 B After Width: | Height: | Size: 1.1 KiB |
BIN
mods/ENTITIES/mobs_mc/textures/mobs_mc_villager_nitwit.png
Normal file
After Width: | Height: | Size: 1008 B |
Before Width: | Height: | Size: 768 B After Width: | Height: | Size: 921 B |
BIN
mods/ENTITIES/mobs_mc/textures/mobs_mc_villager_sheperd.png
Normal file
After Width: | Height: | Size: 983 B |
Before Width: | Height: | Size: 866 B After Width: | Height: | Size: 941 B |
BIN
mods/ENTITIES/mobs_mc/textures/mobs_mc_villager_toolsmith.png
Normal file
After Width: | Height: | Size: 964 B |
BIN
mods/ENTITIES/mobs_mc/textures/mobs_mc_villager_weaponsmith.png
Normal file
After Width: | Height: | Size: 967 B |
@ -10,14 +10,10 @@
|
||||
|
||||
-- TODO: Particles
|
||||
-- TODO: 4s Regeneration I after trade unlock
|
||||
-- TODO: Breeding
|
||||
-- TODO: Baby villagers
|
||||
-- TODO: Spawning in villages
|
||||
-- TODO: Behaviour:
|
||||
-- TODO: Walk around village, but do not leave it intentionally
|
||||
-- TODO: Run into house on rain or danger, open doors
|
||||
-- TODO: Internal inventory, pick up items, trade with other villagers
|
||||
-- TODO: Farm stuff
|
||||
-- TODO: Run into house on rain or danger, open doors
|
||||
-- TODO: Internal inventory, trade with other villagers
|
||||
-- TODO: Schedule stuff (work,sleep,father)
|
||||
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
local N = function(s) return s end
|
||||
@ -61,15 +57,37 @@ if minetest.get_mapgen_setting("mg_name") == "v6" then
|
||||
TRADE_V6_BIRCH_SAPLING = { { "mcl_core:emerald", 8, 11 }, { "mcl_core:birchsapling", 1, 1 } }
|
||||
end
|
||||
|
||||
local tiernames = {
|
||||
"Novice",
|
||||
"Apprentice",
|
||||
"Journeyman",
|
||||
"Expert",
|
||||
"Master",
|
||||
}
|
||||
|
||||
local badges = {
|
||||
"default_wood.png",
|
||||
"default_steel_block.png",
|
||||
"default_gold_block.png",
|
||||
"mcl_core_emerald_block.png",
|
||||
"default_diamond_block.png",
|
||||
}
|
||||
|
||||
local professions = {
|
||||
unemployed = {
|
||||
name = N("Unemployed"),
|
||||
texture = "mobs_mc_villager.png",
|
||||
textures = {
|
||||
"mobs_mc_villager.png",
|
||||
"mobs_mc_villager.png",
|
||||
},
|
||||
trades = nil,
|
||||
},
|
||||
farmer = {
|
||||
name = N("Farmer"),
|
||||
texture = "mobs_mc_villager_farmer.png",
|
||||
textures = {
|
||||
"mobs_mc_villager_farmer.png",
|
||||
"mobs_mc_villager_farmer.png",
|
||||
},
|
||||
jobsite = "mcl_composters:composter",
|
||||
trades = {
|
||||
{
|
||||
@ -103,7 +121,10 @@ local professions = {
|
||||
},
|
||||
fisherman = {
|
||||
name = N("Fisherman"),
|
||||
texture = "mobs_mc_villager_farmer.png",
|
||||
textures = {
|
||||
"mobs_mc_villager_fisherman.png",
|
||||
"mobs_mc_villager_fisherman.png",
|
||||
},
|
||||
jobsite = "mcl_barrels:barrel_closed",
|
||||
trades = {
|
||||
{
|
||||
@ -138,7 +159,10 @@ local professions = {
|
||||
},
|
||||
fletcher = {
|
||||
name = N("Fletcher"),
|
||||
texture = "mobs_mc_villager_farmer.png",
|
||||
textures = {
|
||||
"mobs_mc_villager_fletcher.png",
|
||||
"mobs_mc_villager_fletcher.png",
|
||||
},
|
||||
jobsite = "mcl_fletching_table:fletching_table",
|
||||
trades = {
|
||||
{
|
||||
@ -177,7 +201,10 @@ local professions = {
|
||||
},
|
||||
shepherd ={
|
||||
name = N("Shepherd"),
|
||||
texture = "mobs_mc_villager_farmer.png",
|
||||
textures = {
|
||||
"mobs_mc_villager_sheperd.png",
|
||||
"mobs_mc_villager_sheperd.png",
|
||||
},
|
||||
jobsite = "mcl_loom:loom",
|
||||
trades = {
|
||||
{
|
||||
@ -207,8 +234,11 @@ local professions = {
|
||||
},
|
||||
librarian = {
|
||||
name = N("Librarian"),
|
||||
texture = "mobs_mc_villager_librarian.png",
|
||||
jobsite = "mcl_villages:stonebrickcarved", --FIXME: lectern
|
||||
textures = {
|
||||
"mobs_mc_villager_librarian.png",
|
||||
"mobs_mc_villager_librarian.png",
|
||||
},
|
||||
jobsite = "mcl_books:bookshelf", --FIXME: lectern
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_core:paper", 24, 36 }, E1 },
|
||||
@ -242,7 +272,10 @@ local professions = {
|
||||
},
|
||||
cartographer = {
|
||||
name = N("Cartographer"),
|
||||
texture = "mobs_mc_villager_librarian.png",
|
||||
textures = {
|
||||
"mobs_mc_villager_cartographer.png",
|
||||
"mobs_mc_villager_cartographer.png",
|
||||
},
|
||||
jobsite = "mcl_cartography_table:cartography_table",
|
||||
trades = {
|
||||
{
|
||||
@ -285,7 +318,10 @@ local professions = {
|
||||
},
|
||||
armorer = {
|
||||
name = N("Armorer"),
|
||||
texture = "mobs_mc_villager_smith.png",
|
||||
textures = {
|
||||
"mobs_mc_villager_armorer.png",
|
||||
"mobs_mc_villager_armorer.png",
|
||||
},
|
||||
jobsite = "mcl_blast_furnace:blast_furnace",
|
||||
trades = {
|
||||
{
|
||||
@ -298,7 +334,7 @@ local professions = {
|
||||
|
||||
{
|
||||
{ { "mcl_core:iron_ingot", 4, 4 }, E1 },
|
||||
--{ { "mcl_core:emerald", 36, 36 }, { "FIXME: Bell", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 36, 36 }, { "mcl_bells:bell", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 3, 3 }, { "mcl_armor:leggings_chain", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 1, 1 }, { "mcl_armor:boots_chain", 1, 1 } },
|
||||
},
|
||||
@ -322,7 +358,10 @@ local professions = {
|
||||
},
|
||||
leatherworker = {
|
||||
name = N("Leatherworker"),
|
||||
texture = "mobs_mc_villager_butcher.png",
|
||||
textures = {
|
||||
"mobs_mc_villager_leatherworker.png",
|
||||
"mobs_mc_villager_leatherworker.png",
|
||||
},
|
||||
jobsite = "mcl_cauldrons:cauldron",
|
||||
trades = {
|
||||
{
|
||||
@ -351,7 +390,10 @@ local professions = {
|
||||
},
|
||||
butcher = {
|
||||
name = N("Butcher"),
|
||||
texture = "mobs_mc_villager_butcher.png",
|
||||
textures = {
|
||||
"mobs_mc_villager_butcher.png",
|
||||
"mobs_mc_villager_butcher.png",
|
||||
},
|
||||
jobsite = "mcl_smoker:smoker",
|
||||
trades = {
|
||||
{
|
||||
@ -381,8 +423,11 @@ local professions = {
|
||||
},
|
||||
weapon_smith = {
|
||||
name = N("Weapon Smith"),
|
||||
texture = "mobs_mc_villager_smith.png",
|
||||
jobsite = "mcl_villages:stonebrickcarved", --FIXME: grindstone
|
||||
textures = {
|
||||
"mobs_mc_villager_weaponsmith.png",
|
||||
"mobs_mc_villager_weaponsmith.png",
|
||||
},
|
||||
jobsite = "mcl_furnaces:furnace", --FIXME: grindstone
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_core:coal_lump", 15, 15 }, E1 },
|
||||
@ -392,7 +437,7 @@ local professions = {
|
||||
|
||||
{
|
||||
{ { "mcl_core:iron_ingot", 4, 4 }, E1 },
|
||||
--{ { "mcl_core:emerald", 36, 36 }, { "FIXME: Bell", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 36, 36 }, { "mcl_bells:bell", 1, 1 } },
|
||||
},
|
||||
{
|
||||
{ { "mcl_core:flint", 7, 9 }, E1 },
|
||||
@ -409,8 +454,11 @@ local professions = {
|
||||
},
|
||||
tool_smith = {
|
||||
name = N("Tool Smith"),
|
||||
texture = "mobs_mc_villager_smith.png",
|
||||
jobsite = "mcl_villages:stonebrickcarved", --FIXME: smithing table
|
||||
textures = {
|
||||
"mobs_mc_villager_toolsmith.png",
|
||||
"mobs_mc_villager_toolsmith.png",
|
||||
},
|
||||
jobsite = "mcl_anvils:anvil", --FIXME: smithing table
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_core:coal_lump", 15, 15 }, E1 },
|
||||
@ -422,7 +470,7 @@ local professions = {
|
||||
|
||||
{
|
||||
{ { "mcl_core:iron_ingot", 4, 4 }, E1 },
|
||||
--{ { "mcl_core:emerald", 36, 36 }, { "FIXME: Bell", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 36, 36 }, { "mcl_bells:bell", 1, 1 } },
|
||||
},
|
||||
{
|
||||
{ { "mcl_core:flint", 30, 30 }, E1 },
|
||||
@ -443,8 +491,11 @@ local professions = {
|
||||
},
|
||||
cleric = {
|
||||
name = N("Cleric"),
|
||||
texture = "mobs_mc_villager_priest.png",
|
||||
jobsite = "mcl_brewing:stand",
|
||||
textures = {
|
||||
"mobs_mc_villager_priest.png",
|
||||
"mobs_mc_villager_priest.png",
|
||||
},
|
||||
jobsite = "mcl_brewing:stand_000",
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_mobitems:rotten_flesh", 32, 32 }, E1 },
|
||||
@ -472,7 +523,10 @@ local professions = {
|
||||
},
|
||||
nitwit = {
|
||||
name = N("Nitwit"),
|
||||
texture = "mobs_mc_villager.png",
|
||||
textures = {
|
||||
"mobs_mc_villager_nitwit.png",
|
||||
"mobs_mc_villager_nitwit.png",
|
||||
},
|
||||
-- No trades for nitwit
|
||||
trades = nil,
|
||||
}
|
||||
@ -483,48 +537,106 @@ for id, _ in pairs(professions) do
|
||||
table.insert(profession_names, id)
|
||||
end
|
||||
|
||||
local stand_still = function(self)
|
||||
local jobsites={}
|
||||
for _,n in pairs(profession_names) do
|
||||
table.insert(jobsites,professions[n].jobsite)
|
||||
end
|
||||
|
||||
local function stand_still(self)
|
||||
self.walk_chance = 0
|
||||
self.jump = false
|
||||
end
|
||||
|
||||
local function set_velocity(self, v)
|
||||
local yaw = (self.object:get_yaw() or 0) + self.rotate
|
||||
self.object:set_velocity({
|
||||
x = (math.sin(yaw) * -v),
|
||||
y = self.object:get_velocity().y,
|
||||
z = (math.cos(yaw) * v),
|
||||
})
|
||||
local function init_trader_vars(self)
|
||||
if not self._max_trade_tier then
|
||||
self._max_trade_tier = 1
|
||||
end
|
||||
if not self._locked_trades then
|
||||
self._locked_trades = 0
|
||||
end
|
||||
if not self._trading_players then
|
||||
self._trading_players = {}
|
||||
end
|
||||
end
|
||||
|
||||
local function go_to_pos(entity,b)
|
||||
local s=entity.object:get_pos()
|
||||
local v = { x = b.x - s.x, z = b.z - s.z }
|
||||
local yaw = (math.atan(v.z / v.x) + math.pi / 2) - entity.rotate
|
||||
if b.x > s.x then yaw = yaw + math.pi end
|
||||
entity.object:set_yaw(yaw)
|
||||
set_velocity(entity,entity.follow_velocity)
|
||||
if vector.distance(b,s) < 5 then
|
||||
return true
|
||||
end
|
||||
local function get_badge_textures(self)
|
||||
local t = professions[self._profession].textures
|
||||
if self._profession == "unemployed" or self._profession == "nitwit" then return t end
|
||||
local tier = self._max_trade_tier or 1
|
||||
return {
|
||||
"[combine:64x64:0,0="..t[1]..":11,55=".. badges[tier].."\\^[resize\\:2x2",
|
||||
t[2]
|
||||
}
|
||||
end
|
||||
|
||||
local function set_textures(self)
|
||||
self.object:set_properties({textures=get_badge_textures(self)})
|
||||
end
|
||||
|
||||
local function go_home(entity)
|
||||
entity.state = "go_home"
|
||||
local b=entity.bed
|
||||
local b=entity._bed
|
||||
if not b then return end
|
||||
if go_to_pos(entity,b) then
|
||||
entity.state = "stand"
|
||||
set_velocity(entity,0)
|
||||
entity.object:set_pos(b)
|
||||
local n=minetest.get_node(b)
|
||||
if n and n.name ~= "mcl_beds:bed_red_bottom" then
|
||||
entity.bed=nil --the stormtroopers have killed uncle owen
|
||||
mobs:gopath(entity,b,function(entity,b)
|
||||
if vector.distance(entity.object:get_pos(),b) < 2 then
|
||||
entity.state = "stand"
|
||||
set_velocity(entity,0)
|
||||
entity.object:set_pos(b)
|
||||
local n=minetest.get_node(b)
|
||||
if n and n.name ~= "mcl_beds:bed_red_bottom" then
|
||||
entity._bed=nil --the stormtroopers have killed uncle owen
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local update_max_tradenum = function(self)
|
||||
----- JOBSITE LOGIC
|
||||
local function get_profession_by_jobsite(js)
|
||||
for k,v in pairs(professions) do
|
||||
if v.jobsite == js then return k end
|
||||
end
|
||||
end
|
||||
|
||||
local function employ(self,jobsite_pos)
|
||||
local n = minetest.get_node(jobsite_pos)
|
||||
local m = minetest.get_meta(jobsite_pos)
|
||||
local p = get_profession_by_jobsite(n.name)
|
||||
if p and m:get_string("villager") == "" then
|
||||
self._profession=p
|
||||
m:set_string("villager",self._id)
|
||||
self._jobsite = jobsite_pos
|
||||
set_textures(self)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function look_for_job(self)
|
||||
local p = self.object:get_pos()
|
||||
local nn = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48),vector.offset(p,48,48,48),jobsites)
|
||||
for _,n in pairs(nn) do
|
||||
local m=minetest.get_meta(n)
|
||||
if m:get_string("villager") == "" then
|
||||
--minetest.log("goingt to jobsite "..minetest.pos_to_string(n) )
|
||||
local gp = mobs:gopath(self,n,function()
|
||||
--minetest.log("arrived jobsite "..minetest.pos_to_string(n) )
|
||||
end)
|
||||
if gp then return end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function get_a_job(self)
|
||||
local p = self.object:get_pos()
|
||||
local nn = minetest.find_nodes_in_area(vector.offset(p,-8,-8,-8),vector.offset(p,8,8,8),jobsites)
|
||||
for _,n in pairs(nn) do
|
||||
if n and employ(self,n) then return true end
|
||||
end
|
||||
if self.state ~= "gowp" then look_for_job(self) end
|
||||
end
|
||||
|
||||
local function update_max_tradenum(self)
|
||||
if not self._trades then
|
||||
return
|
||||
end
|
||||
@ -539,31 +651,7 @@ local update_max_tradenum = function(self)
|
||||
self._max_tradenum = #trades
|
||||
end
|
||||
|
||||
local init_trader_vars = function(self)
|
||||
if not self._profession then
|
||||
-- Select random profession from all professions with matching clothing
|
||||
local texture = self.base_texture[1]
|
||||
local matches = {}
|
||||
for prof_id, prof in pairs(professions) do
|
||||
if texture == prof.texture then
|
||||
table.insert(matches, prof_id)
|
||||
end
|
||||
end
|
||||
local p = math.random(1, #matches)
|
||||
self._profession = matches[p]
|
||||
end
|
||||
if not self._max_trade_tier then
|
||||
self._max_trade_tier = 1
|
||||
end
|
||||
if not self._locked_trades then
|
||||
self._locked_trades = 0
|
||||
end
|
||||
if not self._trading_players then
|
||||
self._trading_players = {}
|
||||
end
|
||||
end
|
||||
|
||||
local init_trades = function(self, inv)
|
||||
local function init_trades(self, inv)
|
||||
local profession = professions[self._profession]
|
||||
local trade_tiers = profession.trades
|
||||
if trade_tiers == nil then
|
||||
@ -614,7 +702,7 @@ local init_trades = function(self, inv)
|
||||
minetest.deserialize(self._trades)
|
||||
end
|
||||
|
||||
local set_trade = function(trader, player, inv, concrete_tradenum)
|
||||
local function set_trade(trader, player, inv, concrete_tradenum)
|
||||
local trades = minetest.deserialize(trader._trades)
|
||||
if not trades then
|
||||
init_trades(trader)
|
||||
@ -688,12 +776,17 @@ local function show_trade_formspec(playername, trader, tradenum)
|
||||
w2_formspec = "item_image[3,1;1,1;"..wanted2:to_string().."]"
|
||||
.."tooltip[3,1;0.8,0.8;"..F(wanted2:get_description()).."]"
|
||||
end
|
||||
|
||||
local tiername = tiernames[trader._max_trade_tier]
|
||||
if tiername then
|
||||
tiername = S(tiername)
|
||||
else
|
||||
tiername = S("Master")
|
||||
end
|
||||
local formspec =
|
||||
"size[9,8.75]"
|
||||
.."background[-0.19,-0.25;9.41,9.49;mobs_mc_trading_formspec_bg.png]"
|
||||
..disabled_img
|
||||
.."label[4,0;"..F(minetest.colorize("#313131", S(profession))).."]"
|
||||
.."label[3,0;"..F(minetest.colorize("#313131", S(profession).." - "..tiername)) .."]"
|
||||
.."list[current_player;main;0,4.5;9,3;9]"
|
||||
.."list[current_player;main;0,7.74;9,1;]"
|
||||
..b_prev..b_next
|
||||
@ -713,7 +806,7 @@ local function show_trade_formspec(playername, trader, tradenum)
|
||||
minetest.show_formspec(playername, tradeinv_name, formspec)
|
||||
end
|
||||
|
||||
local update_offer = function(inv, player, sound)
|
||||
local function update_offer(inv, player, sound)
|
||||
local name = player:get_player_name()
|
||||
local trader = player_trading_with[name]
|
||||
local tradenum = player_tradenum[name]
|
||||
@ -737,12 +830,12 @@ local update_offer = function(inv, player, sound)
|
||||
-- compass.
|
||||
-- TODO: Remove these check functions when compass and clock are implemented
|
||||
-- as single items.
|
||||
local check_special = function(special_item, group, wanted1, wanted2, input1, input2)
|
||||
local function check_special(special_item, group, wanted1, wanted2, input1, input2)
|
||||
if minetest.registered_aliases[special_item] then
|
||||
special_item = minetest.registered_aliases[special_item]
|
||||
end
|
||||
if wanted1:get_name() == special_item then
|
||||
local check_input = function(input, wanted, group)
|
||||
local function check_input(input, wanted, group)
|
||||
return minetest.get_item_group(input:get_name(), group) ~= 0 and input:get_count() >= wanted:get_count()
|
||||
end
|
||||
if check_input(input1, wanted1, group) then
|
||||
@ -757,7 +850,7 @@ local update_offer = function(inv, player, sound)
|
||||
end
|
||||
-- Apply above function to all items which we consider special.
|
||||
-- This function succeeds if ANY item check succeeds.
|
||||
local check_specials = function(wanted1, wanted2, input1, input2)
|
||||
local function check_specials(wanted1, wanted2, input1, input2)
|
||||
return check_special(COMPASS, "compass", wanted1, wanted2, input1, input2)
|
||||
end
|
||||
-- END OF SPECIAL HANDLING OF COMPASS
|
||||
@ -811,7 +904,7 @@ local function return_item(itemstack, dropper, pos, inv_p)
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local return_fields = function(player)
|
||||
local function return_fields(player)
|
||||
local name = player:get_player_name()
|
||||
local inv_t = minetest.get_inventory({type="detached", name = "mobs_mc:trade_"..name})
|
||||
local inv_p = player:get_inventory()
|
||||
@ -877,7 +970,7 @@ minetest.register_on_leaveplayer(function(player)
|
||||
end)
|
||||
|
||||
-- Return true if player is trading with villager, and the villager entity exists
|
||||
local trader_exists = function(playername)
|
||||
local function trader_exists(playername)
|
||||
local trader = player_trading_with[playername]
|
||||
return trader ~= nil and trader.object:get_luaentity() ~= nil
|
||||
end
|
||||
@ -904,7 +997,7 @@ local trade_inventory = {
|
||||
wanted1:set_count(wanted1:get_count()*2)
|
||||
wanted2:set_count(wanted2:get_count()*2)
|
||||
-- BEGIN OF SPECIAL HANDLING FOR COMPASS
|
||||
local special_checks = function(wanted1, input1, input2)
|
||||
local function special_checks(wanted1, input1, input2)
|
||||
if wanted1:get_name() == COMPASS then
|
||||
local compasses = 0
|
||||
if (minetest.get_item_group(input1:get_name(), "compass") ~= 0) then
|
||||
@ -1021,6 +1114,10 @@ local trade_inventory = {
|
||||
-- First-time trade unlock all trades and unlock next trade tier
|
||||
if trade.tier + 1 > trader._max_trade_tier then
|
||||
trader._max_trade_tier = trader._max_trade_tier + 1
|
||||
if trader._max_trade_tier > 5 then
|
||||
trader._max_trade_tier = 5
|
||||
end
|
||||
set_textures(trader)
|
||||
update_max_tradenum(trader)
|
||||
update_formspec = true
|
||||
end
|
||||
@ -1113,31 +1210,9 @@ mobs:register_mob("mobs_mc:villager", {
|
||||
visual = "mesh",
|
||||
mesh = "mobs_mc_villager.b3d",
|
||||
textures = {
|
||||
{
|
||||
"mobs_mc_villager.png",
|
||||
"mobs_mc_villager.png", --hat
|
||||
},
|
||||
{
|
||||
"mobs_mc_villager_farmer.png",
|
||||
"mobs_mc_villager_farmer.png", --hat
|
||||
},
|
||||
{
|
||||
"mobs_mc_villager_priest.png",
|
||||
"mobs_mc_villager_priest.png", --hat
|
||||
},
|
||||
{
|
||||
"mobs_mc_villager_librarian.png",
|
||||
"mobs_mc_villager_librarian.png", --hat
|
||||
},
|
||||
{
|
||||
"mobs_mc_villager_butcher.png",
|
||||
"mobs_mc_villager_butcher.png", --hat
|
||||
},
|
||||
{
|
||||
"mobs_mc_villager_smith.png",
|
||||
"mobs_mc_villager_smith.png", --hat
|
||||
},
|
||||
},
|
||||
visual_size = {x=2.75, y=2.75},
|
||||
makes_footstep_sound = true,
|
||||
walk_velocity = 1.2,
|
||||
@ -1165,23 +1240,45 @@ mobs:register_mob("mobs_mc:villager", {
|
||||
die_loop = false,
|
||||
},
|
||||
follow = mobs_mc.follow.villager,
|
||||
nofollow = true,
|
||||
view_range = 16,
|
||||
fear_height = 4,
|
||||
jump = true,
|
||||
walk_chance = DEFAULT_WALK_CHANCE,
|
||||
on_rightclick = function(self, clicker)
|
||||
if clicker:get_wielded_item():get_name() == "mcl_farming:bread" then
|
||||
if mobs:feed_tame(self, clicker, 1, true, true) then return end
|
||||
if mobs:protect(self, clicker) then return end
|
||||
_bed = nil,
|
||||
_id = nil,
|
||||
_profession = "unemployed",
|
||||
look_at_player = true,
|
||||
pick_up = mobs_mc.follow.villager,
|
||||
can_open_doors = true,
|
||||
on_pick_up = function(self,itementity)
|
||||
local clicker
|
||||
for _,p in pairs(minetest.get_connected_players()) do
|
||||
if vector.distance(p:get_pos(),self.object:get_pos()) < 10 then
|
||||
clicker = p
|
||||
end
|
||||
end
|
||||
if self.child then
|
||||
if clicker then
|
||||
mobs:feed_tame(self, clicker, 1, true, false)
|
||||
return
|
||||
end
|
||||
return true --do not pick up
|
||||
end,
|
||||
on_rightclick = function(self, clicker)
|
||||
local trg=vector.new(0,9,0)
|
||||
if self._jobsite then
|
||||
mobs:gopath(self,self._jobsite,function()
|
||||
--minetest.log("arrived at jobsite")
|
||||
end)
|
||||
end
|
||||
if self.child or self._profession == "unemployed" then
|
||||
return
|
||||
end
|
||||
-- Initiate trading
|
||||
init_trader_vars(self)
|
||||
local name = clicker:get_player_name()
|
||||
self._trading_players[name] = true
|
||||
|
||||
init_trader_vars(self)
|
||||
if self._trades == nil then
|
||||
init_trades(self)
|
||||
end
|
||||
@ -1219,10 +1316,6 @@ mobs:register_mob("mobs_mc:villager", {
|
||||
self._player_scan_timer = 0
|
||||
end
|
||||
|
||||
if self.bed and ( self.state == "go_home" or vector.distance(self.object:get_pos(),self.bed) > 50 ) then
|
||||
go_home(self)
|
||||
end
|
||||
|
||||
self._player_scan_timer = self._player_scan_timer + dtime
|
||||
-- Check infrequently to keep CPU load low
|
||||
if self._player_scan_timer > PLAYER_SCAN_INTERVAL then
|
||||
@ -1244,20 +1337,37 @@ mobs:register_mob("mobs_mc:villager", {
|
||||
self.walk_chance = DEFAULT_WALK_CHANCE
|
||||
self.jump = true
|
||||
end
|
||||
if self._bed and ( self.state ~= "go_home" and vector.distance(self.object:get_pos(),self._bed) > 50 ) then
|
||||
go_home(self)
|
||||
end
|
||||
if self._profession == "unemployed" then
|
||||
get_a_job(self)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
on_spawn = function(self)
|
||||
init_trader_vars(self)
|
||||
if self._id then
|
||||
set_textures(self)
|
||||
return
|
||||
end
|
||||
self._id=minetest.sha1(minetest.get_gametime()..minetest.pos_to_string(self.object:get_pos())..tostring(math.random()))
|
||||
self._profession = "unemployed"
|
||||
if math.random(100) == 1 then
|
||||
self._profession = "nitwit"
|
||||
end
|
||||
set_textures(self)
|
||||
end,
|
||||
on_die = function(self, pos)
|
||||
-- Close open trade formspecs and give input back to players
|
||||
local trading_players = self._trading_players
|
||||
for name, _ in pairs(trading_players) do
|
||||
minetest.close_formspec(name, "mobs_mc:trade_"..name)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player then
|
||||
return_fields(player)
|
||||
if trading_players then
|
||||
for name, _ in pairs(trading_players) do
|
||||
minetest.close_formspec(name, "mobs_mc:trade_"..name)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player then
|
||||
return_fields(player)
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
@ -5,7 +5,13 @@ mcl_bells = {}
|
||||
local has_mcl_wip = minetest.get_modpath("mcl_wip")
|
||||
|
||||
function mcl_bells.ring_once(pos)
|
||||
minetest.sound_play( "mcl_bells_bell_stroke", { pos = pos, gain = 1.5, max_hear_distance = 300,});
|
||||
minetest.sound_play( "mcl_bells_bell_stroke", { pos = pos, gain = 1.5, max_hear_distance = 150,})
|
||||
local vv=minetest.get_objects_inside_radius(pos,150)
|
||||
for _,o in pairs(vv) do
|
||||
if o.type == "npc" then
|
||||
mobs:gopath(o:get_luaentity(),pos,function() end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("mcl_bells:bell", {
|
||||
|
@ -188,11 +188,41 @@ local function construct_node(p1, p2, name)
|
||||
end
|
||||
minetest.log("warning", "[mcl_villages] Attempt to 'construct' inexistant nodes: " .. name)
|
||||
end
|
||||
|
||||
local function spawn_iron_golem(pos)
|
||||
local p = minetest.find_node_near(pos,50,"mcl_core:grass_path")
|
||||
if p then
|
||||
local l=minetest.add_entity(p,"mobs_mc:iron_golem"):get_luaentity()
|
||||
if l then
|
||||
l._home = p
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function spawn_villagers(minp,maxp)
|
||||
local beds=minetest.find_nodes_in_area(vector.offset(minp,-20,-20,-20),vector.offset(maxp,20,20,20),{"mcl_beds:bed_red_bottom"})
|
||||
for _,bed in pairs(beds) do
|
||||
local m = minetest.get_meta(bed)
|
||||
if m:get_string("villager") == "" then
|
||||
local v=minetest.add_entity(bed,"mobs_mc:villager")
|
||||
if v then
|
||||
local l=v:get_luaentity()
|
||||
l._bed = bed
|
||||
m:set_string("villager",l._id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function init_nodes(p1, p2, size, rotation, pr)
|
||||
construct_node(p1, p2, "mcl_itemframes:item_frame")
|
||||
construct_node(p1, p2, "mcl_furnaces:furnace")
|
||||
construct_node(p1, p2, "mcl_anvils:anvil")
|
||||
|
||||
construct_node(p1, p2, "mcl_smoker:smoker")
|
||||
construct_node(p1, p2, "mcl_barrels:barrel_closed")
|
||||
construct_node(p1, p2, "mcl_blast_furnace:blast_furnace")
|
||||
construct_node(p1, p2, "mcl_brewing:stand_000")
|
||||
local nodes = construct_node(p1, p2, "mcl_chests:chest")
|
||||
if nodes and #nodes > 0 then
|
||||
for p=1, #nodes do
|
||||
@ -201,9 +231,30 @@ local function init_nodes(p1, p2, size, rotation, pr)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function settlements.place_schematics(settlement_info, pr)
|
||||
local building_all_info
|
||||
|
||||
--attempt to place one belltower in the center of the village - this doesn't always work out great but it's a lot better than doing it first or last.
|
||||
local belltower = table.remove(settlement_info,math.floor(#settlement_info/2))
|
||||
if belltower then
|
||||
mcl_structures.place_schematic(
|
||||
vector.offset(belltower["pos"],0,0,0),
|
||||
settlements.modpath.."/schematics/belltower.mts",
|
||||
belltower["rotation"],
|
||||
nil,
|
||||
true,
|
||||
nil,
|
||||
function(p1, p2, size, rotation, pr)
|
||||
spawn_iron_golem(p1)
|
||||
end,
|
||||
pr
|
||||
)
|
||||
end
|
||||
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
local is_last = i == #settlement_info
|
||||
|
||||
for j, schem in ipairs(settlements.schematic_table) do
|
||||
if settlement_info[i]["name"] == schem["name"] then
|
||||
building_all_info = schem
|
||||
@ -271,7 +322,10 @@ function settlements.place_schematics(settlement_info, pr)
|
||||
nil,
|
||||
true,
|
||||
nil,
|
||||
init_nodes,
|
||||
function(p1, p2, size, rotation, pr)
|
||||
init_nodes(p1, p2, size, rotation, pr)
|
||||
spawn_villagers(p1,p2)
|
||||
end,
|
||||
pr
|
||||
)
|
||||
end
|
||||
|
@ -21,7 +21,6 @@ minetest.register_node("mcl_villages:stonebrickcarved", {
|
||||
description = ("Chiseled Stone Village Bricks"),
|
||||
_doc_items_longdesc = doc.sub.items.temp.build,
|
||||
tiles = {"mcl_core_stonebrick_carved.png"},
|
||||
stack_max = 64,
|
||||
drop = "mcl_core:stonebrickcarved",
|
||||
groups = {pickaxey=1, stone=1, stonebrick=1, building_block=1, material_stone=1},
|
||||
sounds = mcl_sounds.node_sound_stone_defaults(),
|
||||
@ -50,17 +49,6 @@ if minetest.get_modpath("mobs_mc") then
|
||||
end
|
||||
--]]
|
||||
|
||||
local function spawn_villagers(minp,maxp)
|
||||
local beds=minetest.find_nodes_in_area(minp,maxp,{"mcl_beds:bed_red_bottom"})
|
||||
for _,bed in pairs(beds) do
|
||||
minetest.get_meta(bed):set_string("villagebed","true")
|
||||
local v=minetest.add_entity(bed,"mobs_mc:villager")
|
||||
if v then
|
||||
v:get_luaentity().bed = bed
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- on map generation, try to build a settlement
|
||||
--
|
||||
@ -79,10 +67,6 @@ local function build_a_settlement(minp, maxp, blockseed)
|
||||
|
||||
-- evaluate settlement_info and place schematics
|
||||
settlements.place_schematics(settlement_info, pr)
|
||||
|
||||
minetest.after(60,function()
|
||||
spawn_villagers(minp,maxp)
|
||||
end) --give the village some time to fully generate
|
||||
end
|
||||
|
||||
local function ecb_village(blockpos, action, calls_remaining, param)
|
||||
|