2017-07-05 03:15:46 +02:00
--MCmobs v0.4
--maikerumine
--made for MC like Survival game
--License for code WTFPL and otherwise stated in readmes
2018-06-10 14:24:00 +02:00
--###################
--################### VILLAGER
--###################
2018-06-10 15:01:44 +02:00
-- Summary: Villagers are complex NPCs, their main feature allows players to trade with them.
2018-06-10 14:24:00 +02:00
2018-06-06 17:33:14 +02:00
-- TODO: Particles
-- TODO: 4s Regeneration I after trade unlock
2018-06-10 15:22:32 +02:00
-- TODO: Behaviour:
2022-05-20 23:44:33 +02:00
-- TODO: Run into house on rain or danger, open doors
-- TODO: Internal inventory, trade with other villagers
-- TODO: Schedule stuff (work,sleep,father)
2018-06-04 22:21:10 +02:00
2022-10-22 02:28:45 +02:00
local weather_mod = minetest.get_modpath ( " mcl_weather " )
2022-02-13 21:40:12 +01:00
local S = minetest.get_translator ( " mobs_mc " )
2019-03-16 04:14:21 +01:00
local N = function ( s ) return s end
2020-03-19 12:32:30 +01:00
local F = minetest.formspec_escape
2017-07-05 03:15:46 +02:00
2018-06-04 21:46:13 +02:00
-- playername-indexed table containing the previously used tradenum
local player_tradenum = { }
-- playername-indexed table containing the objectref of trader, if trading formspec is open
local player_trading_with = { }
2018-06-10 14:24:00 +02:00
local DEFAULT_WALK_CHANCE = 33 -- chance to walk in percent, if no player nearby
local PLAYER_SCAN_INTERVAL = 5 -- every X seconds, villager looks for players nearby
local PLAYER_SCAN_RADIUS = 4 -- scan radius for looking for nearby players
2017-07-05 03:15:46 +02:00
2022-11-15 23:32:09 +01:00
local RESETTLE_DISTANCE = 100 -- If a mob is transported this far from home, it gives up bed and job and resettles
2022-10-26 00:53:55 +02:00
local PATHFINDING = " gowp "
2023-12-09 15:22:27 +01:00
local VILLAGER_SEARCH_RADIUS = tonumber ( minetest.settings : get ( " mcl_mobs_villager_search_radius " ) ) or 20
2022-10-26 00:53:55 +02:00
2018-06-10 15:01:44 +02:00
--[=======[ TRADING ]=======]
2018-06-04 22:13:24 +02:00
-- LIST OF VILLAGER PROFESSIONS AND TRADES
2018-06-06 19:37:31 +02:00
-- TECHNICAL RESTRICTIONS (FIXME):
-- * You can't use a clock as requested item
-- * You can't use a compass as requested item if its stack size > 1
-- * You can't use a compass in the second requested slot
-- This is a problem in the mcl_compass and mcl_clock mods,
-- these items should be implemented as single items, then everything
-- will be much easier.
2022-10-22 02:28:45 +02:00
local LOGGING_ON = minetest.settings : get_bool ( " mcl_logging_mobs_villager " , false )
local function mcl_log ( message )
2022-11-08 23:58:47 +01:00
if LOGGING_ON then
mcl_util.mcl_log ( message , " [Mobs - Villager] " , true )
2022-10-22 02:28:45 +02:00
end
end
2018-06-06 19:37:31 +02:00
local COMPASS = " mcl_compass:compass "
if minetest.registered_aliases [ COMPASS ] then
COMPASS = minetest.registered_aliases [ COMPASS ]
end
2018-06-04 14:36:06 +02:00
local E1 = { " mcl_core:emerald " , 1 , 1 } -- one emerald
2018-06-06 21:28:23 +02:00
-- Special trades for v6 only
2018-10-23 17:03:42 +02:00
-- NOTE: These symbols MUST only be added at the end of a tier
2018-06-06 21:28:23 +02:00
local TRADE_V6_RED_SANDSTONE , TRADE_V6_DARK_OAK_SAPLING , TRADE_V6_ACACIA_SAPLING , TRADE_V6_BIRCH_SAPLING
if minetest.get_mapgen_setting ( " mg_name " ) == " v6 " then
TRADE_V6_RED_SANDSTONE = { E1 , { " mcl_core:redsandstone " , 12 , 16 } }
TRADE_V6_DARK_OAK_SAPLING = { { " mcl_core:emerald " , 6 , 9 } , { " mcl_core:darksapling " , 1 , 1 } }
TRADE_V6_ACACIA_SAPLING = { { " mcl_core:emerald " , 14 , 17 } , { " mcl_core:acaciasapling " , 1 , 1 } }
TRADE_V6_BIRCH_SAPLING = { { " mcl_core:emerald " , 8 , 11 } , { " mcl_core:birchsapling " , 1 , 1 } }
end
2022-05-17 19:40:20 +02:00
local tiernames = {
" Novice " ,
" Apprentice " ,
" Journeyman " ,
" Expert " ,
" Master " ,
}
2022-05-18 00:03:40 +02:00
local badges = {
2022-10-06 00:16:03 +02:00
" mobs_mc_stone.png " ,
" mobs_mc_iron.png " ,
" mobs_mc_gold.png " ,
" mobs_mc_emerald.png " ,
" mobs_mc_diamond.png " ,
2022-05-18 00:03:40 +02:00
}
2018-06-04 14:36:06 +02:00
local professions = {
2022-05-12 22:29:15 +02:00
unemployed = {
name = N ( " Unemployed " ) ,
2022-05-13 21:28:56 +02:00
textures = {
" mobs_mc_villager.png " ,
" mobs_mc_villager.png " ,
} ,
2022-05-12 22:29:15 +02:00
trades = nil ,
} ,
2018-06-04 14:59:10 +02:00
farmer = {
2019-03-16 04:14:21 +01:00
name = N ( " Farmer " ) ,
2022-10-06 00:16:03 +02:00
texture = " mobs_mc_villager_farmer.png " ,
2022-05-12 22:29:15 +02:00
jobsite = " mcl_composters:composter " ,
2018-06-04 14:36:06 +02:00
trades = {
{
2023-07-25 05:44:28 +02:00
{ { " mcl_farming:wheat_item " , 20 , 20 , } , E1 } ,
{ { " mcl_farming:potato_item " , 26 , 26 , } , E1 } ,
{ { " mcl_farming:carrot_item " , 22 , 22 , } , E1 } ,
{ { " mcl_farming:beetroot_item " , 15 , 15 } , E1 } ,
{ E1 , { " mcl_farming:bread " , 6 , 6 } } ,
2018-06-04 14:36:06 +02:00
} ,
{
2023-07-25 05:44:28 +02:00
{ { " mcl_farming:pumpkin " , 6 , 6 } , E1 } ,
{ E1 , { " mcl_farming:pumpkin_pie " , 4 , 4 } } ,
{ E1 , { " mcl_core:apple " , 4 , 4 } } ,
2018-06-04 14:36:06 +02:00
} ,
{
2023-07-25 05:44:28 +02:00
{ { " mcl_farming:melon " , 4 , 4 } , E1 } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_farming:cookie " , 18 , 18 } , } ,
2022-05-12 16:02:07 +02:00
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 16:02:07 +02:00
{
2023-07-25 05:44:28 +02:00
{ E1 , { " mcl_cake:cake " , 1 , 1 } } ,
2022-05-12 16:02:07 +02:00
{ E1 , { " mcl_mushrooms:mushroom_stew " , 6 , 10 } } , --FIXME: expert level farmer is supposed to sell sus stews.
2018-06-04 14:36:06 +02:00
} ,
2023-07-25 05:44:28 +02:00
2018-06-04 14:36:06 +02:00
{
2023-07-25 05:44:28 +02:00
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_farming:carrot_item_gold " , 3 , 3 } } ,
{ { " mcl_core:emerald " , 4 , 4 } , { " mcl_potions:speckled_melon " , 3 , 3 } } ,
2018-06-06 21:28:23 +02:00
TRADE_V6_BIRCH_SAPLING ,
TRADE_V6_DARK_OAK_SAPLING ,
TRADE_V6_ACACIA_SAPLING ,
2018-06-04 14:36:06 +02:00
} ,
}
} ,
2018-06-04 14:59:10 +02:00
fisherman = {
2019-03-16 04:14:21 +01:00
name = N ( " Fisherman " ) ,
2022-10-06 00:16:03 +02:00
texture = " mobs_mc_villager_fisherman.png " ,
2022-05-12 22:29:15 +02:00
jobsite = " mcl_barrels:barrel_closed " ,
2018-06-04 14:36:06 +02:00
trades = {
{
2023-07-25 05:44:28 +02:00
{ { " mcl_mobitems:string " , 20 , 20 } , E1 } ,
{ { " mcl_core:coal_lump " , 10 , 10 } , E1 } ,
{ { " mcl_core:emerald " , 1 , 1 , " mcl_fishing:fish_raw " , 6 , 6 } , { " mcl_fishing:fish_cooked " , 6 , 6 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_buckets:bucket_cod " , 1 , 1 } } ,
2022-05-12 16:18:33 +02:00
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 16:18:33 +02:00
{
2023-07-25 05:44:28 +02:00
{ { " mcl_fishing:fish_raw " , 15 , 15 } , E1 } ,
{ { " mcl_core:emerald " , 1 , 1 , " mcl_fishing:salmon_raw " , 6 , 6 } , { " mcl_fishing:salmon_cooked " , 6 , 6 } } ,
{ { " mcl_core:emerald " , 2 , 2 } , { " mcl_campfires:campfire_lit " , 1 , 1 } } ,
2022-05-12 16:18:33 +02:00
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 16:18:33 +02:00
{
2023-07-25 05:44:28 +02:00
{ { " mcl_fishing:salmon_raw " , 13 , 13 } , E1 } ,
{ { " mcl_core:emerald " , 8 , 22 } , { " mcl_fishing:fishing_rod_enchanted " , 1 , 1 } } ,
2022-05-12 16:18:33 +02:00
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 16:18:33 +02:00
{
2023-07-25 05:44:28 +02:00
{ { " mcl_fishing:clownfish_raw " , 6 , 6 } , E1 } ,
2022-05-12 16:18:33 +02:00
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 16:18:33 +02:00
{
2023-07-25 05:44:28 +02:00
{ { " mcl_fishing:pufferfish_raw " , 4 , 4 } , E1 } ,
2022-05-12 16:18:33 +02:00
2023-08-19 03:36:04 +02:00
--Boat cherry?
2023-07-25 05:44:28 +02:00
{ { " mcl_boats:boat " , 1 , 1 } , E1 } ,
{ { " mcl_boats:boat_acacia " , 1 , 1 } , E1 } ,
{ { " mcl_boats:boat_spruce " , 1 , 1 } , E1 } ,
{ { " mcl_boats:boat_dark_oak " , 1 , 1 } , E1 } ,
{ { " mcl_boats:boat_birch " , 1 , 1 } , E1 } ,
2018-06-04 14:36:06 +02:00
} ,
} ,
} ,
2018-06-04 14:59:10 +02:00
fletcher = {
2019-03-16 04:14:21 +01:00
name = N ( " Fletcher " ) ,
2022-10-06 00:16:03 +02:00
texture = " mobs_mc_villager_fletcher.png " ,
2022-05-14 23:52:37 +02:00
jobsite = " mcl_fletching_table:fletching_table " ,
2018-06-04 14:36:06 +02:00
trades = {
{
2023-01-31 22:14:23 +01:00
{ { " mcl_core:stick " , 32 , 32 } , E1 } ,
2023-07-25 05:44:28 +02:00
{ E1 , { " mcl_bows:arrow " , 16 , 16 } } ,
{ { " mcl_core:emerald " , 1 , 1 , " mcl_core:gravel " , 10 , 10 } , { " mcl_core:flint " , 10 , 10 } } ,
2018-06-04 14:36:06 +02:00
} ,
2023-07-25 05:44:28 +02:00
2018-06-04 14:36:06 +02:00
{
2022-05-12 17:50:57 +02:00
{ { " mcl_core:flint " , 26 , 26 } , E1 } ,
2023-07-25 05:44:28 +02:00
{ { " mcl_core:emerald " , 2 , 2 } , { " mcl_bows:bow " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 17:50:57 +02:00
{
{ { " mcl_mobitems:string " , 14 , 14 } , E1 } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_bows:crossbow " , 1 , 1 } } ,
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 17:50:57 +02:00
{
2023-07-25 05:44:28 +02:00
{ { " mcl_mobitems:feather " , 24 , 24 } , E1 } ,
2022-05-12 17:50:57 +02:00
{ { " mcl_core:emerald " , 7 , 21 } , { " mcl_bows:bow_enchanted " , 1 , 1 } } ,
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 17:50:57 +02:00
{
2023-07-25 05:44:28 +02:00
--FIXME: supposed to be tripwire hook{ { "tripwirehook", 8, 8 }, E1 },
2022-05-12 17:50:57 +02:00
{ { " mcl_core:emerald " , 8 , 22 } , { " mcl_bows:crossbow_enchanted " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 2 , 2 , " mcl_bows:arrow " , 5 , 5 } , { " mcl_potions:healing_arrow " , 5 , 5 } } ,
{ { " mcl_core:emerald " , 2 , 2 , " mcl_bows:arrow " , 5 , 5 } , { " mcl_potions:harming_arrow " , 5 , 5 } } ,
{ { " mcl_core:emerald " , 2 , 2 , " mcl_bows:arrow " , 5 , 5 } , { " mcl_potions:night_vision_arrow " , 5 , 5 } } ,
{ { " mcl_core:emerald " , 2 , 2 , " mcl_bows:arrow " , 5 , 5 } , { " mcl_potions:swiftness_arrow " , 5 , 5 } } ,
{ { " mcl_core:emerald " , 2 , 2 , " mcl_bows:arrow " , 5 , 5 } , { " mcl_potions:slowness_arrow " , 5 , 5 } } ,
{ { " mcl_core:emerald " , 2 , 2 , " mcl_bows:arrow " , 5 , 5 } , { " mcl_potions:leaping_arrow " , 5 , 5 } } ,
{ { " mcl_core:emerald " , 2 , 2 , " mcl_bows:arrow " , 5 , 5 } , { " mcl_potions:poison_arrow " , 5 , 5 } } ,
{ { " mcl_core:emerald " , 2 , 2 , " mcl_bows:arrow " , 5 , 5 } , { " mcl_potions:regeneration_arrow " , 5 , 5 } } ,
{ { " mcl_core:emerald " , 2 , 2 , " mcl_bows:arrow " , 5 , 5 } , { " mcl_potions:invisibility_arrow " , 5 , 5 } } ,
{ { " mcl_core:emerald " , 2 , 2 , " mcl_bows:arrow " , 5 , 5 } , { " mcl_potions:water_breathing_arrow " , 5 , 5 } } ,
{ { " mcl_core:emerald " , 2 , 2 , " mcl_bows:arrow " , 5 , 5 } , { " mcl_potions:fire_resistance_arrow " , 5 , 5 } } ,
} ,
2018-06-04 14:36:06 +02:00
}
} ,
2018-06-04 14:59:10 +02:00
shepherd = {
2019-03-16 04:14:21 +01:00
name = N ( " Shepherd " ) ,
2022-10-06 00:16:03 +02:00
texture = " mobs_mc_villager_sheperd.png " ,
2022-05-14 23:52:37 +02:00
jobsite = " mcl_loom:loom " ,
2018-06-04 14:36:06 +02:00
trades = {
{
2023-07-25 05:44:28 +02:00
{ { " mcl_wool:white " , 18 , 18 } , E1 } ,
{ { " mcl_wool:brown " , 18 , 18 } , E1 } ,
{ { " mcl_wool:black " , 18 , 18 } , E1 } ,
{ { " mcl_wool:grey " , 18 , 18 } , E1 } ,
{ { " mcl_core:emerald " , 2 , 2 } , { " mcl_tools:shears " , 1 , 1 } } ,
} ,
{
{ { " mcl_dye:black " , 12 , 12 } , E1 } ,
{ { " mcl_dye:dark_grey " , 12 , 12 } , E1 } ,
{ { " mcl_dye:green " , 12 , 12 } , E1 } ,
{ { " mcl_dye:lightblue " , 12 , 12 } , E1 } ,
{ { " mcl_dye:white " , 12 , 12 } , E1 } ,
2023-08-19 03:36:04 +02:00
2023-07-25 05:44:28 +02:00
{ E1 , { " mcl_wool:white " , 1 , 1 } } ,
{ E1 , { " mcl_wool:grey " , 1 , 1 } } ,
{ E1 , { " mcl_wool:silver " , 1 , 1 } } ,
{ E1 , { " mcl_wool:black " , 1 , 1 } } ,
{ E1 , { " mcl_wool:yellow " , 1 , 1 } } ,
{ E1 , { " mcl_wool:orange " , 1 , 1 } } ,
{ E1 , { " mcl_wool:red " , 1 , 1 } } ,
{ E1 , { " mcl_wool:magenta " , 1 , 1 } } ,
{ E1 , { " mcl_wool:purple " , 1 , 1 } } ,
{ E1 , { " mcl_wool:blue " , 1 , 1 } } ,
{ E1 , { " mcl_wool:cyan " , 1 , 1 } } ,
{ E1 , { " mcl_wool:lime " , 1 , 1 } } ,
{ E1 , { " mcl_wool:green " , 1 , 1 } } ,
{ E1 , { " mcl_wool:pink " , 1 , 1 } } ,
{ E1 , { " mcl_wool:light_blue " , 1 , 1 } } ,
{ E1 , { " mcl_wool:brown " , 1 , 1 } } ,
{ E1 , { " mcl_wool:white_carpet " , 4 , 4 } } ,
{ E1 , { " mcl_wool:grey_carpet " , 4 , 4 } } ,
{ E1 , { " mcl_wool:silver_carpet " , 4 , 4 } } ,
{ E1 , { " mcl_wool:black_carpet " , 4 , 4 } } ,
{ E1 , { " mcl_wool:yellow_carpet " , 4 , 4 } } ,
{ E1 , { " mcl_wool:orange_carpet " , 4 , 4 } } ,
{ E1 , { " mcl_wool:red_carpet " , 4 , 4 } } ,
{ E1 , { " mcl_wool:magenta_carpet " , 4 , 4 } } ,
{ E1 , { " mcl_wool:purple_carpet " , 4 , 4 } } ,
{ E1 , { " mcl_wool:blue_carpet " , 4 , 4 } } ,
{ E1 , { " mcl_wool:cyan_carpet " , 4 , 4 } } ,
{ E1 , { " mcl_wool:lime_carpet " , 4 , 4 } } ,
{ E1 , { " mcl_wool:green_carpet " , 4 , 4 } } ,
{ E1 , { " mcl_wool:pink_carpet " , 4 , 4 } } ,
{ E1 , { " mcl_wool:light_blue_carpet " , 4 , 4 } } ,
{ E1 , { " mcl_wool:brown_carpet " , 4 , 4 } } ,
} ,
{
{ { " mcl_dye:red " , 12 , 12 } , E1 } ,
{ { " mcl_dye:grey " , 12 , 12 } , E1 } ,
{ { " mcl_dye:pink " , 12 , 12 } , E1 } ,
{ { " mcl_dye:yellow " , 12 , 12 } , E1 } ,
{ { " mcl_dye:orange " , 12 , 12 } , E1 } ,
2023-08-19 03:36:04 +02:00
2023-07-25 05:44:28 +02:00
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_red_bottom " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_blue_bottom " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_cyan_bottom " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_grey_bottom " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_silver_bottom " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_black_bottom " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_yellow_bottom " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_green_bottom " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_magenta_bottom " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_orange_bottom " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_purple_bottom " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_brown_bottom " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_pink_bottom " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_lime_bottom " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_light_blue_bottom " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_beds:bed_white_bottom " , 1 , 1 } } ,
} ,
{
{ { " mcl_dye:dark_green " , 12 , 12 } , E1 } ,
{ { " mcl_dye:brown " , 12 , 12 } , E1 } ,
{ { " mcl_dye:blue " , 12 , 12 } , E1 } ,
{ { " mcl_dye:violet " , 12 , 12 } , E1 } ,
{ { " mcl_dye:cyan " , 12 , 12 } , E1 } ,
{ { " mcl_dye:magenta " , 12 , 12 } , E1 } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_white " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_grey " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_silver " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_black " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_red " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_yellow " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_green " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_cyan " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_blue " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_magenta " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_orange " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_purple " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_brown " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_pink " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_lime " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_light_blue " , 1 , 1 } } ,
} ,
{
{ { " mcl_core:emerald " , 2 , 2 } , { " mcl_paintings:painting " , 3 , 3 } } ,
2018-06-04 14:36:06 +02:00
} ,
} ,
} ,
2018-06-04 14:59:10 +02:00
librarian = {
2019-03-16 04:14:21 +01:00
name = N ( " Librarian " ) ,
2022-10-06 00:16:03 +02:00
texture = " mobs_mc_villager_librarian.png " ,
2023-01-09 23:21:16 +01:00
jobsite = " mcl_lectern:lectern " ,
2018-06-04 14:36:06 +02:00
trades = {
{
2023-07-25 05:44:28 +02:00
{ { " mcl_core:paper " , 24 , 24 } , E1 } ,
{ { " mcl_core:emerald " , 5 , 64 , " mcl_books:book " , 1 , 1 } , { " mcl_enchanting:book_enchanted " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 9 , 9 } , { " mcl_books:bookshelf " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
2023-07-25 05:44:28 +02:00
2018-06-04 14:36:06 +02:00
{
2023-07-25 05:44:28 +02:00
{ { " mcl_books:book " , 4 , 4 } , E1 } ,
{ { " mcl_core:emerald " , 5 , 64 , " mcl_books:book " , 1 , 1 } , { " mcl_enchanting:book_enchanted " , 1 , 1 } } ,
2022-05-12 18:20:59 +02:00
{ E1 , { " mcl_lanterns:lantern_floor " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
{
2023-07-25 05:44:28 +02:00
{ { " mcl_mobitems:ink_sac " , 5 , 5 } , E1 } ,
{ { " mcl_core:emerald " , 5 , 64 , " mcl_books:book " , 1 , 1 } , { " mcl_enchanting:book_enchanted " , 1 , 1 } } ,
2022-05-12 18:20:59 +02:00
{ E1 , { " mcl_core:glass " , 4 , 4 } } ,
2020-12-22 12:00:04 +01:00
} ,
2021-01-02 21:42:07 +01:00
2020-12-22 12:00:04 +01:00
{
2023-07-25 05:44:28 +02:00
{ { " mcl_books:writable_book " , 1 , 1 } , E1 } ,
{ { " mcl_core:emerald " , 5 , 64 , " mcl_books:book " , 1 , 1 } , { " mcl_enchanting:book_enchanted " , 1 , 1 } } ,
2022-05-12 18:20:59 +02:00
{ { " mcl_core:emerald " , 5 , 5 } , { " mcl_clock:clock " , 1 , 1 } } ,
2023-07-25 05:44:28 +02:00
{ { " mcl_core:emerald " , 4 , 4 } , { " mcl_compass:compass " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
{
2022-05-12 18:20:59 +02:00
{ { " mcl_core:emerald " , 20 , 20 } , { " mcl_mobs:nametag " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
}
} ,
} ,
2018-06-04 14:59:10 +02:00
cartographer = {
2019-03-16 04:14:21 +01:00
name = N ( " Cartographer " ) ,
2022-10-06 00:16:03 +02:00
texture = " mobs_mc_villager_cartographer.png " ,
2022-05-14 23:52:37 +02:00
jobsite = " mcl_cartography_table:cartography_table " ,
2018-06-04 14:36:06 +02:00
trades = {
{
2022-05-12 18:57:44 +02:00
{ { " mcl_core:paper " , 24 , 24 } , E1 } ,
2023-07-25 05:44:28 +02:00
{ { " mcl_core:emerald " , 7 , 7 } , { " mcl_maps:empty_map " , 1 , 1 } } ,
2022-05-12 18:57:44 +02:00
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 18:57:44 +02:00
{
-- compass subject to special checks
2022-10-13 05:46:34 +02:00
{ { " xpanes:pane_natural_flat " , 11 , 11 } , E1 } ,
2023-07-25 05:44:28 +02:00
--{ { "mcl_core:emerald", 13, 13, "mcl_compass:compass", 1, 1 }, { "FIXME:ocean explorer map" 1, 1 } },
2018-06-04 14:36:06 +02:00
} ,
2023-07-25 05:44:28 +02:00
2018-06-06 19:37:31 +02:00
{
{ { " mcl_compass:compass " , 1 , 1 } , E1 } ,
2023-07-25 05:44:28 +02:00
--{ { "mcl_core:emerald", 14, 14, "mcl_compass:compass", 1, 1 }, { "FIXME:woodland explorer map" 1, 1 } },
2018-06-06 19:37:31 +02:00
} ,
2023-07-25 05:44:28 +02:00
2018-06-04 14:36:06 +02:00
{
2023-07-25 05:44:28 +02:00
{ { " mcl_core:emerald " , 7 , 7 } , { " mcl_itemframes:item_frame " , 1 , 1 } } ,
2022-05-26 07:29:28 +02:00
2023-07-25 05:44:28 +02:00
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_white " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_grey " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_silver " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_black " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_red " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_yellow " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_green " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_cyan " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_blue " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_magenta " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_orange " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_purple " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_brown " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_pink " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_lime " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_banners:banner_item_light_blue " , 1 , 1 } } ,
2022-05-12 18:57:44 +02:00
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 18:57:44 +02:00
{
2023-07-25 05:44:28 +02:00
--{ { "mcl_core:emerald", 8, 8 }, { "FIXME: globe banner pattern", 1, 1 } },
2018-06-04 14:36:06 +02:00
} ,
-- TODO: special maps
} ,
} ,
2018-06-04 14:59:10 +02:00
armorer = {
2019-03-16 04:14:21 +01:00
name = N ( " Armorer " ) ,
2022-10-06 00:16:03 +02:00
texture = " mobs_mc_villager_armorer.png " ,
2022-05-17 18:37:55 +02:00
jobsite = " mcl_blast_furnace:blast_furnace " ,
2018-06-04 14:36:06 +02:00
trades = {
{
2022-05-12 21:33:53 +02:00
{ { " mcl_core:coal_lump " , 15 , 15 } , E1 } ,
{ { " mcl_core:emerald " , 5 , 5 } , { " mcl_armor:helmet_iron " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 9 , 9 } , { " mcl_armor:chestplate_iron " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 7 , 7 } , { " mcl_armor:leggings_iron " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 4 , 4 } , { " mcl_armor:boots_iron " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
{
2022-05-12 21:33:53 +02:00
{ { " mcl_core:iron_ingot " , 4 , 4 } , E1 } ,
2022-05-22 01:59:06 +02:00
{ { " mcl_core:emerald " , 36 , 36 } , { " mcl_bells:bell " , 1 , 1 } } ,
2022-05-12 21:33:53 +02:00
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_armor:leggings_chain " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 1 , 1 } , { " mcl_armor:boots_chain " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
2023-07-25 05:44:28 +02:00
2018-06-04 14:36:06 +02:00
{
2022-05-12 21:33:53 +02:00
{ { " mcl_buckets:bucket_lava " , 1 , 1 } , E1 } ,
{ { " mcl_core:diamond " , 1 , 1 } , E1 } ,
{ { " mcl_core:emerald " , 1 , 1 } , { " mcl_armor:helmet_chain " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 4 , 4 } , { " mcl_armor:chestplate_chain " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 5 , 5 } , { " mcl_shields:shield " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
{
2022-05-12 21:33:53 +02:00
{ { " mcl_core:emerald " , 19 , 33 } , { " mcl_armor:leggings_diamond_enchanted " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 13 , 27 } , { " mcl_armor:boots_diamond_enchanted " , 1 , 1 } } ,
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 21:33:53 +02:00
{
{ { " mcl_core:emerald " , 13 , 27 } , { " mcl_armor:helmet_diamond_enchanted " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 21 , 35 } , { " mcl_armor:chestplate_diamond_enchanted " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
} ,
} ,
2018-06-04 14:59:10 +02:00
leatherworker = {
2019-03-16 04:14:21 +01:00
name = N ( " Leatherworker " ) ,
2022-10-06 00:16:03 +02:00
texture = " mobs_mc_villager_leatherworker.png " ,
2023-07-27 13:27:51 +02:00
jobsite = " group:cauldron " ,
2018-06-04 14:36:06 +02:00
trades = {
{
2023-07-25 05:44:28 +02:00
{ { " mcl_mobitems:leather " , 6 , 6 } , E1 } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_armor:leggings_leather " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 7 , 7 } , { " mcl_armor:chestplate_leather " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
2023-07-25 05:44:28 +02:00
2018-06-04 14:36:06 +02:00
{
2022-05-12 21:42:56 +02:00
{ { " mcl_core:flint " , 26 , 26 } , E1 } ,
2023-07-25 05:44:28 +02:00
{ { " mcl_core:emerald " , 5 , 5 } , { " mcl_armor:helmet_leather " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 4 , 4 } , { " mcl_armor:boots_leather " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
2023-07-25 05:44:28 +02:00
2018-06-04 14:36:06 +02:00
{
2022-05-12 21:42:56 +02:00
{ { " mcl_mobitems:rabbit_hide " , 9 , 9 } , E1 } ,
{ { " mcl_core:emerald " , 7 , 7 } , { " mcl_armor:chestplate_leather " , 1 , 1 } } ,
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 21:42:56 +02:00
{
--{ { "FIXME: scute", 4, 4 }, E1 },
2018-06-04 14:36:06 +02:00
{ { " mcl_core:emerald " , 8 , 10 } , { " mcl_mobitems:saddle " , 1 , 1 } } ,
2023-07-25 05:44:28 +02:00
--FIXME: { { "mcl_core:emerald", 6, 6 }, { "mcl_mobitems:leather_horse_armor", 1, 1 } },
2018-06-04 14:36:06 +02:00
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 21:42:56 +02:00
{
{ { " mcl_core:emerald " , 6 , 6 } , { " mcl_mobitems:saddle " , 1 , 1 } } ,
2023-07-25 05:44:28 +02:00
{ { " mcl_core:emerald " , 5 , 5 } , { " mcl_armor:helmet_leather " , 1 , 1 } } ,
2022-05-12 21:42:56 +02:00
} ,
2018-06-04 14:36:06 +02:00
} ,
} ,
2018-06-04 14:59:10 +02:00
butcher = {
2019-03-16 04:14:21 +01:00
name = N ( " Butcher " ) ,
2022-10-06 00:16:03 +02:00
texture = " mobs_mc_villager_butcher.png " ,
2022-05-17 18:37:55 +02:00
jobsite = " mcl_smoker:smoker " ,
2018-06-04 14:36:06 +02:00
trades = {
{
2023-07-25 05:44:28 +02:00
{ { " mcl_mobitems:chicken " , 14 , 14 } , E1 } ,
{ { " mcl_mobitems:porkchop " , 7 , 7 } , E1 } ,
2022-05-12 21:55:25 +02:00
{ { " mcl_mobitems:rabbit " , 4 , 4 } , E1 } ,
{ E1 , { " mcl_mobitems:rabbit_stew " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
{
2022-05-12 21:55:25 +02:00
{ { " mcl_core:coal_lump " , 15 , 15 } , E1 } ,
{ E1 , { " mcl_mobitems:cooked_porkchop " , 5 , 5 } } ,
{ E1 , { " mcl_mobitems:cooked_chicken " , 8 , 8 } } ,
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 21:55:25 +02:00
{
{ { " mcl_mobitems:mutton " , 7 , 7 } , E1 } ,
{ { " mcl_mobitems:beef " , 10 , 10 } , E1 } ,
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 21:55:25 +02:00
{
2023-07-25 05:44:28 +02:00
{ { " mcl_ocean:dried_kelp_block " , 10 , 10 } , E1 } ,
{ { " mcl_farming:sweet_berry " , 10 , 10 } , E1 } ,
2018-06-04 14:36:06 +02:00
} ,
} ,
} ,
2018-06-04 14:59:10 +02:00
weapon_smith = {
2019-03-16 04:14:21 +01:00
name = N ( " Weapon Smith " ) ,
2022-10-06 00:16:03 +02:00
texture = " mobs_mc_villager_weaponsmith.png " ,
2022-06-20 21:46:59 +02:00
jobsite = " mcl_grindstone:grindstone " ,
2018-06-04 14:36:06 +02:00
trades = {
{
2022-05-12 22:01:30 +02:00
{ { " mcl_core:coal_lump " , 15 , 15 } , E1 } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_tools:axe_iron " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 7 , 21 } , { " mcl_tools:sword_iron_enchanted " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
{
2022-05-12 22:01:30 +02:00
{ { " mcl_core:iron_ingot " , 4 , 4 } , E1 } ,
2022-05-22 01:59:06 +02:00
{ { " mcl_core:emerald " , 36 , 36 } , { " mcl_bells:bell " , 1 , 1 } } ,
2022-05-12 22:01:30 +02:00
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 22:01:30 +02:00
{
2023-07-25 05:44:28 +02:00
{ { " mcl_core:flint " , 24 , 24 } , E1 } ,
2022-05-12 22:01:30 +02:00
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 22:01:30 +02:00
{
2023-07-25 05:44:28 +02:00
{ { " mcl_core:diamond " , 1 , 1 } , E1 } ,
2022-05-12 22:01:30 +02:00
{ { " mcl_core:emerald " , 17 , 31 } , { " mcl_tools:axe_diamond_enchanted " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
{
2022-05-12 22:01:30 +02:00
{ { " mcl_core:emerald " , 13 , 27 } , { " mcl_tools:sword_diamond_enchanted " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
} ,
} ,
2018-06-04 14:59:10 +02:00
tool_smith = {
2019-03-16 04:14:21 +01:00
name = N ( " Tool Smith " ) ,
2022-10-06 00:16:03 +02:00
texture = " mobs_mc_villager_toolsmith.png " ,
2022-06-27 18:31:56 +02:00
jobsite = " mcl_smithing_table:table " ,
2018-06-04 14:36:06 +02:00
trades = {
{
2022-05-12 22:11:39 +02:00
{ { " mcl_core:coal_lump " , 15 , 15 } , E1 } ,
{ E1 , { " mcl_tools:axe_stone " , 1 , 1 } } ,
{ E1 , { " mcl_tools:shovel_stone " , 1 , 1 } } ,
{ E1 , { " mcl_tools:pick_stone " , 1 , 1 } } ,
{ E1 , { " mcl_farming:hoe_stone " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
{
2022-05-12 22:11:39 +02:00
{ { " mcl_core:iron_ingot " , 4 , 4 } , E1 } ,
2022-05-22 01:59:06 +02:00
{ { " mcl_core:emerald " , 36 , 36 } , { " mcl_bells:bell " , 1 , 1 } } ,
2022-05-12 22:11:39 +02:00
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 22:11:39 +02:00
{
{ { " mcl_core:flint " , 30 , 30 } , E1 } ,
{ { " mcl_core:emerald " , 6 , 20 } , { " mcl_tools:axe_iron_enchanted " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 7 , 21 } , { " mcl_tools:shovel_iron_enchanted " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 8 , 22 } , { " mcl_tools:pick_iron_enchanted " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 4 , 4 } , { " mcl_farming:hoe_diamond " , 1 , 1 } } ,
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 22:11:39 +02:00
{
{ { " mcl_core:diamond " , 1 , 1 } , E1 } ,
{ { " mcl_core:emerald " , 17 , 31 } , { " mcl_tools:axe_diamond_enchanted " , 1 , 1 } } ,
{ { " mcl_core:emerald " , 10 , 24 } , { " mcl_tools:shovel_diamond_enchanted " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
2023-07-25 05:44:28 +02:00
2018-06-04 14:36:06 +02:00
{
2022-05-12 22:11:39 +02:00
{ { " mcl_core:emerald " , 18 , 32 } , { " mcl_tools:pick_diamond_enchanted " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
} ,
} ,
2018-06-04 14:59:10 +02:00
cleric = {
2019-03-16 04:14:21 +01:00
name = N ( " Cleric " ) ,
2022-10-06 00:16:03 +02:00
texture = " mobs_mc_villager_priest.png " ,
2022-05-13 21:28:56 +02:00
jobsite = " mcl_brewing:stand_000 " ,
2018-06-04 14:36:06 +02:00
trades = {
{
2022-05-12 22:18:55 +02:00
{ { " mcl_mobitems:rotten_flesh " , 32 , 32 } , E1 } ,
{ E1 , { " mesecons:redstone " , 2 , 2 } } ,
2018-06-04 14:36:06 +02:00
} ,
2023-07-25 05:44:28 +02:00
2018-06-04 14:36:06 +02:00
{
2022-05-12 22:18:55 +02:00
{ { " mcl_core:gold_ingot " , 3 , 3 } , E1 } ,
2022-12-22 18:10:59 +01:00
{ E1 , { " mcl_core:lapis " , 1 , 1 } } ,
2022-05-12 22:18:55 +02:00
} ,
2023-07-25 05:44:28 +02:00
2022-05-12 22:18:55 +02:00
{
{ { " mcl_mobitems:rabbit_foot " , 2 , 2 } , E1 } ,
2023-07-25 05:44:28 +02:00
{ { " mcl_core:emerald " , 4 , 4 } , { " mcl_nether:glowstone " , 1 , 1 } } ,
2018-06-04 14:36:06 +02:00
} ,
2023-07-25 05:44:28 +02:00
2018-06-04 14:36:06 +02:00
{
2022-05-12 22:18:55 +02:00
--{ { "FIXME: scute", 4, 4 }, E1 },
{ { " mcl_potions:glass_bottle " , 9 , 9 } , E1 } ,
{ { " mcl_core:emerald " , 5 , 5 } , { " mcl_throwing:ender_pearl " , 1 , 1 } } ,
2018-10-23 17:03:42 +02:00
TRADE_V6_RED_SANDSTONE ,
2018-06-04 14:36:06 +02:00
} ,
2023-07-25 05:44:28 +02:00
2021-01-24 19:55:33 +01:00
{
2023-07-25 05:44:28 +02:00
{ { " mcl_nether:nether_wart_item " , 22 , 22 } , E1 } ,
{ { " mcl_core:emerald " , 3 , 3 } , { " mcl_experience:bottle " , 1 , 1 } } ,
2021-01-24 19:55:33 +01:00
} ,
2018-06-04 14:36:06 +02:00
} ,
} ,
2022-11-05 03:02:24 +01:00
mason = {
2023-08-19 03:36:04 +02:00
name = N ( " Mason " ) ,
texture = " mobs_mc_villager_mason.png " ,
jobsite = " mcl_stonecutter:stonecutter " ,
trades = {
{
{ { " mcl_core:clay_lump " , 10 , 10 } , E1 } ,
{ E1 , { " mcl_core:brick " , 10 , 10 } } ,
} ,
{
{ { " mcl_core:stone " , 20 , 20 } , E1 } ,
{ E1 , { " mcl_core:stonebrickcarved " , 4 , 4 } } ,
} ,
{
{ { " mcl_core:granite " , 16 , 16 } , E1 } ,
{ { " mcl_core:andesite " , 16 , 16 } , E1 } ,
{ { " mcl_core:diorite " , 16 , 16 } , E1 } ,
{ E1 , { " mcl_core:andesite_smooth " , 4 , 4 } } ,
{ E1 , { " mcl_core:granite_smooth " , 4 , 4 } } ,
{ E1 , { " mcl_core:diorite_smooth " , 4 , 4 } } ,
--FIXME: { E1, { "Dripstone Block", 4, 4 } },
} ,
{
{ { " mcl_nether:quartz " , 12 , 12 } , E1 } ,
{ E1 , { " mcl_colorblocks:hardened_clay_white " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:hardened_clay_grey " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:hardened_clay_silver " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:hardened_clay_black " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:hardened_clay_red " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:hardened_clay_yellow " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:hardened_clay_green " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:hardened_clay_cyan " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:hardened_clay_blue " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:hardened_clay_magenta " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:hardened_clay_orange " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:hardened_clay_brown " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:hardened_clay_pink " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:hardened_clay_light_blue " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:hardened_clay_lime " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:hardened_clay_purple " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_white " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_grey " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_silver " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_black " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_red " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_yellow " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_green " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_cyan " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_blue " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_magenta " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_orange " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_brown " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_pink " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_light_blue " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_lime " , 1 , 1 } } ,
{ E1 , { " mcl_colorblocks:glazed_terracotta_purple " , 1 , 1 } } ,
} ,
{
{ E1 , { " mcl_nether:quartz_pillar " , 1 , 1 } } ,
{ E1 , { " mcl_nether:quartz_block " , 1 , 1 } } ,
} ,
2022-11-05 03:02:24 +01:00
} ,
} ,
2018-06-06 13:55:19 +02:00
nitwit = {
2019-03-16 04:14:21 +01:00
name = N ( " Nitwit " ) ,
2022-10-06 00:16:03 +02:00
texture = " mobs_mc_villager_nitwit.png " ,
2018-06-06 13:55:19 +02:00
-- No trades for nitwit
trades = nil ,
}
2018-06-04 14:36:06 +02:00
}
2017-07-05 03:15:46 +02:00
2022-10-19 00:59:53 +02:00
local WORK = " work "
local SLEEP = " sleep "
2022-10-27 23:27:19 +02:00
local GATHERING = " gathering "
2022-10-19 00:59:53 +02:00
2018-06-04 14:59:10 +02:00
local profession_names = { }
for id , _ in pairs ( professions ) do
table.insert ( profession_names , id )
end
2022-10-22 02:28:45 +02:00
local function populate_jobsites ( profession )
if profession then
mcl_log ( " populate_jobsites: " .. tostring ( profession ) )
end
local jobsites_requested = { }
for _ , n in pairs ( profession_names ) do
if n and professions [ n ] . jobsite then
if not profession or ( profession and profession == n ) then
--minetest.log("populate_jobsites. Adding: ".. tostring(n))
table.insert ( jobsites_requested , professions [ n ] . jobsite )
end
2022-10-19 00:59:53 +02:00
end
end
2022-10-22 02:28:45 +02:00
return jobsites_requested
2022-05-13 21:28:56 +02:00
end
2022-10-22 02:28:45 +02:00
jobsites = populate_jobsites ( )
2022-05-18 13:50:48 +02:00
local function stand_still ( self )
2018-06-10 14:24:00 +02:00
self.walk_chance = 0
self.jump = false
end
2022-05-16 19:22:59 +02:00
local function init_trader_vars ( self )
2022-05-13 21:28:56 +02:00
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
2022-05-20 00:02:36 +02:00
local function get_badge_textures ( self )
2022-10-06 00:16:03 +02:00
local t = professions [ self._profession ] . texture
2022-10-23 02:12:19 +02:00
if self._profession == " unemployed " then
t = professions [ self._profession ] . textures -- ideally both scenarios should be textures with a list containing 1 or multiple
--mcl_log("t: " .. tostring(t))
end
2022-05-20 00:02:36 +02:00
if self._profession == " unemployed " or self._profession == " nitwit " then return t end
local tier = self._max_trade_tier or 1
return {
2022-10-06 00:16:03 +02:00
t .. " ^ " .. badges [ tier ]
2022-05-20 00:02:36 +02:00
}
end
local function set_textures ( self )
2022-10-22 02:28:45 +02:00
local badge_textures = get_badge_textures ( self )
2022-10-26 00:53:55 +02:00
--mcl_log("Setting textures: " .. tostring(badge_textures))
2022-10-22 02:28:45 +02:00
self.object : set_properties ( { textures = badge_textures } )
2022-05-16 19:22:59 +02:00
end
2023-02-07 03:39:01 +01:00
-- TODO Pass in self and if nitwit, go to bed later.
local function is_night ( )
local tod = minetest.get_timeofday ( )
tod = ( tod * 24000 ) % 24000
return tod > 17500 or tod < 6500
end
2022-10-19 00:59:53 +02:00
function get_activity ( tod )
-- night hours = tod > 18541 or tod < 5458
if not tod then
tod = minetest.get_timeofday ( )
end
tod = ( tod * 24000 ) % 24000
2022-11-03 01:23:03 +01:00
local lunch_start = 11000
2022-10-26 01:17:29 +02:00
local lunch_end = 13500
2023-02-07 03:39:01 +01:00
local work_start = 7500
local work_end = 16000
2022-10-22 02:28:45 +02:00
2022-10-19 00:59:53 +02:00
local activity = nil
2022-10-27 23:27:19 +02:00
if weather_mod and mcl_weather.get_weather ( ) == " thunder " then
mcl_log ( " Better get to bed. Weather is: " .. mcl_weather.get_weather ( ) )
activity = SLEEP
elseif ( tod > work_start and tod < lunch_start ) or ( tod > lunch_end and tod < work_end ) then
2022-10-19 00:59:53 +02:00
activity = WORK
2023-02-07 03:39:01 +01:00
elseif is_night ( ) then
2022-10-19 00:59:53 +02:00
activity = SLEEP
elseif tod > lunch_start and tod < lunch_end then
2022-10-27 23:27:19 +02:00
activity = GATHERING
2022-10-19 00:59:53 +02:00
else
2022-10-22 02:28:45 +02:00
activity = " chill "
2022-10-19 00:59:53 +02:00
end
2022-12-30 15:17:24 +01:00
--mcl_log("Time is " .. tod ..". Activity is: ".. activity)
2022-10-19 00:59:53 +02:00
return activity
end
2022-11-08 00:25:41 +01:00
local function find_closest_bed ( self )
local p = self.object : get_pos ( )
2022-11-08 23:58:47 +01:00
--local spawnable_bed={}
--table.insert(spawnable_bed, "mcl_beds:bed_red_bottom")
2023-12-09 15:22:27 +01:00
--local nn = minetest.find_nodes_in_area(vector.offset(p,-VILLAGER_SEARCH_RADIUS,-VILLAGER_SEARCH_RADIUS,-VILLAGER_SEARCH_RADIUS),vector.offset(p,VILLAGER_SEARCH_RADIUS,VILLAGER_SEARCH_RADIUS,VILLAGER_SEARCH_RADIUS), spawnable_bed)
2022-11-08 00:25:41 +01:00
--if nn then
-- mcl_log("Red beds: " .. #nn)
--end
local unclaimed_beds = { }
2023-12-09 15:22:27 +01:00
local nn2 = minetest.find_nodes_in_area ( vector.offset ( p , - VILLAGER_SEARCH_RADIUS , - VILLAGER_SEARCH_RADIUS , - VILLAGER_SEARCH_RADIUS ) , vector.offset ( p , VILLAGER_SEARCH_RADIUS , VILLAGER_SEARCH_RADIUS , VILLAGER_SEARCH_RADIUS ) , { " group:bed " } )
2022-11-08 00:25:41 +01:00
if nn2 then
2022-11-08 23:58:47 +01:00
--mcl_log("All bed parts: " .. #nn2)
2022-11-08 00:25:41 +01:00
for a , b in pairs ( nn2 ) do
mcl_log ( " b: " .. minetest.pos_to_string ( b ) )
local bed_node = minetest.get_node ( b )
local bed_name = bed_node.name
local is_bed_bottom = string.find ( bed_name , " _bottom " )
2022-11-08 23:58:47 +01:00
local bed_meta = minetest.get_meta ( b )
2022-11-08 00:25:41 +01:00
local owned_by = bed_meta : get_string ( " villager " )
2022-11-08 23:58:47 +01:00
--mcl_log("Owned by villager: ".. tostring(owned_by))
2022-11-08 00:25:41 +01:00
2022-11-08 23:58:47 +01:00
if ( owned_by and owned_by == self._id ) then
mcl_log ( " Clear as already owned by me. " )
2022-11-08 00:25:41 +01:00
bed_meta : set_string ( " villager " , nil )
2022-11-08 23:58:47 +01:00
owned_by = nil
2022-11-08 00:25:41 +01:00
end
2022-11-08 23:58:47 +01:00
if is_bed_bottom then
local bed_top = mcl_beds.get_bed_top ( b )
mcl_log ( " bed_top: " .. tostring ( bed_top ) )
local bed_top_node = minetest.get_node ( bed_top )
if bed_top_node then
mcl_log ( " There is a block here for bed top: " .. bed_top_node.name )
else
mcl_log ( " There is no block here for bed top " )
end
local bed_top_meta = minetest.get_meta ( bed_top )
local owned_by_player = bed_top_meta : get_string ( " player " )
if bed_top_meta then
mcl_log ( " Player: " .. tostring ( owned_by_player ) )
else
mcl_log ( " No bed top meta " )
end
if owned_by == " " and ( not owned_by_player or owned_by_player == " " ) then
table.insert ( unclaimed_beds , b )
mcl_log ( " is an unowned bed bottom " )
else
end
2022-11-08 00:25:41 +01:00
else
2022-11-08 23:58:47 +01:00
--mcl_log("bed_node name: " .. bed_name)
2022-11-08 00:25:41 +01:00
end
end
end
local distance_to_closest_block = nil
local closest_block = nil
if unclaimed_beds then
mcl_log ( " All unclaimed bed bottoms: " .. # unclaimed_beds )
for i , b in pairs ( unclaimed_beds ) do
mcl_log ( " b: " .. minetest.pos_to_string ( b ) )
local distance_to_block = vector.distance ( p , b )
mcl_log ( " Distance to block " .. i .. " : " .. distance_to_block )
if not distance_to_closest_block or distance_to_closest_block > distance_to_block then
mcl_log ( " This block is closer than the last. " )
closest_block = b
distance_to_closest_block = distance_to_block
end
local bed_node = minetest.get_node ( b )
local bed_name = bed_node.name
mcl_log ( " bed_node name: " .. bed_name )
end
end
return closest_block
end
2022-11-03 01:23:03 +01:00
local function find_closest_unclaimed_block ( p , requested_block_types )
2023-12-09 15:22:27 +01:00
local nn = minetest.find_nodes_in_area ( vector.offset ( p , - VILLAGER_SEARCH_RADIUS , - VILLAGER_SEARCH_RADIUS , - VILLAGER_SEARCH_RADIUS ) , vector.offset ( p , VILLAGER_SEARCH_RADIUS , VILLAGER_SEARCH_RADIUS , VILLAGER_SEARCH_RADIUS ) , requested_block_types )
2022-11-03 01:23:03 +01:00
local distance_to_closest_block = nil
local closest_block = nil
for i , n in pairs ( nn ) do
local m = minetest.get_meta ( n )
if m : get_string ( " villager " ) == " " then
2022-11-03 02:00:48 +01:00
mcl_log ( " Block: " .. minetest.pos_to_string ( n ) .. " , owner: " .. m : get_string ( " villager " ) )
2022-11-03 01:23:03 +01:00
local distance_to_block = vector.distance ( p , n )
mcl_log ( " Distance to block " .. i .. " : " .. distance_to_block )
if not distance_to_closest_block or distance_to_closest_block > distance_to_block then
mcl_log ( " This block is closer than the last. " )
closest_block = n
distance_to_closest_block = distance_to_block
end
end
end
return closest_block
end
2022-10-27 23:27:19 +02:00
local function check_bed ( entity )
local b = entity._bed
if not b then
--minetest.log("No bed set on villager")
return false
end
local n = minetest.get_node ( b )
2022-11-08 00:25:41 +01:00
local is_bed_bottom = string.find ( n.name , " _bottom " )
2022-12-31 20:41:42 +01:00
--mcl_log("is bed bottom: " .. tostring(is_bed_bottom))
2022-11-08 00:25:41 +01:00
if n and not is_bed_bottom then
2022-10-27 23:27:19 +02:00
mcl_log ( " Where did my bed go?! " )
entity._bed = nil --the stormtroopers have killed uncle owen
return false
else
return true
end
end
2022-10-19 00:59:53 +02:00
local function go_home ( entity , sleep )
2022-10-27 23:27:19 +02:00
if not check_bed ( entity ) then
mcl_log ( " Cannot find bed, so cannot go home " )
end
2022-10-19 00:59:53 +02:00
local b = entity._bed
if not b then
return
end
local bed_node = minetest.get_node ( b )
if not bed_node then
entity._bed = nil
2022-10-22 02:28:45 +02:00
mcl_log ( " Cannot find bed. Unset it " )
2022-10-19 00:59:53 +02:00
return
end
2022-10-23 23:16:35 +02:00
2022-10-19 00:59:53 +02:00
if vector.distance ( entity.object : get_pos ( ) , b ) < 2 then
if sleep then
entity.order = SLEEP
2022-10-22 02:28:45 +02:00
mcl_log ( " Sleep time! " )
2022-10-19 00:59:53 +02:00
end
else
if sleep and entity.order == SLEEP then
entity.order = nil
return
end
2022-11-10 00:52:45 +01:00
entity : gopath ( b , function ( entity , b )
2022-10-19 00:59:53 +02:00
local b = entity._bed
if not b then
--minetest.log("NO BED, problem")
2022-05-16 19:22:59 +02:00
return false
end
2022-10-19 00:59:53 +02:00
if not minetest.get_node ( b ) then
--minetest.log("NO BED NODE, problem")
return false
end
if vector.distance ( entity.object : get_pos ( ) , b ) < 2 then
--minetest.log("Managed to walk home callback!")
return true
else
--minetest.log("Need to walk to home")
end
2023-02-07 03:39:01 +01:00
end , true )
2022-10-19 00:59:53 +02:00
end
end
local function take_bed ( entity )
if not entity then return end
2023-01-01 04:19:45 +01:00
if not entity : ready_to_path ( ) then return end
2022-10-19 00:59:53 +02:00
local p = entity.object : get_pos ( )
2022-11-08 00:25:41 +01:00
local closest_block = find_closest_bed ( entity )
2022-11-03 01:23:03 +01:00
if closest_block then
mcl_log ( " Can we path to bed: " .. minetest.pos_to_string ( closest_block ) )
2022-11-08 00:25:41 +01:00
local distance_to_block = vector.distance ( p , closest_block )
mcl_log ( " Distance: " .. distance_to_block )
if distance_to_block < 2 then
2022-11-09 00:42:44 +01:00
local m = minetest.get_meta ( closest_block )
local owner = m : get_string ( " villager " )
mcl_log ( " owner: " .. owner )
if owner and owner ~= " " and owner ~= entity._id then
mcl_log ( " Already taken " )
if entity.order == " stand " then entity.order = nil end
return
end
2022-11-08 00:25:41 +01:00
if entity.order ~= SLEEP then
2022-11-03 01:23:03 +01:00
mcl_log ( " Sleepy time " )
2022-11-08 00:25:41 +01:00
entity.order = SLEEP
m : set_string ( " villager " , entity._id )
entity._bed = closest_block
2022-10-19 00:59:53 +02:00
else
2022-11-09 00:42:44 +01:00
--entity.order = nil
2022-11-08 00:25:41 +01:00
mcl_log ( " Set as sleep already... " )
2022-10-19 00:59:53 +02:00
end
2022-10-22 02:28:45 +02:00
else
2022-11-10 00:52:45 +01:00
local gp = entity : gopath ( closest_block , function ( self ) end )
2022-11-08 00:25:41 +01:00
if gp then
mcl_log ( " Nice bed. I'll defintely take it as I can path " )
else
mcl_log ( " Awww. I can't find my bed. " )
end
2022-05-12 02:05:30 +02:00
end
2022-11-09 00:42:44 +01:00
else
mcl_log ( " Cannot find a bed to claim. " )
if entity.order == " stand " then entity.order = nil end
2022-10-19 00:59:53 +02:00
end
2022-05-12 02:05:30 +02:00
end
2022-08-30 16:37:23 +02:00
local function has_golem ( pos )
local r = false
for _ , o in pairs ( minetest.get_objects_inside_radius ( pos , 16 ) ) do
local l = o : get_luaentity ( )
if l and l.name == " mobs_mc:iron_golem " then return true end
end
end
2022-11-16 00:00:10 +01:00
local function monsters_near ( self )
for _ , o in pairs ( minetest.get_objects_inside_radius ( self.object : get_pos ( ) , 10 ) ) do
local l = o : get_luaentity ( )
if l and l.type == " monster " then return true end
end
end
2022-08-30 16:37:23 +02:00
local function has_summon_participants ( self )
local r = 0
for _ , o in pairs ( minetest.get_objects_inside_radius ( self.object : get_pos ( ) , 10 ) ) do
local l = o : get_luaentity ( )
2022-11-16 00:00:10 +01:00
--TODO check for gossiping
2022-08-30 16:37:23 +02:00
if l and l.name == " mobs_mc:villager " then r = r + 1 end
end
return r > 2
end
local function summon_golem ( self )
vector.offset ( self.object : get_pos ( ) , - 10 , - 10 , - 10 )
2022-08-30 22:58:55 +02:00
local nn = minetest.find_nodes_in_area_under_air ( vector.offset ( self.object : get_pos ( ) , - 10 , - 10 , - 10 ) , vector.offset ( self.object : get_pos ( ) , 10 , 10 , 10 ) , { " group:solid " , " group:water " } )
table.shuffle ( nn )
2022-08-30 16:37:23 +02:00
for _ , n in pairs ( nn ) do
local up = minetest.find_nodes_in_area ( vector.offset ( n , 0 , 1 , 0 ) , vector.offset ( n , 0 , 3 , 0 ) , { " air " } )
if up and # up >= 3 then
minetest.sound_play ( " mcl_portals_open_end_portal " , { pos = n , gain = 0.5 , max_hear_distance = 16 } , true )
return minetest.add_entity ( vector.offset ( n , 0 , 1 , 0 ) , " mobs_mc:iron_golem " )
end
end
end
local function check_summon ( self , dtime )
-- TODO has selpt in last 20?
if self._summon_timer and self._summon_timer > 30 then
local pos = self.object : get_pos ( )
self._summon_timer = 0
2022-11-16 00:00:10 +01:00
if has_golem ( pos ) then return end
if not monsters_near ( self ) then return end
2022-08-30 16:37:23 +02:00
if not has_summon_participants ( self ) then return end
summon_golem ( self )
elseif self._summon_timer == nil then
self._summon_timer = 0
end
self._summon_timer = self._summon_timer + dtime
end
2022-10-27 23:27:19 +02:00
local function debug_trades ( self )
mcl_log ( " Start debug trades " )
if not self or not self._trades then return end
local trades = minetest.deserialize ( self._trades )
if trades and type ( trades ) == " table " then
for trader , trade in pairs ( trades ) do
--mcl_log("Current record: ".. tostring(trader))
for tr3 , tr4 in pairs ( trade ) do
mcl_log ( " Key: " .. tostring ( tr3 ) )
mcl_log ( " Value: " .. tostring ( tr4 ) )
end
end
end
mcl_log ( " End debug trades " )
end
2022-10-23 02:12:19 +02:00
2022-10-27 23:27:19 +02:00
local function has_traded ( self )
2022-10-23 02:12:19 +02:00
if not self._trades then
mcl_log ( " No trades set. has_traded is false " )
return false
end
2022-10-22 02:28:45 +02:00
local cur_trades_tab = minetest.deserialize ( self._trades )
if cur_trades_tab and type ( cur_trades_tab ) == " table " then
for trader , trades in pairs ( cur_trades_tab ) do
if trades.traded_once then
mcl_log ( " Villager has traded before. Returning true " )
return true
end
end
end
mcl_log ( " Villager has not traded before " )
return false
end
local function unlock_trades ( self )
2022-10-27 23:27:19 +02:00
if not self._trades then
mcl_log ( " No trades set. has_traded is false " )
return false
end
mcl_log ( " Unlocking trades " )
local has_unlocked = false
local trades = minetest.deserialize ( self._trades )
if trades and type ( trades ) == " table " then
for trader , trade in pairs ( trades ) do
local trade_tier_too_high = trade.tier > self._max_trade_tier
2022-10-31 20:51:31 +01:00
--mcl_log("Max trade tier of villager: ".. tostring(self._max_trade_tier))
--mcl_log("current trade.tier: ".. tostring(trade.tier))
2022-11-01 21:31:51 +01:00
--mcl_log("trade tier too high: ".. tostring(trade_tier_too_high))
2022-10-31 20:51:31 +01:00
--mcl_log("locked: ".. tostring(trade["locked"]))
2022-10-27 23:27:19 +02:00
if not trade_tier_too_high then
if trade [ " locked " ] == true then
trade.locked = false
2022-11-01 02:01:13 +01:00
trade.trade_counter = 0
2022-10-27 23:27:19 +02:00
has_unlocked = true
mcl_log ( " Villager has a locked trade. Unlocking " )
end
end
end
if has_unlocked then
self._trades = minetest.serialize ( trades )
end
2022-10-22 02:28:45 +02:00
end
end
2022-05-16 19:22:59 +02:00
----- JOBSITE LOGIC
2022-05-13 21:28:56 +02:00
local function get_profession_by_jobsite ( js )
for k , v in pairs ( professions ) do
2023-08-04 03:24:07 +02:00
if v.jobsite == js then
return k
-- Catch Nitwit doesn't have a jobsite
elseif v.jobsite and v.jobsite : find ( " ^group: " ) then
local group = v.jobsite : gsub ( " ^group: " , " " )
if minetest.get_item_group ( js , group ) > 0 then
return k
end
end
2022-05-13 21:28:56 +02:00
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
2022-10-22 02:28:45 +02:00
mcl_log ( " Taking this jobsite " )
2022-10-23 02:17:51 +02:00
2022-05-13 21:28:56 +02:00
m : set_string ( " villager " , self._id )
self._jobsite = jobsite_pos
2022-10-22 02:28:45 +02:00
2022-10-23 02:12:19 +02:00
if not has_traded ( self ) then
2022-10-22 02:28:45 +02:00
self._profession = p
set_textures ( self )
end
2022-05-13 21:28:56 +02:00
return true
2022-10-19 00:59:53 +02:00
else
2022-10-22 02:28:45 +02:00
mcl_log ( " I can not steal someone's job! " )
2022-05-13 21:28:56 +02:00
end
end
2022-10-22 02:28:45 +02:00
local function look_for_job ( self , requested_jobsites )
mcl_log ( " Looking for jobs " )
2022-05-18 00:03:40 +02:00
local p = self.object : get_pos ( )
2022-10-22 02:28:45 +02:00
2022-11-03 01:23:03 +01:00
local closest_block = find_closest_unclaimed_block ( p , requested_jobsites )
2022-10-22 02:28:45 +02:00
2022-11-03 00:06:10 +01:00
if closest_block then
mcl_log ( " It's a free job for me ( " .. minetest.pos_to_string ( p ) .. " )! I might be interested: " .. minetest.pos_to_string ( closest_block ) )
2022-10-22 02:28:45 +02:00
2022-11-10 00:52:45 +01:00
local gp = self : gopath ( closest_block , function ( self )
2022-11-03 00:06:10 +01:00
mcl_log ( " Arrived at block callback " )
if self and self.state == " stand " then
self.order = WORK
2022-10-22 02:28:45 +02:00
else
2022-11-03 00:06:10 +01:00
mcl_log ( " no self. passing param to callback failed " )
2022-10-22 02:28:45 +02:00
end
2022-11-03 00:06:10 +01:00
end )
if gp then
if closest_block then
mcl_log ( " We can path to this block.. " .. tostring ( closest_block ) )
end
return closest_block
else
mcl_log ( " We could not path to block or it's not ready to path yet. " )
2022-05-18 00:03:40 +02:00
end
2022-11-03 00:06:10 +01:00
else
mcl_log ( " We don't have a job block to path to " )
2022-05-18 00:03:40 +02:00
end
2022-10-22 02:28:45 +02:00
return nil
2022-05-13 21:28:56 +02:00
end
2022-10-22 02:28:45 +02:00
2022-05-13 21:28:56 +02:00
local function get_a_job ( self )
2022-10-27 23:27:19 +02:00
if self.order == WORK then self.order = nil end
2023-01-01 00:47:22 +01:00
if not self : ready_to_path ( ) then return end
2022-10-27 23:27:19 +02:00
2022-10-22 02:28:45 +02:00
mcl_log ( " I'm unemployed or lost my job block and have traded. Can I get a job? " )
local requested_jobsites = jobsites
if has_traded ( self ) then
2022-10-25 21:24:37 +02:00
mcl_log ( " Has traded so look for job of my type " )
2022-10-22 02:28:45 +02:00
requested_jobsites = populate_jobsites ( self._profession )
-- Only pass in my jobsite to two functions here
end
2022-05-13 21:28:56 +02:00
local p = self.object : get_pos ( )
2022-10-22 02:28:45 +02:00
local n = minetest.find_node_near ( p , 1 , requested_jobsites )
2022-07-03 21:51:42 +02:00
if n and employ ( self , n ) then return true end
2022-10-19 00:59:53 +02:00
2022-10-26 00:53:55 +02:00
if self.state ~= PATHFINDING then
2022-10-22 02:28:45 +02:00
mcl_log ( " Nothing near. Need to look for a job " )
look_for_job ( self , requested_jobsites )
end
2022-05-13 21:28:56 +02:00
end
2022-10-22 02:28:45 +02:00
local function retrieve_my_jobsite ( self )
2022-10-19 00:59:53 +02:00
if not self or not self._jobsite then
2022-10-27 23:27:19 +02:00
mcl_log ( " find_jobsite. Invalid params. Should not happen " )
2022-10-19 00:59:53 +02:00
return
end
2022-07-04 00:15:50 +02:00
local n = mcl_vars.get_node ( self._jobsite )
local m = minetest.get_meta ( self._jobsite )
2022-10-19 00:59:53 +02:00
if m : get_string ( " villager " ) == self._id then
2022-10-22 02:28:45 +02:00
--mcl_log("find_jobsite. is my job.")
2022-10-19 00:59:53 +02:00
return n
else
2022-10-27 23:27:19 +02:00
mcl_log ( " This isn't my jobsite " )
2022-10-19 00:59:53 +02:00
end
return
end
2022-11-15 23:32:09 +01:00
local function remove_job ( self )
self._jobsite = nil
if not has_traded ( self ) then
mcl_log ( " Cannot retrieve my jobsite. I am now unemployed. " )
self._profession = " unemployed "
self._trades = nil
set_textures ( self )
else
mcl_log ( " Cannot retrieve my jobsite but I've traded so only remove jobsite. " )
end
end
2022-10-22 02:28:45 +02:00
local function validate_jobsite ( self )
2022-10-23 02:12:19 +02:00
if self._profession == " unemployed " then return false end
2022-11-15 23:32:09 +01:00
local job_block = retrieve_my_jobsite ( self )
if not job_block then
2022-10-23 02:12:19 +02:00
if self.order == WORK then
self.order = nil
end
2022-11-15 23:32:09 +01:00
remove_job ( self )
2022-10-19 00:59:53 +02:00
return false
else
2022-11-15 23:32:09 +01:00
local resettle = vector.distance ( self.object : get_pos ( ) , self._jobsite ) > RESETTLE_DISTANCE
mcl_log ( " Jobsite far, so resettle: " .. tostring ( resettle ) )
if resettle then
local m = minetest.get_meta ( self._jobsite )
m : set_string ( " villager " , nil )
remove_job ( self )
return false
end
2022-10-19 00:59:53 +02:00
return true
end
end
local function do_work ( self )
2022-12-31 20:41:42 +01:00
if not self or self.child then
mcl_log ( " No self, or a child so don't work " )
2022-10-27 23:27:19 +02:00
return
end
2022-10-19 00:59:53 +02:00
2022-12-31 20:41:42 +01:00
--mcl_log("Time for work")
local jobsite_node = retrieve_my_jobsite ( self )
2022-10-19 00:59:53 +02:00
2022-12-31 20:41:42 +01:00
if jobsite_node then
2022-10-22 02:28:45 +02:00
local jobsite = self._jobsite
2022-10-19 00:59:53 +02:00
2022-12-31 20:41:42 +01:00
local distance_to_jobsite = vector.distance ( self.object : get_pos ( ) , jobsite )
--mcl_log("Villager: ".. minetest.pos_to_string(self.object:get_pos()) .. ", jobsite: " .. minetest.pos_to_string(self._jobsite) .. ", distance to jobsite: ".. distance_to_jobsite)
2022-10-22 02:28:45 +02:00
2022-12-31 20:41:42 +01:00
if distance_to_jobsite < 2 then
if self.state ~= PATHFINDING and self.order ~= WORK then
mcl_log ( " Setting order to work. " )
self.order = WORK
unlock_trades ( self )
2022-10-22 02:28:45 +02:00
else
2022-12-31 20:41:42 +01:00
--mcl_log("Still pathfinding.")
end
else
mcl_log ( " Not at job block. Need to commute. " )
if self.order == WORK then
self.order = nil
return
2022-10-22 02:28:45 +02:00
end
2023-02-07 03:39:01 +01:00
2022-12-31 20:41:42 +01:00
self : gopath ( jobsite , function ( self , jobsite )
if not self then
--mcl_log("missing self. not good")
return false
end
if not self._jobsite then
--mcl_log("Jobsite not valid")
return false
end
if vector.distance ( self.object : get_pos ( ) , self._jobsite ) < 2 then
--mcl_log("Made it to work ok callback!")
return true
else
--mcl_log("Need to walk to work. Not sure we can get here.")
end
end )
2022-10-19 00:59:53 +02:00
end
2022-10-27 23:27:19 +02:00
end
2022-12-31 20:41:42 +01:00
2022-10-27 23:27:19 +02:00
end
2022-12-08 00:38:44 +01:00
local below_vec = vector.new ( 0 , - 1 , 0 )
local function get_ground_below_floating_object ( float_pos )
local pos = float_pos
repeat
mcl_log ( " Current pos: " .. minetest.pos_to_string ( pos ) )
pos = vector.add ( pos , below_vec )
local node = minetest.get_node ( pos )
mcl_log ( " First non air materials: " .. tostring ( node.name ) )
until node.name ~= " air "
2022-12-30 15:17:24 +01:00
-- If pos is 1 below float_pos, then just return float_pos as there is no air below it
2022-12-30 16:10:55 +01:00
if pos.y == float_pos.y - 1 then
2022-12-30 15:17:24 +01:00
--mcl_log("pos is only 1 lower than float pos so no air below")
return float_pos
else
--mcl_log("pos is more than 1 lower than float pos so air is below")
return pos
end
2022-12-08 00:38:44 +01:00
return pos
end
2022-10-27 23:27:19 +02:00
local function go_to_town_bell ( self )
2022-12-31 20:41:42 +01:00
if self.order == GATHERING then return
else mcl_log ( " Current order " .. self.order ) end
2022-12-09 20:07:45 +01:00
2022-12-31 20:41:42 +01:00
if not self : ready_to_path ( ) then return end
2022-12-09 20:07:45 +01:00
2022-10-27 23:27:19 +02:00
mcl_log ( " Go to town bell " )
local looking_for_type = { }
table.insert ( looking_for_type , " mcl_bells:bell " )
local p = self.object : get_pos ( )
2023-12-09 15:22:27 +01:00
local nn = minetest.find_nodes_in_area ( vector.offset ( p , - VILLAGER_SEARCH_RADIUS , - VILLAGER_SEARCH_RADIUS , - VILLAGER_SEARCH_RADIUS ) , vector.offset ( p , VILLAGER_SEARCH_RADIUS , VILLAGER_SEARCH_RADIUS , VILLAGER_SEARCH_RADIUS ) , looking_for_type )
2022-10-27 23:27:19 +02:00
--Ideally should check for closest available. It'll make pathing easier.
for _ , n in pairs ( nn ) do
mcl_log ( " Found bell " )
2022-12-08 00:38:44 +01:00
local target_point = get_ground_below_floating_object ( n )
2022-12-09 20:07:45 +01:00
2022-12-08 00:38:44 +01:00
local gp = self : gopath ( target_point , function ( self )
2022-10-27 23:27:19 +02:00
if self then
self.order = GATHERING
mcl_log ( " Callback has a self " )
end
mcl_log ( " Arrived at block callback " )
end )
if gp then
if n then
mcl_log ( " We can path to this block.. " .. tostring ( n ) )
end
return n
else
mcl_log ( " We could not path to block or it's not ready to path yet. " )
end
end
return nil
end
2022-11-08 23:58:47 +01:00
local function validate_bed ( self )
if not self or not self._bed then
return false
end
local n = mcl_vars.get_node ( self._bed )
if not n then
self._bed = nil
return false
end
local bed_valid = true
local m = minetest.get_meta ( self._bed )
2022-11-15 23:32:09 +01:00
local resettle = vector.distance ( self.object : get_pos ( ) , self._bed ) > RESETTLE_DISTANCE
mcl_log ( " Bed far, so resettle: " .. tostring ( resettle ) )
if resettle then
mcl_log ( " Resettled. Ditch bed. " )
m : set_string ( " villager " , nil )
self._bed = nil
bed_valid = false
return false
end
2022-11-08 23:58:47 +01:00
local owned_by_player = m : get_string ( " player " )
mcl_log ( " Player owner: " .. owned_by_player )
if owned_by_player ~= " " then
mcl_log ( " Player owns this. Villager won't take this. " )
m : set_string ( " villager " , nil )
self._bed = nil
bed_valid = false
2022-11-15 23:32:09 +01:00
return false
2022-11-08 23:58:47 +01:00
end
if m : get_string ( " villager " ) ~= self._id then
mcl_log ( " This bed is owned by another player. I'll unclaim. " )
self._bed = nil
return false
else
mcl_log ( " Bed is valid " )
return true
end
end
2022-10-27 23:27:19 +02:00
local function do_activity ( self )
2022-12-31 20:41:42 +01:00
2022-11-15 23:32:09 +01:00
if self.following then
mcl_log ( " Following, so do not do activity. " )
return
end
2022-12-31 20:41:42 +01:00
if self.state == PATHFINDING then
mcl_log ( " Pathfinding, so do not do activity. " )
return
end
2022-10-27 23:27:19 +02:00
2022-12-31 20:41:42 +01:00
local jobsite_valid = false
2023-02-07 03:39:01 +01:00
if not is_night ( ) then
2022-11-08 23:58:47 +01:00
if self.order == SLEEP then self.order = nil end
2022-12-31 20:41:42 +01:00
if not validate_jobsite ( self ) then
--debug_trades(self)
if self._profession == " unemployed " or has_traded ( self ) then
get_a_job ( self )
return
end
else
jobsite_valid = true
--mcl_log("My jobsite is valid. Do i need to travel?")
end
else
if self.order == WORK then self.order = nil end
if not validate_bed ( self ) then
if self.order == SLEEP then self.order = nil end
mcl_log ( " Villager at this location has no bed: " .. minetest.pos_to_string ( self.object : get_pos ( ) ) )
take_bed ( self )
end
2022-10-27 23:27:19 +02:00
end
-- Only check in day or during thunderstorm but wandered_too_far code won't work
2022-10-28 01:05:03 +02:00
local wandered_too_far = false
if check_bed ( self ) then
2022-12-31 20:41:42 +01:00
wandered_too_far = vector.distance ( self.object : get_pos ( ) , self._bed ) > 50
2022-10-28 01:05:03 +02:00
end
2022-10-27 23:27:19 +02:00
if wandered_too_far then
--mcl_log("Wandered too far! Return home ")
go_home ( self , false )
elseif get_activity ( ) == SLEEP then
go_home ( self , true )
2022-12-31 20:41:42 +01:00
elseif get_activity ( ) == WORK and jobsite_valid then
2022-10-27 23:27:19 +02:00
do_work ( self )
elseif get_activity ( ) == GATHERING then
go_to_town_bell ( self )
else
mcl_log ( " No order, so remove it. " )
self.order = nil
end
2022-07-04 00:15:50 +02:00
end
2022-05-18 13:50:48 +02:00
local function update_max_tradenum ( self )
2018-06-10 13:06:28 +02:00
if not self._trades then
return
end
local trades = minetest.deserialize ( self._trades )
for t = 1 , # trades do
local trade = trades [ t ]
if trade.tier > self._max_trade_tier then
self._max_tradenum = t - 1
return
end
end
self._max_tradenum = # trades
end
2022-05-18 13:50:48 +02:00
local function init_trades ( self , inv )
2018-06-04 21:07:12 +02:00
local profession = professions [ self._profession ]
local trade_tiers = profession.trades
if trade_tiers == nil then
2018-06-06 13:55:19 +02:00
-- Empty trades
self._trades = false
2018-06-04 21:07:12 +02:00
return
end
2018-06-06 16:34:44 +02:00
local max_tier = # trade_tiers
2018-06-04 21:07:12 +02:00
local trades = { }
for tiernum = 1 , max_tier do
local tier = trade_tiers [ tiernum ]
for tradenum = 1 , # tier do
local trade = tier [ tradenum ]
local wanted1_item = trade [ 1 ] [ 1 ]
local wanted1_count = math.random ( trade [ 1 ] [ 2 ] , trade [ 1 ] [ 3 ] )
local offered_item = trade [ 2 ] [ 1 ]
local offered_count = math.random ( trade [ 2 ] [ 2 ] , trade [ 2 ] [ 3 ] )
2021-01-02 21:42:07 +01:00
2020-12-22 12:00:04 +01:00
local offered_stack = ItemStack ( { name = offered_item , count = offered_count } )
if mcl_enchanting.is_enchanted ( offered_item ) then
if mcl_enchanting.is_book ( offered_item ) then
2022-02-18 02:31:19 +01:00
offered_stack = mcl_enchanting.enchant_uniform_randomly ( offered_stack , { " soul_speed " } )
2020-12-22 12:00:04 +01:00
else
mcl_enchanting.enchant_randomly ( offered_stack , math.random ( 5 , 19 ) , false , false , true )
2021-03-01 10:51:57 +01:00
mcl_enchanting.unload_enchantments ( offered_stack )
2020-12-22 12:00:04 +01:00
end
end
2021-01-02 21:42:07 +01:00
2018-06-04 21:07:12 +02:00
local wanted = { wanted1_item .. " " .. wanted1_count }
if trade [ 1 ] [ 4 ] then
local wanted2_item = trade [ 1 ] [ 4 ]
local wanted2_count = math.random ( trade [ 1 ] [ 5 ] , trade [ 1 ] [ 6 ] )
table.insert ( wanted , wanted2_item .. " " .. wanted2_count )
end
table.insert ( trades , {
wanted = wanted ,
2020-12-22 12:00:04 +01:00
offered = offered_stack : to_table ( ) ,
2018-06-06 16:34:44 +02:00
tier = tiernum , -- tier of this trade
traded_once = false , -- true if trade was traded at least once
trade_counter = 0 , -- how often the this trade was mate after the last time it got unlocked
locked = false , -- if this trade is locked. Locked trades can't be used
2018-06-04 21:07:12 +02:00
} )
end
end
self._trades = minetest.serialize ( trades )
2020-12-22 12:00:04 +01:00
minetest.deserialize ( self._trades )
2018-06-04 21:07:12 +02:00
end
2022-05-18 13:50:48 +02:00
local function set_trade ( trader , player , inv , concrete_tradenum )
2018-06-06 16:34:44 +02:00
local trades = minetest.deserialize ( trader._trades )
2018-06-04 21:07:12 +02:00
if not trades then
2018-06-06 16:34:44 +02:00
init_trades ( trader )
trades = minetest.deserialize ( trader._trades )
2018-06-04 21:07:12 +02:00
if not trades then
2022-10-22 02:28:45 +02:00
--minetest.log("error", "Failed to select villager trade!")
2018-06-04 21:07:12 +02:00
return
end
end
2018-06-10 13:06:28 +02:00
local name = player : get_player_name ( )
2018-06-04 21:07:12 +02:00
2018-06-10 13:06:28 +02:00
-- Stop tradenum from advancing into locked tiers or out-of-range areas
if concrete_tradenum > trader._max_tradenum then
concrete_tradenum = trader._max_tradenum
2018-06-04 21:46:13 +02:00
elseif concrete_tradenum < 1 then
2018-06-06 16:34:44 +02:00
concrete_tradenum = 1
end
2018-06-10 13:06:28 +02:00
player_tradenum [ name ] = concrete_tradenum
local trade = trades [ concrete_tradenum ]
2018-06-04 21:07:12 +02:00
inv : set_stack ( " wanted " , 1 , ItemStack ( trade.wanted [ 1 ] ) )
2021-03-01 10:51:57 +01:00
local offered = ItemStack ( trade.offered )
2022-05-30 22:11:22 +02:00
-- Only load enchantments for enchanted items; fixes unnecessary metadata being applied to regular items from villagers.
if mcl_enchanting.is_enchanted ( offered : get_name ( ) ) then
mcl_enchanting.load_enchantments ( offered )
end
2021-03-01 10:51:57 +01:00
inv : set_stack ( " offered " , 1 , offered )
2018-06-04 21:07:12 +02:00
if trade.wanted [ 2 ] then
local wanted2 = ItemStack ( trade.wanted [ 2 ] )
inv : set_stack ( " wanted " , 2 , wanted2 )
else
inv : set_stack ( " wanted " , 2 , " " )
end
end
2018-06-06 17:33:14 +02:00
local function show_trade_formspec ( playername , trader , tradenum )
if not trader._trades then
return
end
if not tradenum then
tradenum = 1
end
local trades = minetest.deserialize ( trader._trades )
local trade = trades [ tradenum ]
2018-06-04 22:13:24 +02:00
local profession = professions [ trader._profession ] . name
2018-06-06 17:33:14 +02:00
local disabled_img = " "
if trade.locked then
2018-06-06 19:50:17 +02:00
disabled_img = " image[4.3,2.52;1,1;mobs_mc_trading_formspec_disabled.png] " ..
" image[4.3,1.1;1,1;mobs_mc_trading_formspec_disabled.png] "
2018-06-06 14:39:16 +02:00
end
2018-06-10 12:05:05 +02:00
local tradeinv_name = " mobs_mc:trade_ " .. playername
2020-03-19 12:32:30 +01:00
local tradeinv = F ( " detached: " .. tradeinv_name )
2018-06-10 13:06:28 +02:00
local b_prev , b_next = " " , " "
if # trades > 1 then
if tradenum > 1 then
b_prev = " button[1,1;0.5,1;prev_trade;<] "
end
if tradenum < trader._max_tradenum then
b_next = " button[7.26,1;0.5,1;next_trade;>] "
end
end
2020-03-19 12:32:30 +01:00
local inv = minetest.get_inventory ( { type = " detached " , name = " mobs_mc:trade_ " .. playername } )
2020-05-08 17:27:22 +02:00
if not inv then
return
end
2020-03-19 12:32:30 +01:00
local wanted1 = inv : get_stack ( " wanted " , 1 )
local wanted2 = inv : get_stack ( " wanted " , 2 )
local offered = inv : get_stack ( " offered " , 1 )
2021-01-02 21:42:07 +01:00
2020-03-19 12:32:30 +01:00
local w2_formspec = " "
if not wanted2 : is_empty ( ) then
w2_formspec = " item_image[3,1;1,1; " .. wanted2 : to_string ( ) .. " ] "
.. " tooltip[3,1;0.8,0.8; " .. F ( wanted2 : get_description ( ) ) .. " ] "
end
2022-05-19 18:25:31 +02:00
local tiername = tiernames [ trader._max_trade_tier ]
if tiername then
tiername = S ( tiername )
else
tiername = S ( " Master " )
end
2018-06-04 21:46:13 +02:00
local formspec =
2018-06-06 17:33:14 +02:00
" size[9,8.75] "
.. " background[-0.19,-0.25;9.41,9.49;mobs_mc_trading_formspec_bg.png] "
.. disabled_img
2022-05-19 18:25:31 +02:00
.. " label[3,0; " .. F ( minetest.colorize ( " #313131 " , S ( profession ) .. " - " .. tiername ) ) .. " ] "
2018-06-04 22:13:24 +02:00
.. " list[current_player;main;0,4.5;9,3;9] "
2018-06-04 21:46:13 +02:00
.. " list[current_player;main;0,7.74;9,1;] "
2018-06-10 13:06:28 +02:00
.. b_prev .. b_next
2020-03-19 12:32:30 +01:00
.. " [ " .. tradeinv .. " ;wanted;2,1;2,1;] "
.. " item_image[2,1;1,1; " .. wanted1 : to_string ( ) .. " ] "
.. " tooltip[2,1;0.8,0.8; " .. F ( wanted1 : get_description ( ) ) .. " ] "
.. w2_formspec
2020-12-22 12:00:04 +01:00
.. " item_image[5.76,1;1,1; " .. offered : get_name ( ) .. " " .. offered : get_count ( ) .. " ] "
2020-03-19 12:32:30 +01:00
.. " tooltip[5.76,1;0.8,0.8; " .. F ( offered : get_description ( ) ) .. " ] "
2018-06-10 12:05:05 +02:00
.. " list[ " .. tradeinv .. " ;input;2,2.5;2,1;] "
.. " list[ " .. tradeinv .. " ;output;5.76,2.55;1,1;] "
.. " listring[ " .. tradeinv .. " ;output] "
2018-06-04 21:46:13 +02:00
.. " listring[current_player;main] "
2018-06-10 12:05:05 +02:00
.. " listring[ " .. tradeinv .. " ;input] "
2018-06-04 21:46:13 +02:00
.. " listring[current_player;main] "
2022-08-12 15:42:08 +02:00
minetest.sound_play ( " mobs_mc_villager_trade " , { to_player = playername , object = trader.object } , true )
2018-06-10 12:05:05 +02:00
minetest.show_formspec ( playername , tradeinv_name , formspec )
2018-06-04 21:46:13 +02:00
end
2022-05-18 13:50:48 +02:00
local function update_offer ( inv , player , sound )
2018-06-06 17:33:14 +02:00
local name = player : get_player_name ( )
local trader = player_trading_with [ name ]
local tradenum = player_tradenum [ name ]
if not trader or not tradenum then
return false
end
local trades = minetest.deserialize ( trader._trades )
if not trades then
return false
end
local trade = trades [ tradenum ]
if not trade then
return false
end
2018-06-06 19:37:31 +02:00
local wanted1 , wanted2 = inv : get_stack ( " wanted " , 1 ) , inv : get_stack ( " wanted " , 2 )
local input1 , input2 = inv : get_stack ( " input " , 1 ) , inv : get_stack ( " input " , 2 )
-- BEGIN OF SPECIAL HANDLING OF COMPASS
-- These 2 functions are a complicated check to check if the input contains a
-- special item which we cannot check directly against their name, like
-- compass.
-- TODO: Remove these check functions when compass and clock are implemented
-- as single items.
2022-05-18 13:50:48 +02:00
local function check_special ( special_item , group , wanted1 , wanted2 , input1 , input2 )
2018-06-06 19:37:31 +02:00
if minetest.registered_aliases [ special_item ] then
special_item = minetest.registered_aliases [ special_item ]
end
if wanted1 : get_name ( ) == special_item then
2022-05-18 13:50:48 +02:00
local function check_input ( input , wanted , group )
2018-06-06 19:37:31 +02:00
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
return true
elseif check_input ( input2 , wanted1 , group ) then
return true
else
return false
end
end
return false
end
-- Apply above function to all items which we consider special.
-- This function succeeds if ANY item check succeeds.
2022-05-18 13:50:48 +02:00
local function check_specials ( wanted1 , wanted2 , input1 , input2 )
2018-06-06 19:37:31 +02:00
return check_special ( COMPASS , " compass " , wanted1 , wanted2 , input1 , input2 )
end
-- END OF SPECIAL HANDLING OF COMPASS
if (
( ( inv : contains_item ( " input " , wanted1 ) and
( wanted2 : is_empty ( ) or inv : contains_item ( " input " , wanted2 ) ) ) or
-- BEGIN OF SPECIAL HANDLING OF COMPASS
check_specials ( wanted1 , wanted2 , input1 , input2 ) ) and
-- END OF SPECIAL HANDLING OF COMPASS
( trade.locked == false ) ) then
2018-06-04 21:46:13 +02:00
inv : set_stack ( " output " , 1 , inv : get_stack ( " offered " , 1 ) )
if sound then
2022-08-12 15:42:08 +02:00
minetest.sound_play ( " mobs_mc_villager_accept " , { to_player = name , object = trader.object } , true )
2018-06-04 21:46:13 +02:00
end
return true
else
inv : set_stack ( " output " , 1 , ItemStack ( " " ) )
if sound then
2022-08-12 15:42:08 +02:00
minetest.sound_play ( " mobs_mc_villager_deny " , { to_player = name , object = trader.object } , true )
2018-06-04 21:46:13 +02:00
end
return false
end
end
2018-06-04 12:50:31 +02:00
-- Returns a single itemstack in the given inventory to the player's main inventory, or drop it when there's no space left
local function return_item ( itemstack , dropper , pos , inv_p )
if dropper : is_player ( ) then
-- Return to main inventory
if inv_p : room_for_item ( " main " , itemstack ) then
inv_p : add_item ( " main " , itemstack )
else
-- Drop item on the ground
local v = dropper : get_look_dir ( )
local p = { x = pos.x , y = pos.y + 1.2 , z = pos.z }
p.x = p.x + ( math.random ( 1 , 3 ) * 0.2 )
p.z = p.z + ( math.random ( 1 , 3 ) * 0.2 )
local obj = minetest.add_item ( p , itemstack )
if obj then
v.x = v.x * 4
v.y = v.y * 4 + 2
v.z = v.z * 4
2019-03-06 04:38:57 +01:00
obj : set_velocity ( v )
2018-06-04 12:50:31 +02:00
obj : get_luaentity ( ) . _insta_collect = false
end
end
else
-- Fallback for unexpected cases
minetest.add_item ( pos , itemstack )
end
return itemstack
end
2022-05-18 13:50:48 +02:00
local function return_fields ( player )
2018-06-10 12:05:05 +02:00
local name = player : get_player_name ( )
local inv_t = minetest.get_inventory ( { type = " detached " , name = " mobs_mc:trade_ " .. name } )
2018-06-04 12:50:31 +02:00
local inv_p = player : get_inventory ( )
2020-05-08 17:27:22 +02:00
if not inv_t or not inv_p then
return
end
2018-06-04 14:36:06 +02:00
for i = 1 , inv_t : get_size ( " input " ) do
local stack = inv_t : get_stack ( " input " , i )
2018-06-04 12:50:31 +02:00
return_item ( stack , player , player : get_pos ( ) , inv_p )
stack : clear ( )
inv_t : set_stack ( " input " , i , stack )
end
2018-06-04 14:36:06 +02:00
inv_t : set_stack ( " output " , 1 , " " )
2018-06-04 12:50:31 +02:00
end
minetest.register_on_player_receive_fields ( function ( player , formname , fields )
2018-06-10 12:05:05 +02:00
if string.sub ( formname , 1 , 14 ) == " mobs_mc:trade_ " then
2018-06-04 21:46:13 +02:00
local name = player : get_player_name ( )
2018-06-04 12:50:31 +02:00
if fields.quit then
2018-06-10 15:01:44 +02:00
-- Get input items back
2018-06-04 12:50:31 +02:00
return_fields ( player )
2018-06-10 15:01:44 +02:00
-- Reset internal "trading with" state
local trader = player_trading_with [ name ]
if trader then
trader._trading_players [ name ] = nil
end
2018-06-04 21:46:13 +02:00
player_trading_with [ name ] = nil
2018-06-10 13:06:28 +02:00
elseif fields.next_trade or fields.prev_trade then
2018-06-04 21:46:13 +02:00
local trader = player_trading_with [ name ]
if not trader or not trader.object : get_luaentity ( ) then
return
end
2018-06-06 16:34:44 +02:00
local trades = trader._trades
if not trades then
return
end
2018-06-10 13:06:28 +02:00
local dir = 1
if fields.prev_trade then
dir = - 1
2018-06-06 16:34:44 +02:00
end
2018-06-10 13:06:28 +02:00
local tradenum = player_tradenum [ name ] + dir
2018-06-10 12:05:05 +02:00
local inv = minetest.get_inventory ( { type = " detached " , name = " mobs_mc:trade_ " .. name } )
2020-05-08 17:27:22 +02:00
if not inv then
return
end
2018-06-10 13:06:28 +02:00
set_trade ( trader , player , inv , tradenum )
2018-06-04 21:46:13 +02:00
update_offer ( inv , player , false )
2018-06-06 17:33:14 +02:00
show_trade_formspec ( name , trader , player_tradenum [ name ] )
2018-06-04 12:50:31 +02:00
end
end
end )
minetest.register_on_leaveplayer ( function ( player )
2018-06-11 14:47:41 +02:00
local name = player : get_player_name ( )
2018-06-04 12:50:31 +02:00
return_fields ( player )
2018-06-11 14:47:41 +02:00
player_tradenum [ name ] = nil
2018-06-10 15:01:44 +02:00
local trader = player_trading_with [ name ]
if trader then
trader._trading_players [ name ] = nil
end
2018-06-11 14:47:41 +02:00
player_trading_with [ name ] = nil
2018-06-10 15:01:44 +02:00
2018-06-04 21:46:13 +02:00
end )
2018-06-10 15:01:44 +02:00
-- Return true if player is trading with villager, and the villager entity exists
2022-05-18 13:50:48 +02:00
local function trader_exists ( playername )
2018-06-10 15:01:44 +02:00
local trader = player_trading_with [ playername ]
return trader ~= nil and trader.object : get_luaentity ( ) ~= nil
end
2018-06-10 12:05:05 +02:00
local trade_inventory = {
allow_take = function ( inv , listname , index , stack , player )
if listname == " input " then
return stack : get_count ( )
elseif listname == " output " then
2018-06-10 15:01:44 +02:00
if not trader_exists ( player : get_player_name ( ) ) then
return 0
2022-06-11 21:18:25 +02:00
-- Begin Award Code
-- May need to be moved if award gets unlocked in the wrong cases.
elseif trader_exists ( player : get_player_name ( ) ) then
awards.unlock ( player : get_player_name ( ) , " mcl:whatAdeal " )
-- End Award Code
2018-06-10 15:01:44 +02:00
end
2018-06-10 12:05:05 +02:00
-- Only allow taking full stack
local count = stack : get_count ( )
if count == inv : get_stack ( listname , index ) : get_count ( ) then
-- Also update output stack again.
-- If input has double the wanted items, the
-- output will stay because there will be still
-- enough items in input after the trade
local wanted1 = inv : get_stack ( " wanted " , 1 )
local wanted2 = inv : get_stack ( " wanted " , 2 )
local input1 = inv : get_stack ( " input " , 1 )
local input2 = inv : get_stack ( " input " , 2 )
wanted1 : set_count ( wanted1 : get_count ( ) * 2 )
wanted2 : set_count ( wanted2 : get_count ( ) * 2 )
-- BEGIN OF SPECIAL HANDLING FOR COMPASS
2022-05-18 13:50:48 +02:00
local function special_checks ( wanted1 , input1 , input2 )
2018-06-10 12:05:05 +02:00
if wanted1 : get_name ( ) == COMPASS then
local compasses = 0
if ( minetest.get_item_group ( input1 : get_name ( ) , " compass " ) ~= 0 ) then
compasses = compasses + input1 : get_count ( )
end
if ( minetest.get_item_group ( input2 : get_name ( ) , " compass " ) ~= 0 ) then
compasses = compasses + input2 : get_count ( )
end
return compasses >= wanted1 : get_count ( )
end
return false
end
-- END OF SPECIAL HANDLING FOR COMPASS
if ( inv : contains_item ( " input " , wanted1 ) and
( wanted2 : is_empty ( ) or inv : contains_item ( " input " , wanted2 ) ) )
-- BEGIN OF SPECIAL HANDLING FOR COMPASS
or special_checks ( wanted1 , input1 , input2 ) then
-- END OF SPECIAL HANDLING FOR COMPASS
return - 1
else
-- If less than double the wanted items,
-- remove items from output (final trade,
-- input runs empty)
return count
end
else
return 0
end
else
return 0
end
end ,
allow_move = function ( inv , from_list , from_index , to_list , to_index , count , player )
if from_list == " input " and to_list == " input " then
return count
elseif from_list == " output " and to_list == " input " then
2018-06-10 15:01:44 +02:00
if not trader_exists ( player : get_player_name ( ) ) then
return 0
end
2018-06-10 12:05:05 +02:00
local move_stack = inv : get_stack ( from_list , from_index )
if inv : get_stack ( to_list , to_index ) : item_fits ( move_stack ) then
return count
end
end
return 0
end ,
allow_put = function ( inv , listname , index , stack , player )
if listname == " input " then
2018-06-10 15:01:44 +02:00
if not trader_exists ( player : get_player_name ( ) ) then
return 0
else
return stack : get_count ( )
end
2018-06-10 12:05:05 +02:00
else
return 0
end
end ,
on_put = function ( inv , listname , index , stack , player )
update_offer ( inv , player , true )
end ,
on_move = function ( inv , from_list , from_index , to_list , to_index , count , player )
if from_list == " output " and to_list == " input " then
inv : remove_item ( " input " , inv : get_stack ( " wanted " , 1 ) )
local wanted2 = inv : get_stack ( " wanted " , 2 )
if not wanted2 : is_empty ( ) then
inv : remove_item ( " input " , inv : get_stack ( " wanted " , 2 ) )
end
2022-08-12 15:42:08 +02:00
local trader = player_trading_with [ name ]
minetest.sound_play ( " mobs_mc_villager_accept " , { to_player = player : get_player_name ( ) , object = trader.object } , true )
2018-06-10 12:05:05 +02:00
end
update_offer ( inv , player , true )
end ,
on_take = function ( inv , listname , index , stack , player )
local accept
local name = player : get_player_name ( )
if listname == " output " then
local wanted1 = inv : get_stack ( " wanted " , 1 )
inv : remove_item ( " input " , wanted1 )
local wanted2 = inv : get_stack ( " wanted " , 2 )
if not wanted2 : is_empty ( ) then
inv : remove_item ( " input " , inv : get_stack ( " wanted " , 2 ) )
end
-- BEGIN OF SPECIAL HANDLING FOR COMPASS
if wanted1 : get_name ( ) == COMPASS then
for n = 1 , 2 do
local input = inv : get_stack ( " input " , n )
if minetest.get_item_group ( input : get_name ( ) , " compass " ) ~= 0 then
input : set_count ( input : get_count ( ) - wanted1 : get_count ( ) )
inv : set_stack ( " input " , n , input )
break
end
end
end
-- END OF SPECIAL HANDLING FOR COMPASS
local trader = player_trading_with [ name ]
local tradenum = player_tradenum [ name ]
2022-10-25 21:24:37 +02:00
2018-06-10 12:05:05 +02:00
local trades
2022-07-07 12:47:27 +02:00
trader._traded = true
2018-06-10 12:05:05 +02:00
if trader and trader._trades then
trades = minetest.deserialize ( trader._trades )
end
if trades then
local trade = trades [ tradenum ]
local unlock_stuff = false
if not trade.traded_once then
-- Unlock all the things if something was traded
-- for the first time ever
unlock_stuff = true
trade.traded_once = true
elseif trade.trade_counter == 0 and math.random ( 1 , 5 ) == 1 then
-- Otherwise, 20% chance to unlock if used freshly reset trade
unlock_stuff = true
end
2018-06-10 13:48:40 +02:00
local update_formspec = false
2018-06-10 12:05:05 +02:00
if unlock_stuff then
-- 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
2022-05-20 03:06:07 +02:00
if trader._max_trade_tier > 5 then
trader._max_trade_tier = 5
2022-05-20 00:02:36 +02:00
end
set_textures ( trader )
2018-06-10 13:06:28 +02:00
update_max_tradenum ( trader )
2018-06-10 13:48:40 +02:00
update_formspec = true
2018-06-10 12:05:05 +02:00
end
for t = 1 , # trades do
trades [ t ] . locked = false
trades [ t ] . trade_counter = 0
end
2018-06-10 13:48:40 +02:00
trader._locked_trades = 0
2018-06-10 13:20:19 +02:00
-- Also heal trader for unlocking stuff
-- TODO: Replace by Regeneration I
trader.health = math.min ( trader.hp_max , trader.health + 4 )
2018-06-10 12:05:05 +02:00
end
trade.trade_counter = trade.trade_counter + 1
2022-11-01 02:01:13 +01:00
mcl_log ( " Trade counter is: " .. trade.trade_counter )
2018-06-10 13:48:40 +02:00
-- Semi-randomly lock trade for repeated trade (not if there's only 1 trade)
if trader._max_tradenum > 1 then
if trade.trade_counter >= 12 then
2018-06-10 12:05:05 +02:00
trade.locked = true
2018-06-10 13:48:40 +02:00
elseif trade.trade_counter >= 2 then
local r = math.random ( 1 , math.random ( 4 , 10 ) )
if r == 1 then
trade.locked = true
end
2018-06-10 12:05:05 +02:00
end
end
if trade.locked then
inv : set_stack ( " output " , 1 , " " )
2018-06-10 13:48:40 +02:00
update_formspec = true
trader._locked_trades = trader._locked_trades + 1
-- Check if we managed to lock ALL available trades. Rare but possible.
if trader._locked_trades >= trader._max_tradenum then
-- Emergency unlock! Unlock all other trades except the current one
for t = 1 , # trades do
if t ~= tradenum then
trades [ t ] . locked = false
trades [ t ] . trade_counter = 0
end
end
trader._locked_trades = 1
-- Also heal trader for unlocking stuff
-- TODO: Replace by Regeneration I
trader.health = math.min ( trader.hp_max , trader.health + 4 )
end
end
trader._trades = minetest.serialize ( trades )
if update_formspec then
2018-06-10 12:05:05 +02:00
show_trade_formspec ( name , trader , tradenum )
end
else
minetest.log ( " error " , " [mobs_mc] Player took item from trader output but player_trading_with or player_tradenum is nil! " )
end
accept = true
elseif listname == " input " then
update_offer ( inv , player , false )
end
2022-08-12 15:42:08 +02:00
local trader = player_trading_with [ name ]
2018-06-10 12:05:05 +02:00
if accept then
2022-08-12 15:42:08 +02:00
minetest.sound_play ( " mobs_mc_villager_accept " , { to_player = name , object = trader.object } , true )
2018-06-10 12:05:05 +02:00
else
2022-08-12 15:42:08 +02:00
minetest.sound_play ( " mobs_mc_villager_deny " , { to_player = name , object = trader.object } , true )
2018-06-10 12:05:05 +02:00
end
end ,
}
2018-06-04 21:46:13 +02:00
minetest.register_on_joinplayer ( function ( player )
2018-06-10 12:05:05 +02:00
local name = player : get_player_name ( )
player_tradenum [ name ] = 1
player_trading_with [ name ] = nil
-- Create or get player-specific trading inventory
local inv = minetest.get_inventory ( { type = " detached " , name = " mobs_mc:trade_ " .. name } )
if not inv then
inv = minetest.create_detached_inventory ( " mobs_mc:trade_ " .. name , trade_inventory , name )
end
inv : set_size ( " input " , 2 )
inv : set_size ( " output " , 1 )
inv : set_size ( " wanted " , 2 )
inv : set_size ( " offered " , 1 )
2018-06-04 12:50:31 +02:00
end )
2018-06-10 15:01:44 +02:00
--[=======[ MOB REGISTRATION AND SPAWNING ]=======]
2022-11-09 04:09:58 +01:00
mcl_mobs.register_mob ( " mobs_mc:villager " , {
2021-04-25 17:30:15 +02:00
description = S ( " Villager " ) ,
2018-06-10 15:01:44 +02:00
type = " npc " ,
2020-04-11 02:46:03 +02:00
spawn_class = " passive " ,
2022-10-23 23:16:35 +02:00
passive = true ,
2018-06-10 15:01:44 +02:00
hp_min = 20 ,
hp_max = 20 ,
2022-10-06 22:53:40 +02:00
head_swivel = " head.control " ,
bone_eye_height = 6.3 ,
head_eye_height = 2.2 ,
2022-10-06 03:30:02 +02:00
curiosity = 10 ,
2022-10-15 20:25:26 +02:00
runaway = true ,
2018-06-10 15:01:44 +02:00
collisionbox = { - 0.3 , - 0.01 , - 0.3 , 0.3 , 1.94 , 0.3 } ,
visual = " mesh " ,
mesh = " mobs_mc_villager.b3d " ,
textures = {
" mobs_mc_villager.png " ,
" mobs_mc_villager.png " , --hat
} ,
makes_footstep_sound = true ,
walk_velocity = 1.2 ,
2022-02-13 21:40:12 +01:00
run_velocity = 2.4 ,
2018-06-10 15:01:44 +02:00
drops = { } ,
2021-01-26 18:40:16 +01:00
can_despawn = false ,
2018-09-14 16:27:58 +02:00
-- TODO: sounds
2021-03-25 16:52:32 +01:00
sounds = {
random = " mobs_mc_villager " ,
2022-06-06 21:09:14 +02:00
damage = " mobs_mc_villager_hurt " ,
2021-03-25 16:52:32 +01:00
distance = 10 ,
} ,
2018-06-10 15:01:44 +02:00
animation = {
2022-09-28 21:16:01 +02:00
stand_start = 0 , stand_end = 0 ,
walk_start = 0 , walk_end = 40 , walk_speed = 25 ,
run_start = 0 , run_end = 40 , run_speed = 25 ,
head_shake_start = 60 , head_shake_end = 70 , head_shake_loop = false ,
head_nod_start = 50 , head_nod_end = 60 , head_nod_loop = false ,
} ,
child_animations = {
stand_start = 71 , stand_end = 71 ,
walk_start = 71 , walk_end = 111 , walk_speed = 37 ,
run_start = 71 , run_end = 111 , run_speed = 37 ,
head_shake_start = 131 , head_shake_end = 141 , head_shake_loop = false ,
head_nod_start = 121 , head_nod_end = 131 , head_nod_loop = false ,
2018-06-10 15:01:44 +02:00
} ,
2023-01-09 17:54:27 +01:00
follow = { " mcl_farming:bread " , " mcl_farming:carrot_item " , " mcl_farming:beetroot_item " , " mcl_farming:potato_item " } ,
2022-05-19 14:13:59 +02:00
nofollow = true ,
2018-06-10 15:01:44 +02:00
view_range = 16 ,
fear_height = 4 ,
jump = true ,
walk_chance = DEFAULT_WALK_CHANCE ,
2022-05-19 21:36:11 +02:00
_bed = nil ,
2022-05-13 21:28:56 +02:00
_id = nil ,
_profession = " unemployed " ,
2022-05-17 23:35:56 +02:00
look_at_player = true ,
2023-01-09 17:54:27 +01:00
pick_up = { " mcl_farming:bread " , " mcl_farming:carrot_item " , " mcl_farming:beetroot_item " , " mcl_farming:potato_item " } ,
2022-05-19 17:43:45 +02:00
can_open_doors = true ,
2022-05-19 05:43:37 +02:00
on_pick_up = function ( self , itementity )
2022-05-19 13:58:59 +02:00
local clicker
2022-10-14 01:36:10 +02:00
local it = ItemStack ( itementity.itemstring )
2022-05-19 13:58:59 +02:00
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
2022-10-14 01:36:10 +02:00
if clicker and not self.horny then
2022-11-09 04:57:48 +01:00
self : feed_tame ( clicker , 1 , true , false , true )
2022-10-14 01:36:10 +02:00
it : take_item ( 1 )
2022-05-19 13:58:59 +02:00
end
2022-10-14 01:36:10 +02:00
return it
2022-05-19 05:43:37 +02:00
end ,
2018-06-10 15:01:44 +02:00
on_rightclick = function ( self , clicker )
2023-01-09 17:54:27 +01:00
--minetest.log("In villager right click")
2022-10-25 21:24:37 +02:00
if self.child or self._profession == " unemployed " or self._profession == " nitwit " then
self.order = nil
return
end
2022-10-26 00:53:55 +02:00
if self.state == PATHFINDING then
2022-10-25 21:24:37 +02:00
self.state = " stand "
end
-- Can we remove now we possibly have fixed root cause
2022-10-22 02:28:45 +02:00
if self.state == " attack " then
2022-10-25 21:24:37 +02:00
mcl_log ( " Somehow villager got into an invalid attack state. Removed attack state. " )
2022-10-22 02:28:45 +02:00
-- Need to stop villager getting in attack state. This is a workaround to allow players to fix broken villager.
self.state = " stand "
self.attack = nil
end
2022-10-25 21:24:37 +02:00
-- Don't do at night. Go to bed? Maybe do_activity needs it's own method
2022-10-28 23:02:36 +02:00
if validate_jobsite ( self ) and not self.order == WORK then
2022-11-10 00:52:45 +01:00
--self:gopath(self._jobsite,function()
2022-10-28 23:02:36 +02:00
-- minetest.log("sent to jobsite")
--end)
2022-10-22 02:28:45 +02:00
else
self.state = " stand " -- cancel gowp in case it has messed up
2022-11-01 22:02:46 +01:00
--self.order = nil -- cancel work if working
2022-05-18 00:03:40 +02:00
end
2022-10-22 02:28:45 +02:00
2018-06-10 15:01:44 +02:00
-- Initiate trading
2022-05-16 19:22:59 +02:00
init_trader_vars ( self )
2018-06-10 15:01:44 +02:00
local name = clicker : get_player_name ( )
self._trading_players [ name ] = true
2022-10-28 23:02:36 +02:00
if self._trades == nil or self._trades == false then
2022-11-05 01:14:54 +01:00
--minetest.log("Trades is nil so init")
2018-06-10 15:01:44 +02:00
init_trades ( self )
end
update_max_tradenum ( self )
if self._trades == false then
2022-11-05 01:14:54 +01:00
--minetest.log("Trades is false. no right click op")
2018-06-10 15:01:44 +02:00
-- Villager has no trades, rightclick is a no-op
return
end
player_trading_with [ name ] = self
local inv = minetest.get_inventory ( { type = " detached " , name = " mobs_mc:trade_ " .. name } )
2020-05-08 17:27:22 +02:00
if not inv then
return
end
2018-06-10 15:01:44 +02:00
set_trade ( self , clicker , inv , 1 )
show_trade_formspec ( name , self )
-- Behaviour stuff:
-- Make villager look at player and stand still
local selfpos = self.object : get_pos ( )
local clickerpos = clicker : get_pos ( )
local dir = vector.direction ( selfpos , clickerpos )
self.object : set_yaw ( minetest.dir_to_yaw ( dir ) )
stand_still ( self )
end ,
_player_scan_timer = 0 ,
_trading_players = { } , -- list of playernames currently trading with villager (open formspec)
do_custom = function ( self , dtime )
2022-08-30 16:37:23 +02:00
check_summon ( self , dtime )
2022-10-19 00:59:53 +02:00
2018-06-10 15:01:44 +02:00
-- Stand still if player is nearby.
if not self._player_scan_timer then
self._player_scan_timer = 0
end
self._player_scan_timer = self._player_scan_timer + dtime
2022-10-19 00:59:53 +02:00
2018-06-10 15:01:44 +02:00
-- Check infrequently to keep CPU load low
if self._player_scan_timer > PLAYER_SCAN_INTERVAL then
2022-10-19 00:59:53 +02:00
2018-06-10 15:01:44 +02:00
self._player_scan_timer = 0
local selfpos = self.object : get_pos ( )
local objects = minetest.get_objects_inside_radius ( selfpos , PLAYER_SCAN_RADIUS )
local has_player = false
2022-10-19 00:59:53 +02:00
2018-06-10 15:01:44 +02:00
for o , obj in pairs ( objects ) do
if obj : is_player ( ) then
has_player = true
break
end
end
if has_player then
2022-11-08 00:25:41 +01:00
--minetest.log("verbose", "[mobs_mc] Player near villager found!")
2018-06-10 15:01:44 +02:00
stand_still ( self )
else
2022-10-19 00:59:53 +02:00
--minetest.log("verbose", "[mobs_mc] No player near villager found!")
2018-06-10 15:01:44 +02:00
self.walk_chance = DEFAULT_WALK_CHANCE
self.jump = true
end
2022-10-19 00:59:53 +02:00
2022-10-27 23:27:19 +02:00
do_activity ( self )
2022-10-19 00:59:53 +02:00
2018-06-10 15:01:44 +02:00
end
end ,
on_spawn = function ( self )
2022-06-16 16:59:08 +02:00
if not self._profession then
self._profession = " unemployed "
if math.random ( 100 ) == 1 then
self._profession = " nitwit "
end
2022-05-20 02:44:27 +02:00
end
2022-06-26 11:19:21 +02:00
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 ( ) ) )
2022-05-20 00:02:36 +02:00
set_textures ( self )
2018-06-10 15:01:44 +02:00
end ,
2022-11-15 20:23:59 +01:00
on_die = function ( self , pos , cmi_cause )
2018-06-10 15:01:44 +02:00
-- Close open trade formspecs and give input back to players
local trading_players = self._trading_players
2022-05-13 21:28:56 +02:00
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
2018-06-10 15:01:44 +02:00
end
end
2022-10-22 02:28:45 +02:00
local bed = self._bed
if bed then
local bed_meta = minetest.get_meta ( bed )
bed_meta : set_string ( " villager " , nil )
mcl_log ( " Died, so bye bye bed " )
end
local jobsite = self._jobsite
if jobsite then
local jobsite_meta = minetest.get_meta ( jobsite )
jobsite_meta : set_string ( " villager " , nil )
mcl_log ( " Died, so bye bye jobsite " )
end
2022-11-15 20:23:59 +01:00
if cmi_cause and cmi_cause.puncher then
local l = cmi_cause.puncher : get_luaentity ( )
2022-11-15 20:31:49 +01:00
if l and math.random ( 2 ) == 1 and ( l.name == " mobs_mc:zombie " or l.name == " mobs_mc:baby_zombie " or l.name == " mobs_mc:villager_zombie " or l.name == " mobs_mc:husk " ) then
mcl_util.replace_mob ( self.object , " mobs_mc:villager_zombie " )
2022-11-15 20:23:59 +01:00
return true
end
end
2018-06-10 15:01:44 +02:00
end ,
2022-11-04 14:02:59 +01:00
on_lightning_strike = function ( self , pos , pos2 , objects )
mcl_util.replace_mob ( self.object , " mobs_mc:witch " )
return true
end ,
2018-06-10 15:01:44 +02:00
} )
2022-07-03 21:50:54 +02:00
--[[
Villager spawning in mcl_villages
2022-05-25 14:44:49 +02:00
mcl_mobs : spawn_specific (
2021-04-19 14:44:20 +02:00
" mobs_mc:villager " ,
" overworld " ,
2021-04-08 13:39:18 +02:00
" ground " ,
{
" FlowerForest " ,
" Swampland " ,
" Taiga " ,
" ExtremeHills " ,
" BirchForest " ,
" MegaSpruceTaiga " ,
" MegaTaiga " ,
" ExtremeHills+ " ,
" Forest " ,
" Plains " ,
" ColdTaiga " ,
" SunflowerPlains " ,
" RoofedForest " ,
" MesaPlateauFM_grasstop " ,
" ExtremeHillsM " ,
" BirchForestM " ,
} ,
2021-04-19 14:44:20 +02:00
0 ,
minetest.LIGHT_MAX + 1 ,
30 ,
20 ,
4 ,
2022-05-25 23:25:15 +02:00
mobs_mc.water_level + 1 ,
mcl_vars.mg_overworld_max )
2022-07-03 21:50:54 +02:00
--]]
2017-07-05 03:15:46 +02:00
-- spawn eggs
2023-02-10 03:46:23 +01:00
mcl_mobs : non_spawn_specific ( " mobs_mc:villager " , " overworld " , 0 , minetest.LIGHT_MAX + 1 )
2022-11-09 04:09:58 +01:00
mcl_mobs.register_egg ( " mobs_mc:villager " , S ( " Villager " ) , " #563d33 " , " #bc8b72 " , 0 )