QOL improvements, Cows regen milk.

master
NathanSalapat 2020-06-17 20:21:26 -05:00
parent c70334aa2c
commit 56d0c25e6b
44 changed files with 1554 additions and 2783 deletions

2
mods/commoditymarket/.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

40
mods/commoditymarket/.gitignore vendored Normal file
View File

@ -0,0 +1,40 @@
# Compiled Lua sources
luac.out
# luarocks build files
*.src.rock
*.zip
*.tar.gz
# Object files
*.o
*.os
*.ko
*.elf
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
*.def
*.exp
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex

View File

@ -1,528 +0,0 @@
local default_modpath = minetest.get_modpath("default")
if not default_modpath then return end
-- internationalization boilerplate
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
-- Only register gold coins once, if required
local gold_coins_registered = false
local register_gold_coins = function()
if not gold_coins_registered then
minetest.register_craftitem("commoditymarket:gold_coins", {
description = S("Gold Coins"),
_doc_items_longdesc = S("A gold ingot is far too valuable to use as a basic unit of value, so it has become common practice to divide the standard gold bar into one thousand small disks to make trade easier."),
_doc_items_usagehelp = S("Gold coins can be deposited and withdrawn from markets that accept them as currency. These markets can make change if you have a thousand coins and would like them back in ingot form again."),
inventory_image = "commoditymarket_gold_coins.png",
stack_max = 1000,
})
gold_coins_registered = true
end
end
local default_items = {"default:axe_bronze","default:axe_diamond","default:axe_mese","default:axe_steel","default:axe_steel","default:axe_stone","default:axe_wood","default:pick_bronze","default:pick_diamond","default:pick_mese","default:pick_steel","default:pick_stone","default:pick_wood","default:shovel_bronze","default:shovel_diamond","default:shovel_mese","default:shovel_steel","default:shovel_stone","default:shovel_wood","default:sword_bronze","default:sword_diamond","default:sword_mese","default:sword_steel","default:sword_stone","default:sword_wood", "default:blueberries", "default:book", "default:bronze_ingot", "default:clay_brick", "default:clay_lump", "default:coal_lump", "default:copper_ingot", "default:copper_lump", "default:diamond", "default:flint", "default:gold_ingot", "default:gold_lump", "default:iron_lump", "default:mese_crystal", "default:mese_crystal_fragment", "default:obsidian_shard", "default:paper", "default:steel_ingot", "default:stick", "default:tin_ingot", "default:tin_lump", "default:acacia_tree", "default:acacia_wood", "default:apple", "default:aspen_tree", "default:aspen_wood", "default:blueberry_bush_sapling", "default:bookshelf", "default:brick", "default:bronzeblock", "default:bush_sapling", "default:cactus", "default:clay", "default:coalblock", "default:cobble", "default:copperblock", "default:desert_cobble", "default:desert_sand", "default:desert_sandstone", "default:desert_sandstone_block", "default:desert_sandstone_brick", "default:desert_stone", "default:desert_stone_block", "default:desert_stonebrick", "default:diamondblock", "default:dirt", "default:glass", "default:goldblock", "default:gravel", "default:ice", "default:junglegrass", "default:junglesapling", "default:jungletree", "default:junglewood", "default:ladder_steel", "default:ladder_wood", "default:large_cactus_seedling", "default:mese", "default:mese_post_light", "default:meselamp", "default:mossycobble", "default:obsidian", "default:obsidian_block", "default:obsidian_glass", "default:obsidianbrick", "default:papyrus", "default:pine_sapling", "default:pine_tree", "default:pine_wood", "default:sand", "default:sandstone", "default:sandstone_block", "default:sandstonebrick", "default:sapling", "default:silver_sand", "default:silver_sandstone", "default:silver_sandstone_block", "default:silver_sandstone_brick", "default:snow", "default:snowblock", "default:steelblock", "default:stone", "default:stone_block", "default:stonebrick", "default:tinblock", "default:tree", "default:wood",}
local usage_help = S("Right-click on this to open the market interface.")
------------------------------------------------------------------------------
-- King's Market
if minetest.settings:get_bool("commoditymarket_enable_kings_market") then
local kings_def = {
description = S("King's Market"),
long_description = S("The largest and most accessible market for the common man, the King's Market uses gold coins as its medium of exchange (or the equivalent in gold ingots - 1000 coins to the ingot). However, as a respectable institution of the surface world, the King's Market operates only during the hours of daylight. The purchase and sale of swords and explosives is prohibited in the King's Market. Gold coins are represented by a '☼' symbol."),
currency = {
["default:gold_ingot"] = 1000,
["commoditymarket:gold_coins"] = 1
},
currency_symbol = "", -- "\u{263C}" Alchemical symbol for gold
allow_item = function(item)
if item:sub(1,13) == "default:sword" or item:sub(1,4) == "tnt:" then
return false
end
return true
end,
inventory_limit = 100000,
--sell_limit =, -- no sell limit for the King's Market
initial_items = default_items,
}
register_gold_coins()
commoditymarket.register_market("kings", kings_def)
local kings_protect = minetest.settings:get_bool("commoditymarket_protect_kings_market", true)
local on_blast
if kings_protect then
on_blast = function() end
end
minetest.register_node("commoditymarket:kings_market", {
description = kings_def.description,
_doc_items_longdesc = kings_def.long_description,
_doc_items_usagehelp = usage_help,
tiles = {"default_chest_top.png","default_chest_top.png",
"default_chest_side.png","default_chest_side.png",
"commoditymarket_empty_shelf.png","default_chest_side.png^commoditymarket_crown.png",},
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_wood_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local timeofday = minetest.get_timeofday()
if timeofday > 0.2 and timeofday < 0.8 then
commoditymarket.show_market("kings", clicker:get_player_name())
else
minetest.chat_send_player(clicker:get_player_name(), S("At this time of day the King's Market is closed."))
minetest.sound_play({name = "commoditymarket_error", gain = 0.1}, {to_player=clicker:get_player_name()})
end
end,
can_dig = function(pos, player)
return not kings_protect or minetest.check_player_privs(player, "protection_bypass")
end,
on_blast = on_blast,
})
end
-------------------------------------------------------------------------------
-- Night Market
if minetest.settings:get_bool("commoditymarket_enable_night_market") then
local night_def = {
description = S("Night Market"),
long_description = "When the sun sets and the stalls of the King's Market close, other vendors are just waking up to share their wares. The Night Market is not as voluminous as the King's Market but accepts a wider range of wares. It accepts the same gold coinage of the realm, one thousand coins to the gold ingot.",
currency = {
["default:gold_ingot"] = 1000,
["commoditymarket:gold_coins"] = 1
},
currency_symbol = "", --"\u{263C}"
inventory_limit = 10000,
--sell_limit =, -- no sell limit for the Night Market
initial_items = default_items,
anonymous = true,
}
register_gold_coins()
commoditymarket.register_market("night", night_def)
local night_protect = minetest.settings:get_bool("commoditymarket_protect_night_market", true)
local on_blast
if night_protect then
on_blast = function() end
end
minetest.register_node("commoditymarket:night_market", {
description = night_def.description,
_doc_items_longdesc = night_def.long_description,
_doc_items_usagehelp = usage_help,
tiles = {"default_chest_top.png","default_chest_top.png",
"default_chest_side.png","default_chest_side.png",
"commoditymarket_empty_shelf.png","default_chest_side.png^commoditymarket_moon.png",},
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_wood_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local timeofday = minetest.get_timeofday()
if timeofday < 0.2 or timeofday > 0.8 then
commoditymarket.show_market("night", clicker:get_player_name())
else
minetest.chat_send_player(clicker:get_player_name(), S("At this time of day the Night Market is closed."))
minetest.sound_play({name = "commoditymarket_error", gain = 0.1}, {to_player=clicker:get_player_name()})
end
end,
can_dig = function(pos, player)
return not night_protect or minetest.check_player_privs(player, "protection_bypass")
end,
on_blast = on_blast,
})
end
-------------------------------------------------------------------------------
if minetest.settings:get_bool("commoditymarket_enable_caravan_market", true) then
-- "Trader's Caravan" - small-capacity market that players can summon
local time_until_caravan = 120 -- caravan arrives in two minutes
local dwell_time = 600 -- caravan leaves ten minutes after last usage
local caravan_def = {
description = S("Trader's Caravan"),
long_description = S("Unlike most markets that have well-known fixed locations that travelers congregate to, the network of Trader's Caravans is fluid and dynamic in their locations. A Trader's Caravan can show up anywhere, make modest trades, and then be gone the next time you visit them. These caravans accept gold and gold coins as a currency (one gold ingot to one thousand gold coins exchange rate). Any reasonably-wealthy person can create a signpost marking a location where Trader's Caravans will make a stop."),
currency = {
["default:gold_ingot"] = 1000,
["commoditymarket:gold_coins"] = 1
},
currency_symbol = "", --"\u{263C}"
inventory_limit = 1000,
sell_limit = 1000,
initial_items = default_items,
}
register_gold_coins()
minetest.register_craft({
output = "commoditymarket:caravan_post",
recipe = {
{'group:wood', 'group:wood', ''},
{'group:wood', "default:gold_ingot", ''},
{'group:wood', "default:chest_locked", ''},
}
})
commoditymarket.register_market("caravan", caravan_def)
local create_caravan_def = function(override_table)
local def = {
description = caravan_def.description,
_doc_items_longdesc = caravan_def.long_description,
_doc_items_usagehelp = usage_help,
drawtype = "mesh",
mesh = "commoditymarket_wagon.obj",
tiles = {
{ name = "commoditymarket_door_wood.png", backface_culling = true }, -- door
{ name = "default_wood.png", backface_culling = true }, -- base wood
{ name = "default_fence_rail_wood.png", backface_culling = true }, -- wheel sides
{ name = "default_coal_block.png", backface_culling = true }, -- wheel tyre
{ name = "commoditymarket_shingles_wood.png", backface_culling = true }, -- roof
{ name = "default_junglewood.png", backface_culling = true }, -- corner wood
},
collision_box = {
type = "fixed",
fixed = {
{-0.75, -0.5, -1.25, 0.75, 1.5, 1.25},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.75, -0.5, -1.25, 0.75, 1.5, 1.25},
},
},
paramtype2 = "facedir",
drop = "",
groups = {choppy = 2, oddly_breakable_by_hand = 1, not_in_creative_inventory = 1},
sounds = default.node_sound_wood_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
commoditymarket.show_market("caravan", clicker:get_player_name())
local timer = minetest.get_node_timer(pos)
timer:start(dwell_time)
end,
after_destruct = function(pos, oldnode)
local facedir = oldnode.param2
local dir = minetest.facedir_to_dir(facedir)
local target = vector.add(pos, vector.multiply(dir,-3))
local target_node = minetest.get_node(target)
if target_node.name == "commoditymarket:caravan_post" then
local meta = minetest.get_meta(target)
meta:set_string("infotext", S("Right-click to summon a trader's caravan"))
end
end,
on_timer = function(pos, elapsed)
minetest.set_node(pos, {name="air"})
minetest.sound_play("commoditymarket_register_closed", {
pos = pos,
gain = 1.0, -- default
max_hear_distance = 32, -- default, uses an euclidean metric
})
end,
}
if override_table then
for k, v in pairs(override_table) do
def[k] = v
end
end
return def
end
-- Create five caravans with different textures, randomly pick which one shows up.
minetest.register_node("commoditymarket:caravan_market_1", create_caravan_def())
minetest.register_node("commoditymarket:caravan_market_2", create_caravan_def({
tiles = {
{ name = "commoditymarket_door_wood.png^[multiply:#CCCCFF", backface_culling = true }, -- door
{ name = "default_acacia_wood.png", backface_culling = true }, -- base wood
{ name = "default_fence_rail_wood.png", backface_culling = true }, -- wheel sides
{ name = "default_copper_block.png", backface_culling = true }, -- wheel tyre
{ name = "commoditymarket_shingles_wood.png^[multiply:#CC8888", backface_culling = true }, -- roof
{ name = "default_wood.png", backface_culling = true }, -- corner wood
}
}))
minetest.register_node("commoditymarket:caravan_market_3", create_caravan_def({
tiles = {
{ name = "commoditymarket_door_wood.png", backface_culling = true }, -- door
{ name = "default_aspen_wood.png", backface_culling = true }, -- base wood
{ name = "default_fence_aspen_wood.png", backface_culling = true }, -- wheel sides
{ name = "default_cobble.png", backface_culling = true }, -- wheel tyre
{ name = "default_stone_brick.png", backface_culling = true }, -- roof
{ name = "default_pine_tree.png", backface_culling = true }, -- corner wood
}
}))
minetest.register_node("commoditymarket:caravan_market_4", create_caravan_def({
tiles = {
{ name = "commoditymarket_door_wood.png", backface_culling = true }, -- door
{ name = "default_junglewood.png", backface_culling = true }, -- base wood
{ name = "default_fence_rail_junglewood.png", backface_culling = true }, -- wheel sides
{ name = "default_obsidian.png", backface_culling = true }, -- wheel tyre
{ name = "commoditymarket_shingles_wood.png^[multiply:#88FF88", backface_culling = true }, -- roof
{ name = "default_tree.png", backface_culling = true }, -- corner wood
}
}))
minetest.register_node("commoditymarket:caravan_market_5", create_caravan_def({
tiles = {
{ name = "commoditymarket_door_wood.png", backface_culling = true }, -- door
{ name = "default_pine_wood.png", backface_culling = true }, -- base wood
{ name = "default_chest_lock.png", backface_culling = true }, -- wheel sides
{ name = "default_chest_top.png", backface_culling = true }, -- wheel tyre
{ name = "default_furnace_top.png", backface_culling = true }, -- roof
{ name = "default_wood.png", backface_culling = true }, -- corner wood
}
}))
local caravan_protect = minetest.settings:get_bool("commoditymarket_protect_caravan_market", true)
local on_blast
if caravan_protect then
on_blast = function() end
end
-- This one doesn't delete itself, server admins can place a permanent instance of it that way. Maybe inside towns next to bigger stationary markets.
minetest.register_node("commoditymarket:caravan_market_permanent", {
description = caravan_def.description,
_doc_items_longdesc = caravan_def.long_description,
_doc_items_usagehelp = usage_help,
drawtype = "mesh",
mesh = "commoditymarket_wagon.obj",
tiles = {
{ name = "commoditymarket_door_wood.png", backface_culling = true }, -- door
{ name = "default_wood.png", backface_culling = true }, -- base wood
{ name = "default_fence_rail_wood.png", backface_culling = true }, -- wheel sides
{ name = "default_coal_block.png", backface_culling = true }, -- wheel tyre
{ name = "commoditymarket_shingles_wood.png", backface_culling = true }, -- roof
{ name = "default_junglewood.png", backface_culling = true }, -- corner wood
},
collision_box = {
type = "fixed",
fixed = {
{-0.75, -0.5, -1.25, 0.75, 1.5, 1.25},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.75, -0.5, -1.25, 0.75, 1.5, 1.25},
},
},
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_wood_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
commoditymarket.show_market("caravan", clicker:get_player_name())
end,
can_dig = function(pos, player)
return not caravan_protect or minetest.check_player_privs(player, "protection_bypass")
end,
on_blast = on_blast,
})
-- is a 5x3 area centered around pos clear of obstruction and has usable ground?
local is_suitable_caravan_space = function(pos, facedir)
local x_dim = 2
local z_dim = 2
local dir = minetest.facedir_to_dir(facedir)
if dir.x ~= 0 then
z_dim = 1
elseif dir.z ~= 0 then
x_dim = 1
end
-- walkable ground?
for x = pos.x - x_dim, pos.x + x_dim, 1 do
for z = pos.z - z_dim, pos.z + z_dim, 1 do
local node = minetest.get_node({x=x, y=pos.y-1, z=z})
local node_def = minetest.registered_nodes[node.name]
if node_def == nil or node_def.walkable ~= true then return false end
end
end
-- buildable_to in the rest?
for y = pos.y, pos.y+2, 1 do
for x = pos.x - x_dim, pos.x + x_dim, 1 do
for z = pos.z - z_dim, pos.z + z_dim, 1 do
local node = minetest.get_node({x=x, y=y, z=z})
local node_def = minetest.registered_nodes[node.name]
if node_def == nil or node_def.buildable_to ~= true then return false end
end
end
end
return true
end
minetest.register_node("commoditymarket:caravan_post", {
description = S("Trading Post"),
_long_items_longdesc = S("This post signals passing caravan traders that customers can be found here, and signals to customers that caravan traders can be found here. If no caravan is present, right-click to summon one."),
_doc_items_usagehelp = S("The trader's caravan requires a suitable open space next to the trading post for it to arrive, and takes some time to arrive after being summoned. The post gives a countdown to the caravan's arrival when moused over."),
tiles = {"commoditymarket_sign.png^[transformR90", "commoditymarket_sign.png^[transformR270",
"commoditymarket_sign.png^commoditymarket_caravan_sign.png", "commoditymarket_sign.png^commoditymarket_caravan_sign.png^[transformFX",
"commoditymarket_sign_post.png", "commoditymarket_sign_post.png"},
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_wood_defaults(),
inventory_image = "commoditymarket_caravan_sign_inventory.png",
paramtype= "light",
paramtype2 = "facedir",
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.125,-0.5,-0.5,0.125,2.0625,-0.25},
{-0.0625,1.4375,-0.25,0.0625,2.0,0.5},
},
},
on_construct = function(pos)
local timer = minetest.get_node_timer(pos)
timer:start(1.0)
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local timer = minetest.get_node_timer(pos)
timer:start(1.0)
end,
on_timer = function(pos, elapsed)
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
if node.name ~= "commoditymarket:caravan_post" then
return -- the node was removed
end
local facedir = node.param2
local dir = minetest.facedir_to_dir(facedir)
local target = vector.add(pos, vector.multiply(dir,3))
local target_node = minetest.get_node(target)
if target_node.name:sub(1,string.len("commoditymarket:caravan_market")) == "commoditymarket:caravan_market" then
-- It's already here somehow, shut down timer.
meta:set_string("infotext", "")
meta:set_float("wait_time", 0)
return
end
local is_suitable_space = is_suitable_caravan_space(target, facedir)
if not is_suitable_space then
meta:set_string("infotext", S("Indicated parking area isn't suitable.\nA 5x3 open space with solid ground\nis required for a caravan."))
meta:set_float("wait_time", 0)
local timer = minetest.get_node_timer(pos)
timer:start(1.0)
return
end
local wait_time = (meta:get_float("wait_time") or 0) + elapsed
meta:set_float("wait_time", wait_time)
if wait_time < time_until_caravan then
meta:set_string("infotext", S("Caravan summoned\nETA: @1 seconds.", math.floor(time_until_caravan - wait_time)))
local timer = minetest.get_node_timer(pos)
timer:start(1.0)
return
end
-- spawn the caravan. We've already established that the target pos is clear.
minetest.set_node(target, {name="commoditymarket:caravan_market_"..math.random(1,5), param2=facedir})
minetest.sound_play("commoditymarket_register_opened", {
pos = target,
gain = 1.0, -- default
max_hear_distance = 32, -- default, uses an euclidean metric
})
local timer = minetest.get_node_timer(target)
timer:start(dwell_time)
meta:set_string("infotext", "")
meta:set_float("wait_time", 0)
end,
})
end
-------------------------------------------------------------------------------
-- "Goblin Exchange"
if minetest.settings:get_bool("commoditymarket_enable_goblin_market") then
local goblin_def = {
description = S("Goblin Exchange"),
long_description = S("One does not usually associate Goblins with the sort of sophistication that running a market requires. Usually one just associates Goblins with savagery and violence. But they understand the principle of tit-for-tat exchange, and if approached correctly they actually respect the concepts of ownership and debt. However, for some peculiar reason they understand this concept in the context of coal lumps. Goblins deal in the standard coal lump as their form of currency, conceptually divided into 100 coal centilumps (though Goblin brokers prefer to \"keep the change\" when giving back actual coal lumps)."),
currency = {
["default:coal_lump"] = 100
},
currency_symbol = "¢", --"\u{00A2}" cent symbol
inventory_limit = 1000,
--sell_limit =, -- no sell limit
}
commoditymarket.register_market("goblin", goblin_def)
local goblin_protect = minetest.settings:get_bool("commoditymarket_protect_goblin_market", true)
local on_blast
if goblin_protect then
on_blast = function() end
end
minetest.register_node("commoditymarket:goblin_market", {
description = goblin_def.description,
_doc_items_longdesc = goblin_def.long_description,
_doc_items_usagehelp = usage_help,
tiles = {"default_chest_top.png^(default_coal_block.png^[opacity:128)","default_chest_top.png^(default_coal_block.png^[opacity:128)",
"default_chest_side.png^(default_coal_block.png^[opacity:128)","default_chest_side.png^(default_coal_block.png^[opacity:128)",
"commoditymarket_empty_shelf.png^(default_coal_block.png^[opacity:128)","default_chest_side.png^(default_coal_block.png^[opacity:128)^commoditymarket_goblin.png",},
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_wood_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
commoditymarket.show_market("goblin", clicker:get_player_name())
end,
can_dig = function(pos, player)
return not goblin_protect or minetest.check_player_privs(player, "protection_bypass")
end,
on_blast = on_blast,
})
end
--------------------------------------------------------------------------------
if minetest.settings:get_bool("commoditymarket_enable_under_market") then
local undermarket_def = {
description = S("Undermarket"),
long_description = S("Deep in the bowels of the world, below even the goblin-infested warrens and ancient delvings of the dwarves, dark and mysterious beings once dwelled. A few still linger to this day, and facilitate barter for those brave souls willing to travel in their lost realms. The Undermarket uses Mese chips ('₥') as a currency - twenty chips to the Mese fragment. Though traders are loathe to physically break Mese crystals up into units that small, as it renders it useless for other purposes."),
currency = {
["default:mese"] = 9*9*20,
["default:mese_crystal"] = 9*20,
["default:mese_crystal_fragment"] = 20
},
currency_symbol = "", --"\u{20A5}" mill sign
inventory_limit = 10000,
--sell_limit =, -- no sell limit
}
commoditymarket.register_market("under", undermarket_def)
local under_protect = minetest.settings:get_bool("commoditymarket_protect_under_market", true)
local on_blast
if under_protect then
on_blast = function() end
end
minetest.register_node("commoditymarket:under_market", {
description = undermarket_def.description,
_doc_items_longdesc = undermarket_def.long_description,
_doc_items_usagehelp = usage_help,
tiles = {"commoditymarket_under_top.png","commoditymarket_under_top.png",
"commoditymarket_under.png","commoditymarket_under.png","commoditymarket_under.png","commoditymarket_under.png"},
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_stone_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
commoditymarket.show_market("under", clicker:get_player_name())
end,
can_dig = function(pos, player)
return not under_protect or minetest.check_player_privs(player, "protection_bypass")
end,
on_blast = on_blast,
})
end
------------------------------------------------------------------

View File

@ -38,4 +38,4 @@ S(
"If you place a buy order and there are already sell orders for the item that meet or are below your price, some or all of your buy order might be immediately fulfilled. Your purchases will be made at the price that the sell orders have been set to - if you were willing to pay 15 units of currency per item but someone was already offering to sell for 2 units of currency per item, you only pay 2 units for each of that offer's items. If there aren't enough compatible sell orders to fulfill your buy order, the remainder will be placed into the market and made available for future sellers to see and fulfill if they agree to your price. Your buy order will immediately deduct the currency required for it from your account's balance, but if you cancel your order you will get that currency back - it's not gone until the order is actually fulfilled."
.."\n\n"..
"If you place a sell order and there are already buy orders that meet or exceed your price, some or all of your sell order may be immediately fulfilled. You'll be paid the price that the buyers are offering rather than the amount you're demanding. If any of your sell offer is left unfulfilled, the sell order will be added to the market for future buyers to see. The items for this offer will be immediately taken from your market inventory but if you cancel your order you will get those items back.")
}})
}})

View File

@ -0,0 +1,421 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Script to generate the template file and update the translation files.
# Copy the script into the mod or modpack root folder and run it there.
#
# Copyright (C) 2019 Joachim Stolberg, 2020 FaceDeer, 2020 Louis Royer
# LGPLv2.1+
#
# See https://github.com/minetest-tools/update_translations for
# potential future updates to this script.
from __future__ import print_function
import os, fnmatch, re, shutil, errno
from sys import argv as _argv
# Running params
params = {"recursive": False,
"help": False,
"mods": False,
"verbose": False,
"folders": []
}
# Available CLI options
options = {"recursive": ['--recursive', '-r'],
"help": ['--help', '-h'],
"mods": ['--installed-mods'],
"verbose": ['--verbose', '-v']
}
# Strings longer than this will have extra space added between
# them in the translation files to make it easier to distinguish their
# beginnings and endings at a glance
doublespace_threshold = 60
def set_params_folders(tab: list):
'''Initialize params["folders"] from CLI arguments.'''
# Discarding argument 0 (tool name)
for param in tab[1:]:
stop_param = False
for option in options:
if param in options[option]:
stop_param = True
break
if not stop_param:
params["folders"].append(os.path.abspath(param))
def set_params(tab: list):
'''Initialize params from CLI arguments.'''
for option in options:
for option_name in options[option]:
if option_name in tab:
params[option] = True
break
def print_help(name):
'''Prints some help message.'''
print(f'''SYNOPSIS
{name} [OPTIONS] [PATHS...]
DESCRIPTION
{', '.join(options["help"])}
prints this help message
{', '.join(options["recursive"])}
run on all subfolders of paths given
{', '.join(options["mods"])}
run on locally installed modules
{', '.join(options["verbose"])}
add output information
''')
def main():
'''Main function'''
set_params(_argv)
set_params_folders(_argv)
if params["help"]:
print_help(_argv[0])
elif params["recursive"] and params["mods"]:
print("Option --installed-mods is incompatible with --recursive")
else:
# Add recursivity message
print("Running ", end='')
if params["recursive"]:
print("recursively ", end='')
# Running
if params["mods"]:
print(f"on all locally installed modules in {os.path.abspath('~/.minetest/mods/')}")
run_all_subfolders("~/.minetest/mods")
elif len(params["folders"]) >= 2:
print("on folder list:", params["folders"])
for f in params["folders"]:
if params["recursive"]:
run_all_subfolders(f)
else:
update_folder(f)
elif len(params["folders"]) == 1:
print("on folder", params["folders"][0])
if params["recursive"]:
run_all_subfolders(params["folders"][0])
else:
update_folder(params["folders"][0])
else:
print("on folder", os.path.abspath("./"))
if params["recursive"]:
run_all_subfolders(os.path.abspath("./"))
else:
update_folder(os.path.abspath("./"))
#group 2 will be the string, groups 1 and 3 will be the delimiters (" or ')
#See https://stackoverflow.com/questions/46967465/regex-match-text-in-either-single-or-double-quote
pattern_lua = re.compile(r'[\.=^\t,{\(\s]N?S\(\s*(["\'])((?:\\\1|(?:(?!\1)).)*)(\1)[\s,\)]', re.DOTALL)
pattern_lua_bracketed = re.compile(r'[\.=^\t,{\(\s]N?S\(\s*\[\[(.*?)\]\][\s,\)]', re.DOTALL)
# Handles "concatenation" .. " of strings"
pattern_concat = re.compile(r'["\'][\s]*\.\.[\s]*["\']', re.DOTALL)
pattern_tr = re.compile(r'(.+?[^@])=(.*)')
pattern_name = re.compile(r'^name[ ]*=[ ]*([^ \n]*)')
pattern_tr_filename = re.compile(r'\.tr$')
pattern_po_language_code = re.compile(r'(.*)\.po$')
#attempt to read the mod's name from the mod.conf file. Returns None on failure
def get_modname(folder):
try:
with open(os.path.join(folder, "mod.conf"), "r", encoding='utf-8') as mod_conf:
for line in mod_conf:
match = pattern_name.match(line)
if match:
return match.group(1)
except FileNotFoundError:
pass
return None
#If there are already .tr files in /locale, returns a list of their names
def get_existing_tr_files(folder):
out = []
for root, dirs, files in os.walk(os.path.join(folder, 'locale/')):
for name in files:
if pattern_tr_filename.search(name):
out.append(name)
return out
# A series of search and replaces that massage a .po file's contents into
# a .tr file's equivalent
def process_po_file(text):
# The first three items are for unused matches
text = re.sub(r'#~ msgid "', "", text)
text = re.sub(r'"\n#~ msgstr ""\n"', "=", text)
text = re.sub(r'"\n#~ msgstr "', "=", text)
# comment lines
text = re.sub(r'#.*\n', "", text)
# converting msg pairs into "=" pairs
text = re.sub(r'msgid "', "", text)
text = re.sub(r'"\nmsgstr ""\n"', "=", text)
text = re.sub(r'"\nmsgstr "', "=", text)
# various line breaks and escape codes
text = re.sub(r'"\n"', "", text)
text = re.sub(r'"\n', "\n", text)
text = re.sub(r'\\"', '"', text)
text = re.sub(r'\\n', '@n', text)
# remove header text
text = re.sub(r'=Project-Id-Version:.*\n', "", text)
# remove double-spaced lines
text = re.sub(r'\n\n', '\n', text)
return text
# Go through existing .po files and, if a .tr file for that language
# *doesn't* exist, convert it and create it.
# The .tr file that results will subsequently be reprocessed so
# any "no longer used" strings will be preserved.
# Note that "fuzzy" tags will be lost in this process.
def process_po_files(folder, modname):
for root, dirs, files in os.walk(os.path.join(folder, 'locale/')):
for name in files:
code_match = pattern_po_language_code.match(name)
if code_match == None:
continue
language_code = code_match.group(1)
tr_name = modname + "." + language_code + ".tr"
tr_file = os.path.join(root, tr_name)
if os.path.exists(tr_file):
if params["verbose"]:
print(f"{tr_name} already exists, ignoring {name}")
continue
fname = os.path.join(root, name)
with open(fname, "r", encoding='utf-8') as po_file:
if params["verbose"]:
print(f"Importing translations from {name}")
text = process_po_file(po_file.read())
with open(tr_file, "wt", encoding='utf-8') as tr_out:
tr_out.write(text)
# from https://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python/600612#600612
# Creates a directory if it doesn't exist, silently does
# nothing if it already exists
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else: raise
# Converts the template dictionary to a text to be written as a file
# dKeyStrings is a dictionary of localized string to source file sets
# dOld is a dictionary of existing translations and comments from
# the previous version of this text
def strings_to_text(dkeyStrings, dOld, mod_name):
lOut = [f"# textdomain: {mod_name}\n"]
dGroupedBySource = {}
for key in dkeyStrings:
sourceList = list(dkeyStrings[key])
sourceList.sort()
sourceString = "\n".join(sourceList)
listForSource = dGroupedBySource.get(sourceString, [])
listForSource.append(key)
dGroupedBySource[sourceString] = listForSource
lSourceKeys = list(dGroupedBySource.keys())
lSourceKeys.sort()
for source in lSourceKeys:
localizedStrings = dGroupedBySource[source]
localizedStrings.sort()
lOut.append("")
lOut.append(source)
lOut.append("")
for localizedString in localizedStrings:
val = dOld.get(localizedString, {})
translation = val.get("translation", "")
comment = val.get("comment")
if len(localizedString) > doublespace_threshold and not lOut[-1] == "":
lOut.append("")
if comment != None:
lOut.append(comment)
lOut.append(f"{localizedString}={translation}")
if len(localizedString) > doublespace_threshold:
lOut.append("")
unusedExist = False
for key in dOld:
if key not in dkeyStrings:
val = dOld[key]
translation = val.get("translation")
comment = val.get("comment")
# only keep an unused translation if there was translated
# text or a comment associated with it
if translation != None and (translation != "" or comment):
if not unusedExist:
unusedExist = True
lOut.append("\n\n##### not used anymore #####\n")
if len(key) > doublespace_threshold and not lOut[-1] == "":
lOut.append("")
if comment != None:
lOut.append(comment)
lOut.append(f"{key}={translation}")
if len(key) > doublespace_threshold:
lOut.append("")
return "\n".join(lOut) + '\n'
# Writes a template.txt file
# dkeyStrings is the dictionary returned by generate_template
def write_template(templ_file, dkeyStrings, mod_name):
# read existing template file to preserve comments
existing_template = import_tr_file(templ_file)
text = strings_to_text(dkeyStrings, existing_template[0], mod_name)
mkdir_p(os.path.dirname(templ_file))
with open(templ_file, "wt", encoding='utf-8') as template_file:
template_file.write(text)
# Gets all translatable strings from a lua file
def read_lua_file_strings(lua_file):
lOut = []
with open(lua_file, encoding='utf-8') as text_file:
text = text_file.read()
#TODO remove comments here
text = re.sub(pattern_concat, "", text)
strings = []
for s in pattern_lua.findall(text):
strings.append(s[1])
for s in pattern_lua_bracketed.findall(text):
strings.append(s)
for s in strings:
s = re.sub(r'"\.\.\s+"', "", s)
s = re.sub("@[^@=0-9]", "@@", s)
s = s.replace('\\"', '"')
s = s.replace("\\'", "'")
s = s.replace("\n", "@n")
s = s.replace("\\n", "@n")
s = s.replace("=", "@=")
lOut.append(s)
return lOut
# Gets strings from an existing translation file
# returns both a dictionary of translations
# and the full original source text so that the new text
# can be compared to it for changes.
def import_tr_file(tr_file):
dOut = {}
text = None
if os.path.exists(tr_file):
with open(tr_file, "r", encoding='utf-8') as existing_file :
# save the full text to allow for comparison
# of the old version with the new output
text = existing_file.read()
existing_file.seek(0)
# a running record of the current comment block
# we're inside, to allow preceeding multi-line comments
# to be retained for a translation line
latest_comment_block = None
for line in existing_file.readlines():
line = line.rstrip('\n')
if line[:3] == "###":
# Reset comment block if we hit a header
latest_comment_block = None
continue
if line[:1] == "#":
# Save the comment we're inside
if not latest_comment_block:
latest_comment_block = line
else:
latest_comment_block = latest_comment_block + "\n" + line
continue
match = pattern_tr.match(line)
if match:
# this line is a translated line
outval = {}
outval["translation"] = match.group(2)
if latest_comment_block:
# if there was a comment, record that.
outval["comment"] = latest_comment_block
latest_comment_block = None
dOut[match.group(1)] = outval
return (dOut, text)
# Walks all lua files in the mod folder, collects translatable strings,
# and writes it to a template.txt file
# Returns a dictionary of localized strings to source file sets
# that can be used with the strings_to_text function.
def generate_template(folder, mod_name):
dOut = {}
for root, dirs, files in os.walk(folder):
for name in files:
if fnmatch.fnmatch(name, "*.lua"):
fname = os.path.join(root, name)
found = read_lua_file_strings(fname)
if params["verbose"]:
print(f"{fname}: {str(len(found))} translatable strings")
for s in found:
sources = dOut.get(s, set())
sources.add(f"### {os.path.basename(fname)} ###")
dOut[s] = sources
if len(dOut) == 0:
return None
templ_file = os.path.join(folder, "locale/template.txt")
write_template(templ_file, dOut, mod_name)
return dOut
# Updates an existing .tr file, copying the old one to a ".old" file
# if any changes have happened
# dNew is the data used to generate the template, it has all the
# currently-existing localized strings
def update_tr_file(dNew, mod_name, tr_file):
if params["verbose"]:
print(f"updating {tr_file}")
tr_import = import_tr_file(tr_file)
dOld = tr_import[0]
textOld = tr_import[1]
textNew = strings_to_text(dNew, dOld, mod_name)
if textOld and textOld != textNew:
print(f"{tr_file} has changed.")
shutil.copyfile(tr_file, f"{tr_file}.old")
with open(tr_file, "w", encoding='utf-8') as new_tr_file:
new_tr_file.write(textNew)
# Updates translation files for the mod in the given folder
def update_mod(folder):
modname = get_modname(folder)
if modname is not None:
process_po_files(folder, modname)
print(f"Updating translations for {modname}")
data = generate_template(folder, modname)
if data == None:
print(f"No translatable strings found in {modname}")
else:
for tr_file in get_existing_tr_files(folder):
update_tr_file(data, modname, os.path.join(folder, "locale/", tr_file))
else:
print("Unable to find modname in folder " + folder)
# Determines if the folder being pointed to is a mod or a mod pack
# and then runs update_mod accordingly
def update_folder(folder):
is_modpack = os.path.exists(os.path.join(folder, "modpack.txt")) or os.path.exists(os.path.join(folder, "modpack.conf"))
if is_modpack:
subfolders = [f.path for f in os.scandir(folder) if f.is_dir()]
for subfolder in subfolders:
update_mod(subfolder + "/")
else:
update_mod(folder)
print("Done.")
def run_all_subfolders(folder):
for modfolder in [f.path for f in os.scandir(folder) if f.is_dir()]:
update_folder(modfolder + "/")
main()

View File

@ -1,478 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-18 16:58-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: commoditymarket\doc.lua:11
msgid "Commodity Markets"
msgstr ""
#: commoditymarket\doc.lua:12
msgid ""
"Game-wide marketplaces where goods can be bought and sold at prices of your "
"choice."
msgstr ""
#: commoditymarket\doc.lua:17
msgid "User Interface: Inventory"
msgstr ""
#: commoditymarket\doc.lua:19
msgid ""
"Each player's account has an inventory that serves as a holding area for "
"items that are destined to be sold or that have been bought by the player "
"but not yet retrieved. This inventory is a bit different from the standard "
"Minetest inventory in that it doesn't hold item \"stacks\", it just tracks "
"the total number of that item present. Some markets allow for extremely "
"large quantities of an item to be stored here for sale.\n"
"\n"
"To add an item to your market inventory for eventual sale either shift-click "
"on the item in your player inventory or drag the item stack to the inventory "
"slot below the main market inventory list. Some markets may have "
"restrictions on what items can be bought and sold, if an item is not valid "
"for that market it won't go into the market's inventory. Some items are "
"considered \"currency\" and will add to your account's currency balance "
"instead of being listed in your market inventory.\n"
"\n"
"Tools cannot be added to the market inventory if they have any wear on them. "
"The market also can't handle items with attached metadata such as books that "
"have had text added to them.\n"
"\n"
"To remove an item from your market inventory, double-click in it in the "
"market inventory list. As much of the item as can fit into your player "
"inventory will be transferred to you, with any remainder staying behind in "
"the market inventory. To withdraw currency from your market balance type the "
"amount you'd like to withdraw in the field next to the \"Withdraw\" button. "
"The currency will be converted into items and added to your player "
"inventory, with whatever cannot be converted remaining behind in your market "
"balance."
msgstr ""
#: commoditymarket\doc.lua:29
msgid "User Interface: Orders"
msgstr ""
#: commoditymarket\doc.lua:32
msgid ""
"At the core of how a market operates are \"buy\" and \"sell\" orders. A buy "
"order is an announcement to the world that you are interested in purchasing "
"a certain quantity of item and are willing to pay a certain amount of "
"currency in exchange for each unit of that item. Conversely, a sell order is "
"an announcement to the world that you are interested in selling a certain "
"quantity of item and will accept a certain amount of currency in exchange "
"for each unit of that item.\n"
"\n"
"The market price of an item is determined by where the existing buy and sell "
"orders for that item intersect. When you offer to buy an item for a price "
"that someone is offering to sell it at, the item is transferred to you and "
"currency is transferred from your account to theirs to cover the cost. The "
"market will keep track of the most recent price that an item was "
"successfully sold for, but note that this information is for historical "
"interest only - there's no guarantee that anyone is currently willing to "
"match the historical price.\n"
"\n"
"When an item is selected in the upper list, the currently existing buy and "
"sell orders for that item will be displayed in the lower list. Sell orders "
"are listed first in descending price, followed by buy orders in ascending "
"price. The current market price will be somewhere in between the lowest sell "
"order and the highest buy order. If you wish to cancel a buy or sell order "
"that you've placed for an item, double-click on the order and the item or "
"currency that you put into that order will be returned to your inventory.\n"
"\n"
"If you place a buy order and there are already sell orders for the item that "
"meet or are below your price, some or all of your buy order might be "
"immediately fulfilled. Your purchases will be made at the price that the "
"sell orders have been set to - if you were willing to pay 15 units of "
"currency per item but someone was already offering to sell for 2 units of "
"currency per item, you only pay 2 units for each of that offer's items. If "
"there aren't enough compatible sell orders to fulfill your buy order, the "
"remainder will be placed into the market and made available for future "
"sellers to see and fulfill if they agree to your price. Your buy order will "
"immediately deduct the currency required for it from your account's balance, "
"but if you cancel your order you will get that currency back - it's not gone "
"until the order is actually fulfilled.\n"
"\n"
"If you place a sell order and there are already buy orders that meet or "
"exceed your price, some or all of your sell order may be immediately "
"fulfilled. You'll be paid the price that the buyers are offering rather than "
"the amount you're demanding. If any of your sell offer is left unfulfilled, "
"the sell order will be added to the market for future buyers to see. The "
"items for this offer will be immediately taken from your market inventory "
"but if you cancel your order you will get those items back."
msgstr ""
#: commoditymarket\formspecs.lua:104
#: commoditymarket\formspecs.lua:424
msgid "Unknown Item"
msgstr ""
#: commoditymarket\formspecs.lua:136
#: commoditymarket\formspecs.lua:333
#: commoditymarket\formspecs.lua:547
msgid "Your Inventory"
msgstr ""
#: commoditymarket\formspecs.lua:136
#: commoditymarket\formspecs.lua:333
#: commoditymarket\formspecs.lua:547
msgid "Market Orders"
msgstr ""
#: commoditymarket\formspecs.lua:161
msgid ""
"All the items you've transfered to the market to sell and the items you've\n"
"purchased with buy orders. Double-click on an item to bring it back into "
"your\n"
"personal inventory."
msgstr ""
#: commoditymarket\formspecs.lua:167
#: commoditymarket\formspecs.lua:174
msgid "Item"
msgstr ""
#: commoditymarket\formspecs.lua:169
#: commoditymarket\formspecs.lua:176
#: commoditymarket\formspecs.lua:365
msgid "Description"
msgstr ""
#: commoditymarket\formspecs.lua:169
#: commoditymarket\formspecs.lua:176
#: commoditymarket\formspecs.lua:448
#: commoditymarket\formspecs.lua:459
msgid "Quantity"
msgstr ""
#: commoditymarket\formspecs.lua:190
msgid ""
"Drop items here to\n"
"add to your account"
msgstr ""
#: commoditymarket\formspecs.lua:194
msgid "Inventory limit:"
msgstr ""
#: commoditymarket\formspecs.lua:195
msgid ""
"You can still receive purchased items if you've exceeded your inventory "
"limit,\n"
"but you won't be able to transfer items from your personal inventory into\n"
"the market until you've emptied it back down below the limit again."
msgstr ""
#: commoditymarket\formspecs.lua:198
msgid ""
"Enter the amount of currency you'd like to withdraw then click the "
"'Withdraw'\n"
"button to convert it into items and transfer it to your personal inventory."
msgstr ""
#: commoditymarket\formspecs.lua:201
msgid "Withdraw"
msgstr ""
#: commoditymarket\formspecs.lua:349
msgid "Number of items there's demand for in the market."
msgstr ""
#: commoditymarket\formspecs.lua:350
msgid "Maximum price being offered to buy one of these."
msgstr ""
#: commoditymarket\formspecs.lua:352
msgid "Number of items available for sale in the market."
msgstr ""
#: commoditymarket\formspecs.lua:353
msgid "Minimum price being demanded to sell one of these."
msgstr ""
#: commoditymarket\formspecs.lua:354
msgid "Price paid for one of these the last time one was sold."
msgstr ""
#: commoditymarket\formspecs.lua:355
msgid "Quantity of this item that you have in your inventory ready to sell."
msgstr ""
#: commoditymarket\formspecs.lua:365
msgid "Buy Vol"
msgstr ""
#: commoditymarket\formspecs.lua:365
msgid "Buy Max"
msgstr ""
#: commoditymarket\formspecs.lua:366
msgid "Sell Vol"
msgstr ""
#: commoditymarket\formspecs.lua:366
msgid "Sell Min"
msgstr ""
#: commoditymarket\formspecs.lua:366
msgid "Last Price"
msgstr ""
#: commoditymarket\formspecs.lua:366
msgid "Inventory"
msgstr ""
#: commoditymarket\formspecs.lua:409
msgid "My orders"
msgstr ""
#: commoditymarket\formspecs.lua:410
msgid ""
"Select this to show only the markets where you have either a buy or a sell "
"order pending."
msgstr ""
#: commoditymarket\formspecs.lua:411
msgid "Enter substring to search item identifiers for."
msgstr ""
#: commoditymarket\formspecs.lua:412
msgid "Apply search to outputs."
msgstr ""
#: commoditymarket\formspecs.lua:413
msgid "Clear search."
msgstr ""
#: commoditymarket\formspecs.lua:429
msgid "In inventory:"
msgstr ""
#: commoditymarket\formspecs.lua:430
msgid "Balance:"
msgstr ""
#: commoditymarket\formspecs.lua:443
msgid "Sell limit:"
msgstr ""
#: commoditymarket\formspecs.lua:444
msgid ""
"This market limits the total number of items a given seller can have for "
"sale at a time.\n"
"You have @1 items remaining. Cancel old sell orders to free up space."
msgstr ""
#: commoditymarket\formspecs.lua:447
msgid "Use these fields to enter buy and sell orders for the selected item."
msgstr ""
#: commoditymarket\formspecs.lua:448
#: commoditymarket\formspecs.lua:478
msgid "Buy"
msgstr ""
#: commoditymarket\formspecs.lua:449
msgid "Price per"
msgstr ""
#: commoditymarket\formspecs.lua:454
msgid "The price per item in this order."
msgstr ""
#: commoditymarket\formspecs.lua:455
msgid "The total amount of items in this particular order."
msgstr ""
#: commoditymarket\formspecs.lua:456
msgid ""
"The total amount of items available at this price accounting for the other "
"orders also currently being offered."
msgstr ""
#: commoditymarket\formspecs.lua:457
msgid ""
"The name of the player who placed this order.\n"
"Double-click your own orders to cancel them."
msgstr ""
#: commoditymarket\formspecs.lua:458
msgid "How many days ago this order was placed."
msgstr ""
#: commoditymarket\formspecs.lua:459
msgid "Order"
msgstr ""
#: commoditymarket\formspecs.lua:459
msgid "Price"
msgstr ""
#: commoditymarket\formspecs.lua:459
msgid "Total Volume"
msgstr ""
#: commoditymarket\formspecs.lua:459
msgid "Player"
msgstr ""
#: commoditymarket\formspecs.lua:459
msgid "Days Old"
msgstr ""
#: commoditymarket\formspecs.lua:463
msgid "Sell"
msgstr ""
#: commoditymarket\formspecs.lua:487
msgid "Select an item to view or place orders."
msgstr ""
#: commoditymarket\formspecs.lua:503
msgid "yourself"
msgstr ""
#: commoditymarket\formspecs.lua:505
#: commoditymarket\formspecs.lua:513
msgid "someone"
msgstr ""
#: commoditymarket\formspecs.lua:507
#: commoditymarket\formspecs.lua:515
msgid "you"
msgstr ""
#: commoditymarket\formspecs.lua:538
msgid "On day @1 @2 sold @3 @4 to @5 at @6@7 each for a total of @6@8."
msgstr ""
#: commoditymarket\formspecs.lua:548
msgid "Description:"
msgstr ""
#: commoditymarket\formspecs.lua:549
msgid "Your Recent Purchases and Sales:"
msgstr ""
#: commoditymarket\formspecs.lua:562
msgid "Mark logs as read"
msgstr ""
#: commoditymarket\formspecs.lua:563
msgid ""
"Log entries in yellow are new since last time you marked your log as read."
msgstr ""
#: commoditymarket\formspecs.lua:566
msgid "No logged activites in this market yet."
msgstr ""
#: commoditymarket\formspecs.lua:570
msgid "Show Itemnames"
msgstr ""
#: commoditymarket\formspecs.lua:574
msgid "Show Icons"
msgstr ""
#: commoditymarket\market.lua:198
msgid ""
"You have too many items listed for sale in this market, please cancel some "
"sell orders to make room for new ones."
msgstr ""
#: commoditymarket\market.lua:200
msgid "You can't sell items for a negative price."
msgstr ""
#: commoditymarket\market.lua:202
msgid "You can't sell fewer than one item."
msgstr ""
#: commoditymarket\market.lua:204
msgid ""
"You don't have enough of that item in your inventory to post this sell order."
msgstr ""
#: commoditymarket\market.lua:295
msgid "You can't pay less than nothing for an item."
msgstr ""
#: commoditymarket\market.lua:297
msgid "You have to buy at least one item."
msgstr ""
#: commoditymarket\market.lua:299
msgid "You can't afford that many of this item."
msgstr ""
#: commoditymarket\market.lua:385
msgid "show market formspec"
msgstr ""
#: commoditymarket\market.lua:397
msgid "list all registered markets"
msgstr ""
#: commoditymarket\market.lua:426
msgid "remove item from market. All existing buys and sells will be canceled."
msgstr ""
#: commoditymarket\market.lua:445
msgid ""
"removes all unknown items from all markets. All existing buys and sells for "
"those items will be canceled."
msgstr ""
#: commoditymarket\market.lua:457
msgid "Purging item: @1 from market: @2"
msgstr ""
#: commoditymarket\market.lua:471
msgid "Add all registered items to the provided market"
msgstr ""
#: commoditymarket\market.lua:531
msgid "1 @1 = @2@3"
msgstr ""
#: commoditymarket\market.lua:535
msgid "Market inventory is limited to @1 items."
msgstr ""
#: commoditymarket\market.lua:537
msgid "Market has unlimited inventory space."
msgstr ""
#: commoditymarket\market.lua:542
msgid "Total pending sell orders are limited to @1 items."
msgstr ""
#: commoditymarket\market.lua:544
msgid "Market supports unlimited pending sell orders."
msgstr ""
#: commoditymarket\market.lua:551
msgid "Currency item values:"
msgstr ""
#: commoditymarket\market.lua:566
msgid "Market"
msgstr ""
#: commoditymarket\market.lua:567
msgid "A market where orders to buy or sell items can be placed and fulfilled."
msgstr ""

View File

@ -1,6 +0,0 @@
@echo off
setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
cd ..
set LIST=
for /r %%X in (*.lua) do set LIST=!LIST! %%X
..\intllib\tools\xgettext.bat %LIST%

View File

@ -1,153 +0,0 @@
local goblin_enabled = minetest.settings:get_bool("commoditymarket_enable_goblin_market")
local under_enabled = minetest.settings:get_bool("commoditymarket_enable_under_market")
local goblin_prob = tonumber(minetest.settings:get("commoditymarket_goblin_market_dungeon_prob")) or 0.25
local under_prob = tonumber(minetest.settings:get("commoditymarket_under_market_dungeon_prob")) or 0.1
local goblin_max = tonumber(minetest.settings:get("commoditymarket_goblin_market_dungeon_max")) or 100
local goblin_min = tonumber(minetest.settings:get("commoditymarket_goblin_market_dungeon_min")) or -400
local under_max = tonumber(minetest.settings:get("commoditymarket_under_market_dungeon_max")) or -500
local under_min = tonumber(minetest.settings:get("commoditymarket_under_market_dungeon_min")) or -31000
local bad_goblin_range = goblin_min >= goblin_max
local bad_under_range = under_min >= under_max
if bad_goblin_range then
minetest.log("error", "[commoditymarket] Goblin market dungeon generation range has a higher minimum y than maximum y")
end
if bad_under_range then
minetest.log("error", "[commoditymarket] Undermarket dungeon generation range has a higher minimum y than maximum y")
end
local gen_goblin = goblin_enabled and goblin_prob > 0 and not bad_goblin_range
local gen_under = under_enabled and under_prob > 0 and not bad_under_range
if not (gen_goblin or gen_under) then
return
end
-------------------------------------------------------
-- The following is shamelessly copied from dungeon_loot and tweaked for placing markets instead of chests
--Licensed under the MIT License (MIT) Copyright (C) 2017 sfan5
minetest.set_gen_notify({dungeon = true, temple = true})
local function noise3d_integer(noise, pos)
return math.abs(math.floor(noise:get_3d(pos) * 0x7fffffff))
end
local is_wall = function(node)
return node.name ~= "air" and node.name ~= "ignore"
end
local function find_walls(cpos)
local dirs = {{x=1, z=0}, {x=-1, z=0}, {x=0, z=1}, {x=0, z=-1}}
local get_node = minetest.get_node
local ret = {}
local mindist = {x=0, z=0}
local min = function(a, b) return a ~= 0 and math.min(a, b) or b end
for _, dir in ipairs(dirs) do
for i = 1, 9 do -- 9 = max room size / 2
local pos = vector.add(cpos, {x=dir.x*i, y=0, z=dir.z*i})
-- continue in that direction until we find a wall-like node
local node = get_node(pos)
if is_wall(node) then
local front_below = vector.subtract(pos, {x=dir.x, y=1, z=dir.z})
local above = vector.add(pos, {x=0, y=1, z=0})
-- check that it:
--- is at least 2 nodes high (not a staircase)
--- has a floor
if is_wall(get_node(front_below)) and is_wall(get_node(above)) then
pos = vector.subtract(pos, {x=dir.x, y=0, z=dir.z}) -- move goblin markets one node away from the wall
table.insert(ret, {pos = pos, facing = {x=-dir.x, y=0, z=-dir.z}})
if dir.z == 0 then
mindist.x = min(mindist.x, i-1)
else
mindist.z = min(mindist.z, i-1)
end
end
-- abort even if it wasn't a wall cause something is in the way
break
end
end
end
return {
walls = ret,
size = {x=mindist.x*2, z=mindist.z*2},
cpos = cpos,
}
end
minetest.register_on_generated(function(minp, maxp, blockseed)
local min_y = minp.y
local max_y = maxp.y
local gen_goblin_range = gen_goblin and not (min_y > goblin_max or max_y < goblin_min)
local gen_under_range = gen_under and not (min_y > under_max or max_y < under_min)
if not (gen_goblin_range or gen_under_range) then
-- out of both ranges
return
end
local gennotify = minetest.get_mapgen_object("gennotify")
local poslist = gennotify["dungeon"] or {}
for _, entry in ipairs(gennotify["temple"] or {}) do
table.insert(poslist, entry)
end
if #poslist == 0 then return end
local noise = minetest.get_perlin(151994, 4, 0.5, 1)
local rand = PcgRandom(noise3d_integer(noise, poslist[1]))
local rooms = {}
-- process at most 8 rooms to keep runtime of this predictable
local num_process = math.min(#poslist, 8)
for i = 1, num_process do
local room = find_walls(poslist[i])
-- skip small rooms and everything that doesn't at least have 3 walls
if math.min(room.size.x, room.size.z) >= 4 and #room.walls >= 3 then
table.insert(rooms, room)
end
end
if #rooms == 0 then return end
if gen_under_range and rand:next(0, 2147483647)/2147483647 < under_prob then
-- choose a random room
local room = rooms[rand:next(1, #rooms)]
local under_loc = room.cpos
-- put undermarkets in the center of the room
if minetest.get_node(under_loc).name == "air"
and is_wall(vector.subtract(under_loc, {x=0, y=1, z=0})) then
minetest.add_node(under_loc, {name="commoditymarket:under_market"})
end
end
if gen_goblin_range and rand:next(0, 2147483647)/2147483647 < goblin_prob then
-- choose a random room
local room = rooms[rand:next(1, #rooms)]
-- choose place somewhere in front of any of the walls
local wall = room.walls[rand:next(1, #room.walls)]
local v, vi -- vector / axis that runs alongside the wall
if wall.facing.x ~= 0 then
v, vi = {x=0, y=0, z=1}, "z"
else
v, vi = {x=1, y=0, z=0}, "x"
end
local marketpos = vector.add(wall.pos, wall.facing)
local off = rand:next(-room.size[vi]/2 + 1, room.size[vi]/2 - 1)
marketpos = vector.add(marketpos, vector.multiply(v, off))
if minetest.get_node(marketpos).name == "air" then
-- make it face inwards to the room
local facedir = minetest.dir_to_facedir(vector.multiply(wall.facing, -1))
minetest.add_node(marketpos, {name = "commoditymarket:goblin_market", param2 = facedir})
end
end
end)

View File

@ -1,852 +0,0 @@
# Blender v2.79 (sub 0) OBJ File: 'wagon.blend'
# www.blender.org
g Cube.004_Cube.012
v 0.234629 1.147573 -1.166732
v -0.234629 1.147573 -1.166732
v 0.234629 0.678315 -1.166732
v -0.234629 0.678315 -1.166732
v 0.731823 1.147573 -0.234629
v 0.731823 1.147573 0.234629
v 0.731823 0.678315 -0.234629
v 0.731823 0.678315 0.234629
v -0.731823 1.147573 0.234629
v -0.731823 1.147573 -0.234629
v -0.731823 0.678315 0.234629
v -0.731823 0.678315 -0.234629
v -0.259667 0.016670 1.168107
v 0.259668 0.016670 1.168107
v -0.259667 1.170112 1.168107
v 0.259668 1.170112 1.168107
vt 0.000000 0.533333
vt 0.000000 1.000000
vt 1.000000 1.000000
vt 1.000000 0.533333
vt -0.000000 0.533333
vt 1.000000 0.533333
vt 1.000000 1.000000
vt -0.000000 1.000000
vt 0.000000 0.533333
vt 1.000000 0.533333
vt 1.000000 1.000000
vt 0.000000 1.000000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 1.000000 1.000000
vt 0.000000 1.000000
vn 0.0000 0.0000 -1.0000
vn 1.0000 0.0000 0.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 1.0000
s off
f 4/1/1 2/2/1 1/3/1 3/4/1
f 8/5/2 7/6/2 5/7/2 6/8/2
f 12/9/3 11/10/3 9/11/3 10/12/3
f 13/13/4 14/14/4 16/15/4 15/16/4
g Cube.003_Cube.011
v -0.720902 -0.096672 1.153442
v -0.720901 -0.096672 -1.153443
v -0.720902 1.200951 1.153442
v -0.720902 1.200951 -1.153443
v -0.509754 1.608755 -1.153443
v -0.509754 1.608755 1.153443
v -0.792992 1.200951 -1.268787
v -0.792992 1.200951 1.268787
v -0.560730 1.649535 -1.268787
v -0.560730 1.649535 1.268787
v -0.726391 1.178882 -1.268787
v -0.726391 1.178882 1.268787
v -0.509756 1.608756 -1.268787
v -0.509756 1.608756 1.268787
v -0.692620 0.037741 -1.018928
v -0.692620 0.163735 -1.089024
v -0.692620 -0.523026 -2.026881
v -0.692620 -0.397032 -2.096977
v -0.512394 0.037741 -1.018928
v -0.512394 0.163735 -1.089024
v -0.512394 -0.523026 -2.026881
v -0.512394 -0.397032 -2.096977
v -0.324406 0.582331 -1.134006
v -0.324406 0.654421 -1.134006
v -0.324406 0.582331 -1.441803
v -0.324406 0.654421 -1.441803
v 0.720901 -0.096672 -1.153443
v 0.720902 -0.096672 1.153442
v -0.000000 1.200951 1.153443
v 0.720902 1.200951 1.153442
v -0.000000 1.200951 -1.153443
v -0.000000 1.777673 -1.153443
v -0.000000 1.777673 1.153443
v 0.720902 1.200951 -1.153443
v 0.509754 1.608755 -1.153443
v 0.509754 1.608755 1.153443
v -0.000000 1.835345 1.268787
v -0.000000 1.835345 -1.268787
v 0.792992 1.200951 -1.268787
v 0.792992 1.200951 1.268787
v 0.560730 1.649535 -1.268787
v 0.560730 1.649535 1.268787
v -0.000000 1.777673 1.268787
v -0.000000 1.777673 -1.268787
v 0.726391 1.178882 -1.268787
v 0.726391 1.178882 1.268787
v 0.509756 1.608756 -1.268787
v 0.509756 1.608756 1.268787
v 0.692620 0.037741 -1.018928
v 0.692620 0.163735 -1.089024
v 0.692620 -0.523026 -2.026881
v 0.692620 -0.397032 -2.096977
v 0.512394 0.037741 -1.018928
v 0.512394 0.163735 -1.089024
v 0.512394 -0.523026 -2.026881
v 0.512394 -0.397032 -2.096977
v 0.324406 0.582331 -1.134006
v 0.324406 0.654421 -1.134006
v 0.324406 0.582331 -1.441803
v 0.324406 0.654421 -1.441803
vt -1.425823 3.001615
vt -1.425823 2.882734
vt -0.355896 2.882734
vt -0.355896 3.001615
vt 0.375155 -3.373241
vt 0.375155 -2.579424
vt -3.809447 -2.579426
vt -3.809447 -3.373241
vt 0.375154 -1.693858
vt -3.809447 -1.693859
vt 0.381165 -0.154615
vt 4.565710 -0.154608
vt 4.565710 -0.038908
vt 0.381165 -0.038908
vt -0.235621 2.375158
vt -0.235621 3.208172
vt -0.341187 3.187105
vt -0.349886 2.393338
vt 2.764791 -0.422899
vt 2.764791 -1.255914
vt 2.879056 -1.237734
vt 2.870357 -0.443966
vt -1.425823 3.804063
vt -0.451704 3.804062
vt -0.481619 3.894339
vt -1.367183 3.894337
vt -0.451699 3.798052
vt -1.425823 3.798051
vt -1.367184 3.707779
vt -0.481614 3.707775
vt 2.764791 -2.832267
vt 2.764791 -3.070028
vt 4.666879 -3.070028
vt 4.666879 -2.832265
vt 2.885066 -1.553966
vt 2.885066 -1.791727
vt 3.182267 -1.791727
vt 3.182267 -1.553966
vt 4.666881 -2.826254
vt 4.666881 -2.588493
vt 2.764791 -2.588493
vt 2.764791 -2.826255
vt 3.182267 -1.547955
vt 3.182267 -1.310194
vt 2.885066 -1.310194
vt 2.885066 -1.547955
vt 1.902838 4.586475
vt 1.902838 4.883677
vt 0.000747 4.883678
vt 0.000747 4.586475
vt 1.902835 4.283262
vt 1.902835 4.580463
vt 0.000747 4.580466
vt 0.000747 4.283262
vt 2.764791 -0.298008
vt 2.764791 -0.416888
vt 3.272367 -0.416888
vt 3.272367 -0.298008
vt -1.425823 2.375158
vt -0.355896 2.375158
vt -0.355896 3.509191
vt -1.425823 3.509191
vt -3.809448 2.369149
vt -3.809448 -0.008467
vt -0.005263 -0.008466
vt -0.005264 2.369148
vt 0.375154 -0.014477
vt -3.809448 -0.014477
vt -3.809448 -0.808292
vt 0.375154 -0.808291
vt 0.381165 -0.160630
vt 0.381165 -0.276331
vt 4.565711 -0.276331
vt 4.565711 -0.160625
vt 2.764791 -2.094939
vt 2.879056 -2.076759
vt 2.870358 -1.282992
vt 2.764791 -1.261924
vt -0.115346 3.208172
vt -0.220912 3.187105
vt -0.229611 2.393338
vt -0.115346 2.375158
vt -0.451703 3.515201
vt -0.510342 3.605475
vt -1.395907 3.605478
vt -1.425823 3.515201
vt -1.425823 3.701766
vt -1.395907 3.611488
vt -0.510338 3.611492
vt -0.451699 3.701765
vt 2.764791 -2.338711
vt 4.666883 -2.338711
vt 4.666883 -2.100949
vt 2.764791 -2.100949
vt 3.122827 -2.094939
vt 3.122827 -1.797738
vt 2.885066 -1.797738
vt 2.885066 -2.094939
vt 4.666883 -2.344721
vt 2.764791 -2.344721
vt 2.764791 -2.582482
vt 4.666883 -2.582483
vt -0.349886 3.214182
vt -0.052684 3.214182
vt -0.052684 3.451943
vt -0.349886 3.451943
vt 4.666882 -3.076038
vt 2.764791 -3.076038
vt 2.764791 -3.373240
vt 4.666883 -3.373241
vt 3.810932 4.580466
vt 1.908845 4.580463
vt 1.908845 4.283263
vt 3.810934 4.283262
vt 2.885066 -1.304184
vt 3.392642 -1.304184
vt 3.392642 -1.185303
vt 2.885066 -1.185303
vt 0.061193 0.029274
vt 2.438806 0.029274
vt 2.438807 2.169126
vt 1.250000 2.169127
vt 0.061193 2.169127
vt 2.438741 0.029448
vt 2.438741 2.169301
vt 6.242925 2.169302
vt 6.242926 0.029448
vt 2.090614 2.841618
vt 1.250000 2.169127
vt 0.409386 2.841618
vt 0.061192 2.169127
vt 1.250000 3.120173
vt 1.250000 3.120173
vt 2.438532 0.029230
vt 6.242717 0.029228
vt 6.242717 2.169081
vt 2.438534 2.169083
vt 0.409386 2.841618
vt 2.438807 2.169127
vt 2.090614 2.841617
vt 0.061193 0.029273
vt 2.438807 0.029273
vn 0.0000 0.0000 -1.0000
vn 0.8930 -0.4500 -0.0000
vn 0.3145 -0.9492 0.0000
vn -0.3145 -0.9492 0.0000
vn 0.0000 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 -0.4862 -0.8739
vn 1.0000 -0.0000 0.0000
vn 0.0000 0.4862 0.8739
vn 0.0000 -0.8739 0.4862
vn 0.0000 0.8739 -0.4862
vn 0.0000 1.0000 0.0000
vn 0.0000 -1.0000 0.0000
vn -0.8930 -0.4500 -0.0000
s off
f 41/17/5 42/18/5 76/19/5 75/20/5
f 27/21/6 29/22/6 30/23/6 28/24/6
f 29/22/7 60/25/7 59/26/7 30/23/7
f 24/27/8 23/28/8 27/29/8 28/30/8
f 23/31/5 25/32/5 29/33/5 27/34/5
f 26/35/9 24/36/9 28/37/9 30/38/9
f 25/39/5 54/40/5 60/41/5 29/42/5
f 53/43/9 26/44/9 30/45/9 59/46/9
f 31/47/10 32/48/10 34/49/10 33/50/10
f 33/51/11 34/52/11 38/53/11 37/54/11
f 37/55/12 38/56/12 36/57/12 35/58/12
f 35/59/13 36/60/13 32/61/13 31/62/13
f 33/63/14 37/64/14 35/65/14 31/66/14
f 38/67/15 34/68/15 32/69/15 36/70/15
f 39/71/10 40/72/10 42/73/10 41/74/10
f 76/19/16 42/18/16 40/75/16 74/76/16
f 41/17/17 75/20/17 73/77/17 39/78/17
f 44/79/17 17/80/17 18/81/17 43/82/17
f 61/83/18 62/84/18 64/85/18 63/86/18
f 63/86/8 64/85/8 59/26/8 60/25/8
f 56/87/7 62/88/7 61/89/7 55/90/7
f 55/91/5 61/92/5 63/93/5 57/94/5
f 58/95/9 64/96/9 62/97/9 56/98/9
f 57/99/5 63/100/5 60/101/5 54/102/5
f 53/103/9 59/104/9 64/105/9 58/106/9
f 65/107/12 67/108/12 68/109/12 66/110/12
f 67/111/11 71/112/11 72/113/11 68/114/11
f 71/115/10 69/116/10 70/117/10 72/118/10
f 69/119/13 65/120/13 66/121/13 70/122/13
f 67/123/14 65/124/14 69/125/14 71/126/14
f 72/127/15 70/128/15 66/129/15 68/130/15
f 73/131/12 75/132/12 76/133/12 74/134/12
f 43/135/5 18/136/5 20/137/5 47/138/5 50/139/5
f 17/140/10 19/141/10 20/142/10 18/143/10
f 47/138/5 20/137/5 21/144/5
f 45/145/9 22/146/9 19/147/9
f 47/138/5 21/144/5 48/148/5
f 45/145/9 49/149/9 22/146/9
f 44/150/12 43/151/12 50/152/12 46/153/12
f 47/138/5 51/154/5 50/139/5
f 45/145/9 46/155/9 52/156/9
f 47/138/5 48/148/5 51/154/5
f 45/145/9 52/156/9 49/149/9
f 45/145/9 19/147/9 17/157/9 44/158/9 46/155/9
g Cube.002_Cube.010
v -0.901127 0.047509 -0.576721
v -0.720902 0.047509 -0.576721
v -0.901127 0.268210 -1.109542
v -0.720902 0.268210 -1.109542
v -0.901127 -0.173193 -1.109542
v -0.720902 -0.173193 -1.109542
v -0.901127 -0.485312 -0.797423
v -0.720902 -0.485312 -0.797423
v -0.901127 -0.485312 -0.356020
v -0.720902 -0.485312 -0.356020
v -0.901127 -0.173193 -0.043900
v -0.720902 -0.173193 -0.043900
v -0.901127 0.268210 -0.043900
v -0.720902 0.268210 -0.043900
v -0.901127 0.580330 -0.356020
v -0.720902 0.580330 -0.356020
v -0.901127 0.580330 -0.797423
v -0.720902 0.580330 -0.797423
v -0.901127 0.047509 0.576721
v -0.720902 0.047509 0.576721
v -0.901127 0.268210 0.043900
v -0.720902 0.268210 0.043900
v -0.901127 -0.173193 0.043900
v -0.720902 -0.173193 0.043900
v -0.901127 -0.485312 0.356020
v -0.720902 -0.485312 0.356020
v -0.901127 -0.485312 0.797423
v -0.720902 -0.485312 0.797423
v -0.901127 -0.173193 1.109542
v -0.720902 -0.173193 1.109542
v -0.901127 0.268210 1.109542
v -0.720902 0.268210 1.109542
v -0.901127 0.580330 0.797423
v -0.720902 0.580330 0.797423
v -0.901127 0.580330 0.356020
v -0.720902 0.580330 0.356020
v 0.901127 0.047509 -0.576721
v 0.720902 0.047509 -0.576721
v 0.901127 0.268210 -1.109542
v 0.720902 0.268210 -1.109542
v 0.901127 -0.173193 -1.109542
v 0.720902 -0.173193 -1.109542
v 0.901127 -0.485312 -0.797423
v 0.720902 -0.485312 -0.797423
v 0.901127 -0.485312 -0.356020
v 0.720902 -0.485312 -0.356020
v 0.901127 -0.173193 -0.043900
v 0.720902 -0.173193 -0.043900
v 0.901127 0.268210 -0.043900
v 0.720902 0.268210 -0.043900
v 0.901127 0.580330 -0.356020
v 0.720902 0.580330 -0.356020
v 0.901127 0.580330 -0.797423
v 0.720902 0.580330 -0.797423
v 0.901127 0.047509 0.576721
v 0.720902 0.047509 0.576721
v 0.901127 0.268210 0.043900
v 0.720902 0.268210 0.043900
v 0.901127 -0.173193 0.043900
v 0.720902 -0.173193 0.043900
v 0.901127 -0.485312 0.356020
v 0.720902 -0.485312 0.356020
v 0.901127 -0.485312 0.797423
v 0.720902 -0.485312 0.797423
v 0.901127 -0.173193 1.109542
v 0.720902 -0.173193 1.109542
v 0.901127 0.268210 1.109542
v 0.720902 0.268210 1.109542
v 0.901127 0.580330 0.797423
v 0.720902 0.580330 0.797423
v 0.901127 0.580330 0.356020
v 0.720902 0.580330 0.356020
vt 0.499873 0.992213
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.499873 0.992213
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.499873 0.992213
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.499873 0.992213
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.499873 0.992213
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.499873 0.992213
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.499873 0.992213
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.499873 0.992213
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vt 0.085485 -0.008208
vt 0.914261 -0.008208
vt 0.914261 -0.008208
vt 0.085485 -0.008208
vn -1.0000 0.0000 0.0000
vn 1.0000 0.0000 0.0000
s off
f 77/159/19 79/160/19 81/161/19
f 78/162/20 82/163/20 80/164/20
f 77/159/19 81/165/19 83/166/19
f 78/162/20 84/167/20 82/168/20
f 77/159/19 83/169/19 85/170/19
f 78/162/20 86/171/20 84/172/20
f 77/159/19 85/173/19 87/174/19
f 78/162/20 88/175/20 86/176/20
f 77/159/19 87/177/19 89/178/19
f 78/162/20 90/179/20 88/180/20
f 77/159/19 89/181/19 91/182/19
f 78/162/20 92/183/20 90/184/20
f 77/159/19 91/185/19 93/186/19
f 78/162/20 94/187/20 92/188/20
f 77/159/19 93/189/19 79/190/19
f 78/162/20 80/191/20 94/192/20
f 95/193/19 97/194/19 99/195/19
f 96/196/20 100/197/20 98/198/20
f 95/193/19 99/199/19 101/200/19
f 96/196/20 102/201/20 100/202/20
f 95/193/19 101/203/19 103/204/19
f 96/196/20 104/205/20 102/206/20
f 95/193/19 103/207/19 105/208/19
f 96/196/20 106/209/20 104/210/20
f 95/193/19 105/211/19 107/212/19
f 96/196/20 108/213/20 106/214/20
f 95/193/19 107/215/19 109/216/19
f 96/196/20 110/217/20 108/218/20
f 95/193/19 109/219/19 111/220/19
f 96/196/20 112/221/20 110/222/20
f 95/193/19 111/223/19 97/224/19
f 96/196/20 98/225/20 112/226/20
f 113/227/20 117/228/20 115/229/20
f 114/230/19 116/231/19 118/232/19
f 113/227/20 119/233/20 117/234/20
f 114/230/19 118/235/19 120/236/19
f 113/227/20 121/237/20 119/238/20
f 114/230/19 120/239/19 122/240/19
f 113/227/20 123/241/20 121/242/20
f 114/230/19 122/243/19 124/244/19
f 113/227/20 125/245/20 123/246/20
f 114/230/19 124/247/19 126/248/19
f 113/227/20 127/249/20 125/250/20
f 114/230/19 126/251/19 128/252/19
f 113/227/20 129/253/20 127/254/20
f 114/230/19 128/255/19 130/256/19
f 113/227/20 115/257/20 129/258/20
f 114/230/19 130/259/19 116/260/19
f 131/261/20 135/262/20 133/263/20
f 132/264/19 134/265/19 136/266/19
f 131/261/20 137/267/20 135/268/20
f 132/264/19 136/269/19 138/270/19
f 131/261/20 139/271/20 137/272/20
f 132/264/19 138/273/19 140/274/19
f 131/261/20 141/275/20 139/276/20
f 132/264/19 140/277/19 142/278/19
f 131/261/20 143/279/20 141/280/20
f 132/264/19 142/281/19 144/282/19
f 131/261/20 145/283/20 143/284/20
f 132/264/19 144/285/19 146/286/19
f 131/261/20 147/287/20 145/288/20
f 132/264/19 146/289/19 148/290/19
f 131/261/20 133/291/20 147/292/20
f 132/264/19 148/293/19 134/294/19
g Cube.001_Cube.009
v -0.901127 0.268210 -1.109542
v -0.720902 0.268210 -1.109542
v -0.901127 -0.173193 -1.109542
v -0.720902 -0.173193 -1.109542
v -0.901127 -0.485312 -0.797423
v -0.720902 -0.485312 -0.797423
v -0.901127 -0.485312 -0.356020
v -0.720902 -0.485312 -0.356020
v -0.901127 -0.173193 -0.043900
v -0.720902 -0.173193 -0.043900
v -0.901127 0.268210 -0.043900
v -0.720902 0.268210 -0.043900
v -0.901127 0.580330 -0.356020
v -0.720902 0.580330 -0.356020
v -0.901127 0.580330 -0.797423
v -0.720902 0.580330 -0.797423
v -0.901127 0.268210 0.043900
v -0.720902 0.268210 0.043900
v -0.901127 -0.173193 0.043900
v -0.720902 -0.173193 0.043900
v -0.901127 -0.485312 0.356020
v -0.720902 -0.485312 0.356020
v -0.901127 -0.485312 0.797423
v -0.720902 -0.485312 0.797423
v -0.901127 -0.173193 1.109542
v -0.720902 -0.173193 1.109542
v -0.901127 0.268210 1.109542
v -0.720902 0.268210 1.109542
v -0.901127 0.580330 0.797423
v -0.720902 0.580330 0.797423
v -0.901127 0.580330 0.356020
v -0.720902 0.580330 0.356020
v 0.901127 0.268210 -1.109542
v 0.720902 0.268210 -1.109542
v 0.901127 -0.173193 -1.109542
v 0.720902 -0.173193 -1.109542
v 0.901127 -0.485312 -0.797423
v 0.720902 -0.485312 -0.797423
v 0.901127 -0.485312 -0.356020
v 0.720902 -0.485312 -0.356020
v 0.901127 -0.173193 -0.043900
v 0.720902 -0.173193 -0.043900
v 0.901127 0.268210 -0.043900
v 0.720902 0.268210 -0.043900
v 0.901127 0.580330 -0.356020
v 0.720902 0.580330 -0.356020
v 0.901127 0.580330 -0.797423
v 0.720902 0.580330 -0.797423
v 0.901127 0.268210 0.043900
v 0.720902 0.268210 0.043900
v 0.901127 -0.173193 0.043900
v 0.720902 -0.173193 0.043900
v 0.901127 -0.485312 0.356020
v 0.720902 -0.485312 0.356020
v 0.901127 -0.485312 0.797423
v 0.720902 -0.485312 0.797423
v 0.901127 -0.173193 1.109542
v 0.720902 -0.173193 1.109542
v 0.901127 0.268210 1.109542
v 0.720902 0.268210 1.109542
v 0.901127 0.580330 0.797423
v 0.720902 0.580330 0.797423
v 0.901127 0.580330 0.356020
v 0.720902 0.580330 0.356020
vt 0.279164 0.493799
vt 0.072560 0.493799
vt 0.072560 -0.012210
vt 0.279164 -0.012210
vt 0.072559 -0.518219
vt 0.279163 -0.518219
vt 0.072559 -1.024229
vt 0.279163 -1.024229
vt 0.072559 -1.530238
vt 0.279163 -1.530238
vt 0.279165 2.517837
vt 0.072561 2.517837
vt 0.072561 2.011827
vt 0.279165 2.011827
vt 0.072561 1.505818
vt 0.279165 1.505818
vt 0.072560 0.999809
vt 0.279165 0.999809
vt 0.694571 2.011827
vt 0.901175 2.011827
vt 0.901175 2.517837
vt 0.694571 2.517837
vt 0.694571 -1.530238
vt 0.901175 -1.530238
vt 0.901175 -1.024228
vt 0.694571 -1.024228
vt 0.901175 -0.518219
vt 0.694571 -0.518219
vt 0.901175 -0.012210
vt 0.694571 -0.012210
vt 0.901174 0.493799
vt 0.694570 0.493799
vt 0.901174 0.999809
vt 0.694570 0.999809
vt 0.901175 1.505817
vt 0.694570 1.505818
vt 0.279897 0.493799
vt 0.279898 -0.012210
vt 0.486502 -0.012210
vt 0.486501 0.493799
vt 0.279898 -0.518219
vt 0.486502 -0.518219
vt 0.279898 -1.024228
vt 0.486502 -1.024229
vt 0.279898 -1.530238
vt 0.486502 -1.530238
vt 0.279897 2.517837
vt 0.279897 2.011827
vt 0.486501 2.011827
vt 0.486501 2.517837
vt 0.279897 1.505818
vt 0.486501 1.505818
vt 0.279897 0.999809
vt 0.486501 0.999809
vt 0.693838 2.011827
vt 0.693838 2.517837
vt 0.487234 2.517837
vt 0.487234 2.011827
vt 0.693839 -1.530238
vt 0.693838 -1.024229
vt 0.487234 -1.024229
vt 0.487234 -1.530238
vt 0.693838 -0.518220
vt 0.487234 -0.518220
vt 0.693838 -0.012210
vt 0.487234 -0.012210
vt 0.693838 0.493800
vt 0.487234 0.493800
vt 0.693838 0.999809
vt 0.487234 0.999809
vt 0.693838 1.505818
vt 0.487234 1.505818
vn 0.0000 0.0000 -1.0000
vn -0.0000 -0.7071 -0.7071
vn -0.0000 -1.0000 -0.0000
vn -0.0000 -0.7071 0.7071
vn 0.0000 0.0000 1.0000
vn 0.0000 0.7071 0.7071
vn 0.0000 1.0000 0.0000
vn 0.0000 0.7071 -0.7071
s off
f 149/295/21 150/296/21 152/297/21 151/298/21
f 151/298/22 152/297/22 154/299/22 153/300/22
f 153/300/23 154/299/23 156/301/23 155/302/23
f 155/302/24 156/301/24 158/303/24 157/304/24
f 157/305/25 158/306/25 160/307/25 159/308/25
f 159/308/26 160/307/26 162/309/26 161/310/26
f 161/310/27 162/309/27 164/311/27 163/312/27
f 163/312/28 164/311/28 150/296/28 149/295/28
f 165/313/21 166/314/21 168/315/21 167/316/21
f 167/317/22 168/318/22 170/319/22 169/320/22
f 169/320/23 170/319/23 172/321/23 171/322/23
f 171/322/24 172/321/24 174/323/24 173/324/24
f 173/324/25 174/323/25 176/325/25 175/326/25
f 175/326/26 176/325/26 178/327/26 177/328/26
f 177/328/27 178/327/27 180/329/27 179/330/27
f 179/330/28 180/329/28 166/314/28 165/313/28
f 181/331/21 183/332/21 184/333/21 182/334/21
f 183/332/22 185/335/22 186/336/22 184/333/22
f 185/335/23 187/337/23 188/338/23 186/336/23
f 187/337/24 189/339/24 190/340/24 188/338/24
f 189/341/25 191/342/25 192/343/25 190/344/25
f 191/342/26 193/345/26 194/346/26 192/343/26
f 193/345/27 195/347/27 196/348/27 194/346/27
f 195/347/28 181/331/28 182/334/28 196/348/28
f 197/349/21 199/350/21 200/351/21 198/352/21
f 199/353/22 201/354/22 202/355/22 200/356/22
f 201/354/23 203/357/23 204/358/23 202/355/23
f 203/357/24 205/359/24 206/360/24 204/358/24
f 205/359/25 207/361/25 208/362/25 206/360/25
f 207/361/26 209/363/26 210/364/26 208/362/26
f 209/363/27 211/365/27 212/366/27 210/364/27
f 211/365/28 197/349/28 198/352/28 212/366/28
g Cube.000_Cube.008
v -0.792992 1.200951 -1.268787
v -0.792992 1.200951 1.268787
v -0.560730 1.649535 -1.268787
v -0.560730 1.649535 1.268787
v -0.000000 1.835345 1.268787
v -0.000000 1.835345 -1.268787
v 0.792992 1.200951 -1.268787
v 0.792992 1.200951 1.268787
v 0.560730 1.649535 -1.268787
v 0.560730 1.649535 1.268787
vt 3.173871 2.353881
vt -2.391578 2.353881
vt -2.391578 1.288979
vt 3.173871 1.288979
vt -2.391578 0.224077
vt 3.173871 0.224077
vt 3.173871 -1.905729
vt 3.173871 -0.840826
vt -2.391578 -0.840826
vt -2.391578 -1.905728
vn -0.8880 0.4598 0.0000
vn -0.3146 0.9492 0.0000
vn 0.8880 0.4598 0.0000
vn 0.3146 0.9492 0.0000
s off
f 213/367/29 214/368/29 216/369/29 215/370/29
f 215/370/30 216/369/30 217/371/30 218/372/30
f 219/373/31 221/374/31 222/375/31 220/376/31
f 221/374/32 218/372/32 217/371/32 222/375/32
g Cube.006_Cube.007
v -0.722861 -0.094866 1.158711
v -0.722861 1.240430 1.158711
v -0.722861 -0.094866 1.059710
v -0.722861 1.240430 1.059710
v -0.623860 -0.094866 1.158711
v -0.623860 1.240430 1.158711
v -0.725927 -0.094866 -1.158643
v -0.725927 1.240430 -1.158643
v -0.725927 -0.094866 -1.059642
v -0.725927 1.240430 -1.059642
v -0.626926 -0.094866 -1.158643
v -0.626926 1.240430 -1.158643
v 0.722861 -0.094866 1.158711
v 0.722861 1.240430 1.158711
v 0.722861 -0.094866 1.059710
v 0.722861 1.240430 1.059710
v 0.623860 -0.094866 1.158711
v 0.623860 1.240430 1.158711
v 0.725927 -0.094866 -1.158643
v 0.725927 1.240430 -1.158643
v 0.725927 -0.094866 -1.059642
v 0.725927 1.240430 -1.059642
v 0.626926 -0.094866 -1.158643
v 0.626926 1.240430 -1.158643
vt -0.339657 0.628705
vt 1.340090 0.628704
vt 1.340090 0.753243
vt -0.339657 0.753243
vt -0.339658 0.504167
vt 1.340090 0.504165
vt -0.339657 0.129512
vt -0.339657 0.004973
vt 1.340090 0.004973
vt 1.340090 0.129512
vt -0.339657 0.254051
vt 1.340090 0.254050
vt -0.339658 0.878300
vt -0.339658 0.753761
vt 1.340090 0.753762
vt 1.340090 0.878300
vt -0.339657 1.002839
vt 1.340090 1.002838
vt -0.339657 0.379109
vt 1.340090 0.379108
vt 1.340090 0.503647
vt -0.339657 0.503647
vt -0.339658 0.254571
vt 1.340090 0.254569
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 1.0000
vn 0.0000 0.0000 -1.0000
vn 1.0000 0.0000 0.0000
s off
f 223/377/33 224/378/33 226/379/33 225/380/33
f 227/381/34 228/382/34 224/378/34 223/377/34
f 229/383/33 231/384/33 232/385/33 230/386/33
f 233/387/35 229/383/35 230/386/35 234/388/35
f 235/389/36 237/390/36 238/391/36 236/392/36
f 239/393/34 235/389/34 236/392/34 240/394/34
f 241/395/36 242/396/36 244/397/36 243/398/36
f 245/399/35 246/400/35 242/396/35 241/395/35

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1016 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1001 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 759 B

View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

40
mods/commoditymarket_fantasy/.gitignore vendored Normal file
View File

@ -0,0 +1,40 @@
# Compiled Lua sources
luac.out
# luarocks build files
*.src.rock
*.zip
*.tar.gz
# Object files
*.o
*.os
*.ko
*.elf
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
*.def
*.exp
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex

View File

@ -0,0 +1,421 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Script to generate the template file and update the translation files.
# Copy the script into the mod or modpack root folder and run it there.
#
# Copyright (C) 2019 Joachim Stolberg, 2020 FaceDeer, 2020 Louis Royer
# LGPLv2.1+
#
# See https://github.com/minetest-tools/update_translations for
# potential future updates to this script.
from __future__ import print_function
import os, fnmatch, re, shutil, errno
from sys import argv as _argv
# Running params
params = {"recursive": False,
"help": False,
"mods": False,
"verbose": False,
"folders": []
}
# Available CLI options
options = {"recursive": ['--recursive', '-r'],
"help": ['--help', '-h'],
"mods": ['--installed-mods'],
"verbose": ['--verbose', '-v']
}
# Strings longer than this will have extra space added between
# them in the translation files to make it easier to distinguish their
# beginnings and endings at a glance
doublespace_threshold = 60
def set_params_folders(tab: list):
'''Initialize params["folders"] from CLI arguments.'''
# Discarding argument 0 (tool name)
for param in tab[1:]:
stop_param = False
for option in options:
if param in options[option]:
stop_param = True
break
if not stop_param:
params["folders"].append(os.path.abspath(param))
def set_params(tab: list):
'''Initialize params from CLI arguments.'''
for option in options:
for option_name in options[option]:
if option_name in tab:
params[option] = True
break
def print_help(name):
'''Prints some help message.'''
print(f'''SYNOPSIS
{name} [OPTIONS] [PATHS...]
DESCRIPTION
{', '.join(options["help"])}
prints this help message
{', '.join(options["recursive"])}
run on all subfolders of paths given
{', '.join(options["mods"])}
run on locally installed modules
{', '.join(options["verbose"])}
add output information
''')
def main():
'''Main function'''
set_params(_argv)
set_params_folders(_argv)
if params["help"]:
print_help(_argv[0])
elif params["recursive"] and params["mods"]:
print("Option --installed-mods is incompatible with --recursive")
else:
# Add recursivity message
print("Running ", end='')
if params["recursive"]:
print("recursively ", end='')
# Running
if params["mods"]:
print(f"on all locally installed modules in {os.path.abspath('~/.minetest/mods/')}")
run_all_subfolders("~/.minetest/mods")
elif len(params["folders"]) >= 2:
print("on folder list:", params["folders"])
for f in params["folders"]:
if params["recursive"]:
run_all_subfolders(f)
else:
update_folder(f)
elif len(params["folders"]) == 1:
print("on folder", params["folders"][0])
if params["recursive"]:
run_all_subfolders(params["folders"][0])
else:
update_folder(params["folders"][0])
else:
print("on folder", os.path.abspath("./"))
if params["recursive"]:
run_all_subfolders(os.path.abspath("./"))
else:
update_folder(os.path.abspath("./"))
#group 2 will be the string, groups 1 and 3 will be the delimiters (" or ')
#See https://stackoverflow.com/questions/46967465/regex-match-text-in-either-single-or-double-quote
pattern_lua = re.compile(r'[\.=^\t,{\(\s]N?S\(\s*(["\'])((?:\\\1|(?:(?!\1)).)*)(\1)[\s,\)]', re.DOTALL)
pattern_lua_bracketed = re.compile(r'[\.=^\t,{\(\s]N?S\(\s*\[\[(.*?)\]\][\s,\)]', re.DOTALL)
# Handles "concatenation" .. " of strings"
pattern_concat = re.compile(r'["\'][\s]*\.\.[\s]*["\']', re.DOTALL)
pattern_tr = re.compile(r'(.+?[^@])=(.*)')
pattern_name = re.compile(r'^name[ ]*=[ ]*([^ \n]*)')
pattern_tr_filename = re.compile(r'\.tr$')
pattern_po_language_code = re.compile(r'(.*)\.po$')
#attempt to read the mod's name from the mod.conf file. Returns None on failure
def get_modname(folder):
try:
with open(os.path.join(folder, "mod.conf"), "r", encoding='utf-8') as mod_conf:
for line in mod_conf:
match = pattern_name.match(line)
if match:
return match.group(1)
except FileNotFoundError:
pass
return None
#If there are already .tr files in /locale, returns a list of their names
def get_existing_tr_files(folder):
out = []
for root, dirs, files in os.walk(os.path.join(folder, 'locale/')):
for name in files:
if pattern_tr_filename.search(name):
out.append(name)
return out
# A series of search and replaces that massage a .po file's contents into
# a .tr file's equivalent
def process_po_file(text):
# The first three items are for unused matches
text = re.sub(r'#~ msgid "', "", text)
text = re.sub(r'"\n#~ msgstr ""\n"', "=", text)
text = re.sub(r'"\n#~ msgstr "', "=", text)
# comment lines
text = re.sub(r'#.*\n', "", text)
# converting msg pairs into "=" pairs
text = re.sub(r'msgid "', "", text)
text = re.sub(r'"\nmsgstr ""\n"', "=", text)
text = re.sub(r'"\nmsgstr "', "=", text)
# various line breaks and escape codes
text = re.sub(r'"\n"', "", text)
text = re.sub(r'"\n', "\n", text)
text = re.sub(r'\\"', '"', text)
text = re.sub(r'\\n', '@n', text)
# remove header text
text = re.sub(r'=Project-Id-Version:.*\n', "", text)
# remove double-spaced lines
text = re.sub(r'\n\n', '\n', text)
return text
# Go through existing .po files and, if a .tr file for that language
# *doesn't* exist, convert it and create it.
# The .tr file that results will subsequently be reprocessed so
# any "no longer used" strings will be preserved.
# Note that "fuzzy" tags will be lost in this process.
def process_po_files(folder, modname):
for root, dirs, files in os.walk(os.path.join(folder, 'locale/')):
for name in files:
code_match = pattern_po_language_code.match(name)
if code_match == None:
continue
language_code = code_match.group(1)
tr_name = modname + "." + language_code + ".tr"
tr_file = os.path.join(root, tr_name)
if os.path.exists(tr_file):
if params["verbose"]:
print(f"{tr_name} already exists, ignoring {name}")
continue
fname = os.path.join(root, name)
with open(fname, "r", encoding='utf-8') as po_file:
if params["verbose"]:
print(f"Importing translations from {name}")
text = process_po_file(po_file.read())
with open(tr_file, "wt", encoding='utf-8') as tr_out:
tr_out.write(text)
# from https://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python/600612#600612
# Creates a directory if it doesn't exist, silently does
# nothing if it already exists
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else: raise
# Converts the template dictionary to a text to be written as a file
# dKeyStrings is a dictionary of localized string to source file sets
# dOld is a dictionary of existing translations and comments from
# the previous version of this text
def strings_to_text(dkeyStrings, dOld, mod_name):
lOut = [f"# textdomain: {mod_name}\n"]
dGroupedBySource = {}
for key in dkeyStrings:
sourceList = list(dkeyStrings[key])
sourceList.sort()
sourceString = "\n".join(sourceList)
listForSource = dGroupedBySource.get(sourceString, [])
listForSource.append(key)
dGroupedBySource[sourceString] = listForSource
lSourceKeys = list(dGroupedBySource.keys())
lSourceKeys.sort()
for source in lSourceKeys:
localizedStrings = dGroupedBySource[source]
localizedStrings.sort()
lOut.append("")
lOut.append(source)
lOut.append("")
for localizedString in localizedStrings:
val = dOld.get(localizedString, {})
translation = val.get("translation", "")
comment = val.get("comment")
if len(localizedString) > doublespace_threshold and not lOut[-1] == "":
lOut.append("")
if comment != None:
lOut.append(comment)
lOut.append(f"{localizedString}={translation}")
if len(localizedString) > doublespace_threshold:
lOut.append("")
unusedExist = False
for key in dOld:
if key not in dkeyStrings:
val = dOld[key]
translation = val.get("translation")
comment = val.get("comment")
# only keep an unused translation if there was translated
# text or a comment associated with it
if translation != None and (translation != "" or comment):
if not unusedExist:
unusedExist = True
lOut.append("\n\n##### not used anymore #####\n")
if len(key) > doublespace_threshold and not lOut[-1] == "":
lOut.append("")
if comment != None:
lOut.append(comment)
lOut.append(f"{key}={translation}")
if len(key) > doublespace_threshold:
lOut.append("")
return "\n".join(lOut) + '\n'
# Writes a template.txt file
# dkeyStrings is the dictionary returned by generate_template
def write_template(templ_file, dkeyStrings, mod_name):
# read existing template file to preserve comments
existing_template = import_tr_file(templ_file)
text = strings_to_text(dkeyStrings, existing_template[0], mod_name)
mkdir_p(os.path.dirname(templ_file))
with open(templ_file, "wt", encoding='utf-8') as template_file:
template_file.write(text)
# Gets all translatable strings from a lua file
def read_lua_file_strings(lua_file):
lOut = []
with open(lua_file, encoding='utf-8') as text_file:
text = text_file.read()
#TODO remove comments here
text = re.sub(pattern_concat, "", text)
strings = []
for s in pattern_lua.findall(text):
strings.append(s[1])
for s in pattern_lua_bracketed.findall(text):
strings.append(s)
for s in strings:
s = re.sub(r'"\.\.\s+"', "", s)
s = re.sub("@[^@=0-9]", "@@", s)
s = s.replace('\\"', '"')
s = s.replace("\\'", "'")
s = s.replace("\n", "@n")
s = s.replace("\\n", "@n")
s = s.replace("=", "@=")
lOut.append(s)
return lOut
# Gets strings from an existing translation file
# returns both a dictionary of translations
# and the full original source text so that the new text
# can be compared to it for changes.
def import_tr_file(tr_file):
dOut = {}
text = None
if os.path.exists(tr_file):
with open(tr_file, "r", encoding='utf-8') as existing_file :
# save the full text to allow for comparison
# of the old version with the new output
text = existing_file.read()
existing_file.seek(0)
# a running record of the current comment block
# we're inside, to allow preceeding multi-line comments
# to be retained for a translation line
latest_comment_block = None
for line in existing_file.readlines():
line = line.rstrip('\n')
if line[:3] == "###":
# Reset comment block if we hit a header
latest_comment_block = None
continue
if line[:1] == "#":
# Save the comment we're inside
if not latest_comment_block:
latest_comment_block = line
else:
latest_comment_block = latest_comment_block + "\n" + line
continue
match = pattern_tr.match(line)
if match:
# this line is a translated line
outval = {}
outval["translation"] = match.group(2)
if latest_comment_block:
# if there was a comment, record that.
outval["comment"] = latest_comment_block
latest_comment_block = None
dOut[match.group(1)] = outval
return (dOut, text)
# Walks all lua files in the mod folder, collects translatable strings,
# and writes it to a template.txt file
# Returns a dictionary of localized strings to source file sets
# that can be used with the strings_to_text function.
def generate_template(folder, mod_name):
dOut = {}
for root, dirs, files in os.walk(folder):
for name in files:
if fnmatch.fnmatch(name, "*.lua"):
fname = os.path.join(root, name)
found = read_lua_file_strings(fname)
if params["verbose"]:
print(f"{fname}: {str(len(found))} translatable strings")
for s in found:
sources = dOut.get(s, set())
sources.add(f"### {os.path.basename(fname)} ###")
dOut[s] = sources
if len(dOut) == 0:
return None
templ_file = os.path.join(folder, "locale/template.txt")
write_template(templ_file, dOut, mod_name)
return dOut
# Updates an existing .tr file, copying the old one to a ".old" file
# if any changes have happened
# dNew is the data used to generate the template, it has all the
# currently-existing localized strings
def update_tr_file(dNew, mod_name, tr_file):
if params["verbose"]:
print(f"updating {tr_file}")
tr_import = import_tr_file(tr_file)
dOld = tr_import[0]
textOld = tr_import[1]
textNew = strings_to_text(dNew, dOld, mod_name)
if textOld and textOld != textNew:
print(f"{tr_file} has changed.")
shutil.copyfile(tr_file, f"{tr_file}.old")
with open(tr_file, "w", encoding='utf-8') as new_tr_file:
new_tr_file.write(textNew)
# Updates translation files for the mod in the given folder
def update_mod(folder):
modname = get_modname(folder)
if modname is not None:
process_po_files(folder, modname)
print(f"Updating translations for {modname}")
data = generate_template(folder, modname)
if data == None:
print(f"No translatable strings found in {modname}")
else:
for tr_file in get_existing_tr_files(folder):
update_tr_file(data, modname, os.path.join(folder, "locale/", tr_file))
else:
print("Unable to find modname in folder " + folder)
# Determines if the folder being pointed to is a mod or a mod pack
# and then runs update_mod accordingly
def update_folder(folder):
is_modpack = os.path.exists(os.path.join(folder, "modpack.txt")) or os.path.exists(os.path.join(folder, "modpack.conf"))
if is_modpack:
subfolders = [f.path for f in os.scandir(folder) if f.is_dir()]
for subfolder in subfolders:
update_mod(subfolder + "/")
else:
update_mod(folder)
print("Done.")
def run_all_subfolders(folder):
for modfolder in [f.path for f in os.scandir(folder) if f.is_dir()]:
update_folder(modfolder + "/")
main()

View File

@ -1,5 +1,18 @@
local modpath = minetest.get_modpath(minetest.get_current_modname())
minetest.register_alias("commoditymarket:kings_market", "commoditymarket_fantasy:kings_market")
minetest.register_alias("commoditymarket:gold_coins", "commoditymarket_fantasy:gold_coins")
minetest.register_alias("commoditymarket:night_market", "commoditymarket_fantasy:night_market")
minetest.register_alias("commoditymarket:goblin_market", "commoditymarket_fantasy:goblin_market")
minetest.register_alias("commoditymarket:under_market", "commoditymarket_fantasy:under_market")
minetest.register_alias("commoditymarket:caravan_post", "commoditymarket_fantasy:caravan_post")
minetest.register_alias("commoditymarket:caravan_market_1", "commoditymarket_fantasy:caravan_market_1")
minetest.register_alias("commoditymarket:caravan_market_2", "commoditymarket_fantasy:caravan_market_2")
minetest.register_alias("commoditymarket:caravan_market_3", "commoditymarket_fantasy:caravan_market_3")
minetest.register_alias("commoditymarket:caravan_market_4", "commoditymarket_fantasy:caravan_market_4")
minetest.register_alias("commoditymarket:caravan_market_5", "commoditymarket_fantasy:caravan_market_5")
minetest.register_alias("commoditymarket:caravan_market_permanent", "commoditymarket_fantasy:caravan_market_permanent")
local S = minetest.get_translator(minetest.get_current_modname())
dofile(modpath.."/mapgen_dungeon_markets.lua")
@ -9,16 +22,16 @@ local coins_per_ingot = math.floor(tonumber(minetest.settings:get("commoditymark
-- Only register gold coins once, if required
local gold_coins_registered = false
local register_gold_coins = function()
if not gold_coins_registered then
minetest.register_craftitem("commoditymarket_fantasy:gold_coins", {
description = S("Gold Coins"),
_doc_items_longdesc = S("A gold ingot is far too valuable to use as a basic unit of value, so it has become common practice to divide the standard gold bar into @1 small disks to make trade easier.", coins_per_ingot),
_doc_items_usagehelp = S("Gold coins can be deposited and withdrawn from markets that accept them as currency. These markets can make change if you have @1 coins and would like them back in ingot form again.", coins_per_ingot),
inventory_image = "commoditymarket_gold_coins.png",
stack_max = coins_per_ingot,
})
gold_coins_registered = true
end
if not gold_coins_registered then
minetest.register_craftitem("commoditymarket_fantasy:gold_coins", {
description = S("Gold Coins"),
_doc_items_longdesc = S("A gold ingot is far too valuable to use as a basic unit of value, so it has become common practice to divide the standard gold bar into @1 small disks to make trade easier.", coins_per_ingot),
_doc_items_usagehelp = S("Gold coins can be deposited and withdrawn from markets that accept them as currency. These markets can make change if you have @1 coins and would like them back in ingot form again.", coins_per_ingot),
inventory_image = "commoditymarket_gold_coins.png",
stack_max = coins_per_ingot,
})
gold_coins_registered = true
end
end
local default_items = {"default:axe_bronze","default:axe_diamond","default:axe_mese","default:axe_steel","default:axe_steel","default:axe_stone","default:axe_wood","default:pick_bronze","default:pick_diamond","default:pick_mese","default:pick_steel","default:pick_stone","default:pick_wood","default:shovel_bronze","default:shovel_diamond","default:shovel_mese","default:shovel_steel","default:shovel_stone","default:shovel_wood","default:sword_bronze","default:sword_diamond","default:sword_mese","default:sword_steel","default:sword_stone","default:sword_wood", "default:blueberries", "default:book", "default:bronze_ingot", "default:clay_brick", "default:clay_lump", "default:coal_lump", "default:copper_ingot", "default:copper_lump", "default:diamond", "default:flint", "default:gold_ingot", "default:gold_lump", "default:iron_lump", "default:mese_crystal", "default:mese_crystal_fragment", "default:obsidian_shard", "default:paper", "default:steel_ingot", "default:stick", "default:tin_ingot", "default:tin_lump", "default:acacia_tree", "default:acacia_wood", "default:apple", "default:aspen_tree", "default:aspen_wood", "default:blueberry_bush_sapling", "default:bookshelf", "default:brick", "default:bronzeblock", "default:bush_sapling", "default:cactus", "default:clay", "default:coalblock", "default:cobble", "default:copperblock", "default:desert_cobble", "default:desert_sand", "default:desert_sandstone", "default:desert_sandstone_block", "default:desert_sandstone_brick", "default:desert_stone", "default:desert_stone_block", "default:desert_stonebrick", "default:diamondblock", "default:dirt", "default:glass", "default:goldblock", "default:gravel", "default:ice", "default:junglegrass", "default:junglesapling", "default:jungletree", "default:junglewood", "default:ladder_steel", "default:ladder_wood", "default:large_cactus_seedling", "default:mese", "default:mese_post_light", "default:meselamp", "default:mossycobble", "default:obsidian", "default:obsidian_block", "default:obsidian_glass", "default:obsidianbrick", "default:papyrus", "default:pine_sapling", "default:pine_tree", "default:pine_wood", "default:sand", "default:sandstone", "default:sandstone_block", "default:sandstonebrick", "default:sapling", "default:silver_sand", "default:silver_sandstone", "default:silver_sandstone_block", "default:silver_sandstone_brick", "default:snow", "default:snowblock", "default:steelblock", "default:stone", "default:stone_block", "default:stonebrick", "default:tinblock", "default:tree", "default:wood",}
@ -31,22 +44,22 @@ local usage_help = S("Right-click on this to open the market interface.")
if minetest.settings:get_bool("commoditymarket_enable_kings_market", true) then
local kings_def = {
description = S("King's Market"),
long_description = S("The largest and most accessible market for the common man, the King's Market uses gold coins as its medium of exchange (or the equivalent in gold ingots - @1 coins to the ingot). However, as a respectable institution of the surface world, the King's Market operates only during the hours of daylight. The purchase and sale of swords and explosives is prohibited in the King's Market. Gold coins are represented by a '☼' symbol.", coins_per_ingot),
currency = {
["default:gold_ingot"] = coins_per_ingot,
["commoditymarket_fantasy:gold_coins"] = 1
},
currency_symbol = "", -- "\u{263C}" Alchemical symbol for gold
allow_item = function(item)
if item:sub(1,13) == "default:sword" or item:sub(1,4) == "tnt:" then
return false
end
return true
end,
inventory_limit = 100000,
--sell_limit =, -- no sell limit for the King's Market
initial_items = default_items,
description = S("King's Market"),
long_description = S("The largest and most accessible market for the common man, the King's Market uses gold coins as its medium of exchange (or the equivalent in gold ingots - @1 coins to the ingot). However, as a respectable institution of the surface world, the King's Market operates only during the hours of daylight. The purchase and sale of swords and explosives is prohibited in the King's Market. Gold coins are represented by a '☼' symbol.", coins_per_ingot),
currency = {
["default:gold_ingot"] = coins_per_ingot,
["commoditymarket_fantasy:gold_coins"] = 1
},
currency_symbol = "", -- "\u{263C}" Alchemical symbol for gold
allow_item = function(item)
if item:sub(1,13) == "default:sword" or item:sub(1,4) == "tnt:" then
return false
end
return true
end,
inventory_limit = 100000,
--sell_limit =, -- no sell limit for the King's Market
initial_items = default_items,
}
register_gold_coins()
@ -56,33 +69,33 @@ commoditymarket.register_market("kings", kings_def)
local kings_protect = minetest.settings:get_bool("commoditymarket_protect_kings_market", true)
local on_blast
if kings_protect then
on_blast = function() end
on_blast = function() end
end
minetest.register_node("commoditymarket_fantasy:kings_market", {
description = kings_def.description,
_doc_items_longdesc = kings_def.long_description,
_doc_items_usagehelp = usage_help,
tiles = {"default_chest_top.png","default_chest_top.png",
"default_chest_side.png","default_chest_side.png",
"commoditymarket_empty_shelf.png","default_chest_side.png^commoditymarket_crown.png",},
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_wood_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local timeofday = minetest.get_timeofday()
if timeofday > 0.2 and timeofday < 0.8 then
commoditymarket.show_market("kings", clicker:get_player_name())
else
minetest.chat_send_player(clicker:get_player_name(), S("At this time of day the King's Market is closed."))
minetest.sound_play({name = "commoditymarket_error", gain = 0.1}, {to_player=clicker:get_player_name()})
end
end,
can_dig = function(pos, player)
return not kings_protect or minetest.check_player_privs(player, "protection_bypass")
end,
on_blast = on_blast,
description = kings_def.description,
_doc_items_longdesc = kings_def.long_description,
_doc_items_usagehelp = usage_help,
tiles = {"default_chest_top.png","default_chest_top.png",
"default_chest_side.png","default_chest_side.png",
"commoditymarket_empty_shelf.png","default_chest_side.png^commoditymarket_crown.png",},
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_wood_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local timeofday = minetest.get_timeofday()
if timeofday > 0.2 and timeofday < 0.8 then
commoditymarket.show_market("kings", clicker:get_player_name())
else
minetest.chat_send_player(clicker:get_player_name(), S("At this time of day the King's Market is closed."))
minetest.sound_play({name = "commoditymarket_error", gain = 0.1}, {to_player=clicker:get_player_name()})
end
end,
can_dig = function(pos, player)
return not kings_protect or minetest.check_player_privs(player, "protection_bypass")
end,
on_blast = on_blast,
})
end
-------------------------------------------------------------------------------
@ -90,17 +103,17 @@ end
if minetest.settings:get_bool("commoditymarket_enable_night_market", true) then
local night_def = {
description = S("Night Market"),
long_description = S("When the sun sets and the stalls of the King's Market close, other vendors are just waking up to share their wares. The Night Market is not as voluminous as the King's Market but accepts a wider range of wares. It accepts the same gold coinage of the realm, @1 coins to the gold ingot.", coins_per_ingot),
currency = {
["default:gold_ingot"] = coins_per_ingot,
["commoditymarket_fantasy:gold_coins"] = 1
},
currency_symbol = "", --"\u{263C}"
inventory_limit = 10000,
--sell_limit =, -- no sell limit for the Night Market
initial_items = default_items,
anonymous = true,
description = S("Night Market"),
long_description = S("When the sun sets and the stalls of the King's Market close, other vendors are just waking up to share their wares. The Night Market is not as voluminous as the King's Market but accepts a wider range of wares. It accepts the same gold coinage of the realm, @1 coins to the gold ingot.", coins_per_ingot),
currency = {
["default:gold_ingot"] = coins_per_ingot,
["commoditymarket_fantasy:gold_coins"] = 1
},
currency_symbol = "", --"\u{263C}"
inventory_limit = 10000,
--sell_limit =, -- no sell limit for the Night Market
initial_items = default_items,
anonymous = true,
}
register_gold_coins()
@ -110,33 +123,33 @@ commoditymarket.register_market("night", night_def)
local night_protect = minetest.settings:get_bool("commoditymarket_protect_night_market", true)
local on_blast
if night_protect then
on_blast = function() end
on_blast = function() end
end
minetest.register_node("commoditymarket_fantasy:night_market", {
description = night_def.description,
_doc_items_longdesc = night_def.long_description,
_doc_items_usagehelp = usage_help,
tiles = {"default_chest_top.png","default_chest_top.png",
"default_chest_side.png","default_chest_side.png",
"commoditymarket_empty_shelf.png","default_chest_side.png^commoditymarket_moon.png",},
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_wood_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local timeofday = minetest.get_timeofday()
if timeofday < 0.2 or timeofday > 0.8 then
commoditymarket.show_market("night", clicker:get_player_name())
else
minetest.chat_send_player(clicker:get_player_name(), S("At this time of day the Night Market is closed."))
minetest.sound_play({name = "commoditymarket_error", gain = 0.1}, {to_player=clicker:get_player_name()})
end
end,
can_dig = function(pos, player)
return not night_protect or minetest.check_player_privs(player, "protection_bypass")
end,
on_blast = on_blast,
description = night_def.description,
_doc_items_longdesc = night_def.long_description,
_doc_items_usagehelp = usage_help,
tiles = {"default_chest_top.png","default_chest_top.png",
"default_chest_side.png","default_chest_side.png",
"commoditymarket_empty_shelf.png","default_chest_side.png^commoditymarket_moon.png",},
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_wood_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local timeofday = minetest.get_timeofday()
if timeofday < 0.2 or timeofday > 0.8 then
commoditymarket.show_market("night", clicker:get_player_name())
else
minetest.chat_send_player(clicker:get_player_name(), S("At this time of day the Night Market is closed."))
minetest.sound_play({name = "commoditymarket_error", gain = 0.1}, {to_player=clicker:get_player_name()})
end
end,
can_dig = function(pos, player)
return not night_protect or minetest.check_player_privs(player, "protection_bypass")
end,
on_blast = on_blast,
})
end
@ -148,300 +161,300 @@ local time_until_caravan = 120 -- caravan arrives in two minutes
local dwell_time = 600 -- caravan leaves ten minutes after last usage
local caravan_def = {
description = S("Trader's Caravan"),
long_description = S("Unlike most markets that have well-known fixed locations that travelers congregate to, the network of Trader's Caravans is fluid and dynamic in their locations. A Trader's Caravan can show up anywhere, make modest trades, and then be gone the next time you visit them. These caravans accept gold and gold coins as a currency (one gold ingot to @1 gold coins exchange rate). Any reasonably-wealthy person can create a signpost marking a location where Trader's Caravans will make a stop.", coins_per_ingot),
currency = {
["default:gold_ingot"] = coins_per_ingot,
["commoditymarket_fantasy:gold_coins"] = 1
},
currency_symbol = "", --"\u{263C}"
inventory_limit = 1000,
sell_limit = 1000,
initial_items = default_items,
description = S("Trader's Caravan"),
long_description = S("Unlike most markets that have well-known fixed locations that travelers congregate to, the network of Trader's Caravans is fluid and dynamic in their locations. A Trader's Caravan can show up anywhere, make modest trades, and then be gone the next time you visit them. These caravans accept gold and gold coins as a currency (one gold ingot to @1 gold coins exchange rate). Any reasonably-wealthy person can create a signpost marking a location where Trader's Caravans will make a stop.", coins_per_ingot),
currency = {
["default:gold_ingot"] = coins_per_ingot,
["commoditymarket_fantasy:gold_coins"] = 1
},
currency_symbol = "", --"\u{263C}"
inventory_limit = 1000,
sell_limit = 1000,
initial_items = default_items,
}
register_gold_coins()
minetest.register_craft({
output = "commoditymarket_fantasy:caravan_post",
recipe = {
{'group:wood', 'group:wood', ''},
{'group:wood', "default:gold_ingot", ''},
{'group:wood', "default:chest_locked", ''},
}
output = "commoditymarket_fantasy:caravan_post",
recipe = {
{'group:wood', 'group:wood', ''},
{'group:wood', "default:gold_ingot", ''},
{'group:wood', "default:chest_locked", ''},
}
})
commoditymarket.register_market("caravan", caravan_def)
local create_caravan_def = function(override_table)
local def = {
description = caravan_def.description,
_doc_items_longdesc = caravan_def.long_description,
_doc_items_usagehelp = usage_help,
drawtype = "mesh",
mesh = "commoditymarket_wagon.obj",
tiles = {
{ name = "commoditymarket_door_wood.png", backface_culling = true }, -- door
{ name = "default_wood.png", backface_culling = true }, -- base wood
{ name = "default_fence_rail_wood.png", backface_culling = true }, -- wheel sides
{ name = "default_coal_block.png", backface_culling = true }, -- wheel tyre
{ name = "commoditymarket_shingles_wood.png", backface_culling = true }, -- roof
{ name = "default_junglewood.png", backface_culling = true }, -- corner wood
},
collision_box = {
type = "fixed",
fixed = {
-- Note: this nodebox should have a height of 1.5, but using 95/64 as a workaround for
-- https://github.com/minetest/minetest/issues/9322
{-0.75, -0.5, -1.25, 0.75, 95/64, 1.25},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.75, -0.5, -1.25, 0.75, 95/64, 1.25},
},
},
description = caravan_def.description,
_doc_items_longdesc = caravan_def.long_description,
_doc_items_usagehelp = usage_help,
drawtype = "mesh",
mesh = "commoditymarket_wagon.obj",
tiles = {
{ name = "commoditymarket_door_wood.png", backface_culling = true }, -- door
{ name = "default_wood.png", backface_culling = true }, -- base wood
{ name = "default_fence_rail_wood.png", backface_culling = true }, -- wheel sides
{ name = "default_coal_block.png", backface_culling = true }, -- wheel tyre
{ name = "commoditymarket_shingles_wood.png", backface_culling = true }, -- roof
{ name = "default_junglewood.png", backface_culling = true }, -- corner wood
},
collision_box = {
type = "fixed",
fixed = {
-- Note: this nodebox should have a height of 1.5, but using 95/64 as a workaround for
-- https://github.com/minetest/minetest/issues/9322
{-0.75, -0.5, -1.25, 0.75, 95/64, 1.25},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.75, -0.5, -1.25, 0.75, 95/64, 1.25},
},
},
paramtype2 = "facedir",
drop = "",
groups = {choppy = 2, oddly_breakable_by_hand = 1, not_in_creative_inventory = 1},
sounds = default.node_sound_wood_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
commoditymarket.show_market("caravan", clicker:get_player_name())
local timer = minetest.get_node_timer(pos)
timer:start(dwell_time)
end,
after_destruct = function(pos, oldnode)
local facedir = oldnode.param2
local dir = minetest.facedir_to_dir(facedir)
local target = vector.add(pos, vector.multiply(dir,-3))
local target_node = minetest.get_node(target)
if target_node.name == "commoditymarket_fantasy:caravan_post" then
local meta = minetest.get_meta(target)
meta:set_string("infotext", S("Right-click to summon a trader's caravan"))
end
end,
on_timer = function(pos, elapsed)
minetest.set_node(pos, {name="air"})
minetest.sound_play("commoditymarket_register_closed", {
pos = pos,
gain = 1.0, -- default
max_hear_distance = 32, -- default, uses an euclidean metric
})
end,
}
if override_table then
for k, v in pairs(override_table) do
def[k] = v
end
end
return def
paramtype2 = "facedir",
drop = "",
groups = {choppy = 2, oddly_breakable_by_hand = 1, not_in_creative_inventory = 1},
sounds = default.node_sound_wood_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
commoditymarket.show_market("caravan", clicker:get_player_name())
local timer = minetest.get_node_timer(pos)
timer:start(dwell_time)
end,
after_destruct = function(pos, oldnode)
local facedir = oldnode.param2
local dir = minetest.facedir_to_dir(facedir)
local target = vector.add(pos, vector.multiply(dir,-3))
local target_node = minetest.get_node(target)
if target_node.name == "commoditymarket_fantasy:caravan_post" then
local meta = minetest.get_meta(target)
meta:set_string("infotext", S("Right-click to summon a trader's caravan"))
end
end,
on_timer = function(pos, elapsed)
minetest.set_node(pos, {name="air"})
minetest.sound_play("commoditymarket_register_closed", {
pos = pos,
gain = 1.0, -- default
max_hear_distance = 32, -- default, uses an euclidean metric
})
end,
}
if override_table then
for k, v in pairs(override_table) do
def[k] = v
end
end
return def
end
-- Create five caravans with different textures, randomly pick which one shows up.
minetest.register_node("commoditymarket_fantasy:caravan_market_1", create_caravan_def())
minetest.register_node("commoditymarket_fantasy:caravan_market_2", create_caravan_def({
tiles = {
{ name = "commoditymarket_door_wood.png^[multiply:#CCCCFF", backface_culling = true }, -- door
{ name = "default_acacia_wood.png", backface_culling = true }, -- base wood
{ name = "default_fence_rail_wood.png", backface_culling = true }, -- wheel sides
{ name = "default_copper_block.png", backface_culling = true }, -- wheel tyre
{ name = "commoditymarket_shingles_wood.png^[multiply:#CC8888", backface_culling = true }, -- roof
{ name = "default_wood.png", backface_culling = true }, -- corner wood
{ name = "commoditymarket_door_wood.png^[multiply:#CCCCFF", backface_culling = true }, -- door
{ name = "default_acacia_wood.png", backface_culling = true }, -- base wood
{ name = "default_fence_rail_wood.png", backface_culling = true }, -- wheel sides
{ name = "default_copper_block.png", backface_culling = true }, -- wheel tyre
{ name = "commoditymarket_shingles_wood.png^[multiply:#CC8888", backface_culling = true }, -- roof
{ name = "default_wood.png", backface_culling = true }, -- corner wood
}
}))
minetest.register_node("commoditymarket_fantasy:caravan_market_3", create_caravan_def({
tiles = {
{ name = "commoditymarket_door_wood.png", backface_culling = true }, -- door
{ name = "default_aspen_wood.png", backface_culling = true }, -- base wood
{ name = "default_fence_aspen_wood.png", backface_culling = true }, -- wheel sides
{ name = "default_cobble.png", backface_culling = true }, -- wheel tyre
{ name = "default_stone_brick.png", backface_culling = true }, -- roof
{ name = "default_pine_tree.png", backface_culling = true }, -- corner wood
{ name = "commoditymarket_door_wood.png", backface_culling = true }, -- door
{ name = "default_aspen_wood.png", backface_culling = true }, -- base wood
{ name = "default_fence_aspen_wood.png", backface_culling = true }, -- wheel sides
{ name = "default_cobble.png", backface_culling = true }, -- wheel tyre
{ name = "default_stone_brick.png", backface_culling = true }, -- roof
{ name = "default_pine_tree.png", backface_culling = true }, -- corner wood
}
}))
minetest.register_node("commoditymarket_fantasy:caravan_market_4", create_caravan_def({
tiles = {
{ name = "commoditymarket_door_wood.png", backface_culling = true }, -- door
{ name = "default_junglewood.png", backface_culling = true }, -- base wood
{ name = "default_fence_rail_junglewood.png", backface_culling = true }, -- wheel sides
{ name = "default_obsidian.png", backface_culling = true }, -- wheel tyre
{ name = "commoditymarket_shingles_wood.png^[multiply:#88FF88", backface_culling = true }, -- roof
{ name = "default_tree.png", backface_culling = true }, -- corner wood
{ name = "commoditymarket_door_wood.png", backface_culling = true }, -- door
{ name = "default_junglewood.png", backface_culling = true }, -- base wood
{ name = "default_fence_rail_junglewood.png", backface_culling = true }, -- wheel sides
{ name = "default_obsidian.png", backface_culling = true }, -- wheel tyre
{ name = "commoditymarket_shingles_wood.png^[multiply:#88FF88", backface_culling = true }, -- roof
{ name = "default_tree.png", backface_culling = true }, -- corner wood
}
}))
minetest.register_node("commoditymarket_fantasy:caravan_market_5", create_caravan_def({
tiles = {
{ name = "commoditymarket_door_wood.png", backface_culling = true }, -- door
{ name = "default_pine_wood.png", backface_culling = true }, -- base wood
{ name = "default_chest_lock.png", backface_culling = true }, -- wheel sides
{ name = "default_chest_top.png", backface_culling = true }, -- wheel tyre
{ name = "default_furnace_top.png", backface_culling = true }, -- roof
{ name = "default_wood.png", backface_culling = true }, -- corner wood
{ name = "commoditymarket_door_wood.png", backface_culling = true }, -- door
{ name = "default_pine_wood.png", backface_culling = true }, -- base wood
{ name = "default_chest_lock.png", backface_culling = true }, -- wheel sides
{ name = "default_chest_top.png", backface_culling = true }, -- wheel tyre
{ name = "default_furnace_top.png", backface_culling = true }, -- roof
{ name = "default_wood.png", backface_culling = true }, -- corner wood
}
}))
local caravan_protect = minetest.settings:get_bool("commoditymarket_protect_caravan_market", true)
local on_blast
if caravan_protect then
on_blast = function() end
on_blast = function() end
end
-- This one doesn't delete itself, server admins can place a permanent instance of it that way. Maybe inside towns next to bigger stationary markets.
minetest.register_node("commoditymarket_fantasy:caravan_market_permanent", {
description = caravan_def.description,
_doc_items_longdesc = caravan_def.long_description,
_doc_items_usagehelp = usage_help,
drawtype = "mesh",
mesh = "commoditymarket_wagon.obj",
light_source = 7,
tiles = {
{ name = "commoditymarket_door_wood.png", backface_culling = true }, -- door
{ name = "default_wood.png", backface_culling = true }, -- base wood
{ name = "default_fence_rail_wood.png", backface_culling = true }, -- wheel sides
{ name = "default_coal_block.png", backface_culling = true }, -- wheel tyre
{ name = "commoditymarket_shingles_wood.png", backface_culling = true }, -- roof
{ name = "default_junglewood.png", backface_culling = true }, -- corner wood
},
description = caravan_def.description,
_doc_items_longdesc = caravan_def.long_description,
_doc_items_usagehelp = usage_help,
drawtype = "mesh",
light_source = 10,
mesh = "commoditymarket_wagon.obj",
tiles = {
{ name = "commoditymarket_door_wood.png", backface_culling = true }, -- door
{ name = "default_wood.png", backface_culling = true }, -- base wood
{ name = "default_fence_rail_wood.png", backface_culling = true }, -- wheel sides
{ name = "default_coal_block.png", backface_culling = true }, -- wheel tyre
{ name = "commoditymarket_shingles_wood.png", backface_culling = true }, -- roof
{ name = "default_junglewood.png", backface_culling = true }, -- corner wood
},
collision_box = {
type = "fixed",
type = "fixed",
fixed = {
-- Note: this nodebox should have a height of 1.5, but using 95/64 as a workaround for
-- https://github.com/minetest/minetest/issues/9322
-- Note: this nodebox should have a height of 1.5, but using 95/64 as a workaround for
-- https://github.com/minetest/minetest/issues/9322
{-0.75, -0.5, -1.25, 0.75, 95/64, 1.25},
},
},
selection_box = {
type = "fixed",
selection_box = {
type = "fixed",
fixed = {
{-0.75, -0.5, -1.25, 0.75, 95/64, 1.25},
},
},
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_wood_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
commoditymarket.show_market("caravan", clicker:get_player_name())
end,
can_dig = function(pos, player)
return not caravan_protect or minetest.check_player_privs(player, "protection_bypass")
end,
on_blast = on_blast,
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_wood_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
commoditymarket.show_market("caravan", clicker:get_player_name())
end,
can_dig = function(pos, player)
return not caravan_protect or minetest.check_player_privs(player, "protection_bypass")
end,
on_blast = on_blast,
})
-- is a 5x3 area centered around pos clear of obstruction and has usable ground?
local is_suitable_caravan_space = function(pos, facedir)
local x_dim = 2
local z_dim = 2
local dir = minetest.facedir_to_dir(facedir)
if dir.x ~= 0 then
z_dim = 1
elseif dir.z ~= 0 then
x_dim = 1
end
local x_dim = 2
local z_dim = 2
local dir = minetest.facedir_to_dir(facedir)
if dir.x ~= 0 then
z_dim = 1
elseif dir.z ~= 0 then
x_dim = 1
end
-- walkable ground?
for x = pos.x - x_dim, pos.x + x_dim, 1 do
for z = pos.z - z_dim, pos.z + z_dim, 1 do
local node = minetest.get_node({x=x, y=pos.y-1, z=z})
local node_def = minetest.registered_nodes[node.name]
if node_def == nil or node_def.walkable ~= true then return false end
end
end
-- buildable_to in the rest?
for y = pos.y, pos.y+2, 1 do
for x = pos.x - x_dim, pos.x + x_dim, 1 do
for z = pos.z - z_dim, pos.z + z_dim, 1 do
local node = minetest.get_node({x=x, y=y, z=z})
local node_def = minetest.registered_nodes[node.name]
if node_def == nil or node_def.buildable_to ~= true then return false end
end
end
end
return true
-- walkable ground?
for x = pos.x - x_dim, pos.x + x_dim, 1 do
for z = pos.z - z_dim, pos.z + z_dim, 1 do
local node = minetest.get_node({x=x, y=pos.y-1, z=z})
local node_def = minetest.registered_nodes[node.name]
if node_def == nil or node_def.walkable ~= true then return false end
end
end
-- buildable_to in the rest?
for y = pos.y, pos.y+2, 1 do
for x = pos.x - x_dim, pos.x + x_dim, 1 do
for z = pos.z - z_dim, pos.z + z_dim, 1 do
local node = minetest.get_node({x=x, y=y, z=z})
local node_def = minetest.registered_nodes[node.name]
if node_def == nil or node_def.buildable_to ~= true then return false end
end
end
end
return true
end
minetest.register_node("commoditymarket_fantasy:caravan_post", {
description = S("Trading Post"),
_long_items_longdesc = S("This post signals passing caravan traders that customers can be found here, and signals to customers that caravan traders can be found here. If no caravan is present, right-click to summon one."),
_doc_items_usagehelp = S("The trader's caravan requires a suitable open space next to the trading post for it to arrive, and takes some time to arrive after being summoned. The post gives a countdown to the caravan's arrival when moused over."),
tiles = {"commoditymarket_sign.png^[transformR90", "commoditymarket_sign.png^[transformR270",
"commoditymarket_sign.png^commoditymarket_caravan_sign.png", "commoditymarket_sign.png^commoditymarket_caravan_sign.png^[transformFX",
"commoditymarket_sign_post.png", "commoditymarket_sign_post.png"},
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_wood_defaults(),
inventory_image = "commoditymarket_caravan_sign_inventory.png",
paramtype= "light",
paramtype2 = "facedir",
drawtype = "nodebox",
node_box = {
description = S("Trading Post"),
_long_items_longdesc = S("This post signals passing caravan traders that customers can be found here, and signals to customers that caravan traders can be found here. If no caravan is present, right-click to summon one."),
_doc_items_usagehelp = S("The trader's caravan requires a suitable open space next to the trading post for it to arrive, and takes some time to arrive after being summoned. The post gives a countdown to the caravan's arrival when moused over."),
tiles = {"commoditymarket_sign.png^[transformR90", "commoditymarket_sign.png^[transformR270",
"commoditymarket_sign.png^commoditymarket_caravan_sign.png", "commoditymarket_sign.png^commoditymarket_caravan_sign.png^[transformFX",
"commoditymarket_sign_post.png", "commoditymarket_sign_post.png"},
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_wood_defaults(),
inventory_image = "commoditymarket_caravan_sign_inventory.png",
paramtype= "light",
paramtype2 = "facedir",
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.125,-0.5,-0.5,0.125,2.0625,-0.25},
{-0.0625,1.4375,-0.25,0.0625,2.0,0.5},
},
{-0.125,-0.5,-0.5,0.125,2.0625,-0.25},
{-0.0625,1.4375,-0.25,0.0625,2.0,0.5},
},
},
on_construct = function(pos)
local timer = minetest.get_node_timer(pos)
timer:start(1.0)
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local timer = minetest.get_node_timer(pos)
timer:start(1.0)
end,
on_timer = function(pos, elapsed)
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
if node.name ~= "commoditymarket_fantasy:caravan_post" then
return -- the node was removed
end
local facedir = node.param2
local dir = minetest.facedir_to_dir(facedir)
local target = vector.add(pos, vector.multiply(dir,3))
on_construct = function(pos)
local timer = minetest.get_node_timer(pos)
timer:start(1.0)
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local timer = minetest.get_node_timer(pos)
timer:start(1.0)
end,
on_timer = function(pos, elapsed)
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
if node.name ~= "commoditymarket_fantasy:caravan_post" then
return -- the node was removed
end
local facedir = node.param2
local dir = minetest.facedir_to_dir(facedir)
local target = vector.add(pos, vector.multiply(dir,3))
local target_node = minetest.get_node(target)
local target_node = minetest.get_node(target)
if target_node.name:sub(1,string.len("commoditymarket_fantasy:caravan_market")) == "commoditymarket_fantasy:caravan_market" then
-- It's already here somehow, shut down timer.
meta:set_string("infotext", "")
meta:set_float("wait_time", 0)
return
end
if target_node.name:sub(1,string.len("commoditymarket_fantasy:caravan_market")) == "commoditymarket_fantasy:caravan_market" then
-- It's already here somehow, shut down timer.
meta:set_string("infotext", "")
meta:set_float("wait_time", 0)
return
end
local is_suitable_space = is_suitable_caravan_space(target, facedir)
local is_suitable_space = is_suitable_caravan_space(target, facedir)
if not is_suitable_space then
meta:set_string("infotext", S("Indicated parking area isn't suitable.\nA 5x3 open space with solid ground\nis required for a caravan."))
meta:set_float("wait_time", 0)
local timer = minetest.get_node_timer(pos)
timer:start(1.0)
return
end
if not is_suitable_space then
meta:set_string("infotext", S("Indicated parking area isn't suitable.\nA 5x3 open space with solid ground\nis required for a caravan."))
meta:set_float("wait_time", 0)
local timer = minetest.get_node_timer(pos)
timer:start(1.0)
return
end
local wait_time = (meta:get_float("wait_time") or 0) + elapsed
meta:set_float("wait_time", wait_time)
if wait_time < time_until_caravan then
meta:set_string("infotext", S("Caravan summoned\nETA: @1 seconds.", math.floor(time_until_caravan - wait_time)))
local timer = minetest.get_node_timer(pos)
timer:start(1.0)
return
end
local wait_time = (meta:get_float("wait_time") or 0) + elapsed
meta:set_float("wait_time", wait_time)
if wait_time < time_until_caravan then
meta:set_string("infotext", S("Caravan summoned\nETA: @1 seconds.", math.floor(time_until_caravan - wait_time)))
local timer = minetest.get_node_timer(pos)
timer:start(1.0)
return
end
-- spawn the caravan. We've already established that the target pos is clear.
minetest.set_node(target, {name="commoditymarket_fantasy:caravan_market_"..math.random(1,5), param2=facedir})
minetest.sound_play("commoditymarket_register_opened", {
pos = target,
gain = 1.0, -- default
max_hear_distance = 32, -- default, uses an euclidean metric
})
local timer = minetest.get_node_timer(target)
timer:start(dwell_time)
meta:set_string("infotext", "")
meta:set_float("wait_time", 0)
end,
-- spawn the caravan. We've already established that the target pos is clear.
minetest.set_node(target, {name="commoditymarket_fantasy:caravan_market_"..math.random(1,5), param2=facedir})
minetest.sound_play("commoditymarket_register_opened", {
pos = target,
gain = 1.0, -- default
max_hear_distance = 32, -- default, uses an euclidean metric
})
local timer = minetest.get_node_timer(target)
timer:start(dwell_time)
meta:set_string("infotext", "")
meta:set_float("wait_time", 0)
end,
})
end
@ -450,14 +463,14 @@ end
if minetest.settings:get_bool("commoditymarket_enable_goblin_market", true) then
local goblin_def = {
description = S("Goblin Exchange"),
long_description = S("One does not usually associate Goblins with the sort of sophistication that running a market requires. Usually one just associates Goblins with savagery and violence. But they understand the principle of tit-for-tat exchange, and if approached correctly they actually respect the concepts of ownership and debt. However, for some peculiar reason they understand this concept in the context of coal lumps. Goblins deal in the standard coal lump as their form of currency, conceptually divided into 100 coal centilumps (though Goblin brokers prefer to \"keep the change\" when giving back actual coal lumps)."),
currency = {
["default:coal_lump"] = 100
},
currency_symbol = "¢", --"\u{00A2}" cent symbol
inventory_limit = 1000,
--sell_limit =, -- no sell limit
description = S("Goblin Exchange"),
long_description = S("One does not usually associate Goblins with the sort of sophistication that running a market requires. Usually one just associates Goblins with savagery and violence. But they understand the principle of tit-for-tat exchange, and if approached correctly they actually respect the concepts of ownership and debt. However, for some peculiar reason they understand this concept in the context of coal lumps. Goblins deal in the standard coal lump as their form of currency, conceptually divided into 100 coal centilumps (though Goblin brokers prefer to \"keep the change\" when giving back actual coal lumps)."),
currency = {
["default:coal_lump"] = 100
},
currency_symbol = "¢", --"\u{00A2}" cent symbol
inventory_limit = 1000,
--sell_limit =, -- no sell limit
}
commoditymarket.register_market("goblin", goblin_def)
@ -465,43 +478,43 @@ commoditymarket.register_market("goblin", goblin_def)
local goblin_protect = minetest.settings:get_bool("commoditymarket_protect_goblin_market", true)
local on_blast
if goblin_protect then
on_blast = function() end
on_blast = function() end
end
minetest.register_node("commoditymarket_fantasy:goblin_market", {
description = goblin_def.description,
_doc_items_longdesc = goblin_def.long_description,
_doc_items_usagehelp = usage_help,
tiles = {"default_chest_top.png^(default_coal_block.png^[opacity:128)","default_chest_top.png^(default_coal_block.png^[opacity:128)",
"default_chest_side.png^(default_coal_block.png^[opacity:128)","default_chest_side.png^(default_coal_block.png^[opacity:128)",
"commoditymarket_empty_shelf.png^(default_coal_block.png^[opacity:128)","default_chest_side.png^(default_coal_block.png^[opacity:128)^commoditymarket_goblin.png",},
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_wood_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
commoditymarket.show_market("goblin", clicker:get_player_name())
end,
can_dig = function(pos, player)
return not goblin_protect or minetest.check_player_privs(player, "protection_bypass")
end,
on_blast = on_blast,
description = goblin_def.description,
_doc_items_longdesc = goblin_def.long_description,
_doc_items_usagehelp = usage_help,
tiles = {"default_chest_top.png^(default_coal_block.png^[opacity:128)","default_chest_top.png^(default_coal_block.png^[opacity:128)",
"default_chest_side.png^(default_coal_block.png^[opacity:128)","default_chest_side.png^(default_coal_block.png^[opacity:128)",
"commoditymarket_empty_shelf.png^(default_coal_block.png^[opacity:128)","default_chest_side.png^(default_coal_block.png^[opacity:128)^commoditymarket_goblin.png",},
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_wood_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
commoditymarket.show_market("goblin", clicker:get_player_name())
end,
can_dig = function(pos, player)
return not goblin_protect or minetest.check_player_privs(player, "protection_bypass")
end,
on_blast = on_blast,
})
end
--------------------------------------------------------------------------------
if minetest.settings:get_bool("commoditymarket_enable_under_market", true) then
local undermarket_def = {
description = S("Undermarket"),
long_description = S("Deep in the bowels of the world, below even the goblin-infested warrens and ancient delvings of the dwarves, dark and mysterious beings once dwelt. A few still linger to this day, and facilitate barter for those brave souls willing to travel in their lost realms. The Undermarket uses Mese chips ('₥') as a currency - twenty chips to the Mese fragment. Though traders are loathe to physically break Mese crystals up into units that small, as it renders it useless for other purposes."),
currency = {
["default:mese"] = 9*9*20,
["default:mese_crystal"] = 9*20,
["default:mese_crystal_fragment"] = 20
},
currency_symbol = "", --"\u{20A5}" mill sign
inventory_limit = 10000,
--sell_limit =, -- no sell limit
description = S("Undermarket"),
long_description = S("Deep in the bowels of the world, below even the goblin-infested warrens and ancient delvings of the dwarves, dark and mysterious beings once dwelt. A few still linger to this day, and facilitate barter for those brave souls willing to travel in their lost realms. The Undermarket uses Mese chips ('₥') as a currency - twenty chips to the Mese fragment. Though traders are loathe to physically break Mese crystals up into units that small, as it renders it useless for other purposes."),
currency = {
["default:mese"] = 9*9*20,
["default:mese_crystal"] = 9*20,
["default:mese_crystal_fragment"] = 20
},
currency_symbol = "", --"\u{20A5}" mill sign
inventory_limit = 10000,
--sell_limit =, -- no sell limit
}
commoditymarket.register_market("under", undermarket_def)
@ -509,26 +522,26 @@ commoditymarket.register_market("under", undermarket_def)
local under_protect = minetest.settings:get_bool("commoditymarket_protect_under_market", true)
local on_blast
if under_protect then
on_blast = function() end
on_blast = function() end
end
minetest.register_node("commoditymarket_fantasy:under_market", {
description = undermarket_def.description,
_doc_items_longdesc = undermarket_def.long_description,
_doc_items_usagehelp = usage_help,
tiles = {"commoditymarket_under_top.png","commoditymarket_under_top.png",
"commoditymarket_under.png","commoditymarket_under.png","commoditymarket_under.png","commoditymarket_under.png"},
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_stone_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
commoditymarket.show_market("under", clicker:get_player_name())
end,
can_dig = function(pos, player)
return not under_protect or minetest.check_player_privs(player, "protection_bypass")
end,
on_blast = on_blast,
description = undermarket_def.description,
_doc_items_longdesc = undermarket_def.long_description,
_doc_items_usagehelp = usage_help,
tiles = {"commoditymarket_under_top.png","commoditymarket_under_top.png",
"commoditymarket_under.png","commoditymarket_under.png","commoditymarket_under.png","commoditymarket_under.png"},
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 1,},
sounds = default.node_sound_stone_defaults(),
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
commoditymarket.show_market("under", clicker:get_player_name())
end,
can_dig = function(pos, player)
return not under_protect or minetest.check_player_privs(player, "protection_bypass")
end,
on_blast = on_blast,
})
end
------------------------------------------------------------------

View File

@ -1,45 +0,0 @@
-- Fallback functions for when `intllib` is not installed.
-- Code released under Unlicense <http://unlicense.org>.
-- Get the latest version of this file at:
-- https://raw.githubusercontent.com/minetest-mods/intllib/master/lib/intllib.lua
local function format(str, ...)
local args = { ... }
local function repl(escape, open, num, close)
if escape == "" then
local replacement = tostring(args[tonumber(num)])
if open == "" then
replacement = replacement..close
end
return replacement
else
return "@"..open..num..close
end
end
return (str:gsub("(@?)@(%(?)(%d+)(%)?)", repl))
end
local gettext, ngettext
if minetest.get_modpath("intllib") then
if intllib.make_gettext_pair then
-- New method using gettext.
gettext, ngettext = intllib.make_gettext_pair()
else
-- Old method using text files.
gettext = intllib.Getter()
end
end
-- Fill in missing functions.
gettext = gettext or function(msgid, ...)
return format(msgid, ...)
end
ngettext = ngettext or function(msgid, msgid_plural, n, ...)
return format(n==1 and msgid or msgid_plural, ...)
end
return gettext, ngettext

View File

@ -1,155 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-02-13 22:14-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: commoditymarket_fantasy\init.lua:28
msgid "Gold Coins"
msgstr ""
#: commoditymarket_fantasy\init.lua:29
msgid ""
"A gold ingot is far too valuable to use as a basic unit of value, so it has "
"become common practice to divide the standard gold bar into @1 small disks "
"to make trade easier."
msgstr ""
#: commoditymarket_fantasy\init.lua:30
msgid ""
"Gold coins can be deposited and withdrawn from markets that accept them as "
"currency. These markets can make change if you have @1 coins and would like "
"them back in ingot form again."
msgstr ""
#: commoditymarket_fantasy\init.lua:40
msgid "Right-click on this to open the market interface."
msgstr ""
#: commoditymarket_fantasy\init.lua:48
msgid "King's Market"
msgstr ""
#: commoditymarket_fantasy\init.lua:49
msgid ""
"The largest and most accessible market for the common man, the King's Market "
"uses gold coins as its medium of exchange (or the equivalent in gold ingots "
"- @1 coins to the ingot). However, as a respectable institution of the "
"surface world, the King's Market operates only during the hours of daylight. "
"The purchase and sale of swords and explosives is prohibited in the King's "
"Market. Gold coins are represented by a '☼' symbol."
msgstr ""
#: commoditymarket_fantasy\init.lua:92
msgid "At this time of day the King's Market is closed."
msgstr ""
#: commoditymarket_fantasy\init.lua:107
msgid "Night Market"
msgstr ""
#: commoditymarket_fantasy\init.lua:108
msgid ""
"When the sun sets and the stalls of the King's Market close, other vendors "
"are just waking up to share their wares. The Night Market is not as "
"voluminous as the King's Market but accepts a wider range of wares. It "
"accepts the same gold coinage of the realm, @1 coins to the gold ingot."
msgstr ""
#: commoditymarket_fantasy\init.lua:146
msgid "At this time of day the Night Market is closed."
msgstr ""
#: commoditymarket_fantasy\init.lua:165
msgid "Trader's Caravan"
msgstr ""
#: commoditymarket_fantasy\init.lua:166
msgid ""
"Unlike most markets that have well-known fixed locations that travelers "
"congregate to, the network of Trader's Caravans is fluid and dynamic in "
"their locations. A Trader's Caravan can show up anywhere, make modest "
"trades, and then be gone the next time you visit them. These caravans accept "
"gold and gold coins as a currency (one gold ingot to @1 gold coins exchange "
"rate). Any reasonably-wealthy person can create a signpost marking a "
"location where Trader's Caravans will make a stop."
msgstr ""
#: commoditymarket_fantasy\init.lua:236
msgid "Right-click to summon a trader's caravan"
msgstr ""
#: commoditymarket_fantasy\init.lua:379
msgid "Trading Post"
msgstr ""
#: commoditymarket_fantasy\init.lua:380
msgid ""
"This post signals passing caravan traders that customers can be found here, "
"and signals to customers that caravan traders can be found here. If no "
"caravan is present, right-click to summon one."
msgstr ""
#: commoditymarket_fantasy\init.lua:381
msgid ""
"The trader's caravan requires a suitable open space next to the trading post "
"for it to arrive, and takes some time to arrive after being summoned. The "
"post gives a countdown to the caravan's arrival when moused over."
msgstr ""
#: commoditymarket_fantasy\init.lua:428
msgid ""
"Indicated parking area isn't suitable.\n"
"A 5x3 open space with solid ground\n"
"is required for a caravan."
msgstr ""
#: commoditymarket_fantasy\init.lua:438
msgid ""
"Caravan summoned\n"
"ETA: @1 seconds."
msgstr ""
#: commoditymarket_fantasy\init.lua:464
msgid "Goblin Exchange"
msgstr ""
#: commoditymarket_fantasy\init.lua:465
msgid ""
"One does not usually associate Goblins with the sort of sophistication that "
"running a market requires. Usually one just associates Goblins with savagery "
"and violence. But they understand the principle of tit-for-tat exchange, and "
"if approached correctly they actually respect the concepts of ownership and "
"debt. However, for some peculiar reason they understand this concept in the "
"context of coal lumps. Goblins deal in the standard coal lump as their form "
"of currency, conceptually divided into 100 coal centilumps (though Goblin "
"brokers prefer to \"keep the change\" when giving back actual coal lumps)."
msgstr ""
#: commoditymarket_fantasy\init.lua:506
msgid "Undermarket"
msgstr ""
#: commoditymarket_fantasy\init.lua:507
msgid ""
"Deep in the bowels of the world, below even the goblin-infested warrens and "
"ancient delvings of the dwarves, dark and mysterious beings once dwelled. A "
"few still linger to this day, and facilitate barter for those brave souls "
"willing to travel in their lost realms. The Undermarket uses Mese chips "
"('₥') as a currency - twenty chips to the Mese fragment. Though traders are "
"loathe to physically break Mese crystals up into units that small, as it "
"renders it useless for other purposes."
msgstr ""

View File

@ -1,6 +0,0 @@
@echo off
setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
cd ..
set LIST=
for /r %%X in (*.lua) do set LIST=!LIST! %%X
..\intllib\tools\xgettext.bat %LIST%

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -5,191 +5,183 @@ local S = mobs.intllib
-- Cow by Krupnovpavel (additional texture by JurajVajda)
mobs:register_mob("mobs_animal:cow", {
type = "animal",
passive = false,
attack_type = "dogfight",
attack_npcs = false,
reach = 2,
damage = 4,
hp_min = 5,
hp_max = 20,
armor = 200,
collisionbox = {-0.4, -0.01, -0.4, 0.4, 1.2, 0.4},
visual = "mesh",
mesh = "mobs_cow.x",
textures = {
{"mobs_cow.png"},
{"mobs_cow2.png"},
},
makes_footstep_sound = true,
sounds = {
random = "mobs_cow",
},
walk_velocity = 1,
run_velocity = 2,
jump = true,
jump_height = 6,
pushable = true,
drops = {
{name = "mobs:meat_raw", chance = 1, min = 1, max = 3},
{name = "mobs:leather", chance = 1, min = 1, max = 2},
type = "animal",
passive = false,
attack_type = "dogfight",
attack_npcs = false,
reach = 2,
damage = 4,
hp_min = 5,
hp_max = 20,
armor = 200,
collisionbox = {-0.4, -0.01, -0.4, 0.4, 1.2, 0.4},
visual = "mesh",
mesh = "mobs_cow.x",
textures = {
{"mobs_cow.png"},
{"mobs_cow2.png"},
},
makes_footstep_sound = true,
sounds = {
random = "mobs_cow",
},
walk_velocity = 1,
run_velocity = 2,
jump = true,
jump_height = 6,
pushable = true,
drops = {
{name = "mobs:meat_raw", chance = 1, min = 1, max = 3},
{name = "mobs:leather", chance = 1, min = 1, max = 2},
{name = 'bonemeal:bone', chance = 2, min = 1, max = 10},
},
water_damage = 1,
lava_damage = 5,
light_damage = 0,
animation = {
speed_normal = 15,
speed_run = 15,
stand_start = 0,
stand_end = 30,
walk_start = 35,
walk_end = 65,
run_start = 105,
run_end = 135,
punch_start = 70,
punch_end = 100,
},
follow = "farming:wheat",
view_range = 8,
replace_rate = 10,
replace_what = {"default:grass_3", "default:grass_4", "default:grass_5", "group:grain"},
replace_with = "air",
fear_height = 2,
on_rightclick = function(self, clicker)
},
water_damage = 1,
lava_damage = 5,
light_damage = 0,
animation = {
speed_normal = 15,
speed_run = 15,
stand_start = 0,
stand_end = 30,
walk_start = 35,
walk_end = 65,
run_start = 105,
run_end = 135,
punch_start = 70,
punch_end = 100,
},
follow = "farming:wheat",
view_range = 8,
replace_rate = 10,
replace_what = {"default:grass_3", "default:grass_4", "default:grass_5", "group:grain"},
replace_with = "air",
fear_height = 2,
on_rightclick = function(self, clicker)
if mobs:feed_tame(self, clicker, 8, true, true) then return end
if mobs:protect(self, clicker) then return end
if mobs:capture_mob(self, clicker, 0, 5, 60, false, nil) then return end
local tool = clicker:get_wielded_item()
local name = clicker:get_player_name()
-- feed or tame
if mobs:feed_tame(self, clicker, 8, true, true) then return end
if mobs:protect(self, clicker) then return end
if mobs:capture_mob(self, clicker, 0, 5, 60, false, nil) then return end
local tool = clicker:get_wielded_item()
local name = clicker:get_player_name()
-- milk cow with empty bucket
if tool:get_name() == "bucket:bucket_empty" then
--if self.gotten == true
if self.child == true then
return
end
if self.gotten == true then
minetest.chat_send_player(name,
S("Cow already milked!"))
return
end
local inv = clicker:get_inventory()
tool:take_item()
clicker:set_wielded_item(tool)
if inv:room_for_item("main", {name = "mobs:bucket_milk"}) then
clicker:get_inventory():add_item("main", "mobs:bucket_milk")
else
local pos = self.object:get_pos()
pos.y = pos.y + 0.5
minetest.add_item(pos, {name = "mobs:bucket_milk"})
end
self.gotten = true -- milked
return
end
end,
if tool:get_name() == "bucket:bucket_empty" then
if self.child == true then
return
end
if self.gotten == true then
minetest.chat_send_player(name,
S("Cow already milked!"))
return
end
local inv = clicker:get_inventory()
tool:take_item()
clicker:set_wielded_item(tool)
if inv:room_for_item("main", {name = "mobs:bucket_milk"}) then
clicker:get_inventory():add_item("main", "mobs:bucket_milk")
else
local pos = self.object:get_pos()
pos.y = pos.y + 0.5
minetest.add_item(pos, {name = "mobs:bucket_milk"})
end
self.gotten = true -- milked
return
end
end,
on_replace = function(self, pos, oldnode, newnode)
self.food = (self.food or 0) + 1
if self.food >= 8 then
self.food = 0
self.gotten = false
end
end,
})
mobs:spawn({
name = "mobs_animal:cow",
nodes = {"default:dirt_with_grass", "ethereal:green_dirt"},
neighbors = {"group:grass"},
min_light = 14,
interval = 60,
chance = 8000, -- 15000
min_height = 5,
max_height = 200,
day_toggle = true,
name = "mobs_animal:cow",
nodes = {"default:dirt_with_grass", "ethereal:green_dirt"},
neighbors = {"group:grass"},
min_light = 14,
interval = 60,
chance = 8000, -- 15000
min_height = 5,
max_height = 200,
day_toggle = true,
})
mobs:register_egg("mobs_animal:cow", S("Cow"), "default_grass.png", 1)
mobs:alias_mob("mobs:cow", "mobs_animal:cow") -- compatibility
-- bucket of milk
minetest.register_craftitem(":mobs:bucket_milk", {
description = S("Bucket of Milk"),
inventory_image = "mobs_bucket_milk.png",
stack_max = 1,
on_use = minetest.item_eat(8, 'bucket:bucket_empty'),
groups = {food_milk = 1, flammable = 3},
description = S("Bucket of Milk"),
inventory_image = "mobs_bucket_milk.png",
stack_max = 1,
on_use = minetest.item_eat(8, 'bucket:bucket_empty'),
groups = {food_milk = 1, flammable = 3},
})
-- butter
minetest.register_craftitem(":mobs:butter", {
description = S("Butter"),
inventory_image = "mobs_butter.png",
on_use = minetest.item_eat(1),
groups = {food_butter = 1, flammable = 2},
description = S("Butter"),
inventory_image = "mobs_butter.png",
on_use = minetest.item_eat(1),
groups = {food_butter = 1, flammable = 2},
})
if minetest.get_modpath("farming") and farming and farming.mod then
minetest.register_craft({
type = "shapeless",
output = "mobs:butter",
recipe = {"mobs:bucket_milk", "farming:salt"},
replacements = {{ "mobs:bucket_milk", "bucket:bucket_empty"}}
type = "shapeless",
output = "mobs:butter",
recipe = {"mobs:bucket_milk", "farming:salt"},
replacements = {{ "mobs:bucket_milk", "bucket:bucket_empty"}}
})
else -- some saplings are high in sodium so makes a good replacement item
minetest.register_craft({
type = "shapeless",
output = "mobs:butter",
recipe = {"mobs:bucket_milk", "default:sapling"},
replacements = {{ "mobs:bucket_milk", "bucket:bucket_empty"}}
type = "shapeless",
output = "mobs:butter",
recipe = {"mobs:bucket_milk", "default:sapling"},
replacements = {{ "mobs:bucket_milk", "bucket:bucket_empty"}}
})
end
-- cheese wedge
minetest.register_craftitem(":mobs:cheese", {
description = S("Cheese"),
inventory_image = "mobs_cheese.png",
on_use = minetest.item_eat(4),
groups = {food_cheese = 1, flammable = 2},
description = S("Cheese"),
inventory_image = "mobs_cheese.png",
on_use = minetest.item_eat(4),
groups = {food_cheese = 1, flammable = 2},
})
minetest.register_craft({
type = "cooking",
output = "mobs:cheese",
recipe = "mobs:bucket_milk",
cooktime = 5,
replacements = {{ "mobs:bucket_milk", "bucket:bucket_empty"}}
type = "cooking",
output = "mobs:cheese",
recipe = "mobs:bucket_milk",
cooktime = 5,
replacements = {{ "mobs:bucket_milk", "bucket:bucket_empty"}}
})
-- cheese block
minetest.register_node(":mobs:cheeseblock", {
description = S("Cheese Block"),
tiles = {"mobs_cheeseblock.png"},
is_ground_content = false,
groups = {crumbly = 3},
sounds = default.node_sound_dirt_defaults()
description = S("Cheese Block"),
tiles = {"mobs_cheeseblock.png"},
is_ground_content = false,
groups = {crumbly = 3},
sounds = default.node_sound_dirt_defaults()
})
minetest.register_craft({
output = "mobs:cheeseblock",
recipe = {
{'mobs:cheese', 'mobs:cheese', 'mobs:cheese'},
{'mobs:cheese', 'mobs:cheese', 'mobs:cheese'},
{'mobs:cheese', 'mobs:cheese', 'mobs:cheese'},
}
output = "mobs:cheeseblock",
recipe = {
{'mobs:cheese', 'mobs:cheese', 'mobs:cheese'},
{'mobs:cheese', 'mobs:cheese', 'mobs:cheese'},
{'mobs:cheese', 'mobs:cheese', 'mobs:cheese'},
}
})
minetest.register_craft({
output = "mobs:cheese 9",
recipe = {
{'mobs:cheeseblock'},
}
output = "mobs:cheese 9",
recipe = {
{'mobs:cheeseblock'},
}
})

View File

@ -1,6 +1,9 @@
local news = {
'6/17/20',
'Some items crafted in stations now show their crafts in unified inventory.',
'',
'6/15/20',
'Added locked varients of the dying and staining stations, and the weaving loom.',
'Added locked variants of the dying and staining stations, and the weaving loom.',
'',
'6/14/20',
'Shop signs can now only be edited by the person that placed it.',

View File

@ -1,3 +1,38 @@
-- check for Unified Inventory
local is_uninv = minetest.global_exists("unified_inventory") or false
local function dual_register_recipe(craft_type, def)
if is_uninv then
local input_list = {}
for item, count in pairs(def.input) do
table.insert(input_list, item..' '..count)
end
-- divide the output name the same way simple crafting does...
--
local output_name
if def.output then
def.output = ItemStack(def.output)
output_name = def.output:get_name()
else
output_name = "none" -- special value for recipes with no output.
end
-- register with unified inventory
-- make sure the station has been registered as well using unified_inventory.register_craft_type()
--
unified_inventory.register_craft({
type = craft_type,
items = input_list,
output = output_name
})
end
-- register with simple crafting
--
simplecrafting_lib.register(craft_type, def)
end
local tool_repair ={
{'default:axe_steel', 'default:steel_ingot'},
{'default:pick_steel', 'default:steel_ingot'},
@ -50,6 +85,8 @@ for i in ipairs (tool_repair) do
local tool = tool_repair[i][1]
local material = tool_repair[i][2]
-- no dual_register_recipe() to ignore registering repair recipes...
--
simplecrafting_lib.register('anvil', {
input = {
[tool] = 1,
@ -60,7 +97,7 @@ for i in ipairs (tool_repair) do
end
--Steel Tools
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:steel_ingot'] = 3,
['group:stick'] = 1,
@ -68,7 +105,7 @@ simplecrafting_lib.register('anvil', {
output = 'default:pick_steel',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:steel_ingot'] = 3,
['group:stick'] = 1,
@ -76,15 +113,15 @@ simplecrafting_lib.register('anvil', {
output = 'default:axe_steel',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:steel_ingot'] = 1,
['group:stick'] = 2,
['default:stick'] = 2,
},
output = 'default:shovel_steel',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:steel_ingot'] = 3,
},
@ -92,7 +129,7 @@ simplecrafting_lib.register('anvil', {
})
--Bronze tools
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:bronze_ingot'] = 3,
['group:stick'] = 1,
@ -100,7 +137,7 @@ simplecrafting_lib.register('anvil', {
output = 'default:pick_bronze',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:bronze_ingot'] = 3,
['group:stick'] = 1,
@ -108,7 +145,7 @@ simplecrafting_lib.register('anvil', {
output = 'default:axe_bronze',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:bronze_ingot'] = 1,
['group:stick'] = 2,
@ -116,7 +153,7 @@ simplecrafting_lib.register('anvil', {
output = 'default:shovel_bronze',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:bronze_ingot'] = 3,
},
@ -124,7 +161,7 @@ simplecrafting_lib.register('anvil', {
})
--Mese tools
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:mese_crystal'] = 3,
['group:stick'] = 1,
@ -132,7 +169,7 @@ simplecrafting_lib.register('anvil', {
output = 'default:pick_mese',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:mese_crystal'] = 3,
['group:stick'] = 1,
@ -140,7 +177,7 @@ simplecrafting_lib.register('anvil', {
output = 'default:axe_mese',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:mese_crystal'] = 1,
['group:stick'] = 2,
@ -148,7 +185,7 @@ simplecrafting_lib.register('anvil', {
output = 'default:shovel_mese',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:mese_crystal'] = 3,
},
@ -156,7 +193,7 @@ simplecrafting_lib.register('anvil', {
})
--Titanium tools
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['epic:titanium_ingot'] = 3,
['darkage:iron_stick'] = 1,
@ -164,7 +201,7 @@ simplecrafting_lib.register('anvil', {
output = 'epic:pick_titanium',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['epic:titanium_ingot'] = 1,
['darkage:iron_stick'] = 2,
@ -172,7 +209,7 @@ simplecrafting_lib.register('anvil', {
output = 'epic:shovel_titanium',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['epic:titanium_ingot'] = 3,
['darkage:iron_stick'] = 1,
@ -180,7 +217,7 @@ simplecrafting_lib.register('anvil', {
output = 'epic:axe_titanium',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['epic:titanium_ingot'] = 3,
},
@ -188,7 +225,7 @@ simplecrafting_lib.register('anvil', {
})
--Misc
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['ropes:ropesegment'] = 1,
['default:steel_ingot'] = 2,
@ -196,7 +233,7 @@ simplecrafting_lib.register('anvil', {
output = 'epic:sign_post_metal',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['ocean:prismarine_crystals'] = 1,
['epic:bloodstone'] = 1,
@ -205,7 +242,7 @@ simplecrafting_lib.register('anvil', {
output = 'furniture:lantern_ceiling',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:tin_ingot'] = 3,
['darkage:iron_stick'] = 2,
@ -213,14 +250,14 @@ simplecrafting_lib.register('anvil', {
output = 'epic:shovel_soft',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:steel_ingot'] = 6,
},
output = 'castle_weapons:battleaxe',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['epic:titanium_ingot'] = 2,
['group:stick'] = 1,
@ -228,7 +265,7 @@ simplecrafting_lib.register('anvil', {
output = 'farming:scythe',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:steel_ingot'] = 4,
['default:tin_ingot'] = 1,
@ -236,63 +273,63 @@ simplecrafting_lib.register('anvil', {
output = 'stations:stain',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:steel_ingot'] = 1,
},
output = 'epic:arrow_tip 20',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:steel_ingot'] = 1,
},
output = 'mobs:horseshoe_steel',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:bronze_ingot'] = 1,
},
output = 'mobs:horseshoe_bronze',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:mese_crystal'] = 1,
},
output = 'mobs:horseshoe_mese',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:steel_ingot'] = 2,
},
output = 'scaffolding:scaffolding_wrench',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['epic:lead_lump'] = 1,
},
output = 'epic:lead_wire 10',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:steel_ingot'] = 1,
},
output = 'furniture:hinge 10',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:steel_ingot'] = 1,
},
output = 'furniture:lock',
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:steel_ingot'] = 2,
},
@ -300,7 +337,7 @@ simplecrafting_lib.register('anvil', {
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:diamondblock'] = 1,
['default:goldblock'] = 1,
@ -319,7 +356,7 @@ local armor_material = {
}
for name, mat in pairs(armor_material) do
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
[mat] = 5,
['mobs:leather'] = 1,
@ -327,7 +364,7 @@ for name, mat in pairs(armor_material) do
output = '3d_armor:helmet_'..name,
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
[mat] = 8,
['mobs:leather'] = 1,
@ -335,7 +372,7 @@ for name, mat in pairs(armor_material) do
output = '3d_armor:chestplate_'..name,
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
[mat] = 7,
['mobs:leather'] = 1,
@ -343,7 +380,7 @@ for name, mat in pairs(armor_material) do
output = '3d_armor:leggings_'..name,
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
[mat] = 4,
['mobs:leather'] = 1,
@ -351,7 +388,7 @@ for name, mat in pairs(armor_material) do
output = '3d_armor:boots_'..name,
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
[mat] = 7,
},
@ -365,7 +402,7 @@ local armor_material = {
}
for name, mat in pairs(armor_material) do
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
[mat] = 5,
['mobs:leather'] = 1,
@ -373,7 +410,7 @@ for name, mat in pairs(armor_material) do
output = 'epic:helmet_'..name,
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
[mat] = 8,
['mobs:leather'] = 1,
@ -381,7 +418,7 @@ for name, mat in pairs(armor_material) do
output = 'epic:chestplate_'..name,
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
[mat] = 7,
['mobs:leather'] = 1,
@ -389,7 +426,7 @@ for name, mat in pairs(armor_material) do
output = 'epic:leggings_'..name,
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
[mat] = 4,
['mobs:leather'] = 1,
@ -397,7 +434,7 @@ for name, mat in pairs(armor_material) do
output = 'epic:boots_'..name,
})
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
[mat] = 7,
},
@ -405,29 +442,29 @@ for name, mat in pairs(armor_material) do
})
end
--[[ only needed once I find out how to use the fuel stuff.
simplecrafting_lib.register('anvil_fuel', {
dual_register_recipe('anvil_fuel', {
input = {['default:coal_lump'] = 1},
output = 'simplecrafting_lib:heat 20',
})
simplecrafting_lib.register('anvil_fuel', {
dual_register_recipe('anvil_fuel', {
input = {['default:coalblock'] = 1},
output = 'simplecrafting_lib:heat 180',
})
simplecrafting_lib.register('anvil_fuel', {
dual_register_recipe('anvil_fuel', {
input = {['charcoal:charcoal'] = 1},
output = 'simplecrafting_lib:heat 15',
})
simplecrafting_lib.register('anvil_fuel', {
dual_register_recipe('anvil_fuel', {
input = {['charcoal:charcoal_block'] = 1},
output = 'simplecrafting_lib:heat 135',
})
--]]
--shapes
simplecrafting_lib.register('anvil', {
dual_register_recipe('anvil', {
input = {
['default:gold_ingot'] = 1,
},

View File

@ -101,3 +101,10 @@ simplecrafting_lib.register('mortar', {
},
output = 'epic:poison',
})
simplecrafting_lib.register('mortar', {
input = {
['farming:corn_cob'] = 1,
},
output = 'farming:cornstarch',
})

View File

@ -127,3 +127,19 @@ end
--minetest.register_node('stations:anvil0', anvil_multifurnace0_def)
minetest.register_node('stations:anvil_locked', anvil_locked_multifurnace_def)
local is_uninv = minetest.global_exists("unified_inventory") or false
if is_uninv then
-- "anvil" from simplecrafting_lib.generate_table_functions('anvil') above...
-- the same name used to register recipes for the anvil station to simple crafting
--
-- register_craft_type sets up the icon shown in inventory GUI... such as furnace for cooking things
--
unified_inventory.register_craft_type("anvil", {
description = "Smithy Station",
icon = 'stations_anvil_icon.png', -- from the simple crafting definition above
width = 4, -- like when shown in station guide... 4 wide
height = 2, -- 1 high
uses_crafting_grid = false -- obviously not the normal crafting grid
})
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -329,7 +329,7 @@ unified_inventory.register_page("craftguide", {
unified_inventory.craft_type_defaults(craft.type, {})
if craft_type.icon then
fs[#fs + 1] = string.format("image[%f,%f;%f,%f;%s]",
5.7, (formspecy + 0.05), 0.5, 0.5, craft_type.icon)
5.6, (formspecy), 0.85, 0.85, craft_type.icon)
end
fs[#fs + 1] = "label[5.5,"..(formspecy + 1)..";" .. F(craft_type.description).."]"
fs[#fs + 1] = stack_image_button(6.5, formspecy, 1.1, 1.1,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 962 B

After

Width:  |  Height:  |  Size: 2.2 KiB