trim the fat
@ -1 +0,0 @@
|
||||
default
|
@ -1,314 +0,0 @@
|
||||
|
||||
--tool
|
||||
|
||||
local another_charcoal = {}
|
||||
local function add_tool(name, func)
|
||||
another_charcoal[name] = func
|
||||
end
|
||||
|
||||
minetest.register_on_dignode(function(_, oldnode, digger)
|
||||
if digger == nil then
|
||||
return
|
||||
end
|
||||
local func = another_charcoal[digger:get_wielded_item():get_name()]
|
||||
if func
|
||||
and oldnode.name ~= "air" then
|
||||
func(digger, oldnode)
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_tool("another_charcoal:steel_splitting_axe", {
|
||||
description = "Steel Splitting Axe",
|
||||
inventory_image = "another_charcoal_steel_splitting_axe.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 1.2,
|
||||
max_drop_level=0,
|
||||
groupcaps={
|
||||
choppy={times={[1]=3.00, [2]=2.00, [3]=1.30}, uses=30, maxlevel=2},
|
||||
},
|
||||
damage_groups = {fleshy=4},
|
||||
},
|
||||
})
|
||||
|
||||
add_tool("another_charcoal:steel_splitting_axe", function(digger, node)
|
||||
local nam = node.name
|
||||
local items = minetest.get_node_drops(nam)
|
||||
local inv = digger:get_inventory()
|
||||
local drops = minetest.get_node_drops(nam)
|
||||
if node.group == tree then do
|
||||
inv:add_item("main", "another_charcoal:split_wood 3")
|
||||
local namn = node.name
|
||||
local drops = minetest.get_node_drops(namn)
|
||||
for _,item in ipairs(drops) do
|
||||
inv:remove_item("main", item)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
--craftitem
|
||||
|
||||
minetest.register_craftitem("another_charcoal:charcoal_lump", {
|
||||
description = "Charcoal Lump",
|
||||
inventory_image = "another_charcoal_charcoal_lump.png",
|
||||
groups = {coal=1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("another_charcoal:split_wood", {
|
||||
description = "Split Wood",
|
||||
inventory_image = "another_charcoal_split_wood.png",
|
||||
})
|
||||
|
||||
minetest.register_craftitem("another_charcoal:ash", {
|
||||
description = "Ash",
|
||||
inventory_image = "another_charcoal_ash.png",
|
||||
})
|
||||
|
||||
--node
|
||||
|
||||
minetest.register_node("another_charcoal:burning_wood_pile", {
|
||||
description = "Burning Wood Pile",
|
||||
tiles = {"another_charcoal_wood_pile2.png^another_charcoal_air_dry.png^another_charcoal_burning_wood.png", "another_charcoal_wood_pile2.png^another_charcoal_air_dry.png^another_charcoal_burning_wood.png", "another_charcoal_wood_pile1.png^another_charcoal_air_dry.png^another_charcoal_burning_wood.png",
|
||||
"another_charcoal_wood_pile1.png^another_charcoal_air_dry.png^another_charcoal_burning_wood.png", "another_charcoal_wood_pile.png^another_charcoal_air_dry.png^another_charcoal_burning_wood.png", "another_charcoal_wood_pile.png^another_charcoal_air_dry.png^another_charcoal_burning_wood.png"},
|
||||
drop = "another_charcoal:air_dry_wood_pile",
|
||||
paramtype2 = "facedir",
|
||||
legacy_facedir_simple = true,
|
||||
is_ground_content = false,
|
||||
groups = {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2, not_in_creative_inventory = 1},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
on_place = minetest.rotate_node
|
||||
})
|
||||
|
||||
minetest.register_node("another_charcoal:air_dry_wood_pile", {
|
||||
description = "Air-dry Wood Pile",
|
||||
tiles = {"another_charcoal_wood_pile2.png^another_charcoal_air_dry.png", "another_charcoal_wood_pile2.png^another_charcoal_air_dry.png", "another_charcoal_wood_pile1.png^another_charcoal_air_dry.png",
|
||||
"another_charcoal_wood_pile1.png^another_charcoal_air_dry.png", "another_charcoal_wood_pile.png^another_charcoal_air_dry.png", "another_charcoal_wood_pile.png^another_charcoal_air_dry.png"},
|
||||
paramtype2 = "facedir",
|
||||
legacy_facedir_simple = true,
|
||||
is_ground_content = false,
|
||||
groups = {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
on_place = minetest.rotate_node
|
||||
})
|
||||
|
||||
minetest.register_node("another_charcoal:wood_pile", {
|
||||
description = "Wood Pile",
|
||||
tiles = {"another_charcoal_wood_pile2.png", "another_charcoal_wood_pile2.png", "another_charcoal_wood_pile1.png",
|
||||
"another_charcoal_wood_pile1.png", "another_charcoal_wood_pile.png", "another_charcoal_wood_pile.png"},
|
||||
paramtype2 = "facedir",
|
||||
legacy_facedir_simple = true,
|
||||
is_ground_content = false,
|
||||
groups = {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
on_place = minetest.rotate_node
|
||||
})
|
||||
|
||||
minetest.register_node("another_charcoal:scorched_wood_pile", {
|
||||
description = "Scorched Wood Pile",
|
||||
tiles = {"another_charcoal_wood_pile2scorched.png", "another_charcoal_wood_pile2scorched.png", "another_charcoal_wood_pile1scorched.png",
|
||||
"another_charcoal_wood_pile1scorched.png", "another_charcoal_wood_pilescorched.png", "another_charcoal_wood_pilescorched.png"},
|
||||
drop = {
|
||||
max_items = 9,
|
||||
items = {
|
||||
{items = {"another_charcoal:charcoal_lump 6"}},
|
||||
{items = {"another_charcoal:ash 3"}}
|
||||
}
|
||||
},
|
||||
paramtype2 = "facedir",
|
||||
legacy_facedir_simple = true,
|
||||
is_ground_content = false,
|
||||
groups = {crumbly = 2},
|
||||
sounds = default.node_sound_sand_defaults(),
|
||||
on_place = minetest.rotate_node
|
||||
})
|
||||
|
||||
minetest.register_node("another_charcoal:ash_pile", {
|
||||
description = "Ash Pile",
|
||||
tiles = {"another_charcoal_wood_pile2scorched.png^another_charcoal_wood_pile_ash.png", "another_charcoal_wood_pile2scorched.png^another_charcoal_wood_pile_ash.png", "another_charcoal_wood_pile1scorched.png^another_charcoal_wood_pile_ash.png",
|
||||
"another_charcoal_wood_pile1scorched.png^another_charcoal_wood_pile_ash.png", "another_charcoal_wood_pilescorched.png^another_charcoal_wood_pile_ash.png", "another_charcoal_wood_pilescorched.png^another_charcoal_wood_pile_ash.png"},
|
||||
drop = "another_charcoal:ash 9",
|
||||
paramtype2 = "facedir",
|
||||
legacy_facedir_simple = true,
|
||||
is_ground_content = false,
|
||||
groups = {crumbly = 2},
|
||||
sounds = default.node_sound_sand_defaults(),
|
||||
on_place = minetest.rotate_node
|
||||
})
|
||||
|
||||
minetest.register_node("another_charcoal:charcoalblock", {
|
||||
description = "Charcoal Block",
|
||||
tiles = {"another_charcoal_charcoalblock.png"},
|
||||
is_ground_content = false,
|
||||
groups = {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2},
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("another_charcoal:ashblock", {
|
||||
description = "Ash Block",
|
||||
tiles = {"another_charcoal_ashblock.png"},
|
||||
is_ground_content = false,
|
||||
groups = {crumbly = 2, falling_node = 1},
|
||||
sounds = default.node_sound_sand_defaults(),
|
||||
})
|
||||
|
||||
|
||||
--crafting
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'another_charcoal:charcoalblock',
|
||||
recipe = {
|
||||
{'another_charcoal:charcoal_lump', 'another_charcoal:charcoal_lump', 'another_charcoal:charcoal_lump'},
|
||||
{'another_charcoal:charcoal_lump', 'another_charcoal:charcoal_lump', 'another_charcoal:charcoal_lump'},
|
||||
{'another_charcoal:charcoal_lump', 'another_charcoal:charcoal_lump', 'another_charcoal:charcoal_lump'},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'another_charcoal:charcoal_lump 9',
|
||||
recipe = {
|
||||
{'another_charcoal:charcoalblock'},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'another_charcoal:ashblock',
|
||||
recipe = {
|
||||
{'another_charcoal:ash', 'another_charcoal:ash', 'another_charcoal:ash'},
|
||||
{'another_charcoal:ash', 'another_charcoal:ash', 'another_charcoal:ash'},
|
||||
{'another_charcoal:ash', 'another_charcoal:ash', 'another_charcoal:ash'},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'another_charcoal:ash 9',
|
||||
recipe = {
|
||||
{'another_charcoal:ashblock'},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'another_charcoal:wood_pile',
|
||||
recipe = {
|
||||
{'another_charcoal:split_wood', 'another_charcoal:split_wood', 'another_charcoal:split_wood'},
|
||||
{'another_charcoal:split_wood', 'another_charcoal:split_wood', 'another_charcoal:split_wood'},
|
||||
{'another_charcoal:split_wood', 'another_charcoal:split_wood', 'another_charcoal:split_wood'},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'another_charcoal:split_wood 9',
|
||||
recipe = {
|
||||
{'another_charcoal:wood_pile'},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'another_charcoal:steel_splitting_axe',
|
||||
recipe = {
|
||||
{'', 'default:steel_ingot', 'default:steel_ingot'},
|
||||
{'', 'group:stick', ''},
|
||||
{'group:stick', '', ''},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'default:torch 4',
|
||||
recipe = {
|
||||
{'another_charcoal:charcoal_lump'},
|
||||
{'group:stick'},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "tnt:gunpowder",
|
||||
type = "shapeless",
|
||||
recipe = {"another_charcoal:charcoal_lump", "default:gravel"}
|
||||
})
|
||||
|
||||
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "another_charcoal:split_wood",
|
||||
burntime = 10,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "another_charcoal:wood_pile",
|
||||
burntime = 90,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "another_charcoal:air_dry_wood_pile",
|
||||
burntime = 135,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "another_charcoal:charcoal_lump",
|
||||
burntime = 33,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "another_charcoal:charcoalblock",
|
||||
burntime = 297,
|
||||
})
|
||||
|
||||
|
||||
--abm
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"another_charcoal:wood_pile"},
|
||||
neighbors = {"air"},
|
||||
interval = 100.0,
|
||||
chance = 3,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
minetest.set_node(pos, {name = "another_charcoal:air_dry_wood_pile"})
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"another_charcoal:air_dry_wood_pile"},
|
||||
neighbors = {"another_charcoal:burning_wood_pile", "fire:basic_flame","default:torch", "default:lava_source", "default:lava_flowing"},
|
||||
interval = 2.0,
|
||||
chance = 1,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
minetest.set_node(pos, {name = "another_charcoal:burning_wood_pile"})
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"another_charcoal:burning_wood_pile"},
|
||||
neighbors = {"air"},
|
||||
interval = 10.0,
|
||||
chance = 1,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
minetest.set_node(pos, {name = "another_charcoal:ash_pile"})
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"another_charcoal:burning_wood_pile"},
|
||||
interval = 100.0,
|
||||
chance = 1,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
minetest.set_node(pos, {name = "another_charcoal:scorched_wood_pile"})
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"another_charcoal:ashblock"},
|
||||
interval = 60.0,
|
||||
chance = 30,
|
||||
neighbors = {"default:water_source", "default:water_flowing"},
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
minetest.set_node(pos, {name = "default:dirt"})
|
||||
end,
|
||||
})
|
||||
|
||||
|
Before Width: | Height: | Size: 744 B |
Before Width: | Height: | Size: 456 B |
Before Width: | Height: | Size: 478 B |
Before Width: | Height: | Size: 724 B |
Before Width: | Height: | Size: 426 B |
Before Width: | Height: | Size: 610 B |
Before Width: | Height: | Size: 668 B |
Before Width: | Height: | Size: 346 B |
Before Width: | Height: | Size: 985 B |
Before Width: | Height: | Size: 891 B |
Before Width: | Height: | Size: 718 B |
Before Width: | Height: | Size: 867 B |
Before Width: | Height: | Size: 792 B |
Before Width: | Height: | Size: 477 B |
Before Width: | Height: | Size: 883 B |
Before Width: | Height: | Size: 378 B |
@ -1,3 +1,18 @@
|
||||
--Extreme Survival created by maikerumine
|
||||
-- Minetest 0.4.13 mod: "Extreme Survival"
|
||||
-- namespace: es
|
||||
--https://github.com/maikerumine
|
||||
|
||||
--License:
|
||||
--~~~~~~~~
|
||||
--Code:
|
||||
--(c) Copyright 2015 maikerumine; modified zlib-License
|
||||
--see "LICENSE.txt" for details.
|
||||
|
||||
|
||||
es = {}
|
||||
|
||||
|
||||
|
||||
-- rnd: anti noclip cheat
|
||||
local clip_nodes = {["default:stone"]=1,["default:cobble"]=1,["default:stonebrick"]=1,["default:dirt"]=1,["default:glass"]=1,["default:dirt"]=1,["default:steelblock"]=1}
|
||||
@ -37,7 +52,7 @@ minetest.register_globalstep(function(dtime)
|
||||
|
||||
end
|
||||
if check then
|
||||
player:set_hp(1); -- kill player
|
||||
player:set_hp(0.5); -- kill player
|
||||
minetest.chat_send_all(name.. " was caught walking inside walls at " .. p.x .. " " .. p.y .. " " .. p.z)
|
||||
minetest.log("action", name.. " was caught walking inside walls at " .. p.x .. " " .. p.y .. " " .. p.z)
|
||||
end
|
@ -22,10 +22,12 @@ es.modpath = modpath
|
||||
|
||||
-- REMOVE NODES DO NOT USE IN YOUR WORLD
|
||||
-- Alias
|
||||
--dofile(modpath.."/technodrem.lua")
|
||||
--dofile(modpath.."/moreorerem.lua")
|
||||
dofile(modpath.."/technodrem.lua")
|
||||
dofile(modpath.."/moreorerem.lua")
|
||||
dofile(modpath.."/alias.lua")
|
||||
|
||||
-- Anticheat by RND
|
||||
dofile(modpath.."/anticheat.lua")
|
||||
-- Armor [abort migration]
|
||||
dofile(modpath.."/armor.lua")
|
||||
-- Craft recipes for items
|
||||
|
@ -279,7 +279,7 @@ minetest.register_craft({
|
||||
output = "homedecor:microwave_oven 2",
|
||||
recipe = {
|
||||
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot", },
|
||||
{"default:steel_ingot", "moreblocks:iron_glass", "homedecor:ic", },
|
||||
{"default:steel_ingot", "default:glass", "homedecor:ic", },
|
||||
{"default:steel_ingot", "default:copper_ingot", "homedecor:power_crystal", },
|
||||
}
|
||||
})
|
||||
|
@ -171,7 +171,7 @@ homedecor.register("desk", {
|
||||
tiles = {
|
||||
homedecor.plain_wood,
|
||||
"homedecor_desk_drawers.png",
|
||||
"homedecor_generic_metal_black.png",
|
||||
"default_obsidian.png",
|
||||
},
|
||||
inventory_image = "homedecor_desk_inv.png",
|
||||
selection_box = desk_cbox,
|
||||
|
@ -1,674 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{one line to give the program's name and a brief idea of what it does.}
|
||||
Copyright (C) {year} {name of author}
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
{project} Copyright (C) {year} {fullname}
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
@ -1,7 +0,0 @@
|
||||
jdukebox
|
||||
========
|
||||
|
||||
Modified and bugfixed Jukebox for Minetest+ by BlockMen and Jordach
|
||||
|
||||
Right click with music disc to play, right click again to stop.
|
||||
|
@ -1 +0,0 @@
|
||||
default
|
@ -1,96 +0,0 @@
|
||||
-- some classic C64 game chiptunes:
|
||||
local discs = {
|
||||
-- Track name Color
|
||||
{ "Critical Mass", "yellow", },
|
||||
{ "Project Stealth Fighter (J.S. Bach)", "blue", },
|
||||
{ "Adidas Championship Football", "pink", },
|
||||
{ "Out Run", "green", },
|
||||
{ "Back To The Future II", "red", },
|
||||
{ "Airwolf", "white", },
|
||||
}
|
||||
|
||||
-- jukebox crafting
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'jdukebox:box',
|
||||
recipe = {
|
||||
{'group:wood', 'group:wood', 'group:wood'},
|
||||
{'group:wood', 'default:diamond', 'group:wood'},
|
||||
{'group:wood', 'group:wood', 'group:wood'},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_node("jdukebox:box", {
|
||||
description = "Jukebox",
|
||||
tiles = {"jdukebox_top.png", "jdukebox_side.png"},
|
||||
groups = {oddly_breakable_by_hand=1, flammable=1, choppy=3},
|
||||
on_rightclick = function(pos, node, clicker, itemstack)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
local wield = clicker:get_wielded_item():get_name()
|
||||
if inv:is_empty("main") then
|
||||
if string.find(wield, "jdukebox:disc") then
|
||||
inv:set_stack("main", 1, itemstack:take_item())
|
||||
local discid = wield:match("jdukebox:disc_(%d)")
|
||||
meta:set_string("hwnd", minetest.sound_play("jukebox_track_"..discid, {pos = pos, loop = true, gain = 10, max_hear_distance = 100}))
|
||||
end
|
||||
else
|
||||
local drop_pos = minetest.find_node_near(pos, 1, "air")
|
||||
if drop_pos == nil then drop_pos = {x=pos.x, y=pos.y+1, z=pos.z} end
|
||||
minetest.add_item(drop_pos, inv:get_stack("main", 1))
|
||||
if meta:get_string("hwnd") then minetest.sound_stop(meta:get_string("hwnd")) end
|
||||
inv:remove_item("main", inv:get_stack("main", 1))
|
||||
end
|
||||
|
||||
end,
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("main", 1)
|
||||
end,
|
||||
on_destruct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
if not inv:is_empty("main") then
|
||||
local drop_pos = minetest.find_node_near(pos, 1, "air")
|
||||
if drop_pos == nil then drop_pos = {x=pos.x, y=pos.y+1,z=pos.z} end
|
||||
minetest.add_item(drop_pos, inv:get_stack("main", 1))
|
||||
if meta:get_string("hwnd") then minetest.sound_stop(meta:get_string("hwnd")) end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
for i = 1, #discs do
|
||||
local track_name, dye = discs[i][1], discs[i][2]
|
||||
|
||||
minetest.register_alias("jdukebox:box"..i, "jdukebox:box")
|
||||
|
||||
minetest.register_craftitem("jdukebox:disc_"..i, {
|
||||
description = track_name,
|
||||
inventory_image = "jdukebox_disc_"..i..".png",
|
||||
stack_max = 1,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "jdukebox:disc_"..i,
|
||||
recipe = {
|
||||
{"default:coal_lump", "default:coal_lump", "default:coal_lump"},
|
||||
{"default:coal_lump", "dye:"..dye, "default:coal_lump"},
|
||||
{"default:coal_lump", "default:coal_lump", "default:coal_lump"},
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "jdukebox:box",
|
||||
burntime = 30,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "mesecons_noteblock:noteblock",
|
||||
burntime = 30,
|
||||
})
|
||||
|
||||
|
Before Width: | Height: | Size: 283 B |
Before Width: | Height: | Size: 279 B |
Before Width: | Height: | Size: 279 B |
Before Width: | Height: | Size: 282 B |
Before Width: | Height: | Size: 289 B |
Before Width: | Height: | Size: 304 B |
Before Width: | Height: | Size: 277 B |
Before Width: | Height: | Size: 282 B |
Before Width: | Height: | Size: 759 B |
Before Width: | Height: | Size: 592 B |
@ -1,41 +0,0 @@
|
||||
###Lavender Mod for Minetest by Xanthin
|
||||
|
||||
####Mod description
|
||||
|
||||
The mod will just add lavender to the map that gives you an item, that lets you listen to a
|
||||
calm and moody melody. And violet dye. Its more a fun than a serious attempt to improve the gameplay. ;)
|
||||
|
||||
Look around for lavender bushes being generated at sand.
|
||||
Pick them up, and get 2 or 4 lavender fruits.
|
||||
You can put a lavender fruit anywhere into the craft grid and craft 4 violet dyes from it.
|
||||
|
||||
Use a lavender fruit when selected in the hotbar and enjoy the sound. :)
|
||||
The lavender fruit also heals one health point (1/2 heart).
|
||||
Isn't that nice to calm down after frustrating moments in or with the game.
|
||||
|
||||
Ahhhhhh. :)
|
||||
|
||||
####Mod Dependencies
|
||||
|
||||
default (needed, for the node sounds and the default sand)
|
||||
|
||||
dye (optional, if you want to craft violet dye from the lavender fruits)
|
||||
|
||||
####Credits/Licenses
|
||||
|
||||
#####code:
|
||||
mapgen and growing abm taken and modified from flowers mod by Ironzorg, VanessaE: WTFPL
|
||||
https://github.com/minetest/minetest_game/tree/master/mods/flowers
|
||||
|
||||
health gaining code taken from Hunger mod by BlockMen: LGPL 2.1
|
||||
https://github.com/BlockMen/hunger
|
||||
|
||||
what's made by me: WTFPL
|
||||
|
||||
#####textures:
|
||||
by Gael de Sailly from his Forest mod (https://github.com/Gael-de-Sailly/Forest)
|
||||
|
||||
#####sound:
|
||||
by camalbio from (https://www.freesound.org/people/camalbio/sounds/35261/):
|
||||
CC BY 3.0 (http://creativecommons.org/licenses/by/3.0/)
|
||||
modified by Xanthin
|
@ -1,2 +0,0 @@
|
||||
default
|
||||
dye?
|
@ -1,40 +0,0 @@
|
||||
Lavender Mod for Minetest
|
||||
=========================
|
||||
|
||||
Mod description
|
||||
---------------
|
||||
The mod will just add lavender to the map that gives you an item, that lets you listen to a
|
||||
calm and moody melody. And violet dye. Its more a fun than a serious attempt to improve the gameplay. ;)
|
||||
|
||||
Look around for lavender bushes being generated at sand.
|
||||
Pick them up, and get 2 or 4 lavender fruits.
|
||||
You can put a lavender fruit anywhere into the craft grid and craft 4 violet dyes from it.
|
||||
Use a lavender fruit when selected in the hotbar and enjoy the sound. :)
|
||||
The lavender fruit also heals one health point (1/2 heart).
|
||||
Isn't that nice to calm down after frustrating moments in or with the game.
|
||||
Ahhhhhh. :)
|
||||
|
||||
Mod Dependencies
|
||||
----------------
|
||||
default (needed, for the node sounds and the default sand)
|
||||
dye (optional, if you want to craft violet dye from the lavender fruits)
|
||||
|
||||
Licenses
|
||||
--------
|
||||
code: mapgen and growing abm taken and modified from flowers mod by Ironzorg, VanessaE: WTFPL
|
||||
https://github.com/minetest/minetest_game/tree/master/mods/flowers
|
||||
|
||||
health gaining code taken from Hunger mod by BlockMen: LGPL 2.1
|
||||
https://github.com/BlockMen/hunger
|
||||
|
||||
what's made by me: WTFPL
|
||||
|
||||
textures: by Gael de Sailly from his Forest mod (https://github.com/Gael-de-Sailly/Forest)
|
||||
|
||||
sound: by camalbio from (https://www.freesound.org/people/camalbio/sounds/35261/):
|
||||
CC BY 3.0 (http://creativecommons.org/licenses/by/3.0/)
|
||||
modified by Xanthin
|
||||
|
||||
Code and download @
|
||||
-------------------
|
||||
https://github.com/Xanthin/lavender
|
@ -1,80 +0,0 @@
|
||||
-- lavender mod by Xanthin
|
||||
-- June/02/2015
|
||||
|
||||
dofile(minetest.get_modpath("lavender").."/mapgen.lua")
|
||||
|
||||
minetest.register_node("lavender:lavender", {
|
||||
description = "Lavender",
|
||||
drawtype = "plantlike",
|
||||
visual_scale = 1.3,
|
||||
waving = 1,
|
||||
tiles = {"lavender_fruitleaves.png"},
|
||||
inventory_image = "lavender_fruitleaves.png",
|
||||
paramtype = "light",
|
||||
is_ground_content = true,
|
||||
groups = {snappy=3,flammable=2,attached_node=1},
|
||||
drop = {
|
||||
max_items = 1,
|
||||
items = {
|
||||
{items = {"lavender:lavender_fruit 2"},rarity=1},
|
||||
{items = {"lavender:lavender_fruit 4"},rarity=20},
|
||||
}
|
||||
},
|
||||
sounds = default.node_sound_leaves_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("lavender:lavender_fruit", {
|
||||
description = "Lavender Fruit",
|
||||
drawtype = "plantlike",
|
||||
visual_scale = 1.0,
|
||||
tiles = {"lavender_fruit.png"},
|
||||
inventory_image = "lavender_fruit.png",
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
is_ground_content = false,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {-0.2, -0.5, -0.2, 0.2, 0, 0.2}
|
||||
},
|
||||
groups = {snappy=3,flammable=2,flower=1,attached_node=1,color_violet=1},
|
||||
sounds = default.node_sound_leaves_defaults(),
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
if itemstack:take_item() ~= nil and user ~= nil then -- this and below as seen in Hunger mod
|
||||
local name = user:get_player_name()
|
||||
local hp = user:get_hp()
|
||||
if hp < 20 then
|
||||
hp = hp + 1
|
||||
if hp > 20 then
|
||||
hp = 20
|
||||
end
|
||||
user:set_hp(hp)
|
||||
end
|
||||
local sound = "lavender_mipiace"
|
||||
minetest.sound_play(sound, {to_player = name, gain = 0.7})
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_abm({ -- modified from flowers mod
|
||||
nodenames = {"lavender:lavender_fruit"},
|
||||
neighbors = {"default:sand", "default:desert_sand"},
|
||||
interval = 10,
|
||||
chance = 30,
|
||||
action = function(pos, node)
|
||||
pos.y = pos.y - 1
|
||||
local under = minetest.get_node(pos)
|
||||
pos.y = pos.y + 1
|
||||
local light = minetest.get_node_light(pos)
|
||||
if not light or light < 13 then
|
||||
return
|
||||
end
|
||||
if under.name == "default:desert_sand" then
|
||||
minetest.set_node(pos, {name="default:dry_shrub"})
|
||||
elseif under.name == "default:sand" then
|
||||
minetest.set_node(pos, {name="lavender:lavender"})
|
||||
return
|
||||
end
|
||||
end
|
||||
})
|
Before Width: | Height: | Size: 1.2 MiB |
@ -1,50 +0,0 @@
|
||||
-- code from flowers mod by Ironzorg, VanessaE
|
||||
-- with just a small adjustion
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp, seed)
|
||||
if maxp.y >= 5 and minp.y <= 0 then
|
||||
-- Generate flowers
|
||||
local perlin1 = minetest.get_perlin(436, 3, 0.6, 100)
|
||||
-- Assume X and Z lengths are equal
|
||||
local divlen = 16
|
||||
local divs = (maxp.x-minp.x)/divlen+1;
|
||||
for divx=0,divs-1 do
|
||||
for divz=0,divs-1 do
|
||||
local x0 = minp.x + math.floor((divx+0)*divlen)
|
||||
local z0 = minp.z + math.floor((divz+0)*divlen)
|
||||
local x1 = minp.x + math.floor((divx+1)*divlen)
|
||||
local z1 = minp.z + math.floor((divz+1)*divlen)
|
||||
-- Determine flowers amount from perlin noise
|
||||
local grass_amount = math.floor(perlin1:get2d({x=x0, y=z0}) ^ 3 * 9)
|
||||
-- Find random positions for flowers based on this random
|
||||
local pr = PseudoRandom(seed+456)
|
||||
for i=0,grass_amount do
|
||||
local x = pr:next(x0, x1)
|
||||
local z = pr:next(z0, z1)
|
||||
-- Find ground level (0...15)
|
||||
local ground_y = nil
|
||||
for y=30,0,-1 do
|
||||
if minetest.get_node({x = x, y = y, z = z}).name ~= "air" then
|
||||
ground_y = y
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if ground_y then
|
||||
local p = {x = x, y = ground_y + 1, z = z}
|
||||
local nn = minetest.get_node(p).name
|
||||
-- Check if the node can be replaced
|
||||
if minetest.registered_nodes[nn] and
|
||||
minetest.registered_nodes[nn].buildable_to then
|
||||
nn = minetest.get_node({x = x, y = ground_y, z = z}).name
|
||||
if nn == "default:sand" then -- would like to see them preferable in sandstone biomes
|
||||
minetest.set_node(p, {name = "lavender:lavender"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
Before Width: | Height: | Size: 1001 B |
Before Width: | Height: | Size: 1.0 KiB |
@ -1,10 +0,0 @@
|
||||
|
||||
This is a trader for minetest.
|
||||
Dependencies: none
|
||||
|
||||
Please use the chatcommand /trader to spawn traders.
|
||||
|
||||
Textures bauerin.png, kuhhaendler.png and bauer_in_sonntagslkeidung.png where done by Jordach.
|
||||
Texture wheat_farmer_by_addi.png has been done by Addi and is CC-BY-SA. It is based on Jordachs SAM texture.
|
||||
|
||||
Texture for the money/money2 (textures/mobf_trader_money.png) has been created by John1.
|
@ -1,19 +0,0 @@
|
||||
|
||||
mobf_trader.MAX_TRADER_PER_PLAYER = 12; -- players can only have this many traders
|
||||
mobf_trader.MAX_MOBS_PER_PLAYER = 24; -- ..and this many mobs alltogether
|
||||
|
||||
mobf_trader.TRADER_PRICE = 'default:gold_ingot 12';
|
||||
|
||||
-- all traders will offer a random subset of their possible trades
|
||||
mobf_trader.ALL_TRADERS_RANDOM = true;
|
||||
-- whenever a random trader gets a new offer added, he will have a random number of
|
||||
-- these items in stock; the number is choosen randombly between these two values:
|
||||
mobf_trader.RANDOM_STACK_MIN_SIZE = 1;
|
||||
mobf_trader.RANDOM_STACK_MAX_SIZE = 10;
|
||||
|
||||
mobf_trader.global_trade_offers = {}
|
||||
|
||||
mobf_trader.add_as_trader = {"mobs:male1_npc", "mobs:male2_npc", "mobs:male3_npc",
|
||||
"mobs:female1_npc", "mobs:female2_npc", "mobs:female3_npc",
|
||||
"mobs:npc",
|
||||
"lottmobs:elf", "lottmobs:rohan_guard", "lottmobs:gondor_guard", "lottmobs:dunlending", "lottmobs:hobbit", "lottmobs:dwarf"}
|
@ -1,3 +0,0 @@
|
||||
mobs?
|
||||
lottmobs?
|
||||
3d_armor?
|
@ -1,434 +0,0 @@
|
||||
|
||||
--[[
|
||||
Modified: 20.05.14 Added diffrent trader types for medieval villages.
|
||||
Those traders offer almost all items from default plus cottages.
|
||||
Items from animals (mobf, https://forum.minetest.net/viewtopic.php?id=629) and bushes (Plantlife modpack, https://forum.minetest.net/viewtopic.php?id=3898) are partly included.
|
||||
|
||||
Features:
|
||||
* supports up to 16 different trade offers (for more, space might get too tight in the formspec)
|
||||
* up to three diffrent payments can be offered per trade offer (if more, space might get too tight in the formspec)
|
||||
* one offer (either what the trader offers or what he requests as price) may consist of up to four diffrent stacks
|
||||
* trader types can be pre-defined; each trader of that type will then sell the same goods for the same prices
|
||||
* individual traders have their own set of trade offers:
|
||||
add, edit and delete is supported for trade offers
|
||||
* traders can be spawned with the chatcommand "/trader <type>", i.e. "/trader individual";
|
||||
the trader_spawn priv is needed in order to use that chat command
|
||||
* traders can be picked up, added to your inventory, carried to another place and be placed there;
|
||||
it requires the trader_take priv or ownership of that particular trader ('.. is my employer') and is offered in the trader's formspec
|
||||
* supports money mod: use mobf_trader:money as item name for money and stack size for actual price
|
||||
* supports money2 mod: use mobf_trader:money2 as item name and stack size for actual price
|
||||
* no media data required other than skins for the traders; the normal player-model is used
|
||||
* traders only do something if you right-click them and call up their offer, so they do not require many ressources
|
||||
* the formspec could also be used by i.e. trade chests (mobs are more decorative!)
|
||||
--]]
|
||||
|
||||
|
||||
-- TODO: produce a bench occasionally and sit down on it; pick up bench when getting up
|
||||
-- TODO: rename mod?
|
||||
mobf_trader = {}
|
||||
|
||||
|
||||
|
||||
|
||||
dofile(minetest.get_modpath("mobf_trader").."/config.lua"); -- local configuration values
|
||||
dofile(minetest.get_modpath("mobf_trader").."/mob_basics.lua"); -- basic functionality: onfig, spawn, ...
|
||||
dofile(minetest.get_modpath("mobf_trader").."/mob_pickup.lua"); -- pick trader up/place again
|
||||
dofile(minetest.get_modpath("mobf_trader").."/mob_trading.lua"); -- the actual trading code - complete with formspecs
|
||||
dofile(minetest.get_modpath("mobf_trader").."/mob_trading_random.lua"); -- traders with a more random stock
|
||||
dofile(minetest.get_modpath("mobf_trader").."/large_chest.lua"); -- one large chest is easier to handle than a collectoin of chests
|
||||
dofile(minetest.get_modpath("mobf_trader").."/village_traders.lua"); -- functionality for interaction with mg_villages
|
||||
--TODO dofile(minetest.get_modpath("mobf_trader").."/mob_sitting.lua"); -- allows the mob to sit/lie on furniture
|
||||
|
||||
|
||||
-- find out the right mesh; if the wrong one is used, the traders become invisible
|
||||
mobf_trader.mesh = "character.b3d";
|
||||
--[[
|
||||
-- if we are dealing with realtest - that still uses the old model
|
||||
if( minetest.get_modpath( 'trees' )
|
||||
and minetest.get_modpath( 'anvil')
|
||||
and minetest.get_modpath( 'joiner_table')
|
||||
and minetest.get_modpath( 'scribing_table' )) then
|
||||
mobf_trader.mesh = "character.x";
|
||||
end
|
||||
--]]
|
||||
-- 3darmor/wieldview is great
|
||||
|
||||
|
||||
--this doesnt work-edited out by maikerumine
|
||||
--[[
|
||||
if( minetest.get_modpath( '3d_armor' )) then
|
||||
--mobf_trader.mesh = "3d_armor_character.b3d";
|
||||
mobf_trader.mesh = "3d_armor_character.x";
|
||||
end]]
|
||||
|
||||
|
||||
mobf_trader.trader_entity_prototype = {
|
||||
|
||||
-- so far, this is more or less the redefinition of the standard player model
|
||||
physical = true,
|
||||
collisionbox = {-0.30,-1.0,-0.30, 0.30,0.8,0.30},
|
||||
|
||||
visual = "mesh";
|
||||
visual_size = {x=1, y=1, z=1},
|
||||
mesh = mobf_trader.mesh,
|
||||
textures = {"character.png"},
|
||||
|
||||
|
||||
description = 'Trader',
|
||||
|
||||
-- this mob only has to stand around and wait for customers
|
||||
animation = {
|
||||
stand_START = 0,
|
||||
stand_END = 79,
|
||||
sit_START = 81,
|
||||
sit_END = 160,
|
||||
sleep_START = 162,
|
||||
sleep_END = 166,
|
||||
walk_START = 168,
|
||||
walk_END = 187,
|
||||
mine_START = 189,
|
||||
mine_END = 198,
|
||||
walkmine_START = 200,
|
||||
walkmine_END = 219,
|
||||
},
|
||||
animation_speed = 30,
|
||||
|
||||
armor_groups = {immortal=1},
|
||||
hp_max = 100, -- just to be sure
|
||||
|
||||
|
||||
-- specific data for the trader:
|
||||
|
||||
-- individual name (e.g. Fritz or John)
|
||||
trader_name = '',
|
||||
-- the goods he sells
|
||||
trader_typ = '',
|
||||
-- who has put the trader here? (might be mapgen or a player)
|
||||
trader_owner = '',
|
||||
-- where is the build chest or other object that caused this trader to spawn?
|
||||
trader_home_pos = {x=0,y=0,z=0},
|
||||
-- at which position has the trader been last?
|
||||
trader_pos = {x=0,y=0,z=0},
|
||||
-- when was the NPC first created?
|
||||
trader_birthtime = 0,
|
||||
-- additional data (perhaps statistics of how much of what has been sold)
|
||||
trader_sold = {},
|
||||
-- some traders may have a limited (more random) stock
|
||||
trader_stock = nil,
|
||||
-- unique ID for each trader
|
||||
trader_id = '',
|
||||
|
||||
decription = "Default NPC",
|
||||
inventory_image = "npcf_inv_top.png",
|
||||
|
||||
|
||||
-- Information that is specific to this particular trader
|
||||
get_staticdata = function(self)
|
||||
return mobf_trader.trader_entity_get_staticdata( self, nil );
|
||||
end,
|
||||
|
||||
-- Called when the object is instantiated.
|
||||
on_activate = function(self, staticdata, dtime_s)
|
||||
-- set up the trader
|
||||
mobf_trader.trader_entity_on_activate(self, staticdata, dtime_s);
|
||||
|
||||
-- the mob will do nothing but stand around
|
||||
self.object:set_animation({x=self.animation[ self.trader_animation..'_START'], y=self.animation[ self.trader_animation..'_END']},
|
||||
self.animation_speed-5+math.random(10));
|
||||
|
||||
-- the trader has to be subject to gravity
|
||||
self.object:setvelocity( {x=0, y= 0, z=0});
|
||||
self.object:setacceleration({x=0, y=-10, z=0});
|
||||
end,
|
||||
|
||||
-- this mob waits for rightclicks and does nothing else
|
||||
--[[
|
||||
-- Called on every server tick (dtime is usually 0.1 seconds)
|
||||
on_step = function(self, dtime)
|
||||
end,
|
||||
--]]
|
||||
|
||||
-- this is a fast way to get rid of obsolete/misconfigured traders
|
||||
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
|
||||
|
||||
if( not( self.trader_name )
|
||||
or not( self.trader_id )
|
||||
or not( self.trader_typ )
|
||||
or not( mob_basics.mob_types[ 'trader' ][ self.trader_typ ] )) then
|
||||
|
||||
self.object:remove();
|
||||
return;
|
||||
else
|
||||
self.hp_max = 100;
|
||||
end
|
||||
-- prevent accidental (or purposeful!) kills
|
||||
self.object:set_hp( self.hp_max );
|
||||
-- talk to the player
|
||||
if( puncher and puncher:get_player_name() ) then
|
||||
minetest.chat_send_player( puncher:get_player_name(),
|
||||
( self.trader_name or 'A trader' )..': '..
|
||||
'Hey! Stop doing that. I am a peaceful trader. Here, buy something:');
|
||||
-- marketing - if *that* doesn't disencourage aggressive players... :-)
|
||||
mobf_trader.trader_entity_trade( self, puncher );
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
-- show the trade menu
|
||||
on_rightclick = function(self, clicker)
|
||||
mobf_trader.trader_entity_trade( self, clicker );
|
||||
end,
|
||||
}
|
||||
|
||||
|
||||
mobf_trader.trader_entity_trade = function( self, clicker )
|
||||
if( not( self) or not( clicker ) or not( self.trader_typ ) or not( mob_basics.mob_types[ 'trader' ][ self.trader_typ ])) then
|
||||
return;
|
||||
end
|
||||
|
||||
mob_basics.turn_towards_player( self, clicker );
|
||||
mob_trading.show_trader_formspec( self, clicker, nil, nil,
|
||||
mob_basics.mob_types[ 'trader' ][ self.trader_typ ].goods ); -- this is handled in mob_trading.lua
|
||||
end
|
||||
|
||||
|
||||
mobf_trader.trader_entity_get_staticdata = function( self, serialized_data )
|
||||
|
||||
local data = {};
|
||||
if( serialized_data ) then
|
||||
data = minetest.deserialize( serialized_data );
|
||||
end
|
||||
|
||||
-- traders of a standard type do not save their list of goods
|
||||
if( self and self.trader_typ and self.trader_typ ~= 'individual' ) then
|
||||
self.trader_goods = {};
|
||||
end
|
||||
|
||||
data.mob_prefix = 'trader';
|
||||
data.trader_name = self.trader_name;
|
||||
data.trader_typ = self.trader_typ;
|
||||
data.trader_owner = self.trader_owner;
|
||||
data.trader_home_pos = self.trader_home_pos;
|
||||
data.trader_pos = self.trader_pos;
|
||||
data.trader_birthtime = self.trader_birthtime;
|
||||
data.trader_sold = self.trader_sold;
|
||||
data.trader_stock = self.trader_stock;
|
||||
data.trader_id = self.trader_id;
|
||||
data.trader_texture = self.trader_texture;
|
||||
data.trader_goods = self.trader_goods;
|
||||
data.trader_limit = self.trader_limit;
|
||||
data.trader_animation = self.trader_animation;
|
||||
data.trader_vsize = self.trader_vsize;
|
||||
|
||||
return minetest.serialize( data );
|
||||
end
|
||||
|
||||
|
||||
mobf_trader.trader_entity_on_activate = function(self, staticdata, dtime_s)
|
||||
-- do the opposite of get_staticdata
|
||||
if( staticdata ) then
|
||||
|
||||
local data = minetest.deserialize( staticdata );
|
||||
if( data and data.trader_id ~= '') then
|
||||
|
||||
self.trader_name = data.trader_name;
|
||||
self.trader_typ = data.trader_typ;
|
||||
self.trader_owner = data.trader_owner;
|
||||
self.trader_home_pos = data.trader_home_pos;
|
||||
self.trader_pos = data.trader_pos;
|
||||
self.trader_birthtime = data.trader_birthtime;
|
||||
self.trader_sold = data.trader_sold;
|
||||
self.trader_stock = data.trader_stock;
|
||||
self.trader_id = data.trader_id;
|
||||
self.trader_texture = data.trader_texture;
|
||||
self.trader_goods = data.trader_goods;
|
||||
self.trader_animation = data.trader_animation;
|
||||
self.trader_vsize = data.trader_vsize;
|
||||
end
|
||||
|
||||
if( not( self.trader_animation )) then
|
||||
self.trader_animation = 'stand';
|
||||
end
|
||||
|
||||
if( self.trader_texture ) then
|
||||
mob_basics.update_texture( self, 'trader', nil );
|
||||
end
|
||||
|
||||
if( self.trader_vsize ) then
|
||||
mob_basics.update_visual_size( self, self.trader_vsize, false, 'trader' );
|
||||
end
|
||||
end
|
||||
|
||||
-- initialize a new trader
|
||||
if( not( self.trader_name ) or self.trader_name=='' or self.trader_id=='') then
|
||||
-- no name supplied - it will be choosen automaticly
|
||||
-- the typ of trader is unknown at this stage
|
||||
local typen = mob_basics.type_list_for_prefix('trader');
|
||||
local i = math.random(1,#typen );
|
||||
-- if trader_id is a duplicate, this entity here (self) will be removed
|
||||
mob_basics.initialize_mob( self, nil, typen[ i ], nil, {x=0,y=0,z=0}, 'trader' );
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
minetest.register_entity( "mobf_trader:trader", mobf_trader.trader_entity_prototype);
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- diffrent types of traders trade diffrent goods, have diffrent name lists etc.
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
mobf_trader.add_trader = function( prototype, description, speciality, goods, names, textures )
|
||||
|
||||
-- register traders as such
|
||||
if( not( mob_basics.mob_types[ 'trader' ] )) then
|
||||
mob_basics.mob_types['trader'] = {};
|
||||
end
|
||||
|
||||
-- default texture/skin for the trader; if multiple are supplied, a random one will be selected
|
||||
if( not(textures) or (textures == "" )) then
|
||||
textures = {"character.png"};
|
||||
end
|
||||
|
||||
-- mob_basics.log('Adding trader typ '..speciality, nil, 'trader' );
|
||||
|
||||
|
||||
mob_basics.mob_types[ 'trader' ][ speciality ] = {
|
||||
description = description,
|
||||
speciality = speciality,
|
||||
goods = goods,
|
||||
names = names,
|
||||
textures = textures
|
||||
}
|
||||
end
|
||||
|
||||
-- this trader can be configured by a player or admin
|
||||
mobf_trader.add_trader( nil, 'Trader who is working for someone', 'individual', {}, {'nameless'}, {} );
|
||||
mobf_trader.add_trader( nil, 'Trader with limited stock', 'random', {}, {'nameless'}, {} );
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- add a chat command to spawn a trader with a "/trader <typ>" command
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
minetest.register_chatcommand( 'trader', {
|
||||
params = "<trader type>",
|
||||
description = "Spawns a trader of the given type. Returns a list of types if called without parameter.",
|
||||
privs = {},
|
||||
func = function(name, param)
|
||||
-- this function handles the sanity checks and the actual spawning
|
||||
return mob_basics.handle_chat_command( name, param, 'trader', 'mobf_trader:trader' );
|
||||
end
|
||||
});
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- the mob as an item - carried in the inventory
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- If you want to add mobs with diffrent names/descriptions/inventory images/entities, just add your
|
||||
-- own register_craftitem and use this as an example.
|
||||
minetest.register_craftitem("mobf_trader:trader_item", {
|
||||
name = "Trader",
|
||||
description = "Trader. Place him somewhere to activate.",
|
||||
groups = {},
|
||||
inventory_image = "character.png",
|
||||
wield_image = "character.png",
|
||||
wield_scale = {x=1,y=1,z=1},
|
||||
on_place = function( itemstack, placer, pointed_thing )
|
||||
return mob_pickup.place_mob( itemstack, placer, pointed_thing, 'trader', 'mobf_trader:trader', true );
|
||||
end,
|
||||
-- carries individual metadata - stacking would interfere with that
|
||||
stack_max = 1,
|
||||
|
||||
})
|
||||
|
||||
|
||||
mob_pickup.register_mob_for_pickup( 'mobf_trader:trader', 'mobf_trader:trader_item', {
|
||||
deny_pickup = function( self, player )
|
||||
|
||||
if( not( self )) then
|
||||
return 'Error: Internal error. Trader not found.';
|
||||
end
|
||||
if( not( mob_basics.mob_types[ 'trader' ][ self[ 'trader_typ' ]] )) then
|
||||
return 'Error: The typ of this trader is unkown. Cannot pick him up.';
|
||||
end
|
||||
return '';
|
||||
end,
|
||||
|
||||
deny_place = function( data, pos, player )
|
||||
|
||||
if( data and not( mob_basics.mob_types[ 'trader' ][ data[ 'trader_typ']])) then
|
||||
return 'Error: The typ of this trader is unkown. Cannot place him.';
|
||||
end
|
||||
|
||||
if( not( player )) then
|
||||
return '';
|
||||
end
|
||||
local pname = player:get_player_name();
|
||||
|
||||
local mobs = mob_basics.mob_id_list_by_player( player:get_player_name(), 'trader' );
|
||||
if( #mobs >= mobf_trader.MAX_TRADER_PER_PLAYER and not( minetest.check_player_privs(pname, {mob_basics_spawn=true}))) then
|
||||
return 'Error: You are only allowed to have up to '..tostring( mobf_trader.MAX_TRADER_PER_PLAYER )..' traders '..
|
||||
' (you have '..tostring( #mobs )..' currently).';
|
||||
end
|
||||
|
||||
mobs = mob_basics.mob_id_list_by_player( pname, nil );
|
||||
if( #mobs >= mobf_trader.MAX_MOBS_PER_PLAYER and not( minetest.check_player_privs(pname, {mob_basics_spawn=true}))) then
|
||||
return 'Error: You are only allowed to have up to '..tostring( mobf_trader.MAX_MOBS_PER_PLAYER )..' mobs'..
|
||||
' (you have '..tostring( #mobs )..' currently).';
|
||||
end
|
||||
|
||||
return '';
|
||||
end,
|
||||
|
||||
pickup_success_msg = 'Mob picked up. In order to use him again, just wield him and place him somewhere.',
|
||||
|
||||
place_success_msg = 'Trader placed and waiting for trades.',
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- import all the traders; if you do not want any of them, comment out the line representing the unwanted traders (they are only created if their mods exists)
|
||||
|
||||
dofile(minetest.get_modpath("mobf_trader").."/trader_misc.lua"); -- trades a mixed assortment
|
||||
dofile(minetest.get_modpath("mobf_trader").."/trader_clay.lua"); -- no more destroying beaches while digging for clay and sand!
|
||||
dofile(minetest.get_modpath("mobf_trader").."/trader_moretrees.lua"); -- get wood from moretrees without chopping down trees
|
||||
dofile(minetest.get_modpath("mobf_trader").."/trader_animals.lua"); -- buy animals - no need to catch them with a lasso
|
||||
dofile(minetest.get_modpath("mobf_trader").."/trader_farming.lua"); -- they sell seeds and fruits - good against hunger! also contains special seeds trader
|
||||
dofile(minetest.get_modpath("mobf_trader").."/trader_flowers.lua"); -- flowers and other plants from default (cactus, papyrus, ..)
|
||||
dofile(minetest.get_modpath("mobf_trader").."/trader_ores.lua"); -- sells ores for tree/wood and food (both needed for further mining)
|
||||
dofile(minetest.get_modpath("mobf_trader").."/trader_village.lua"); -- historic occupations that can be found in medieval villages
|
||||
|
||||
|
||||
mobf_trader.add_as_trader_data = {}
|
||||
for i,v in ipairs( mobf_trader.add_as_trader ) do
|
||||
local entity = minetest.registered_entities[ v ];
|
||||
|
||||
if( entity ) then
|
||||
mobf_trader.add_as_trader_data[ v ] = {
|
||||
get_staticdata = entity.get_staticdata,
|
||||
on_activate = entity.on_activate,
|
||||
on_rightclick = entity.on_rightclick,
|
||||
}
|
||||
|
||||
entity.get_staticdata = function(self)
|
||||
local data = mobf_trader.add_as_trader_data[ v ].get_staticdata( self );
|
||||
return mobf_trader.trader_entity_get_staticdata( self, data );
|
||||
end
|
||||
|
||||
entity.on_activate = function(self, staticdata, dtime_s)
|
||||
mobf_trader.add_as_trader_data[ v ].on_activate( self, staticdata, dtime_s );
|
||||
mobf_trader.trader_entity_on_activate(self, staticdata, dtime_s);
|
||||
end
|
||||
|
||||
entity.on_rightclick = function(self, clicker)
|
||||
mobf_trader.trader_entity_trade( self, clicker );
|
||||
end
|
||||
end
|
||||
end
|
@ -1,278 +0,0 @@
|
||||
---------------------------------------------------------------------------------------------------
|
||||
-- Extra large chest for traders
|
||||
---------------------------------------------------------------------------------------------------
|
||||
-- Features:
|
||||
-- * traders may find all they can sell (plus storage space) in one inventory
|
||||
-- * the chest does not allow placement next to another locked chest
|
||||
-- * contains mobf_trader.LARGE_CHEST_SIZE inventory slots
|
||||
-- * it is possible to show virtual pages containing 4x10=40 of those inventory slots each
|
||||
-- * it is possible to scroll row-wise (in steps of 10 inventory slots)
|
||||
---------------------------------------------------------------------------------------------------
|
||||
|
||||
mobf_trader.LARGE_CHEST_SIZE = 4*10*10;
|
||||
|
||||
mobf_trader.large_chest_formspec = function( start, player )
|
||||
if( start < 0 or start > mobf_trader.LARGE_CHEST_SIZE-10 ) then
|
||||
start = 0;
|
||||
end
|
||||
local prev_row = start-10;
|
||||
local next_row = (start+10)%mobf_trader.LARGE_CHEST_SIZE;
|
||||
if( prev_row < 0 ) then
|
||||
prev_row = mobf_trader.LARGE_CHEST_SIZE-10;
|
||||
end
|
||||
local formspec = "size[12,9]"..
|
||||
"button[0.1,1.3;0.6,1;"..tostring( prev_row )..";"..minetest.formspec_escape('^')..']'..
|
||||
"button[0.1,1.8;0.6,1;"..tostring( next_row )..";"..minetest.formspec_escape('v')..']'..
|
||||
"button[11.2,1.3;0.6,1;"..tostring( prev_row )..";"..minetest.formspec_escape('^')..']'..
|
||||
"button[11.2,1.8;0.6,1;"..tostring( next_row )..";"..minetest.formspec_escape('v')..']'..
|
||||
"label[1,4.1;Show rows:]"..
|
||||
"label[0.5,-0.3;Row:]"..
|
||||
"label[10.9,-0.3;Row:]"..
|
||||
"list[current_name;main;1,0;10,4;"..tostring( start ).."]"..
|
||||
"list[current_player;main;2,5;8,4;]"..
|
||||
"button[10.8,4.2;1.4,0.5;statistic;Statistic]"..
|
||||
"button[10.0,4.8;2.2,0.5;request_trader;Request Trader]";
|
||||
|
||||
-- show the rest of the list from the beginning in order to allow continous scrolling
|
||||
local rows_missing = mobf_trader.LARGE_CHEST_SIZE-start;
|
||||
if( rows_missing < 40 ) then
|
||||
rows_missing = math.floor( rows_missing/10);
|
||||
formspec = formspec..
|
||||
"list[current_name;main;1,"..tostring( rows_missing )..";10,"..tostring( 4-rows_missing )..";0]";
|
||||
end
|
||||
|
||||
-- label each row with its number
|
||||
for i=1, 4 do
|
||||
formspec = formspec..
|
||||
"label[0.7," ..tostring( i-1.0 )..";"..tostring( (math.floor(start/10)+i)%(mobf_trader.LARGE_CHEST_SIZE/10) ).."]"..
|
||||
"label[10.9,"..tostring( i-1.0 )..";"..tostring( (math.floor(start/10)+i)%(mobf_trader.LARGE_CHEST_SIZE/10) ).."]";
|
||||
end
|
||||
|
||||
-- show buttons for quick access to sets of 4 rows each (kind of like a page)
|
||||
for i=1,10 do
|
||||
formspec = formspec..
|
||||
"button["..tostring( i*0.8 +1.6)..",4.2;1.0,0.5;"..tostring( (i-1)*40 )..";"..tostring( (i-1)*4+1 ).." - "..tostring((i*4)).."]";
|
||||
end
|
||||
return formspec;
|
||||
end
|
||||
|
||||
|
||||
mobf_trader.large_chest_statistic = function( pos )
|
||||
local meta = minetest.get_meta( pos );
|
||||
local self = {};
|
||||
-- we need to supply the counting function with an inventory location
|
||||
self.trader_inv = meta:get_inventory();
|
||||
-- ..so that the counting function in mob_trading can do the counting
|
||||
local counted = mob_trading.count_trader_inv( self )
|
||||
local formspec = 'size[12,11]'..
|
||||
'label[5,10.0;Content summed up]'..
|
||||
'button[3.5,10.2;1.0,0.5;1;Back]'..
|
||||
'button[7.5,10.2;1.0,0.5;1;Back]';
|
||||
local i = 0; -- offset
|
||||
-- the chest contains v pieces of item k - now display that
|
||||
for k,v in pairs( counted ) do
|
||||
if( k and k~="" and minetest.registered_items[ k ] and i<120) then
|
||||
formspec = formspec..
|
||||
'item_image['..tostring(i%12)..','..tostring( math.floor(i/12)+1)..';1.0,1.0;'..minetest.formspec_escape( k )..']'..
|
||||
'label['..(tostring(i%12)+0.5)..','..tostring( math.floor(i/12)+1+0.4)..';'..tostring( v )..'x]';
|
||||
i = i+1;
|
||||
end
|
||||
end
|
||||
-- show free inventory slot
|
||||
if( counted and counted[""] ) then
|
||||
formspec = formspec..
|
||||
'label[10,10.0;Free slots: '..tostring( counted[""] )..']';
|
||||
end
|
||||
return formspec;
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- players with the spawn_mob priv can own an unlimited number of mobs
|
||||
mobf_trader.request_trader = function( pos, player, fields )
|
||||
local meta = minetest.get_meta( pos );
|
||||
local owner = meta:get_string( 'owner' );
|
||||
local pname = player:get_player_name();
|
||||
local formspec = 'size[12,11]'..
|
||||
'abel[5,10.0;Request Trader]'..
|
||||
'button[5.0,10.2;1.0,0.5;1;Back]'..
|
||||
'textarea[3,7;6,2.5;info;;';
|
||||
if( not( owner ) or owner ~= pname ) then
|
||||
return formspec..'Only the owner of this chest, namely '..tostring( owner )..', may request traders.]';
|
||||
end
|
||||
|
||||
local mobs = mob_basics.mob_id_list_by_player( pname, 'trader' );
|
||||
if( #mobs >= mobf_trader.MAX_TRADER_PER_PLAYER and not( minetest.check_player_privs(pname, {mob_basics_spawn=true}))) then
|
||||
return formspec..'You are only allowed to have up to '..tostring( mobf_trader.MAX_TRADER_PER_PLAYER )..' traders '..
|
||||
' (you have '..tostring( #mobs )..' currently).]';
|
||||
end
|
||||
formspec = formspec..'You currently employ '..tostring( #mobs )..' traders ('..tostring( mobf_trader.MAX_TRADER_PER_PLAYER )..' allowed).\n';
|
||||
|
||||
mobs = mob_basics.mob_id_list_by_player( pname, nil );
|
||||
if( #mobs >= mobf_trader.MAX_MOBS_PER_PLAYER and not( minetest.check_player_privs(pname, {mob_basics_spawn=true}))) then
|
||||
return formspec..'You are only allowed to have up to '..tostring( mobf_trader.MAX_MOBS_PER_PLAYER )..' mobs'..
|
||||
' (you have '..tostring( #mobs )..' currently).]';
|
||||
end
|
||||
formspec = formspec..'And you do have '..tostring( #mobs )..' mobs alltogether ('..tostring( mobf_trader.MAX_MOBS_PER_PLAYER )..' allowed).\n';
|
||||
|
||||
|
||||
-- hire a new trader
|
||||
if( fields and fields.hire_trader ) then
|
||||
local inv = meta:get_inventory();
|
||||
if( not( inv ) or not( inv:contains_item('main', mobf_trader.TRADER_PRICE ))) then
|
||||
return formspec..'\n\nPlease place the requested price into the chest first!\n'..
|
||||
'You have to pay it once per trader.';
|
||||
end
|
||||
|
||||
-- remove the price
|
||||
inv:remove_item( 'main', mobf_trader.TRADER_PRICE );
|
||||
-- place a trader on top of the chest
|
||||
mob_basics.spawn_mob( {x=pos.x, y=(pos.y+1), z=pos.z}, 'individual', pname, 'mobf_trader:trader', 'trader', true );
|
||||
return formspec..'\n\nCongratulations! You now employ a new trader.]';
|
||||
end
|
||||
|
||||
-- show price information for a new trader
|
||||
local price_stack = ItemStack( mobf_trader.TRADER_PRICE );
|
||||
formspec = formspec..'\nHiring a trader will cost you the items shown above.\n'..
|
||||
'In order to actually hire one, place those items in this chest\n'..
|
||||
'and click on the price above.]'..
|
||||
'label[5.0,2.9;Price:]'..
|
||||
'item_image_button[5.0,3.5;1,1;'..tostring( price_stack:get_name() )..';hire_trader;]'..
|
||||
'label[5.5,3.9;'..tostring( price_stack:get_count() )..'x]';
|
||||
return formspec;
|
||||
end
|
||||
|
||||
|
||||
-- unfortionately, this only works with a dely
|
||||
mobf_trader.give_chest_back = function( player )
|
||||
if( not( player )) then
|
||||
return;
|
||||
end
|
||||
local inv = player:get_inventory();
|
||||
local rest = inv:add_item( 'main', "mobf_trader:large_chest 1" );
|
||||
if( not( rest ) or rest:get_count()==0) then
|
||||
minetest.chat_send_player( player:get_player_name(),'Your large storage chest for traders has been returned to you.');
|
||||
else
|
||||
minetest.chat_send_player( player:get_player_name(),'Failed to return your large storage chest for traders to you.');
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- this is basically a copy of default:chest_locked - except that it has several times the inventory size
|
||||
minetest.register_node("mobf_trader:large_chest", {
|
||||
description = "Large Storage Chest for Traders",
|
||||
tiles = {"default_chest_top.png^default_book.png", "default_chest_top.png^default_book.png", "default_chest_side.png^default_book.png",
|
||||
"default_chest_side.png^default_book.png", "default_chest_side.png^default_book.png", "default_chest_lock.png^default_book.png"},
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2,oddly_breakable_by_hand=2},
|
||||
legacy_facedir_simple = true,
|
||||
is_ground_content = false,
|
||||
after_place_node = function(pos, placer)
|
||||
local other_chests = minetest.find_nodes_in_area(
|
||||
{x=pos.x-1, y=pos.y-1, z=pos.z-1},
|
||||
{x=pos.x+1, y=pos.y+1, z=pos.z+1},
|
||||
mob_trading.KNOWN_LOCKED_CHESTS );
|
||||
-- the chest itself will be found - so we have to look for "more than one"
|
||||
if( other_chests and #other_chests > 1 ) then
|
||||
if( placer ) then
|
||||
minetest.chat_send_player( placer:get_player_name(),
|
||||
'Error: The large storage chest for traders needs to keep a distance of at least 1 block to all other locked chests.');
|
||||
minetest.after( 1, mobf_trader.give_chest_back, placer );
|
||||
end
|
||||
minetest.remove_node( pos );
|
||||
return;
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("owner", placer:get_player_name() or "")
|
||||
meta:set_string("infotext", "Large Storage Chest for Traders (owned by "..
|
||||
meta:get_string("owner")..")")
|
||||
end,
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("infotext", "Large Storage Chest for Traders")
|
||||
meta:set_string("owner", "")
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("main", mobf_trader.LARGE_CHEST_SIZE) -- 10x the inventory space of a normal locked chest
|
||||
meta:set_string('formspec',mobf_trader.large_chest_formspec( 0, nil ));
|
||||
end,
|
||||
can_dig = function(pos,player)
|
||||
local meta = minetest.get_meta(pos);
|
||||
local inv = meta:get_inventory()
|
||||
meta:set_string('formspec',mobf_trader.large_chest_formspec( 0, nil ));
|
||||
if( meta:get_string('owner') and meta:get_string('owner')~='' and player:get_player_name() ~= meta:get_string("owner")) then
|
||||
return false
|
||||
end
|
||||
return inv:is_empty("main");
|
||||
end,
|
||||
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if( meta:get_string('owner') and player:get_player_name() ~= meta:get_string("owner")) then
|
||||
return 0
|
||||
end
|
||||
return count
|
||||
end,
|
||||
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if( meta:get_string('owner') and player:get_player_name() ~= meta:get_string("owner")) then
|
||||
return 0
|
||||
end
|
||||
return stack:get_count()
|
||||
end,
|
||||
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if( meta:get_string('owner') and player:get_player_name() ~= meta:get_string("owner")) then
|
||||
return 0
|
||||
end
|
||||
return stack:get_count()
|
||||
end,
|
||||
on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||
minetest.log("action", player:get_player_name()..
|
||||
" moves stuff in mobf_trader:large_chest at "..minetest.pos_to_string(pos))
|
||||
end,
|
||||
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
minetest.log("action", player:get_player_name()..
|
||||
" moves stuff to mobf_trader:large_chest chest at "..minetest.pos_to_string(pos))
|
||||
end,
|
||||
on_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||
minetest.log("action", player:get_player_name()..
|
||||
" takes stuff from mobf_trader:large_chest at "..minetest.pos_to_string(pos))
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
-- only the owner can operate the formspec
|
||||
if( not( player ) or (meta:get_string('owner') and player:get_player_name() ~= meta:get_string("owner"))) then
|
||||
return 0
|
||||
end
|
||||
|
||||
if( fields and fields.statistic ) then
|
||||
meta:set_string('formspec',mobf_trader.large_chest_statistic( pos ));
|
||||
return;
|
||||
end
|
||||
|
||||
if( fields and (fields.request_trader or fields.hire_trader)) then
|
||||
meta:set_string('formspec', mobf_trader.request_trader( pos, player, fields ));
|
||||
return;
|
||||
end
|
||||
|
||||
for k,v in pairs( fields ) do
|
||||
local i = tonumber( k );
|
||||
if( i and i>-1 and i<mobf_trader.LARGE_CHEST_SIZE ) then
|
||||
|
||||
meta:set_string('formspec',mobf_trader.large_chest_formspec( i, player ));
|
||||
return;
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'mobf_trader:large_chest',
|
||||
recipe = {
|
||||
{'default:chest_locked', 'default:chest_locked', 'default:chest_locked'},
|
||||
{'default:chest_locked', 'default:bookshelf', 'default:chest_locked'},
|
||||
{'default:chest_locked', 'default:chest_locked', 'default:chest_locked'},
|
||||
}
|
||||
})
|
||||
|
@ -1,892 +0,0 @@
|
||||
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Provides basic mob functionality:
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- * handles formspec input of a mob
|
||||
-- * allows configuration of the mob
|
||||
-- * adds spawn command
|
||||
-- * initializes a mob
|
||||
-- * helper functions (i.e. turn towards player)
|
||||
-- * data of *active* traders (those that stand around somewhere in the world; excluding those in
|
||||
-- inventories in players or chests) is stored
|
||||
------------------------------------------------------------------------------------------------------
|
||||
|
||||
minetest.register_privilege("mob_basics_spawn", { description = "allows to spawn mob_basic based mobs with a chat command (i.e. /trader)", give_to_singleplayer = false});
|
||||
|
||||
-- reserve namespace for basic mob operations
|
||||
mob_basics = {}
|
||||
|
||||
-- store information about the diffrent mobs
|
||||
mob_basics.mob_types = {}
|
||||
|
||||
-- if you want to add a new texture, do it here
|
||||
mob_basics.TEXTURES = {'kuhhaendler.png', 'bauer_in_sonntagskleidung.png', 'baeuerin.png', 'character.png', 'wheat_farmer_by_addi.png', 'tomatenhaendler.png', 'blacksmith.png',
|
||||
'holzfaeller.png' };
|
||||
-- further good looking skins:
|
||||
--mob_basics.TEXTURES = {'kuhhaendler.png', 'bauer_in_sonntagskleidung.png', 'baeuerin.png', 'character.png', 'wheat_farmer_by_addi.png',
|
||||
-- "pawel04z.png", "character.png", "skin_2014012302322877138.png",
|
||||
-- "6265356020613120.png","4535914155999232.png","6046371190669312.png","1280435.png"};
|
||||
|
||||
-- TODO: gather textures from installed skin mods?
|
||||
|
||||
|
||||
-- keep a list of all mobs that are handled by this mod
|
||||
mob_basics.known_mobs = {}
|
||||
|
||||
-- this is a list of the indices of mob_basics.known_mobs needed for the /moblist command
|
||||
mob_basics.mob_list = {};
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- Logging is important for debugging
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
mob_basics.log = function( msg, self, prefix )
|
||||
if( self==nil ) then
|
||||
minetest.log("action", '[mob_basics] '..tostring( msg ) );
|
||||
else
|
||||
minetest.log("action", '[mob_basics] '..tostring( msg )..
|
||||
' id:'..tostring( self[ prefix..'_id'] )..
|
||||
' typ:'..tostring( self[ prefix..'_typ'] or '?' )..
|
||||
' prefix:'..tostring( prefix or '?' )..
|
||||
' at:'..minetest.pos_to_string( self.object:getpos() )..
|
||||
' by:'..tostring( self[ prefix..'_owner'] )..'.');
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- Save mob data to a file
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- TODO: save and restore ought to be library functions and not implemented in each individual mod!
|
||||
mob_basics.save_data = function()
|
||||
|
||||
local data = minetest.serialize( mob_basics.known_mobs );
|
||||
local path = minetest.get_worldpath().."/mod_mob_basics.data";
|
||||
|
||||
local file = io.open( path, "w" );
|
||||
if( file ) then
|
||||
file:write( data );
|
||||
file:close();
|
||||
else
|
||||
print("[Mod mob_basics] Error: Savefile '"..tostring( path ).."' could not be written.");
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- restore data
|
||||
-- Note: At first start, there will be a complaint about missing savefile. That message can be ignored.
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
mob_basics.restore_data = function()
|
||||
|
||||
local path = minetest.get_worldpath().."/mod_mob_basics.data";
|
||||
|
||||
local file = io.open( path, "r" );
|
||||
if( file ) then
|
||||
local data = file:read("*all");
|
||||
mob_basics.known_mobs = minetest.deserialize( data );
|
||||
file:close();
|
||||
|
||||
-- this is also a good time to create a list of all mobs which is used for /moblist
|
||||
mob_basics.mob_list = {};
|
||||
for k,v in pairs( mob_basics.known_mobs ) do
|
||||
table.insert( mob_basics.mob_list, k );
|
||||
end
|
||||
else
|
||||
print("[Mod mob_basics] Error: Savefile '"..tostring( path ).."' not found.");
|
||||
end
|
||||
end
|
||||
|
||||
-- read information about known mob entities from a savefile
|
||||
-- (do this once at each startup)
|
||||
mob_basics.restore_data();
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- A new mob has been added or a mob has been changed (i.e. new trade goods added)
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
mob_basics.update = function( self, prefix )
|
||||
if( not( self )) then
|
||||
return;
|
||||
end
|
||||
-- make sure we save the current position
|
||||
self[ prefix..'_pos' ] = self.object:getpos();
|
||||
|
||||
local staticdata = self:get_staticdata();
|
||||
|
||||
-- deserialize to do some tests
|
||||
local staticdata_table = minetest.deserialize( staticdata );
|
||||
if( not( staticdata_table[ prefix..'_name'] )
|
||||
or not( staticdata_table[ prefix..'_id' ] )
|
||||
or not( staticdata_table[ prefix..'_typ' ] )) then
|
||||
return;
|
||||
end
|
||||
|
||||
-- if it is a new mob, register it in the list
|
||||
if( not( mob_basics.known_mobs[ staticdata_table[ prefix..'_id' ] ] )) then
|
||||
table.insert( mob_basics.mob_list, staticdata_table[ prefix..'_id' ] );
|
||||
end
|
||||
mob_basics.known_mobs[ staticdata_table[ prefix..'_id' ] ] = staticdata_table;
|
||||
|
||||
-- actually store the changed data
|
||||
mob_basics.save_data();
|
||||
--minetest.chat_send_player('singleplayer','UPDATING MOB '..tostring( self[ prefix..'_id'] ));
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- Data about mobs that where picked up and are stored in the player's inventory is not saved here;
|
||||
-- Those mobs need to be forgotten.
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
mob_basics.forget_mob = function( id )
|
||||
mob_basics.known_mobs[ id ] = nil;
|
||||
mob_basics.save_data();
|
||||
--minetest.chat_send_player('singleplayer','FORGETTING MOB '..tostring( id ));
|
||||
-- the mob does *not* get deleted out of mob_basics.known_mobs because that would screw up the list
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- return a list of all known mob types which use prefix
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
mob_basics.type_list_for_prefix = function( prefix )
|
||||
local list = {};
|
||||
if( not( prefix ) or not( mob_basics.mob_types[ prefix ] )) then
|
||||
return list;
|
||||
end
|
||||
for k,v in pairs( mob_basics.mob_types[ prefix ] ) do
|
||||
table.insert( list, k );
|
||||
end
|
||||
return list;
|
||||
end
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- return the mobs owned by pname
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- if prefix is nil, then all mobs owned by the player will be returned
|
||||
mob_basics.mob_id_list_by_player = function( pname, search_prefix )
|
||||
local res = {};
|
||||
|
||||
if( not( pname )) then
|
||||
return res;
|
||||
end
|
||||
for k,v in ipairs( mob_basics.mob_list ) do
|
||||
|
||||
local data = mob_basics.known_mobs[ v ];
|
||||
if( data ) then
|
||||
|
||||
local prefix = data['mob_prefix'];
|
||||
if( (not( search_prefix ) or search_prefix == prefix)
|
||||
and data[ prefix..'_owner']
|
||||
and data[ prefix..'_owner']==pname ) then
|
||||
table.insert( res, v );
|
||||
end
|
||||
end
|
||||
end
|
||||
return res;
|
||||
end
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- idea taken from npcf
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
mob_basics.find_mob_by_id = function( id, prefix )
|
||||
|
||||
if( not( id )) then
|
||||
return;
|
||||
end
|
||||
|
||||
for i, v in pairs( minetest.luaentities ) do
|
||||
if( v.object and v[ prefix..'_typ'] and v[ prefix..'_id'] and v[ prefix..'_id'] == id ) then
|
||||
return v;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- helper function that lets the mob turn towards a target; taken from npcf
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
mob_basics.get_face_direction = function(v1, v2)
|
||||
if v1 and v2 then
|
||||
if v1.x and v2.x and v1.z and v2.z then
|
||||
local dx = v1.x - v2.x
|
||||
local dz = v2.z - v1.z
|
||||
return math.atan2(dx, dz)
|
||||
end
|
||||
end
|
||||
end
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- turn towards the player
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
mob_basics.turn_towards_player = function( self, player )
|
||||
if( self.object and self.object.setyaw ) then
|
||||
self.object:setyaw( mob_basics.get_face_direction( self.object:getpos(), player:getpos() ));
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- the mobs can vary in height and width
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- create pseudoradom gaussian distributed numbers
|
||||
mob_basics.random_number_generator_polar = function()
|
||||
local u = 0;
|
||||
local v = 0;
|
||||
local q = 0;
|
||||
repeat
|
||||
u = 2 * math.random() - 1;
|
||||
v = 2 * math.random() - 1;
|
||||
q = u * u + v * v
|
||||
until( (0 < q) and (q < 1));
|
||||
|
||||
local p = math.sqrt(-2 * math.log(q) / q) -- math.log returns ln(q)
|
||||
return {x1 = u * p, x2 = v * p };
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- visual_size needs to be updated whenever changed or the mob is activated
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- called whenever changed/configured;
|
||||
-- called from the entity itself in on_activate;
|
||||
-- standard size is assumed to be 180 cm
|
||||
mob_basics.update_visual_size = function( self, new_size, generate, prefix )
|
||||
if( not( new_size ) or not( new_size.x )) then
|
||||
if( generate ) then
|
||||
local res = mob_basics.random_number_generator_polar();
|
||||
local width = 1.0+(res.x1/20.0);
|
||||
local height = 1.0+(res.x2/10.0);
|
||||
width = math.floor( width * 100 + 0.5 );
|
||||
height = math.floor( height * 100 + 0.5 );
|
||||
new_size = {x=(width/100.0), y=(height/100.0), z=(width/100.0)};
|
||||
else
|
||||
new_size = {x=1, y=1, z=1};
|
||||
end
|
||||
end
|
||||
if( not( self[ prefix..'_vsize'] ) or not(self[ prefix..'_vsize'].x)) then
|
||||
self[ prefix..'_vsize'] = {x=1, y=1, z=1};
|
||||
end
|
||||
self[ prefix..'_vsize'].x = new_size.x;
|
||||
self[ prefix..'_vsize'].y = new_size.y;
|
||||
self[ prefix..'_vsize'].z = new_size.z;
|
||||
self.object:set_properties( { visual_size = {x=self[ prefix..'_vsize'].x, y=self[ prefix..'_vsize'].y, z=self[ prefix..'_vsize'].z}});
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- configure a mob using a formspec menu
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
mob_basics.config_mob = function( self, player, menu_path, prefix, formname, fields )
|
||||
|
||||
local mob_changed = false; -- do we need to store the changes? There might be multiple changes in one go
|
||||
|
||||
-- change texture
|
||||
if( menu_path and #menu_path>3 and menu_path[2]=='config' and menu_path[3]=='texture' ) then
|
||||
local nr = tonumber( menu_path[4] );
|
||||
-- actually set the new texture
|
||||
if( nr and nr > 0 and nr <= #mob_basics.TEXTURES ) then
|
||||
self[ prefix..'_texture'] = mob_basics.TEXTURES[ nr ];
|
||||
mob_basics.update_texture( self, prefix, nil );
|
||||
end
|
||||
mob_changed = true;
|
||||
|
||||
-- change animation (i.e. sit, walk, ...)
|
||||
elseif( menu_path and #menu_path>3 and menu_path[2]=='config' and menu_path[3]=='anim' ) then
|
||||
self[ prefix..'_animation'] = menu_path[4];
|
||||
self.object:set_animation({x=self.animation[ self[ prefix..'_animation']..'_START'], y=self.animation[ self[ prefix..'_animation']..'_END']},
|
||||
self.animation_speed-5+math.random(10));
|
||||
mob_changed = true;
|
||||
end
|
||||
|
||||
|
||||
-- texture and animation are changed via buttons; the other options use input fields
|
||||
-- prepare variables needed for the size of the mob and the actual formspec
|
||||
local formspec = 'size[10,8]';
|
||||
fields['MOBheight'] = tonumber( fields['MOBheight']);
|
||||
fields['MOBwidth'] = tonumber( fields['MOBwidth']);
|
||||
|
||||
if( not( self[ prefix..'_vsize'] ) or not( self[ prefix..'_vsize'].x )) then
|
||||
self[ prefix..'_vsize'] = {x=1,y=1,z=1};
|
||||
end
|
||||
-- rename a mob
|
||||
if( fields['MOBname'] and fields['MOBname'] ~= "" and fields['MOBname'] ~= self[ prefix..'_name'] ) then
|
||||
|
||||
if( string.len(fields['MOBname']) < 2 or string.len(fields['MOBname']) > 40 ) then
|
||||
minetest.chat_send_player( player:get_player_name(),
|
||||
"Sorry. This name is not allowed. The name has to be between 2 and 40 letters long.");
|
||||
elseif( not( fields['MOBname']:match("^[A-Za-z0-9%_%-% ]+$"))) then
|
||||
minetest.chat_send_player( player:get_player_name(),
|
||||
"Sorry. The name may only contain letters, numbers, _, - and blanks.");
|
||||
elseif( minetest.check_player_privs( fields['MOBname'], {shout=true})) then
|
||||
minetest.chat_send_player( player:get_player_name(),
|
||||
"Sorry. The name may not be the same as that one of a player.");
|
||||
else
|
||||
minetest.chat_send_player( player:get_player_name(),
|
||||
'Your mob has been renamed from \"'..tostring( self[ prefix..'_name'] )..'\" to \"'..
|
||||
fields['MOBname']..'\".');
|
||||
self[ prefix..'_name'] = fields['MOBname'];
|
||||
formspec = formspec..'label[3.0,1.5;Renamed successfully.]';
|
||||
mob_changed = true;
|
||||
end
|
||||
|
||||
-- height has to be at least halfway reasonable
|
||||
elseif( fields['MOBheight'] and fields['MOBheight']>20 and fields['MOBheight']<300
|
||||
and (fields['MOBheight']/180.0)~=self[ prefix..'_vsize'].y ) then
|
||||
|
||||
local new_height = math.floor((fields['MOBheight']/1.8) +0.5)/100.0;
|
||||
mob_basics.update_visual_size( self, {x=self[ prefix..'_vsize'].x, y=new_height, z=self[ prefix..'_vsize'].z}, false, prefix );
|
||||
formspec = formspec..'label[3.0,1.5;Height changed to '..tostring( self[ prefix..'_vsize'].y*180)..' cm.]';
|
||||
mob_changed = true;
|
||||
|
||||
-- width (x and z direction) has to be at least halfway reasonable
|
||||
elseif( fields['MOBwidth'] and fields['MOBwidth']>50 and fields['MOBwidth']<150
|
||||
and (fields['MOBwidth']/100.0)~=self[ prefix..'_vsize'].x ) then
|
||||
|
||||
local new_width = math.floor(fields['MOBwidth'] +0.5)/100.0;
|
||||
mob_basics.update_visual_size( self, {x=new_width, y=self[ prefix..'_vsize'].y, z=new_width}, false, prefix );
|
||||
formspec = formspec..'label[3.0,1.5;Width changed to '..tostring( self[ prefix..'_vsize'].x*100)..'%.]';
|
||||
mob_changed = true;
|
||||
end
|
||||
|
||||
-- save only if there where any actual changes
|
||||
if( mob_changed ) then
|
||||
mob_basics.update( self, prefix );
|
||||
end
|
||||
|
||||
local npc_id = self[ prefix..'_id'];
|
||||
formspec = formspec..
|
||||
'label[3.0,0.0;Configure your mob]'..
|
||||
'label[0.0,0.5;Activity:]'..
|
||||
'button[1.5,0.6;1,0.5;'..npc_id..'_config_anim_stand;*stand*]'..
|
||||
'button[2.5,0.6;1,0.5;'..npc_id..'_config_anim_sit;*sit*]'..
|
||||
'button[3.5,0.6;1,0.5;'..npc_id..'_config_anim_sleep;*sleep*]'..
|
||||
'button[4.5,0.6;1,0.5;'..npc_id..'_config_anim_walk;*walk*]'..
|
||||
'button[5.5,0.6;1,0.5;'..npc_id..'_config_anim_mine;*mine*]'..
|
||||
'button[6.5,0.6;1,0.5;'..npc_id..'_config_anim_walkmine;*w&m*]'..
|
||||
'label[0.0,1.0;Name of the mob:]'..
|
||||
'field[3.0,1.5;3.0,0.5;MOBname;;'..( self[ prefix..'_name'] or '?' )..']'..
|
||||
'label[5.8,1.0;Height:]'..
|
||||
'field[6.8,1.5;0.9,0.5;MOBheight;;'..( self[ prefix..'_vsize'].y*180)..']'..
|
||||
'label[7.2,1.0;cm]'..
|
||||
'label[5.8,1.5;Width:]'..
|
||||
'field[6.8,2.0;0.9,0.5;MOBwidth;;'..( (self[ prefix..'_vsize'].x*100) or '100' )..']'..
|
||||
'label[7.2,1.5;%]'..
|
||||
'label[0.0,1.6;Select a texture:]'..
|
||||
'button_exit[7.5,0.2;2,0.5;'..npc_id..'_take;Take]'..
|
||||
'button[7.5,0.7;2,0.5;'..npc_id..'_main;Back]'..
|
||||
'button[7.5,1.2;2,0.5;'..npc_id..'_config_store;Store]';
|
||||
|
||||
-- list available textures and mark the currently selected one
|
||||
for i,v in ipairs( mob_basics.TEXTURES ) do
|
||||
local label = '';
|
||||
if( v==self[ prefix..'_texture'] ) then
|
||||
label = 'current';
|
||||
end
|
||||
formspec = formspec..
|
||||
'image_button['..tostring(((i-1)%8)*1.1-1.0)..','..tostring(math.ceil((i-1)/8)*1.1+1.2)..
|
||||
';1.0,1.0;'..v..';'..npc_id..'_config_texture_'..tostring(i)..';'..label..']';
|
||||
end
|
||||
|
||||
-- show the resulting formspec to the player
|
||||
minetest.show_formspec( player:get_player_name(), formname, formspec );
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- formspec input received
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
mob_basics.form_input_handler = function( player, formname, fields)
|
||||
|
||||
if( formname and formname == "mob_basics:mob_list" ) then
|
||||
mob_basics.mob_list_formspec( player, formname, fields );
|
||||
return;
|
||||
end
|
||||
-- are we responsible to handle this input?
|
||||
if( not( formname ) or formname ~= "mob_trading:trader" ) then -- TODO
|
||||
return false;
|
||||
end
|
||||
|
||||
-- TODO: determine prefix from formname
|
||||
local prefix = 'trader';
|
||||
|
||||
-- all the relevant information is contained in the name of the button that has
|
||||
-- been clicked on: npc-id, selections
|
||||
for k,v in pairs( fields ) do
|
||||
|
||||
if( k == 'quit' and #fields==1) then
|
||||
return true;
|
||||
end
|
||||
|
||||
-- all values are seperated by _
|
||||
local menu_path = k:split( '_');
|
||||
if( menu_path and #menu_path > 0 ) then
|
||||
-- find the mob object
|
||||
local self = mob_basics.find_mob_by_id( menu_path[1], prefix );
|
||||
if( self ) then
|
||||
if( #menu_path == 1 ) then
|
||||
menu_path = nil;
|
||||
end
|
||||
|
||||
-- pick the mob up
|
||||
if( v=='Take' ) then
|
||||
if( mob_pickup and mob_pickup.pick_mob_up ) then
|
||||
-- all these mobs do have a unique id and are personalized, so the parameter before the last one is true
|
||||
-- we really want to pick up the mob - so the very last parameter is nil (not only a copy)
|
||||
mob_pickup.pick_mob_up( self, player, menu_path, prefix, true, nil);
|
||||
end
|
||||
return true;
|
||||
|
||||
-- configure mob (the mob turns towards the player and shows a formspec)
|
||||
elseif( v=='Config' or (#menu_path>1 and menu_path[2]=='config')) then
|
||||
mob_basics.turn_towards_player( self, player );
|
||||
mob_basics.config_mob( self, player, menu_path, prefix, formname, fields );
|
||||
return true;
|
||||
|
||||
-- trade with the mob (who turns towards the player and shows a formspec)
|
||||
else
|
||||
mob_basics.turn_towards_player( self, player );
|
||||
mob_trading.show_trader_formspec( self, player, menu_path, fields,
|
||||
mob_basics.mob_types[ prefix ][ self.trader_typ ].goods ); -- this is handled in mob_trading.lua
|
||||
return true;
|
||||
end
|
||||
return true;
|
||||
end
|
||||
end
|
||||
end
|
||||
return true;
|
||||
end
|
||||
|
||||
|
||||
-- make sure we receive the input
|
||||
minetest.register_on_player_receive_fields( mob_basics.form_input_handler );
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- initialize a newly created mob
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
mob_basics.initialize_mob = function( self, mob_name, mob_typ, mob_owner, mob_home_pos, prefix)
|
||||
|
||||
local typ_data = mob_basics.mob_types[ prefix ];
|
||||
|
||||
-- does this typ of mob actually exist?
|
||||
if( not( mob_typ ) or not( typ_data ) or not( typ_data[ mob_typ ] )) then
|
||||
mob_typ = 'default'; -- a default mob
|
||||
end
|
||||
|
||||
-- each mob may have an individual name
|
||||
if( not( mob_name )) then
|
||||
local i = math.random( 1, #typ_data[ mob_typ ].names );
|
||||
self[ prefix..'_name'] = typ_data[ mob_typ ].names[ i ];
|
||||
else
|
||||
self[ prefix..'_name'] = mob_name;
|
||||
end
|
||||
|
||||
if( typ_data[ mob_typ ].description ) then
|
||||
self.description = typ_data[ mob_typ ].description;
|
||||
else
|
||||
self.description = prefix..' '..self[ prefix..'_name'];
|
||||
end
|
||||
|
||||
|
||||
self[ prefix..'_typ'] = mob_typ; -- the type of the mob
|
||||
self[ prefix..'_owner'] = mob_owner; -- who spawned this guy?
|
||||
self[ prefix..'_home_pos'] = mob_home_pos; -- position of a control object (build chest, sign?)
|
||||
self[ prefix..'_pos'] = self.object:getpos(); -- the place where the mob was "born"
|
||||
self[ prefix..'_birthtime'] = os.time(); -- when was the npc first called into existence?
|
||||
self[ prefix..'_sold'] = {}; -- the trader is new and had no time to sell anything yet (only makes sense for traders)
|
||||
|
||||
-- select a random texture for the mob depending on the mob type
|
||||
if( typ_data[ mob_typ ].textures ) then
|
||||
local texture = typ_data[ mob_typ ].textures[ math.random( 1, #typ_data[ mob_typ ].textures )];
|
||||
self[ prefix..'_texture'] = texture;
|
||||
mob_basics.update_texture( self, prefix, nil );
|
||||
end
|
||||
mob_basics.update_visual_size( self, nil, true, prefix ); -- generate random visual size
|
||||
|
||||
-- create unique ID for the mob
|
||||
-- uniq_id: time in seconds, _, adress of entitty data, _, prefix
|
||||
local uniq_id = os.time()..'.'..string.sub( tostring(self), 8 )..'.'..prefix;
|
||||
|
||||
-- does a mob with that id exist already?
|
||||
if( mob_basics.known_mobs[ uniq_id ] ) then
|
||||
return false;
|
||||
end
|
||||
|
||||
-- mobs flying in the air would be odd
|
||||
self.object:setvelocity( {x=0, y= 0, z=0});
|
||||
self.object:setacceleration({x=0, y=-10, z=0});
|
||||
|
||||
|
||||
-- if there is already a mob with the same id, remove this one here in order to avoid duplicates
|
||||
if( mob_basics.find_mob_by_id( uniq_id, prefix )) then
|
||||
|
||||
self.object:remove();
|
||||
return false;
|
||||
else
|
||||
-- if the mob was already known under a temporary id
|
||||
if( self[ prefix..'_id'] ) then
|
||||
mob_basics.forget_mob( self[ prefix..'_id'] )
|
||||
end
|
||||
self[ prefix..'_id'] = uniq_id;
|
||||
mob_basics.update( self, prefix ); -- store the newly created mob
|
||||
return true;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- spawn a mob
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
mob_basics.spawn_mob = function( pos, mob_typ, player_name, mob_entity_name, prefix, initialize, no_messages )
|
||||
|
||||
if( not( no_messages )) then
|
||||
mob_basics.log('Trying to spawn '..tostring( mob_entity_name )..' of type '..tostring( mob_typ )..' at '..minetest.pos_to_string( pos ));
|
||||
end
|
||||
-- spawning from random_buildings
|
||||
if( not( mob_entity_name ) and not( prefix )) then
|
||||
mob_entity_name = 'mobf_trader:trader';
|
||||
prefix = 'trader';
|
||||
initialize = true;
|
||||
end
|
||||
-- slightly above the position of the player so that it does not end up in a solid block
|
||||
local object = minetest.env:add_entity( {x=pos.x, y=(pos.y+1.5), z=pos.z}, mob_entity_name );
|
||||
if( not( initialize )) then
|
||||
if( object ~= nil ) then
|
||||
local self = object:get_luaentity();
|
||||
mob_basics.update( self, prefix ); -- a mob has been added
|
||||
end
|
||||
return;
|
||||
end
|
||||
if object ~= nil then
|
||||
object:setyaw( -1.14 );
|
||||
local self = object:get_luaentity();
|
||||
-- initialize_mob does a mob_basics.update() already
|
||||
if( mob_basics.initialize_mob( self, nil, mob_typ, player_name, pos, prefix )) then
|
||||
|
||||
if( not( no_messages )) then
|
||||
mob_basics.log( 'Spawned mob', self, prefix );
|
||||
end
|
||||
self[ prefix..'_texture'] = mob_basics.TEXTURES[ math.random( 1, #mob_basics.TEXTURES )];
|
||||
self.object:set_properties( { textures = { self[ prefix..'_texture'] }});
|
||||
elseif( not( no_messages )) then
|
||||
mob_basics.log( 'Error: ID already taken. Can not spawn mob.', nil, prefix );
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- compatibility function for random_buildings
|
||||
mobf_trader_spawn_trader = mob_basics.spawn_mob;
|
||||
|
||||
if( minetest.get_modpath( "mobf_trader" ) and mobf_trader ) then
|
||||
mobf_trader.spawn_trader = mob_basics.spawn_mob;
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- handle input from a chat command to spawn a mob
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
mob_basics.handle_chat_command = function( name, param, prefix, mob_entity_name )
|
||||
|
||||
if( param == "" or param==nil) then
|
||||
minetest.chat_send_player(name,
|
||||
"Please supply the type of "..prefix.."! Supported: "..
|
||||
table.concat( mob_basics.type_list_for_prefix( prefix ), ', ')..'.' );
|
||||
return;
|
||||
end
|
||||
|
||||
if( not( mob_basics.mob_types[ prefix ] ) or not( mob_basics.mob_types[ prefix ][ param ] )) then
|
||||
minetest.chat_send_player(name,
|
||||
"A mob "..prefix.." of type \""..tostring( param )..
|
||||
"\" does not exist. Supported: "..
|
||||
table.concat( mob_basics.type_list_for_prefix( prefix ), ', ')..'.' );
|
||||
return;
|
||||
end
|
||||
|
||||
-- the actual spawning requires a priv; the type list as such may be seen by anyone
|
||||
if( not( minetest.check_player_privs(name, {mob_basics_spawn=true}))) then
|
||||
minetest.chat_send_player(name,
|
||||
"You need the mob_basics_spawn priv in order to spawn "..prefix..".");
|
||||
return;
|
||||
end
|
||||
|
||||
local player = minetest.env:get_player_by_name(name);
|
||||
local pos = player:getpos();
|
||||
|
||||
minetest.chat_send_player(name,
|
||||
"Placing "..prefix.." \'"..tostring( param )..
|
||||
"\' at your position: "..minetest.pos_to_string( pos )..".");
|
||||
mob_basics.spawn_mob( pos, param, name, mob_entity_name, prefix, true );
|
||||
end
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- It is sometimes helpful to be able to figure out where the traders and other mobs actually are
|
||||
-- and where the nearest one can be found.
|
||||
-- This is also useful for restoring mobs after a /clearallobjects.
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
minetest.register_chatcommand( 'moblist', {
|
||||
params = "<trader type>",
|
||||
description = "Shows a list of all mobs known to mob_basics.",
|
||||
privs = {},
|
||||
func = function(name, param)
|
||||
-- this function handles the sanity checks and the actual spawning
|
||||
return mob_basics.mob_list_formspec( minetest.get_player_by_name( name ), "mob_basics:mob_list", {});
|
||||
end
|
||||
});
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- show a list of existing mobs and their positions
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
mob_basics.mob_list_formspec = function( player, formname, fields )
|
||||
|
||||
if( not( player ) or fields.quit) then
|
||||
return
|
||||
end
|
||||
local pname = player:get_player_name();
|
||||
local ppos = player:getpos();
|
||||
|
||||
local search_for = nil;
|
||||
local id_found = nil;
|
||||
local col = 0;
|
||||
local text = '';
|
||||
if( fields and fields.mob_list and not( fields.back )) then
|
||||
|
||||
local row = 1;
|
||||
local selection = minetest.explode_table_event( fields.mob_list );
|
||||
if( selection ) then
|
||||
row = selection.row;
|
||||
col = selection.column;
|
||||
end
|
||||
if( not( row ) or row > #mob_basics.mob_list or row < 1 or not( mob_basics.known_mobs[ mob_basics.mob_list[ row ]])) then
|
||||
row = 1; -- default to first row
|
||||
end
|
||||
if( not( col ) or col < 1 or col > 10 ) then
|
||||
col = 0; -- default to no limitation
|
||||
end
|
||||
|
||||
local data = mob_basics.known_mobs[ mob_basics.mob_list[ row ]];
|
||||
if( not( data )) then
|
||||
data = {};
|
||||
end
|
||||
local prefix = data['mob_prefix'];
|
||||
if( not( prefix )) then
|
||||
prefix = 'trader';
|
||||
end
|
||||
local mpos = data[ prefix..'_pos'];
|
||||
if( not( prefix )) then
|
||||
prefix = 'trader';
|
||||
end
|
||||
if( col == 1 ) then
|
||||
search_for = math.ceil( math.sqrt(((ppos.x-mpos.x)*(ppos.x-mpos.x))
|
||||
+ ((ppos.y-mpos.y)*(ppos.y-mpos.y))
|
||||
+ ((ppos.z-mpos.z)*(ppos.z-mpos.z))));
|
||||
text = 'Mobs that are less than '..tostring( search_for )..' m away from you';
|
||||
elseif( col == 2 ) then -- same prefix
|
||||
search_for = prefix;
|
||||
text = 'Mobs of typ \''..tostring( search_for )..'\'';
|
||||
elseif( col == 3 ) then
|
||||
search_for = data[ prefix..'_typ'];
|
||||
text = 'Mobs of the subtyp \''..tostring( search_for )..'\'';
|
||||
-- 4, 5 and 6 store the mobs position
|
||||
elseif( col == 7 ) then
|
||||
search_for = data[ prefix..'_name'];
|
||||
text = 'Mobs with the name \''..tostring( search_for )..'\'';
|
||||
elseif( col == 8 ) then
|
||||
search_for = data[ prefix..'_owner'];
|
||||
text = 'Mobs belonging to player '..tostring(search_for);
|
||||
-- create a copy of the mob data and store that as a placeable item in the player's inventory
|
||||
elseif( col == 9 ) then
|
||||
|
||||
-- actually create a copy of the mob
|
||||
if( mob_pickup and mob_pickup.pick_mob_up ) then
|
||||
|
||||
local mobself = {};
|
||||
mobself.name = 'mobf_trader:trader'; -- TODO: there may be further types in the future
|
||||
mobself[ prefix..'_owner' ] = data[ prefix..'_owner'];
|
||||
-- all these mobs do have a unique id and are personalized, so the parameter before the last one is true
|
||||
-- the mob as such is not affected - we only want a copy (thus, last parameter is data)
|
||||
mob_pickup.pick_mob_up(mobself, player, menu_path, prefix, true, minetest.serialize( data ));
|
||||
end
|
||||
|
||||
id_found = data[ prefix..'_id']; -- show details about this particular mob
|
||||
search_for = nil;
|
||||
col = 0;
|
||||
-- visit the mob
|
||||
elseif( col == 10 ) then
|
||||
if( not( minetest.check_player_privs(pname, {teleport=true}))) then
|
||||
search_for = nil;
|
||||
col = 0;
|
||||
minetest.chat_send_player( pname, 'You do not have the teleport priv. Please walk there manually.');
|
||||
elseif( mpos and mpos.x and mpos.y and mpos.z ) then
|
||||
player:moveto( mpos, false ); -- teleport the player to the mob
|
||||
-- TODO: check if the mob is there; if not: restore it
|
||||
return;
|
||||
end
|
||||
-- else no search
|
||||
else
|
||||
search_for = nil;
|
||||
col = 0;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- selections in that list lead back to the main list
|
||||
local input_form_name = 'mob_list';
|
||||
if( search_for ) then
|
||||
input_form_name = 'mob_list_searched';
|
||||
end
|
||||
local formspec = 'size[12,12]'..
|
||||
'button_exit[4.0,0.5;2,0.5;quit;Quit]'..
|
||||
'tablecolumns[' ..
|
||||
-- 'text,align=left;'..
|
||||
'text,align=right;'..
|
||||
'text,align=center;'..
|
||||
'text,align=center;'..
|
||||
'text,align=right;'..
|
||||
'text,align=right;'..
|
||||
'text,align=right;'..
|
||||
'text,align=left;'..
|
||||
'text,align=left;'..
|
||||
'text,align=center;'..
|
||||
'text,align=center]'..
|
||||
'table[0.1,2.7;11.4,8.8;'..input_form_name..';';
|
||||
|
||||
-- the list mob_basic.mob_list contains the ids of all known mobs; they act as indices for mob_basics.known_mobs;
|
||||
-- important part: mob_basics.mob_list only gets extended but not shortened during the runtime of a server
|
||||
for k,v in ipairs( mob_basics.mob_list ) do
|
||||
|
||||
local data = mob_basics.known_mobs[ v ];
|
||||
if( data ) then
|
||||
|
||||
local prefix = data['mob_prefix'];
|
||||
if( not( prefix )) then
|
||||
prefix = 'trader';
|
||||
end
|
||||
|
||||
local mpos = data[ prefix..'_pos'];
|
||||
local distance = math.sqrt(((ppos.x-mpos.x)*(ppos.x-mpos.x))
|
||||
+ ((ppos.y-mpos.y)*(ppos.y-mpos.y))
|
||||
+ ((ppos.z-mpos.z)*(ppos.z-mpos.z)));
|
||||
|
||||
if( not( search_for ) -- list all mobs
|
||||
or( col==1 and search_for and search_for >= distance ) -- list all mobs less than this many m away
|
||||
or( col==2 and search_for and search_for==data['mob_prefix'] ) -- list all mobs with the same prefix
|
||||
or( col==3 and search_for and search_for==data[ prefix..'_typ' ] ) -- " " " typ (i.e. fruit traders)
|
||||
or( col==7 and search_for and search_for==data[ prefix..'_name' ] ) -- " " " name
|
||||
or( col==8 and search_for and search_for==data[ prefix..'_owner' ] ) -- " " " owner
|
||||
) then
|
||||
|
||||
formspec = formspec..
|
||||
-- tostring( data[ prefix..'_id' ])..','.. -- left aligned
|
||||
tostring( math.floor( distance ) )..','.. -- right-aligned
|
||||
tostring( data[ 'mob_prefix' ] or '')..','.. -- centered
|
||||
tostring( data[ prefix..'_typ' ] or '')..','..
|
||||
tostring( math.floor(data[ prefix..'_pos'].x ))..','.. -- right-aligned
|
||||
tostring( math.floor(data[ prefix..'_pos'].y ))..','..
|
||||
tostring( math.floor(data[ prefix..'_pos'].z ))..','..
|
||||
tostring( data[ prefix..'_name' ] or '')..','..
|
||||
tostring( data[ prefix..'_owner' ] or '')..','; -- left aligned
|
||||
if( data[ prefix..'_owner' ] and data[ prefix..'_owner'] == pname ) then
|
||||
formspec = formspec..'Copy';
|
||||
elseif( minetest.check_player_privs( pname, {mob_pickup=true})) then
|
||||
formspec = formspec..'Admin-Copy';
|
||||
end
|
||||
formspec = formspec..',Visit MOB,';
|
||||
-- Note: The fields _sold, _goods and _limit are specific to the trader; they cannot be displayed here.
|
||||
-- The values animation and vsize are of no intrest here (only when watching the trader).
|
||||
-- The values home_pos, birthtime, and id could be of intrest to a limited degree (at least for admins).
|
||||
-- texture is of intrest.
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
formspec = formspec..';]'..
|
||||
'tabheader[0.1,2.2;spalte;Dist,Type,Subtype,X,Y,Z,Name of Mob,Owner;;true;true]';
|
||||
if( search_for and text ) then
|
||||
formspec = formspec..
|
||||
'label[1.0,1.0;'..minetest.formspec_escape( text )..':]'..
|
||||
'button[7.0,1.5;2,0.5;back;Back]';
|
||||
end
|
||||
|
||||
-- display the formspec
|
||||
minetest.show_formspec( pname, "mob_basics:mob_list", formspec );
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- traders may have diffrent textures; if 3d_armor is installed, they show what they sell
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- TODO: add an option for mobs to statically wield something
|
||||
mob_basics.update_texture = function( self, prefix, trader_goods )
|
||||
|
||||
-- set a default fallback texture
|
||||
if( not( self[ prefix..'_texture'] )) then
|
||||
self[ prefix..'_texture'] = "character.png";
|
||||
end
|
||||
-- normal model
|
||||
if( mobf_trader.mesh ~= "3d_armor_character.b3d" ) then
|
||||
self.object:set_properties( { textures = { self[ prefix..'_texture'] }});
|
||||
-- we are done; no way to show the player what the mob is trying to sell
|
||||
return;
|
||||
end
|
||||
|
||||
-- we are dealing with wieldview now
|
||||
|
||||
-- fallback in case we find no image for the trade good
|
||||
local wield_texture = "3d_armor_trans.png";
|
||||
|
||||
-- get the goods the trader has to offer
|
||||
if( not( trader_goods )) then
|
||||
trader_goods = mob_trading.get_trader_goods( self, nil, nil);
|
||||
end
|
||||
if( not( trader_goods )) then
|
||||
trader_goods = {};
|
||||
end
|
||||
|
||||
local wield_offer = trader_goods[1];
|
||||
if( type(trader_goods[1])== 'table' ) then
|
||||
wield_offer = trader_goods[1][1];
|
||||
end
|
||||
-- update what the trader wields
|
||||
if( wield_offer
|
||||
and trader_goods
|
||||
and type(wield_offer)=='string' ) then
|
||||
|
||||
local stack = ItemStack( wield_offer );
|
||||
local stack_name = stack:get_name();
|
||||
if( stack_name and minetest.registered_items[ stack_name ] ) then
|
||||
wield_texture = minetest.registered_items[ stack_name ].wield_image;
|
||||
if( not( wield_texture ) or wield_texture=="") then
|
||||
wield_texture = minetest.registered_items[ stack_name ].inventory_image;
|
||||
end
|
||||
if( not( wield_texture ) or wield_texture=="") then
|
||||
wield_texture = minetest.registered_items[ stack_name ].tiles;
|
||||
if( type(wield_texture)=='table' ) then
|
||||
wield_texture = wield_texture[1];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- actually update the textures
|
||||
self.object:set_properties( { textures = {
|
||||
self[ prefix..'_texture'],
|
||||
"3d_armor_trans.png",
|
||||
wield_texture
|
||||
}});
|
||||
end
|
||||
|
||||
|
||||
-- TODO: show additional data
|
||||
-- trader_home_pos = self.trader_home_pos,
|
||||
-- trader_birthtime = self.trader_birthtime,
|
||||
-- trader_id = self.trader_id,
|
||||
-- trader_texture = self.trader_texture,
|
@ -1,288 +0,0 @@
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- Allows to pick up a mob, carry him around in the player's inventory, and place the mob back
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- uses mob_basics.find_mob_by_id and mob_basics.update_visual_size when available
|
||||
|
||||
-- TODO: add after_place, after_pickup?
|
||||
|
||||
-- the privilege allows admins/moderators to pick up and remove mobs which are undesired for whatever reason
|
||||
minetest.register_privilege("mob_pickup", { description = "allows to pick up mobs (which use mob_pickup) that are not your own", give_to_singleplayer = false});
|
||||
|
||||
|
||||
-- namespace used for functions and variables of this part of the mod
|
||||
mob_pickup = {}
|
||||
|
||||
-- find the right object for an entity so that a mob can be stored in the player's inventory after pickup
|
||||
mob_pickup.entity_to_object_name = {}
|
||||
|
||||
mob_pickup.pickup_success_msg = {}
|
||||
|
||||
mob_pickup.place_success_msg = {}
|
||||
|
||||
-- this can hold functions (in a table) which deny the pickup of a mob; structure:
|
||||
-- key: entity name
|
||||
-- value: function( self, player ) that gets an entity as parameter, returns '' on success; returns error message on failure
|
||||
mob_pickup.deny_pickup = {}
|
||||
-- if you want to deny placement - i.e. if there are already too many around or something like that; structure:
|
||||
-- key: entity name
|
||||
-- value: function( data, pos, player ) that gets an entity name as parameter, returns '' on success; returns error message on failure
|
||||
-- data is minetest.deserialize( item[ "metadata" ]); pos is the position where the mob is to be placed
|
||||
mob_pickup.deny_place = {}
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- We need to know something about the mobs and their corresponding items
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- the "functions" parameter may contain the deny_* functions
|
||||
mob_pickup.register_mob_for_pickup = function( entity_name, item_name, data )
|
||||
if( not( entity_name ) or not( item_name )) then
|
||||
return false;
|
||||
end
|
||||
-- has the mob been registered already?
|
||||
if( mob_pickup.entity_to_object_name[ entity_name ] ) then
|
||||
return false;
|
||||
end
|
||||
-- store which item the player will get when picking up the mob
|
||||
mob_pickup.entity_to_object_name[ entity_name ] = item_name;
|
||||
|
||||
-- for animals, pickup might be denied if the player does not wield the appropriate lasso/cage/watever
|
||||
if( data and data.deny_pickup ) then
|
||||
mob_pickup.deny_pickup[ entity_name ] = data.deny_pickup;
|
||||
end
|
||||
|
||||
if( data and data.deny_place ) then
|
||||
mob_pickup.deny_place[ entity_name ] = data.deny_place;
|
||||
end
|
||||
|
||||
if( data and data.pickup_success_msg ) then
|
||||
mob_pickup.pickup_success_msg[ entity_name ] = data.pickup_success_msg;
|
||||
else
|
||||
mob_pickup.pickup_success_msg[ entity_name ] =
|
||||
'Mob picked up. In order to use him again, just wield him and place him somewhere.';
|
||||
end
|
||||
|
||||
if( data and data.place_success_msg ) then
|
||||
mob_pickup.place_success_msg[ entity_name ] = data.place_success_msg;
|
||||
else
|
||||
mob_pickup.place_success_msg[ entity_name ] =
|
||||
'Mob placed.';
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- Log when someone picks up a mob or places one (in case there's debate of who removed or placed a mob)
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- The position of the mob is important here; also who picked him up (might not always be the owner)
|
||||
-- This is more or less a copy from mob_basics.log
|
||||
mob_pickup.log = function( msg, self, prefix )
|
||||
if( self==nil ) then
|
||||
minetest.log("action", '[mob_pickup] '..tostring( msg ) );
|
||||
else
|
||||
minetest.log("action", '[mob_pickup] '..tostring( msg )..
|
||||
' id:'..tostring( self[ prefix..'_id'] )..
|
||||
' typ:'..tostring( self[ prefix..'_typ'] or '?' )..
|
||||
' prefix:'..tostring( prefix or '?' )..
|
||||
' at:'..minetest.pos_to_string( self.object:getpos() )..
|
||||
' by:'..tostring( self[ prefix..'_owner'] )..'.');
|
||||
end
|
||||
end
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- pick the mob up and store in the players inventory;
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- the mob's data will be saved and he can be placed at another location
|
||||
-- NOTE: only mobs which are owned by the player can be picked up (unless the player has the mob_pickup priv)
|
||||
mob_pickup.pick_mob_up = function( self, player, menu_path, prefix, is_personalized, stored_data )
|
||||
|
||||
if( not( self ) or not( player ) or not(self.name)) then
|
||||
return;
|
||||
end
|
||||
|
||||
local pname = player:get_player_name();
|
||||
|
||||
-- check the privs again to be sure that there's no maliscious client input
|
||||
if( not( (self[ prefix..'_owner'] and self[ prefix..'_owner'] == pname)
|
||||
or minetest.check_player_privs( pname, {mob_pickup=true}))) then
|
||||
|
||||
minetest.chat_send_player( pname,
|
||||
'Error: You do not own this mob and do not have the mob_pickup priv. Taking failed.');
|
||||
return;
|
||||
end
|
||||
|
||||
|
||||
local staticdata = {};
|
||||
if( not( stored_data )) then
|
||||
staticdata = self:get_staticdata();
|
||||
else
|
||||
staticdata = stored_data;
|
||||
end
|
||||
|
||||
-- deserialize to do some tests
|
||||
local staticdata_table = minetest.deserialize( staticdata );
|
||||
if( not( staticdata_table[ prefix..'_name'] )
|
||||
or not( staticdata_table[ prefix..'_id' ] )
|
||||
or not( staticdata_table[ prefix..'_typ' ] )) then
|
||||
|
||||
minetest.chat_send_player( pname,
|
||||
'Error: This mob is misconfigured. Name, id or typ are missing. Please punch him in order to remove him.');
|
||||
return;
|
||||
end
|
||||
|
||||
-- is picking this mob up allowed?
|
||||
local deny = mob_pickup.deny_pickup[ self.name ];
|
||||
if( not( stored_data ) and deny ) then
|
||||
local deny_msg = deny( self, player );
|
||||
if( deny_msg ~= '') then
|
||||
minetest.chat_send_player( pname,
|
||||
deny_msg );
|
||||
return;
|
||||
end
|
||||
end
|
||||
|
||||
local mob_object_name = mob_pickup.entity_to_object_name[ self.name ];
|
||||
if( not( mob_object_name )) then
|
||||
minetest.chat_send_player( pname,
|
||||
'Error: This mob is unknown by mob_pickup. Taking failed.');
|
||||
return;
|
||||
end
|
||||
|
||||
local player_inv = player:get_inventory();
|
||||
-- no point in doing more if the player can't take the mob due to too few space
|
||||
if( not( player_inv:room_for_item("main", mob_object_name ))) then
|
||||
minetest.chat_send_player( pname,
|
||||
'Error: You do not have a free inventory slot for the mob. Taking failed.');
|
||||
return;
|
||||
end
|
||||
|
||||
|
||||
-- create a stack with a general mob item
|
||||
local mob_as_item = ItemStack( mob_object_name );
|
||||
|
||||
-- turn that stack data into a form we can manipulate
|
||||
local item = mob_as_item:to_table();
|
||||
-- the metadata field became available - it now stores the real data
|
||||
item[ "metadata" ] = staticdata;
|
||||
-- save the changed table
|
||||
mob_as_item:replace( item );
|
||||
|
||||
if( stored_data ) then
|
||||
minetest.chat_send_player( pname,
|
||||
'A copy of the mob has been dropped into your inventory.');
|
||||
-- put the copy of the mob into the players inventory
|
||||
player_inv:add_item( "main", mob_as_item );
|
||||
-- do not remove the mob
|
||||
return;
|
||||
end
|
||||
minetest.chat_send_player( pname,
|
||||
mob_pickup.pickup_success_msg[ self.name ] );
|
||||
|
||||
mob_pickup.log( pname..' picked up', self, prefix );
|
||||
|
||||
-- put the mob into the players inventory
|
||||
player_inv:add_item( "main", mob_as_item );
|
||||
-- remove the now obsolete mob
|
||||
self.object:remove();
|
||||
-- remove the mob from the stored list
|
||||
mob_basics.forget_mob( staticdata_table[ prefix..'_id' ] );
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- place the mob back into the world
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
-- called from on_place: on_place = function( itemstack, placer, pointed_thing )
|
||||
-- is_personalized has to be true for all mobs that carry metadata
|
||||
mob_pickup.place_mob = function( itemstack, placer, pointed_thing, prefix, entity_name, is_personalized )
|
||||
if( not( placer )) then
|
||||
return itemstack;
|
||||
end
|
||||
local pname = placer:get_player_name();
|
||||
if( not( pointed_thing ) or pointed_thing.type ~= "node" ) then
|
||||
minetest.chat_send_player( pname,
|
||||
'Error: No node selected for mob to spawn on. Cannot spawn him.');
|
||||
return itemstack;
|
||||
end
|
||||
|
||||
local data = {};
|
||||
|
||||
-- some mobs carry individual data (i.e. traders owned by players), wile others (i.e. animals) do not
|
||||
if( is_personalized ) then
|
||||
local item = itemstack:to_table();
|
||||
if( not( item[ "metadata"] ) or item["metadata"]=="" ) then
|
||||
minetest.chat_send_player( pname,
|
||||
'Error: Mob is not properly configured. Cannot spawn him.');
|
||||
return itemstack;
|
||||
end
|
||||
|
||||
data = minetest.deserialize( item[ "metadata" ]);
|
||||
if( not( data ) or data[ prefix..'_id'] == '') then
|
||||
minetest.chat_send_player( pname,
|
||||
'Error: Mob is misconfigured. Cannot spawn him.');
|
||||
return itemstack;
|
||||
end
|
||||
|
||||
-- if there is already a mob with the same id, do not create a new one
|
||||
if( mob_basics and mob_basics.find_mob_by_id( data[ prefix..'_id'], prefix )) then
|
||||
|
||||
minetest.chat_send_player( pname,
|
||||
'Error: A mob with that ID exists already. Please destroy this duplicate!');
|
||||
return itemstack;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local pos = minetest.get_pointed_thing_position( pointed_thing, above );
|
||||
|
||||
-- does this particular mob want to be placed there?
|
||||
local deny = mob_pickup.deny_place[ entity_name ];
|
||||
if( deny ) then
|
||||
local deny_msg = deny( data, pos, placer );
|
||||
if( deny_msg ~= '' ) then
|
||||
minetest.chat_send_player( pname,
|
||||
deny_msg );
|
||||
return itemstack;
|
||||
end
|
||||
end
|
||||
|
||||
-- spawn a mob
|
||||
local object = minetest.env:add_entity( {x=pos.x, y=(pos.y+1.5), z=pos.z}, entity_name );
|
||||
if( not( object )) then
|
||||
minetest.chat_send_player( pname,
|
||||
'Error: Spawning of mob failed.');
|
||||
return itemstack;
|
||||
end
|
||||
|
||||
object:setyaw( -1.14 );
|
||||
|
||||
|
||||
local self = object:get_luaentity();
|
||||
local tmp_id = self[ prefix..'_id'];
|
||||
|
||||
-- transfer the data to the mob object
|
||||
for k,v in pairs( data ) do
|
||||
if( type( k )=='string' ) then
|
||||
local help = k:split( '_');
|
||||
if( help and #help>1 and help[1]==prefix ) then
|
||||
self[ k ] = v;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self[ prefix..'_animation' ] = 'stand';
|
||||
|
||||
self.object:set_properties( { textures = { data[ prefix..'_texture'] }});
|
||||
if( mob_basics and mob_basics.update_visual_size ) then
|
||||
mob_basics.update_visual_size( self, data[ prefix..'_vsize'], false, prefix );
|
||||
end
|
||||
|
||||
-- the mob was placed at a new location
|
||||
self[ prefix..'_pos'] = pos;
|
||||
|
||||
minetest.chat_send_player( pname, mob_pickup.place_success_msg[ entity_name ]);
|
||||
|
||||
mob_pickup.log( pname..' placed', self, prefix );
|
||||
|
||||
mob_basics.forget_mob( tmp_id );
|
||||
mob_basics.update( self, prefix ); -- store data about this placed mob
|
||||
return '';
|
||||
end
|
@ -1,98 +0,0 @@
|
||||
|
||||
-- fallback function that populates mobf_trader.global_trade_offers with some random offers
|
||||
mobf_trader.init_global_trade_offers = function()
|
||||
local materials = {'wood','stone','steel','copper','bronze','mese','diamond'};
|
||||
local tools = {'default:pick_', 'default:axe_', 'default:shovel_', 'default:sword_'};
|
||||
for _,m in ipairs( materials ) do
|
||||
for _,t in ipairs( tools ) do
|
||||
for k=3,5 do
|
||||
mobf_trader.global_trade_offers[ #mobf_trader.global_trade_offers+1 ] = {
|
||||
offer = { t..m, 'default:steel_ingot '..math.random(1,20)},
|
||||
min = math.random(1,3),
|
||||
max = math.random(1,20)
|
||||
};
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- make sure the global trade offer list contains some values to choose from
|
||||
if( not( mobf_trader.global_trade_offers ) or #mobf_trader.global_trade_offers<1 ) then
|
||||
mobf_trader.init_global_trade_offers();
|
||||
end
|
||||
|
||||
|
||||
mobf_trader.trader_with_stock_add_random_offer = function( self, anz_new_offers, trader_goods )
|
||||
|
||||
if( not( self.trader_stock )) then
|
||||
self.trader_stock = {};
|
||||
end
|
||||
|
||||
if( not( trader_goods ) or #trader_goods<1) then
|
||||
trader_goods = mobf_trader.global_trade_offers;
|
||||
end
|
||||
|
||||
for i=1,anz_new_offers do
|
||||
-- select a random offer
|
||||
local nr = math.random(1,#trader_goods );
|
||||
-- avoid duplicate offers
|
||||
local found = false;
|
||||
for _,v in ipairs( self.trader_stock ) do
|
||||
if( v[1]==nr ) then
|
||||
found = true;
|
||||
end
|
||||
end
|
||||
-- give the trader a random amount of these trade goods
|
||||
if( not( found ) and trader_goods[ nr ]) then
|
||||
local stock_size = 1;
|
||||
if( trader_goods[ nr ].min and trader_goods[ nr ].max ) then
|
||||
stock_size = math.random( trader_goods[ nr ].min, trader_goods[ nr ].max );
|
||||
else
|
||||
-- TODO: make this configurable for each trader?
|
||||
stock_size = math.random(mobf_trader.RANDOM_STACK_MIN_SIZE,mobf_trader.RANDOM_STACK_MAX_SIZE);
|
||||
end
|
||||
self.trader_stock[ #self.trader_stock+1 ] = { nr, stock_size };
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- sets self.trader_stock
|
||||
mobf_trader.trader_with_stock_init = function( self, trader_goods )
|
||||
mobf_trader.trader_with_stock_add_random_offer( self, math.random(1,math.min(24, trader_goods)), trader_goods );
|
||||
end
|
||||
|
||||
-- return the list of goods represented by self.trader_stock
|
||||
mobf_trader.trader_with_stock_get_goods = function( self, player, trader_goods )
|
||||
if( not( trader_goods ) or #trader_goods<1) then
|
||||
trader_goods = mobf_trader.global_trade_offers;
|
||||
end
|
||||
|
||||
if( not( self.trader_stock )) then
|
||||
mobf_trader.trader_with_stock_init( self, trader_goods );
|
||||
end
|
||||
local goods = {};
|
||||
for i,v in ipairs( self.trader_stock ) do
|
||||
if( trader_goods[ v[1] ] ) then
|
||||
if( trader_goods[ v[1] ].offer ) then
|
||||
goods[#goods+1] = trader_goods[ v[1] ].offer;
|
||||
else
|
||||
goods[#goods+1] = trader_goods[ v[1] ];
|
||||
end
|
||||
end
|
||||
end
|
||||
return goods;
|
||||
end
|
||||
|
||||
-- can be used to give the trader new stock
|
||||
-- self.trader_goods are the goods the trader has on offer
|
||||
-- self.trader_sold is what he sold up until now (including the recent trade)
|
||||
-- self.trader_stock is how many times the trader is willing to do a particular trade until he runs out of stock
|
||||
mobf_trader.trader_with_stock_after_sale = function( self, player, menu_path, trade_details, trader_goods )
|
||||
-- traders without offers get a new random one;
|
||||
-- otherwise, getting a new offer is less likely the more offers the trader already has
|
||||
if( #self.trader_stock<1 or math.random(1,#self.trader_stock*2)==1 ) then
|
||||
mobf_trader.trader_with_stock_add_random_offer( self, math.random(1,2), trader_goods );
|
||||
end
|
||||
mob_basics.update_texture( self, "trader", nil );
|
||||
end
|
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 784 B |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 3.1 KiB |
@ -1,123 +0,0 @@
|
||||
-------------------------------------------------------------------
|
||||
-- Traders for Mobf animals
|
||||
-------------------------------------------------------------------
|
||||
-- adds traders for cows, sheep, chicken and "exotic" animals (=everything else)
|
||||
|
||||
-- trader for cows and steers
|
||||
if( minetest.get_modpath("animal_cow") ~= nil ) then
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"Trader of cows",
|
||||
"animal_cow",
|
||||
{
|
||||
{"animal_cow:cow 1", "default:mese_crystal 39", "moreores:gold_ingot 19"},
|
||||
{"animal_cow:steer 1", "default:mese_crystal 39", "moreores:gold_ingot 19"},
|
||||
{"animal_cow:baby_calf_f 1", "default:mese_crystal 19", "moreores:gold_ingot 9"},
|
||||
{"animal_cow:baby_calf_m 1", "default:mese_crystal 19", "moreores:gold_ingot 9"},
|
||||
|
||||
{"animalmaterials:milk 1", "default:apple 10", "default:leaves 29"},
|
||||
{"animalmaterials:meat_beef 1","default:steel_ingot 1", "default:leaves 29"},
|
||||
|
||||
{"animalmaterials:lasso 5", "default:steel_ingot 2", "default:leaves 39"},
|
||||
{"animalmaterials:net 1", "default:steel_ingot 2", "default:leaves 39"}, -- to protect the animals
|
||||
},
|
||||
{ "cow trader" },
|
||||
""
|
||||
);
|
||||
end
|
||||
|
||||
|
||||
-- trader for sheep and lambs
|
||||
if( minetest.get_modpath("animal_sheep") ~= nil ) then
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"Trader of sheep",
|
||||
"animal_sheep",
|
||||
{
|
||||
{"animal_sheep:sheep 1", "default:mese_crystal 19", "moreores:gold_ingot 19"},
|
||||
{"animal_sheep:lamb 1", "default:mese_crystal 9", "moreores:gold_ingot 5"},
|
||||
|
||||
{"wool:white 10", "default:steel_ingot 1", "default:leaves 29"},
|
||||
{"animalmaterials:meat_lamb 2","default:steel_ingot 1", "default:leaves 29"},
|
||||
{"animalmaterials:scissors 1", "default:steel_ingot 8", "default:mese_crystal 3"}, -- TODO: sell elsewhere as well?
|
||||
|
||||
{"animalmaterials:lasso 5", "default:steel_ingot 2", "default:leaves 39"},
|
||||
{"animalmaterials:net 1", "default:steel_ingot 2", "default:leaves 39"}, -- to protect the animals
|
||||
},
|
||||
{ "sheep trader" },
|
||||
""
|
||||
);
|
||||
end
|
||||
|
||||
|
||||
-- trader for chicken
|
||||
if( minetest.get_modpath("animal_chicken") ~= nil ) then
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"Trader of chicken",
|
||||
"animal_chicken",
|
||||
{
|
||||
{"animal_chicken:chicken 1", "default:apple 10", "default:coal_lump 20"},
|
||||
{"animal_chicken:rooster 1", "default:apple 5", "default:coal_lump 10"},
|
||||
{"animal_chicken:chick_f 1", "default:apple 4", "default:coal_lump 8"},
|
||||
{"animal_chicken:chick_m 1", "default:apple 2", "default:coal_lump 4"},
|
||||
|
||||
{"animalmaterials:feather 1", "default:leaves 1", "default:leaves 1"},
|
||||
{"animalmaterials:egg 2", "default:leaves 4", "default:leaves 4"},
|
||||
{"animalmaterials:meat_chicken 1","default:apple 6", "default:coal_lump 11"},
|
||||
|
||||
{"animalmaterials:lasso 5", "default:steel_ingot 2", "default:leaves 39"},
|
||||
{"animalmaterials:net 1", "default:steel_ingot 2", "default:leaves 39"}, -- to protect the animals
|
||||
},
|
||||
{ "chicken trader" },
|
||||
""
|
||||
);
|
||||
end
|
||||
|
||||
|
||||
-- trader for exotic animals
|
||||
exotic_animals = {};
|
||||
-- deers are expensive
|
||||
if( minetest.get_modpath("animal_deer") ~= nil ) then
|
||||
table.insert( exotic_animals, { "animal_deer:deer_m 1", "default:mese_crystal 49", "moreores:gold_ingot 39"});
|
||||
table.insert( exotic_animals, { "animalmaterials:meat_venison 1", "default:steel_ingot 5", "default:mese_crystal 1"});
|
||||
end
|
||||
-- rats are...not expensive
|
||||
if( minetest.get_modpath("animal_rat") ~= nil ) then
|
||||
table.insert( exotic_animals, { "animal_rat:rat 1", "default:coal_lump 1", "default:leaves 9"});
|
||||
end
|
||||
-- wolfs are sold only in the tamed version (the rest end up as fur)
|
||||
if( minetest.get_modpath("animal_wolf") ~= nil ) then
|
||||
table.insert( exotic_animals, { "animal_wolf:tamed_wolf 1", "default:mese_crystal 89", "moreores:gold_ingot 59"});
|
||||
table.insert( exotic_animals, { "animalmaterials:fur 1", "default:steel_ingot 5", "default:mese_crystal 3"});
|
||||
end
|
||||
-- ostrichs - great to ride on :-)
|
||||
if( minetest.get_modpath("mob_ostrich") ~= nil ) then
|
||||
table.insert( exotic_animals, { "mob_ostrich:ostrich_f 1", "default:mese_crystal 39", "moreores:gold_ingot 24"});
|
||||
table.insert( exotic_animals, { "mob_ostrich:ostrich_m 1", "default:mese_crystal 29", "moreores:gold_ingot 14"});
|
||||
table.insert( exotic_animals, { "animalmaterials:meat_ostrich 1", "default:steel_ingot 6", "default:mese_crystal 2"});
|
||||
table.insert( exotic_animals, { "animalmaterials:egg_big 1", "default:steel_ingot 1", "default:leaves 29"});
|
||||
end
|
||||
-- general tools for usage with animals
|
||||
if( minetest.get_modpath("animalmaterials") ~= nil ) then
|
||||
table.insert( exotic_animals, { "animalmaterials:scissors 1", "default:steel_ingot 8", "default:mese_crystal 3"});
|
||||
table.insert( exotic_animals, { "animalmaterials:lasso 5", "default:steel_ingot 2", "default:leaves 39"});
|
||||
table.insert( exotic_animals, { "animalmaterials:net 1", "default:steel_ingot 2", "default:leaves 39"});
|
||||
table.insert( exotic_animals, { "animalmaterials:saddle 1", "default:steel_ingot 19", "default:leaves 99"});
|
||||
end
|
||||
-- barns to breed animals
|
||||
if( minetest.get_modpath("barn") ~= nil ) then
|
||||
table.insert( exotic_animals, { "barn:barn_empty 1", "default:steel_ingot 1", "default:leaves 29"});
|
||||
table.insert( exotic_animals, { "barn:barn_small_empty 2", "default:steel_ingot 1", "default:leaves 29"});
|
||||
table.insert( exotic_animals, { "default:leaves 9", "default:steel_ingot 1", "default:coal_lump 5"});
|
||||
end
|
||||
|
||||
-- IMPORTANT: this trader has no more spaces left for further goods!
|
||||
-- add the trader
|
||||
if( #exotic_animals > 0 ) then
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"Trader of exotic animals",
|
||||
"animal_exotic",
|
||||
exotic_animals,
|
||||
{ "trader of exotic animals" },
|
||||
""
|
||||
);
|
||||
end
|
||||
|
@ -1,33 +0,0 @@
|
||||
--------------------------------------------
|
||||
-- Trader for clay, sand, desert_sand, glass, some glass items etc.
|
||||
--------------------------------------------
|
||||
|
||||
-- everyone has clay and sand; no mod dependencies for this trader!
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"Trader of clay",
|
||||
"clay",
|
||||
{
|
||||
{"default:clay 1", "default:dirt 10", "default:cobble 20"},
|
||||
{"default:brick 1", "default:dirt 49", "default:cobble 99"},
|
||||
{"default:sand 1", "default:dirt 2", "default:cobble 10"},
|
||||
{"default:sandstone 1", "default:dirt 10", "default:cobble 48"},
|
||||
{"default:sandstonebrick 1", "default:dirt 20", "default:cobble 99"},
|
||||
{"default:desert_sand 1", "default:dirt 2", "default:cobble 10"},
|
||||
{"default:glass 1", "default:dirt 10", "default:cobble 48"},
|
||||
|
||||
{"vessels:glass_bottle 2", "default:steel_ingot 1", "default:coal_lump 10"},
|
||||
|
||||
{"default:clay 10", "default:steel_ingot 2", "default:coal_lump 20"},
|
||||
{"default:brick 10", "default:steel_ingot 9", "default:mese_crystal 1"},
|
||||
{"default:sand 10", "default:steel_ingot 1", "default:coal_lump 20"},
|
||||
{"default:sandstone 10", "default:steel_ingot 2", "default:coal_lump 38"},
|
||||
{"default:sandstonebrick 10", "default:steel_ingot 4", "default:coal_lump 99"},
|
||||
{"default:desert_sand 10","default:steel_ingot 1", "default:coal_lump 20"},
|
||||
{"default:glass 10", "default:steel_ingot 2", "default:coal_lump 38"},
|
||||
|
||||
{"vessels:drinking_glass 2","default:steel_ingot 1", "default:coal_lump 10"},
|
||||
},
|
||||
{ "Toni" },
|
||||
""
|
||||
);
|
||||
|
@ -1,139 +0,0 @@
|
||||
------------------------------------------
|
||||
-- farming and farming_plus
|
||||
------------------------------------------
|
||||
-- adds traders for wheat, cotton and pumpkin (with farming);
|
||||
-- additionally trader for carrot, orange, potatoe, rhubarb, strawberry, tomatoe, banana, cacoa, rubber (with farming_plus)
|
||||
|
||||
local seeds = {}; -- there will be a special trader for seeds
|
||||
|
||||
if( minetest.get_modpath("farming") ~= nil ) then
|
||||
|
||||
for i,v in ipairs( {'wheat','cotton','pumpkin'}) do
|
||||
|
||||
local goods = {
|
||||
{"farming:"..v.."_seed 1", "farming:scarecrow", "farming:scarecrow_light 1"},
|
||||
{"farming:hoe_wood 1", "default:wood 10", "default:cobble 10"},
|
||||
};
|
||||
|
||||
table.insert( seeds, {"farming:"..v.."_seed 2", "default:dirt 20", "default:bucket_water", "default:steel_ingot 4", "default:leaves 99" });
|
||||
|
||||
if( v=='wheat') then
|
||||
table.insert( goods, {"farming:bread 1", "default:coal_lump 9", "default:apple 2"});
|
||||
table.insert( goods, {"farming:bread 10", "default:steel_ingot 4", "bucket:bucket_water 1"});
|
||||
table.insert( goods, {"farming:flour 5", "default:coal_lump 5", "default:apple 1"});
|
||||
table.insert( goods, {"farming:flour 10", "default:coal_lump 9", "default:apple 4"});
|
||||
elseif( v=='cotton') then
|
||||
table.insert( goods, {"farming:string 1", "default:coal_lump 3", "default:wood 8"} );
|
||||
table.insert( goods, {"farming:string 10", "default:steel_ingot 2", "default:chest_locked 1"});
|
||||
table.insert( goods, {"wool:white 1", "default:coal_lump 3", "default:wood 8"});
|
||||
table.insert( goods, {"wool:white 10"; "default:steel_ingot 2", "default:chest_locked 1"});
|
||||
elseif( v=='pumpkin') then
|
||||
table.insert( goods, {"farming:pumpkin 1", "default:coal_lump 1", "default:cobble 3"});
|
||||
table.insert( goods, {"farming:pumpkin 10", "default:coal_lump 18", "bucket:bucket_empty 1"});
|
||||
table.insert( goods, {"farming:pumpkin_bread 1", "default:coal_lump 9", "default:apple 2"});
|
||||
table.insert( goods, {"farming:pumpkin_bread 10", "default:steel_ingot 4", "bucket:bucket_empty 1"});
|
||||
table.insert( goods, {"farming:pumpkin_seed 1", "default:mese_crystal 9", "moreores:gold_ingot 5"});
|
||||
table.insert( goods, {"farming:pumpkin_face 1", "default:steel_ingot 4", "bucket:bucket_empty 1"});
|
||||
table.insert( goods, {"farming:pumpkin_face_light 1", "default:steel_ingot 4", "bucket:bucket_empty 1"});
|
||||
table.insert( goods, {"farming:big_pumpkin 1", "default:steel_ingot 4", "bucket:bucket_empty 1"});
|
||||
table.insert( goods, {"farming:scarecrow 1", "default:mese_crystal 99", "moreores:gold_ingot 48"});
|
||||
end
|
||||
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"farmer growing "..v,
|
||||
v.."_farmer",
|
||||
goods,
|
||||
{ v.." farmer" },
|
||||
""
|
||||
);
|
||||
end
|
||||
|
||||
|
||||
-- for each type of farming product, there is a specialized trader
|
||||
if( minetest.get_modpath("farming_plus") ~= nil ) then
|
||||
-- add traders for the diffrent versions of wood
|
||||
for i,v in ipairs( {'carrot', 'orange', 'potatoe', 'rhubarb', 'strawberry', 'tomato' }) do
|
||||
|
||||
table.insert( seeds, {"farming_plus:"..v.."_seed 2", "default:dirt 20", "default:bucket_water", "default:steel_ingot 4", "default:leaves 99" });
|
||||
|
||||
local goods = {
|
||||
{"farming_plus:"..v.."_item 1", "default:coal_lump 3", "default:wood 8"},
|
||||
{"farming_plus:"..v.."_item 10", "default:steel_ingot 2", "default:chest_locked 1"},
|
||||
{"farming_plus:"..v.."_seed 1", "farming:scarecrow", "farming:scarecrow_light 1"},
|
||||
{"farming:hoe_wood 1", "default:wood 10", "default:cobble 10"},
|
||||
};
|
||||
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"farmer growing "..v.."s", -- not always the right grammatical form
|
||||
v.."_farmer",
|
||||
goods,
|
||||
{ "farmer" },
|
||||
""
|
||||
);
|
||||
end
|
||||
|
||||
for i,v in ipairs( {'banana','cocoa','rubber'} ) do
|
||||
|
||||
table.insert( seeds, {"farming_plus:"..v.."_sapling", "default:dirt 40", "default:steel_ingot 16", "default:gold_ingot 2" });
|
||||
|
||||
local goods = {
|
||||
{"farming_plus:"..v.."_sapling 1", "default:mese_crystal 3", "bucket:bucket_water 1"},
|
||||
{"farming_plus:"..v.."_leaves 10", "default:coal_lump 1", "default:wood 4"},
|
||||
{"default:axe_wood 1", "default:coal_lump 3", "default:wood 9"},
|
||||
{"default:axe_stone 1", "default:steel_ingot 1", "bucket:bucket_empty 1"}, -- a bit expensive :-)
|
||||
};
|
||||
|
||||
if( v ~= 'rubber' ) then
|
||||
table.insert( goods, {"farming_plus:"..v.." 1", "default:coal_lump 4", "default:wood 8"} );
|
||||
table.insert( goods, {"farming_plus:"..v.." 10", "default:steel_ingot 1", "default:axe_stone 1"} );
|
||||
else
|
||||
table.insert( goods, {"farming_plus:bucket_rubber 1", "default:steel_ingot 19", "default:mese_crystal 8"} );
|
||||
end
|
||||
|
||||
if( v=='cocoa' ) then
|
||||
table.insert( goods, { "farming_plus:cocoa_bean 1", "default:coal_lump 3", "default:wood 6"});
|
||||
table.insert( goods, { "farming_plus:cocoa_bean 12", "default:steel_ingot 1", "default:axe_stone 1"});
|
||||
end
|
||||
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"farmer growing "..v.." trees",
|
||||
v.."_tree_farmer",
|
||||
goods,
|
||||
{ "farmer" },
|
||||
""
|
||||
);
|
||||
end
|
||||
|
||||
-- not sold here because they are no fruits: cotton and bucket_rubber; bread and pumpkin_bread are sold
|
||||
goods = {};
|
||||
for i,v in ipairs( {
|
||||
'carrot_item', 'orange_item', 'potatoe_item', 'rhubarb_item', 'strawberry_item', 'tomato_item',
|
||||
'banana', 'cocoa' }) do
|
||||
table.insert( goods, { "farming_plus:"..v.." 1", "default:coal_lump 5", "default:cobble 20"});
|
||||
end
|
||||
for i,v in ipairs( {'pumpkin', 'pumpkin_bread','bread' }) do
|
||||
table.insert( goods, { "farming:"..v.." 1", "default:coal_lump 5", "default:cobble 20"});
|
||||
end
|
||||
|
||||
table.insert( goods, { "default:apple 1", "default:coal_lump 5", "default:wood 6"});
|
||||
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"fruit trader",
|
||||
"fruit_trader",
|
||||
goods,
|
||||
{ "fruit trader" },
|
||||
""
|
||||
);
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if( seeds and #seeds > 0 ) then
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"trader specialized in seeds",
|
||||
"seeds",
|
||||
seeds,
|
||||
{ "Sebastian" },
|
||||
""
|
||||
);
|
||||
end
|
@ -1,35 +0,0 @@
|
||||
|
||||
if( minetest.get_modpath("flowers") ~= nil ) then
|
||||
|
||||
local flowers = {
|
||||
"flowers:rose",
|
||||
"flowers:tulip",
|
||||
"flowers:dandelion_yellow",
|
||||
"flowers:dandelion_white",
|
||||
"flowers:geranium",
|
||||
"flowers:viola",
|
||||
"default:junglegrass",
|
||||
"default:grass_1",
|
||||
"default:sapling",
|
||||
"default:junglesapling",
|
||||
"default:dry_shrub",
|
||||
}
|
||||
local goods = {};
|
||||
for i,v in ipairs( flowers ) do
|
||||
table.insert( goods, { v.." 3", "default:steel_ingot", "default:copper_ingot"});
|
||||
end
|
||||
|
||||
table.insert( goods, { "default:cactus 16", "default:steel_ingot", "default:copper_ingot"});
|
||||
table.insert( goods, { "default:papyrus 16", "default:steel_ingot", "default:copper_ingot"});
|
||||
table.insert( goods, { "default:seed_wheat 1", "default:steel_ingot", "default:copper_ingot"});
|
||||
table.insert( goods, { "default:seed_cotton 1", "default:steel_ingot", "default:copper_ingot"});
|
||||
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"flower trader selling plants",
|
||||
"flowers",
|
||||
goods,
|
||||
{ "Gert" },
|
||||
""
|
||||
);
|
||||
end
|
||||
|
@ -1,54 +0,0 @@
|
||||
--------------------------------------------
|
||||
-- Trader for miscelaneus items
|
||||
--------------------------------------------
|
||||
|
||||
-- the old mobf trader
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"Trader of miscelanous",
|
||||
"misc",
|
||||
{
|
||||
{ "default:mese 1", "default:dirt 99", "default:cobble 50"},
|
||||
{ "default:steel_ingot 1", "default:mese_crystal 5", "default:cobble 20"},
|
||||
{ "default:stone 5", "default:mese_crystal 1", "default:cobble 50"},
|
||||
{ "default:furnace 1", "default:mese_crystal 3", nil},
|
||||
{ "default:sword_steel 1", "default:mese_crystal 4", "default:stone 20"},
|
||||
{ "bucket:bucket_empty 1", "default:cobble 10", "default:stone 2"},
|
||||
{ "default:pick_mese 1", "default:mese_crystal 12", "default:stone 60"},
|
||||
{ "default:shovel_steel 1", "default:mese_crystal 2", "default:stone 10"},
|
||||
{ "default:axe_steel 1", "default:mese_crystal 2", "default:stone 22"},
|
||||
{ "default:torch 33", "default:mese_crystal 2", "default:stone 10"},
|
||||
{ "default:ladder 12", "default:mese_crystal 1", "default:stone 5"},
|
||||
{ "default:paper 12", "default:mese_crystal 2", "default:stone 10"},
|
||||
{ "default:chest 1", "default:mese_crystal 2", "default:stone 10"},
|
||||
},
|
||||
{ "Ali"},
|
||||
""
|
||||
);
|
||||
|
||||
|
||||
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"Trader",
|
||||
"default",
|
||||
{
|
||||
{ "default:mese 1", "default:iron_lump 30",},
|
||||
{ "doors:door_wood 1", "default:mese_crystal 1", "default:cobble 10"},
|
||||
{ "default:fence_wood 20", "default:mese_crystal 5", "default:cobble 25"},
|
||||
{ "animalmaterials:saddle 1", "default:mese 1", "default:cobble 50"},
|
||||
{ "default:sword_steel 1", "default:mese_crystal 4", "default:stone 20"},
|
||||
{ "default:iron_lump 1", "default:dirt 99", "default:cobble 50"},
|
||||
{ "default:pick_mese 1", "default:mese_crystal 12", "default:stone 60"},
|
||||
{ "default:shovel_steel 1", "default:mese_crystal 2", "default:stone 10"},
|
||||
{ "default:axe_steel 1", "default:mese_crystal 2", "default:stone 22"},
|
||||
{ "default:torch 33", "default:mese_crystal 2", "default:stone 10"},
|
||||
{ "default:ladder 12", "default:mese 1", "default:cobble 50"},
|
||||
{ "default:paper 12", "default:mese_crystal 2", "default:stone 10"},
|
||||
{ "default:chest_locked 1", "default:mese_crystal 5", "default:cobble 25"},
|
||||
{ "mob_archer:archer 1","default:mese_crystal 10",nil},
|
||||
{ "mob_guard:guard 1","default:mese_crystal 10",nil},
|
||||
{ "doors:door_steel 1","default:mese_crystal 3","default:cobble 20"},
|
||||
},
|
||||
{ "Kurt"},
|
||||
""
|
||||
);
|
||||
|
@ -1,93 +0,0 @@
|
||||
-------------------------------------------
|
||||
-- Traders for moretrees (and normal trees)
|
||||
--------------------------------------------
|
||||
-- without moretrees, you get only one lumberjack that sells default trees
|
||||
-- with moretrees, traders for all tree types are added as well: normal trees, birch, spruce, jungletree, fir, beech, apple_tree, oak, sequoia, palm, pine, willow, rubber_tree
|
||||
|
||||
-- sell normal wood - rather expensive...
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"Trader of common wood",
|
||||
"common_wood",
|
||||
{
|
||||
{"default:wood 4", "default:dirt 24", "default:cobble 24"},
|
||||
{"default:tree 4", "default:apple 2", "default:coal_lump 4"},
|
||||
{"default:tree 8", "default:pick_stone 1", "default:axe_stone 1"},
|
||||
{"default:tree 12", "default:cobble 80", "default:steel_ingot 1"},
|
||||
{"default:tree 36", "bucket:bucket_empty 1", "bucket:bucket_water 1"},
|
||||
{"default:tree 42", "default:axe_steel 1", "default:mese_crystal 4"},
|
||||
|
||||
{"default:sapling 1", "default:dirt 10", "default:cobble 10"},
|
||||
{"default:leaves 10", "default:dirt 10", "default:cobble 10"}
|
||||
},
|
||||
{ "lumberjack" },
|
||||
{"holzfaeller.png"}
|
||||
);
|
||||
|
||||
|
||||
-- not everyone has moretrees (though selling wood is one of the main purposes of this mod)
|
||||
if( minetest.get_modpath("moretrees") ~= nil ) then
|
||||
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"Trader of wood",
|
||||
"wood",
|
||||
{
|
||||
{"moretrees:birch_trunk 8", "default:cobble 80", "default:steel_ingot 1"},
|
||||
{"moretrees:spruce_trunk 8", "default:cobble 80", "default:steel_ingot 1"},
|
||||
{"moretrees:jungletree_trunk 8", "default:cobble 80", "default:steel_ingot 1"},
|
||||
{"moretrees:fir_trunk 8", "default:cobble 80", "default:steel_ingot 1"},
|
||||
{"moretrees:beech_trunk 8", "default:cobble 80", "default:steel_ingot 1"},
|
||||
{"moretrees:apple_tree_trunk 8", "default:cobble 80", "default:steel_ingot 1"},
|
||||
{"moretrees:oak_trunk 8", "default:cobble 80", "default:steel_ingot 1"},
|
||||
{"moretrees:sequoia_trunk 8", "default:cobble 80", "default:steel_ingot 1"},
|
||||
{"moretrees:palm_trunk 8", "default:cobble 80", "default:steel_ingot 1"},
|
||||
{"moretrees:pine_trunk 8", "default:cobble 80", "default:steel_ingot 1"},
|
||||
{"moretrees:willow_trunk 8", "default:cobble 80", "default:steel_ingot 1"},
|
||||
{"moretrees:rubber_tree_trunk 8", "default:cobble 80", "default:steel_ingot 1"},
|
||||
},
|
||||
{ "Woody" },
|
||||
{"holzfaeller.png"}
|
||||
);
|
||||
|
||||
|
||||
-- add traders for the diffrent versions of wood
|
||||
for i,v in ipairs( {'birch', 'spruce', 'jungletree', 'fir', 'beech', 'apple_tree', 'oak', 'sequoia', 'palm', 'pine', 'willow', 'rubber_tree' }) do
|
||||
|
||||
-- all trunk types cost equally much
|
||||
local goods = {
|
||||
{"moretrees:"..v.."_planks 4", "default:dirt 24", "default:cobble 24"},
|
||||
{"moretrees:"..v.."_trunk 4", "default:apple 2", "default:coal_lump 4"},
|
||||
{"moretrees:"..v.."_trunk 8", "default:pick_stone 1", "default:axe_stone 1"},
|
||||
{"moretrees:"..v.."_trunk 12", "default:cobble 80", "default:steel_ingot 1"},
|
||||
{"moretrees:"..v.."_trunk 36", "bucket:bucket_empty 1", "bucket:bucket_water 1"},
|
||||
{"moretrees:"..v.."_trunk 42", "default:axe_steel 1", "default:mese_crystal 4"},
|
||||
|
||||
{"moretrees:"..v.."_sapling 1", "default:mese 10", "default:steel_ingot 48"},
|
||||
{"moretrees:"..v.."_leaves 10", "default:cobble 1", "default:dirt 2"}
|
||||
};
|
||||
|
||||
-- sell the fruits of the trees (apples and coconuts have a slightly higher value than the rest)
|
||||
if( v=='oak' ) then
|
||||
table.insert( goods, { "moretrees:acorn 10", "default:cobble 10", "default:dirt 10"} );
|
||||
elseif( v=='palm' ) then
|
||||
table.insert( goods, { "moretrees:coconut 1", "default:cobble 10", "default:dirt 10"} );
|
||||
elseif( v=='spruce' ) then
|
||||
table.insert( goods, { "moretrees:spruce_cone 10", "default:cobble 10", "default:dirt 10"} );
|
||||
elseif( v=='pine' ) then
|
||||
table.insert( goods, { "moretrees:pine_cone 10", "default:cobble 10", "default:dirt 10"} );
|
||||
elseif( v=='fir' ) then
|
||||
table.insert( goods, { "moretrees:fir_cone 10", "default:cobble 10", "default:dirt 10"} );
|
||||
elseif( v=='apple_tree' ) then
|
||||
table.insert( goods, { "default:apple 1", "default:cobble 10", "default:dirt 10"} );
|
||||
end
|
||||
-- TODO: rubber_tree: sell rubber? (or rather do so in the farmingplus-trader?)
|
||||
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"Trader of "..( v or "unknown" ).." wood",
|
||||
v.."_wood",
|
||||
goods,
|
||||
{ "lumberjack" },
|
||||
{"holzfaeller.png"}
|
||||
);
|
||||
end
|
||||
end
|
||||
|
@ -1,18 +0,0 @@
|
||||
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
"miner selling ores",
|
||||
"ores",
|
||||
{
|
||||
{ "default:coal_lump", "default:tree", "default:wood 4", "default:stick 12", "default:apple 2" },
|
||||
{ "default:coal_lump 10", "default:tree 9", "default:wood 35", "farming:bread", "default:apple 18" },
|
||||
{ "default:torch 3", "default:tree 2", "default:wood 8", "default:apple 4"},
|
||||
{ "default:torch 12", "default:tree 6", "default:wood 25", "default:apple 11"},
|
||||
{ "default:iron_lump", "default:tree 19", "default:wood 75", "farming:bread 2", "default:apple 35"},
|
||||
{ "default:copper_lump", "default:tree 19", "default:wood 75", "farming:bread 2", "default:apple 35"},
|
||||
{ "default:gold_lump", "default:tree 40", "farming:bread 4", "default:apple 35"},
|
||||
{ "default:obsidian_shard 4", "default:tree 5", "default:wood 20","default:stick 75", "farming:bread", "default:apple 10" },
|
||||
},
|
||||
{ "Martin" },
|
||||
""
|
||||
);
|
||||
|
@ -1,565 +0,0 @@
|
||||
--------------------------------------------
|
||||
-- Trader for villages
|
||||
--------------------------------------------
|
||||
|
||||
-- general textures shared by the traders in the villages
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES = {'kuhhaendler.png', 'bauer_in_sonntagskleidung.png', 'character.png'};
|
||||
|
||||
-- the smith takes twice as much as he'll really need
|
||||
mobf_trader.price_smith = function( anz_iron, anz_copper, anz_stick )
|
||||
local price = {};
|
||||
if( anz_iron > 0 ) then
|
||||
table.insert( price, 'default:iron_lump '..tostring( anz_iron * 2 ) );
|
||||
end
|
||||
if( anz_copper > 0 ) then
|
||||
table.insert( price, 'default:copper_lump '..tostring( anz_copper * 2 ) );
|
||||
end
|
||||
if( anz_iron > 0 or anz_copper > 0 ) then
|
||||
table.insert( price, 'default:coal_lump '..tostring( (anz_iron + anz_copper) * 2 ));
|
||||
end
|
||||
if( anz_stick > 0 ) then
|
||||
table.insert( price, 'default:stick '..tostring( anz_stick * 2 ));
|
||||
end
|
||||
return price;
|
||||
end
|
||||
|
||||
-- a smith; does steel and bronze
|
||||
-- sells pick, axe, shovel, hoe and sword out of steel
|
||||
-- also sells blocks and ingots out of those materials
|
||||
-- also sells locked chests, buckets, steel doors, hatch, stovepipe, rails, steel bottle and scredriver
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'Blacksmith',
|
||||
'blacksmith',
|
||||
{
|
||||
|
||||
{ 'default:pick_steel', mobf_trader.price_smith( 3, 0, 2 ) },
|
||||
{ 'default:axe_steel', mobf_trader.price_smith( 3, 0, 2 ) },
|
||||
{ 'default:shovel_steel', mobf_trader.price_smith( 1, 0, 2 ) },
|
||||
{ 'farming:hoe_steel', mobf_trader.price_smith( 2, 0, 2 ) },
|
||||
{ 'default:sword_steel', mobf_trader.price_smith( 2, 0, 1 ) },
|
||||
{ 'screwdriver:screwdriver',mobf_trader.price_smith( 1, 0, 1 ) },
|
||||
{ 'cottages:hammer', mobf_trader.price_smith( 6, 0, 1 ) },
|
||||
|
||||
{ 'cottages:anvil', mobf_trader.price_smith( 7, 0, 1 ) },
|
||||
|
||||
{ 'default:steelblock', mobf_trader.price_smith( 9, 0, 0 ) },
|
||||
|
||||
{ 'default:steel_ingot', mobf_trader.price_smith( 1, 0, 0 ) },
|
||||
|
||||
{ 'default:chest_locked', {'default:tree 4', 'default:iron_lump 2', 'default:coal_lump 2'}},
|
||||
{ 'bucket:bucket_empty', mobf_trader.price_smith( 3, 0, 0 ) },
|
||||
{ 'doors:door_steel', mobf_trader.price_smith( 6, 0, 0 ) },
|
||||
{ 'cottages:hatch_steel', mobf_trader.price_smith( 2, 0, 0 ) },
|
||||
-- the stovepipe is too seldom needed, and there was one item too many offered
|
||||
-- { 'cottages:stovepipe', mobf_trader.price_smith( 1, 0, 0 ) },
|
||||
{ 'default:rail 15', mobf_trader.price_smith( 6, 0, 2 ) },
|
||||
{ 'vessels:steel_bottle', mobf_trader.price_smith( 1, 0, 0 ) },
|
||||
|
||||
{ 'animalmaterials:scissors',mobf_trader.price_smith(2, 0, 2 ) },
|
||||
|
||||
},
|
||||
{ 'Blacky','Simon'},
|
||||
{'blacksmith.png'}
|
||||
);
|
||||
|
||||
|
||||
-- copper/bronze is done by another guy (too much for one smith)
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'Bronze smith',
|
||||
'bronzesmith',
|
||||
{
|
||||
|
||||
{ 'default:pick_bronze', mobf_trader.price_smith( 3, 3, 2 ) },
|
||||
{ 'default:axe_bronze', mobf_trader.price_smith( 3, 3, 2 ) },
|
||||
{ 'default:shovel_bronze', mobf_trader.price_smith( 1, 1, 2 ) },
|
||||
{ 'farming:hoe_bronze', mobf_trader.price_smith( 2, 2, 2 ) },
|
||||
{ 'default:sword_bronze', mobf_trader.price_smith( 2, 2, 1 ) },
|
||||
|
||||
{ 'default:copperblock', mobf_trader.price_smith( 0, 9, 0 ) },
|
||||
{ 'default:bronzeblock', mobf_trader.price_smith( 9, 9, 0 ) },
|
||||
|
||||
{ 'default:copper_ingot', mobf_trader.price_smith( 0, 1, 0 ) },
|
||||
{ 'default:bronze_ingot', mobf_trader.price_smith( 1, 1, 0 ) },
|
||||
|
||||
},
|
||||
{ 'Charly','Bert'},
|
||||
{'blacksmith.png'}
|
||||
);
|
||||
|
||||
|
||||
-- the stonemason calculates his prices based on cobble, stone and sticks used;
|
||||
-- he takes wood instead of cobble because he's got a lot of cobble already and
|
||||
-- intends to either use the wood or trade it for other items
|
||||
-- (obtaining wood is roughly comparable to obtaining cobble; at least for players)
|
||||
mobf_trader.price_stonemason = function( anz_cobble, anz_stone, anz_stick )
|
||||
local price = {};
|
||||
if( anz_cobble > 0 ) then
|
||||
table.insert( price, 'default:wood '..tostring( anz_cobble * 2 ) );
|
||||
end
|
||||
if( anz_stone > 0 ) then
|
||||
table.insert( price, 'default:wood '..tostring( anz_stone * 2 ));
|
||||
-- cobble needs to be smelted in order to get stone
|
||||
table.insert( price, 'default:coal_lump '..tostring( anz_stone * 2 ));
|
||||
end
|
||||
if( anz_stick > 0 ) then
|
||||
table.insert( price, 'default:stick '..tostring( anz_stick * 2 ));
|
||||
end
|
||||
return price;
|
||||
end
|
||||
|
||||
|
||||
-- a stonemason (=Steinmetz)
|
||||
-- this one does NOT provide sandstone and such - that's the domain of the clay trader
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'Stonemason',
|
||||
'stonemason',
|
||||
{
|
||||
{ 'default:pick_stone', mobf_trader.price_stonemason( 3, 0, 2 ) },
|
||||
{ 'default:axe_stone', mobf_trader.price_stonemason( 3, 0, 2 ) },
|
||||
{ 'default:shovel_stone', mobf_trader.price_stonemason( 1, 0, 2 ) },
|
||||
{ 'farming:hoe_stone', mobf_trader.price_stonemason( 2, 0, 2 ) },
|
||||
{ 'default:sword_stone', mobf_trader.price_stonemason( 2, 0, 1 ) },
|
||||
|
||||
-- even a furnace is a bit of work
|
||||
{ 'default:furnace', {'default:tree 2', 'default:pick_steel' }},
|
||||
-- this is a useful and rather expensive item; it seperates harvested wheat into straw and seeds
|
||||
{ 'cottages:threshing_floor', {'default:tree 4', 'default:chest', 'default:chest_locked 2', 'default:pick_bronze' }},
|
||||
-- the mill allows to craft wheat seeds into flour
|
||||
{ 'cottages:handmill', {'default:tree 12', 'default:coal_lump 24', 'default:steel_ingot', 'default:pick_bronze' }},
|
||||
|
||||
-- stairs and slabs are sold in larger quantities
|
||||
{ 'stairs:stair_cobble 12', mobf_trader.price_stonemason(12, 0, 0 ) },
|
||||
{ 'stairs:stair_stone 12', mobf_trader.price_stonemason( 0,12, 0 ) },
|
||||
{ 'stairs:stair_sandstone 12', mobf_trader.price_stonemason( 0,48, 0 ) },
|
||||
{ 'stairs:stair_stonebrick 12',mobf_trader.price_stonemason( 0,48, 0 ) },
|
||||
|
||||
{ 'stairs:slab_cobble 24', mobf_trader.price_stonemason(12, 0, 0 ) },
|
||||
{ 'stairs:slab_stone 24', mobf_trader.price_stonemason( 0,12, 0 ) },
|
||||
{ 'stairs:slab_sandstone 24', mobf_trader.price_stonemason( 0,48, 0 ) },
|
||||
{ 'stairs:slab_stonebrick 24', mobf_trader.price_stonemason( 0,48, 0 ) },
|
||||
|
||||
},
|
||||
{ 'Metz'},
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
|
||||
-- TODO: a better name for this guy would be helpful
|
||||
-- all these items where too many for the stonemason; plus the stones themshelves are better sold by a miner
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'stoneminer',
|
||||
'stoneminer',
|
||||
{
|
||||
-- those items are needed in larger quantities
|
||||
{ 'default:stone 24', mobf_trader.price_stonemason( 0,24, 1 ) },
|
||||
{ 'default:mossycobble 12', mobf_trader.price_stonemason( 3,24, 0 ) },
|
||||
{ 'default:stonebrick 12', mobf_trader.price_stonemason( 0,24, 0 ) },
|
||||
{ 'default:desert_stone 12', mobf_trader.price_stonemason(12, 0, 1 ) },
|
||||
{ 'default:desert_stonebrick 12',mobf_trader.price_stonemason(24,0, 1 ) },
|
||||
{ 'default:gravel 12', mobf_trader.price_stonemason( 0, 2, 0 ) }, -- he probably has a grinder from technic at home :-)
|
||||
},
|
||||
{'Stoni'},
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
|
||||
-- woodworkers use wood and turn it into other useful stuff
|
||||
mobf_trader.price_woodworker = function( anz_wood, anz_tree, anz_stick )
|
||||
local price = {};
|
||||
if( anz_wood > 0 ) then
|
||||
table.insert( price, 'default:wood '..tostring( anz_wood * 2 ) );
|
||||
end
|
||||
if( anz_tree > 0 ) then
|
||||
table.insert( price, 'default:tree '..tostring( anz_tree * 2 ));
|
||||
end
|
||||
if( anz_stick > 0 ) then
|
||||
table.insert( price, 'default:stick '..tostring( anz_stick * 2 ));
|
||||
end
|
||||
return price;
|
||||
end
|
||||
|
||||
|
||||
-- carpenter (=Zimmerer)
|
||||
-- It is very unlikely that players want individual fences; thus, packages are sold
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'Carpenter, specialized in fences',
|
||||
'carpenter',
|
||||
{
|
||||
{ 'default:fence_wood 16', mobf_trader.price_woodworker( 0, 3, 0 ) },
|
||||
{ 'cottages:fence_small 24', mobf_trader.price_woodworker( 0, 3, 0 ) },
|
||||
{ 'cottages:fence_corner 4', mobf_trader.price_woodworker( 0, 1, 0 ) },
|
||||
{ 'cottages:fence_end 2', mobf_trader.price_woodworker( 0, 1, 0 ) },
|
||||
{ 'cottages:gate_closed', mobf_trader.price_woodworker( 0, 1, 0 ) },
|
||||
},
|
||||
{ 'Friedrich', 'Friedhelm' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
-- this one does wooden tools
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'Joiner, specialized in tools',
|
||||
'toolmaker',
|
||||
{
|
||||
{ 'default:pick_wood', mobf_trader.price_woodworker( 3, 0, 2 ) },
|
||||
{ 'default:axe_wood', mobf_trader.price_woodworker( 3, 0, 2 ) },
|
||||
{ 'default:shovel_wood', mobf_trader.price_woodworker( 1, 0, 2 ) },
|
||||
{ 'farming:hoe_wood', mobf_trader.price_woodworker( 2, 0, 2 ) },
|
||||
{ 'default:sword_wood', mobf_trader.price_woodworker( 2, 0, 1 ) },
|
||||
},
|
||||
{ 'Ted' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
-- joiner (=Schreiner, Tischler)
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'Joiner, specialized in doors',
|
||||
'doormaker',
|
||||
{
|
||||
{ 'doors:door_wood', mobf_trader.price_woodworker( 6, 0, 0 ) },
|
||||
{ 'cottages:hatch_wood', mobf_trader.price_woodworker( 2, 0, 0 ) },
|
||||
{ 'cottages:window_shutter_open', mobf_trader.price_woodworker( 2, 0, 0 ) },
|
||||
{ 'cottages:half_door 2', mobf_trader.price_woodworker( 7, 0, 0 ) },
|
||||
{ 'cottages:gate_closed', mobf_trader.price_woodworker( 2, 0, 0 ) },
|
||||
},
|
||||
{ 'Donald' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
-- this is done by a joiner as well..
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'Joiner, specialized in furniture',
|
||||
'furnituremaker',
|
||||
{
|
||||
{ 'cottages:bench', mobf_trader.price_woodworker( 0, 0, 4 ) },
|
||||
{ 'cottages:table', mobf_trader.price_woodworker( 1, 0, 1 ) },
|
||||
{ 'cottages:shelf', mobf_trader.price_woodworker( 2, 0, 6 ) },
|
||||
{ 'default:chest', mobf_trader.price_woodworker( 8, 0, 0 ) },
|
||||
{ 'default:bookshelf', {'default:book 3', 'default:wood 12'}},
|
||||
{ {'cottages:bed_head', 'cottages:bed_foot'}, {'wool:white 2', 'default:wood 4', 'default:stick 6'}},
|
||||
{ 'default:ladder 3', mobf_trader.price_woodworker( 0, 0, 7 ) },
|
||||
{ 'default:sign_wall 4', mobf_trader.price_woodworker( 6, 0, 1 ) },
|
||||
},
|
||||
{ 'Donald' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
-- a joiner who does ladders and staircases
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'Joiner, specialized in stairs',
|
||||
'stairmaker',
|
||||
{
|
||||
{ 'stairs:stair_wood 12', mobf_trader.price_woodworker(12, 0, 0 ) },
|
||||
{ 'stairs:stair_junglewood 12', mobf_trader.price_woodworker(12, 0, 0 ) },
|
||||
|
||||
{ 'stairs:slab_wood 24', mobf_trader.price_woodworker(12, 0, 0 ) },
|
||||
{ 'stairs:slab_junglewood 24', mobf_trader.price_woodworker(12, 0, 0 ) },
|
||||
|
||||
{ 'default:ladder 3', mobf_trader.price_woodworker( 0, 0, 7 ) },
|
||||
},
|
||||
{ 'Siegfried' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
|
||||
-- cooper (=Boettcher)
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'cooper',
|
||||
'cooper',
|
||||
{
|
||||
{ 'cottages:barrel', {'default:wood 10', 'default:steel_ingot 4'}},
|
||||
{ 'cottages:tub', {'default:wood 5', 'default:steel_ingot 2'}},
|
||||
},
|
||||
{ 'Balduin' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
|
||||
-- weelwright (=Wagner)
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'wheelwright',
|
||||
'wheelwright',
|
||||
{
|
||||
{ 'cottages:wagon_wheel', {'default:wood 4', 'default:stick 20', 'default:steel_ingot 2'}},
|
||||
},
|
||||
{ 'Werner' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
|
||||
-- saddler (=Sattler)
|
||||
-- most of these products are from animalmaterials
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'Saddler',
|
||||
'saddler',
|
||||
{
|
||||
{ 'cottages:sleeping_mat', {'wool:white', 'cottages:straw_mat 4'}},
|
||||
{ 'unified_inventory:bag_small 2', {'default:wood 8', 'default:stick 2'}},
|
||||
{ 'unified_inventory:bag_medium', {'wool:white 2', 'default:stick 2'}},
|
||||
{ 'unified_inventory:bag_large', {'wool:white 4', 'default:stick 3'}},
|
||||
{ 'animalmaterials:lasso', 'wool:white 8'},
|
||||
{ 'animalmaterials:net', 'wool:white 10'},
|
||||
{ 'animalmaterials:saddle', {'wool:white 5', 'default:sword_steel'}},
|
||||
},
|
||||
{ 'Sammy' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- roofer (=Dachdecker); although they tend to place that stuff on the roof and not create it...
|
||||
-- the actual receipes require diffrent dye-replacements (i.e. coal, dirt, clay lump), but that
|
||||
-- would be impractical here
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'Roofer',
|
||||
'roofer',
|
||||
{
|
||||
{ 'cottages:roof_straw 24', 'cottages:straw_mat 12'},
|
||||
{ 'cottages:roof_reet 24', 'default:papyrus 12'},
|
||||
{ 'cottages:roof_wood 24', mobf_trader.price_woodworker( 8, 0, 0 ) },
|
||||
{ 'cottages:roof_red 24', mobf_trader.price_woodworker( 8, 0, 0 ) },
|
||||
{ 'cottages:roof_black 24', mobf_trader.price_woodworker( 8, 0, 0 ) },
|
||||
{ 'cottages:roof_brown 24', mobf_trader.price_woodworker( 8, 0, 0 ) },
|
||||
{ 'cottages:roof_slate 24', mobf_trader.price_woodworker( 8, 0, 0 ) },
|
||||
|
||||
-- removed the roof connectors as those would be too many; left one so that all the items are aligned well
|
||||
{ 'cottages:roof_connector_straw 6',{'cottages:straw_mat 3', 'default:wood 1'} },
|
||||
-- { 'cottages:roof_connector_reet 6', {'default:papyrus 3', 'default:wood 1'} },
|
||||
-- { 'cottages:roof_connector_wood 6', mobf_trader.price_woodworker( 3, 0, 0 ) },
|
||||
-- { 'cottages:roof_connector_red 6', mobf_trader.price_woodworker( 3, 0, 0 ) },
|
||||
-- { 'cottages:roof_connector_black 6',mobf_trader.price_woodworker( 3, 0, 0 ) },
|
||||
-- { 'cottages:roof_connector_brown 6',mobf_trader.price_woodworker( 3, 0, 0 ) },
|
||||
-- { 'cottages:roof_connector_slate 6',mobf_trader.price_woodworker( 3, 0, 0 ) },
|
||||
|
||||
{ 'cottages:roof_flat_straw 6', 'cottages:straw_mat 6'},
|
||||
{ 'cottages:roof_flat_reet 6', 'default:papyrus 6'},
|
||||
{ 'cottages:roof_flat_wood 6', mobf_trader.price_woodworker( 2, 0, 0 ) },
|
||||
{ 'cottages:roof_flat_red 6', mobf_trader.price_woodworker( 2, 0, 0 ) },
|
||||
{ 'cottages:roof_flat_black 6', mobf_trader.price_woodworker( 2, 0, 0 ) },
|
||||
{ 'cottages:roof_flat_brown 6', mobf_trader.price_woodworker( 2, 0, 0 ) },
|
||||
{ 'cottages:roof_flat_slate 6', mobf_trader.price_woodworker( 2, 0, 0 ) },
|
||||
},
|
||||
{ 'Ronald', 'Robert' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- bread production:
|
||||
-- (anyone) digging wheat -> farming:wheat
|
||||
-- (anyone) farming:wheat -> farming:seed_wheat + cottages:straw_mat
|
||||
|
||||
-- miller: farming:seed_wheat -> farming:flour (same as the handmill)
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'miller',
|
||||
'miller',
|
||||
{
|
||||
{ 'farming:flour 10', 'farming:seed_wheat 15'},
|
||||
{ 'farming:flour 40', 'farming:seed_wheat 49'},
|
||||
{ 'farming:flour 90', 'farming:seed_wheat 99'},
|
||||
},
|
||||
{ 'Martin' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
|
||||
-- baker: farming:flour -> farming:bread (can be done in a furnace as well); also sells pies
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'baker',
|
||||
'baker',
|
||||
{
|
||||
{ 'farming:bread 6', {'farming:flour 10', 'default:coal_lump 3'}},
|
||||
{ 'bushes:blueberry_pie_slice', {'default:papyrus 2'}},
|
||||
|
||||
{ 'bushes:blackberry_pie_cooked', {'bushes:blackberry 9', 'default:coal_lump 2'}},
|
||||
{ 'bushes:blueberry_pie_cooked', {'bushes:blueberry 9', 'default:coal_lump 2'}},
|
||||
{ 'bushes:gooseberry_pie_cooked', {'bushes:gooseberry 9', 'default:coal_lump 2'}},
|
||||
{ 'bushes:mixed_berry_pie_cooked', {'bushes:blackberry 18', 'default:coal_lump 2'}},
|
||||
{ 'bushes:raspberry_pie_cooked', {'bushes:raspberry 9', 'default:coal_lump 2'}},
|
||||
{ 'bushes:strawberry_pie_cooked', {'bushes:strawberry 9', 'default:coal_lump 2'}},
|
||||
|
||||
{ 'farming:bread 34', {'farming:flour 49', 'default:coal_lump 12'}},
|
||||
{ 'farming:bread 80', {'farming:flour 90', 'default:coal_lump 20'}},
|
||||
|
||||
{ 'bushes:basket_blackberry', {'bushes:blackberry 24', 'default:coal_lump 2'}},
|
||||
{ 'bushes:basket_blueberry', {'bushes:blueberry 24', 'default:coal_lump 2'}},
|
||||
{ 'bushes:basket_gooseberry', {'bushes:gooseberry 24', 'default:coal_lump 2'}},
|
||||
{ 'bushes:basket_mixed_berry', {'bushes:blackberry 36', 'default:coal_lump 2'}},
|
||||
{ 'bushes:basket_raspberry', {'bushes:raspberry 24', 'default:coal_lump 2'}},
|
||||
{ 'bushes:basket_strawberry', {'bushes:strawberry 24', 'default:coal_lump 2'}},
|
||||
|
||||
},
|
||||
{ 'Ben', 'Berthold' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
|
||||
-- a teacher - sells paper and books (librarians are less likely to be found in villages)
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'teacher',
|
||||
'teacher',
|
||||
{
|
||||
{'default:paper 2', {'default:papyrus 6', 'default:coal_lump 1'}},
|
||||
{'default:book', {'default:papyrus 9', 'default:tree 4'}}, -- for heating the school
|
||||
},
|
||||
{ 'Lars', 'Leon' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
-- ice trader
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'iceman',
|
||||
'iceman',
|
||||
{
|
||||
{'default:ice', 'default:pick_steel'},
|
||||
},
|
||||
{ 'Ian', 'Jan' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
|
||||
-- potterer (Toepfer)
|
||||
-- TODO: the potterer could have more work to do...
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'potterer',
|
||||
'potterer',
|
||||
{
|
||||
{'default:clay_lump 2', 'default:coal_lump'},
|
||||
{'default:clay 6', 'default:shovel_stone'},
|
||||
{'cottages:washing', 'default:shovel_steel'}, -- 1 clay
|
||||
},
|
||||
{ 'Peter', 'Paul' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
-- a bricklayer
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'bricklayer',
|
||||
'bricklayer',
|
||||
{
|
||||
{'default:clay_brick 8', {'default:shovel_stone', 'default:coal_lump 2'}},
|
||||
{'default:brick 12', {'default:shovel_steel', 'default:coal_lump 12'}},
|
||||
{'stairs:stair_brick 8', {'default:shovel_stone', 'default:coal_lump 12'}},
|
||||
{'stairs:slab_brick 6', {'default:shovel_stone', 'default:coal_lump 3'}},
|
||||
},
|
||||
{ 'Billy' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
-- someone has to color the wool
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'dyemaker',
|
||||
'dyemaker',
|
||||
{
|
||||
{'wool:red 4', {'wool:white 4', 'flowers:rose'}},
|
||||
{'wool:yellow 4', {'wool:white 4', 'flowers:dandelion_yellow'}},
|
||||
{'wool:green 4', {'wool:white 4', 'default:cactus'}},
|
||||
{'wool:dark_green 4', {'wool:white 4', 'default:cactus', 'default:coal_lump'}},
|
||||
{'wool:cyan 4', {'wool:white 4', 'flowers:geranium'}},
|
||||
{'wool:blue 4', {'wool:white 4', 'flowers:geranium'}},
|
||||
{'wool:magenta 4', {'wool:white 4', 'flowers:tulip'}},
|
||||
{'wool:orange 4', {'wool:white 4', 'flowers:tulip'}},
|
||||
{'wool:violet 4', {'wool:white 4', 'flowers:viola'}},
|
||||
{'wool:brown 4', {'wool:white 4', 'default:junglewood 4'}},
|
||||
{'wool:pink 4', {'wool:white 4', 'flowers:rose'}},
|
||||
{'wool:grey 4', {'wool:white 4', 'default:coal_lump'}},
|
||||
{'wool:dark_grey 4', {'wool:white 4', 'default:coal_lump 2'}},
|
||||
{'wool:black 4', {'wool:white 4', 'default:coal_lump 3'}},
|
||||
},
|
||||
{ 'Fabian' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'dyemaker, specialized in large quantities',
|
||||
'dyemakerl',
|
||||
{
|
||||
{'wool:red 24', {'wool:white 24', 'flowers:rose 2', 'cottages:tub'}},
|
||||
{'wool:yellow 24', {'wool:white 24', 'flowers:dandelion_yellow 2', 'cottages:tub'}},
|
||||
{'wool:green 24', {'wool:white 24', 'default:cactus 2', 'cottages:tub'}},
|
||||
{'wool:dark_green 24', {'wool:white 24', 'default:cactus', 'default:coal_lump 2', 'cottages:tub'}},
|
||||
{'wool:cyan 24', {'wool:white 24', 'flowers:geranium 2', 'cottages:tub'}},
|
||||
{'wool:blue 24', {'wool:white 24', 'flowers:geranium 2', 'cottages:tub'}},
|
||||
{'wool:magenta 24', {'wool:white 24', 'flowers:tulip 2', 'cottages:tub'}},
|
||||
{'wool:orange 24', {'wool:white 24', 'flowers:tulip 2', 'cottages:tub'}},
|
||||
{'wool:violet 24', {'wool:white 24', 'flowers:viola 2', 'cottages:tub'}},
|
||||
{'wool:brown 24', {'wool:white 24', 'default:junglewood 8', 'cottages:tub'}},
|
||||
{'wool:pink 24', {'wool:white 24', 'flowers:rose 2', 'cottages:tub'}},
|
||||
{'wool:grey 24', {'wool:white 24', 'default:coal_lump 2', 'cottages:tub'}},
|
||||
{'wool:dark_grey 24', {'wool:white 24', 'default:coal_lump 4', 'cottages:tub'}},
|
||||
{'wool:black 24', {'wool:white 24', 'default:coal_lump 6', 'cottages:tub'}},
|
||||
},
|
||||
{ 'Friedrich' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
|
||||
-- there is the clay trader who also sells glass; however, for the medieval villages, an extra trader is more practical
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'glassmaker',
|
||||
'glassmaker',
|
||||
{
|
||||
{'default:glass 2', {'default:sand 1', 'default:coal_lump 3'}},
|
||||
{'default:glass 12', {'default:sand 5', 'default:coal_lump 9', 'default:shovel_stone'}},
|
||||
{'default:glass 48', {'default:sand 19', 'default:coal_lump 30', 'default:shovel_steel'}},
|
||||
{'default:obsidian_glass 2', {'default:obsidian_shard 2', 'default:wood 2'}},
|
||||
{'default:obsidian_glass 12', {'default:obsidian', 'default:coal_lump 6', 'default:shovel_stone'}},
|
||||
{'default:obsidian_glass 48', {'default:obsidian 4', 'default:coal_lump 30','default:shovel_steel', 'default:pick_steel'}},
|
||||
{'cottages:glass_pane 12', {'default:sand 2', 'default:coal_lump 1'}},
|
||||
{'vessels:glass_bottle', {'default:sand', 'default:wood 1'}},
|
||||
{'vessels:drinking_glass 2', {'default:sand', 'default:wood 1'}},
|
||||
|
||||
},
|
||||
{ 'Peter', 'Paul' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
|
||||
-- charachoal burners (=Koehler) used to be located outside villages
|
||||
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||
'characoal burner',
|
||||
'charachoal',
|
||||
{
|
||||
{'default:coal_lump', 'default:tree 2', 'default:apple'},
|
||||
{'default:coal_lump 12', 'default:tree 16', 'default:apple 12'},
|
||||
{'default:coal_lump 19', 'default:tree 25', 'farming:bread 2', 'default:apple 19', 'bucket:bucket_empty'},
|
||||
{'default:coalblock', 'default:tree 12', 'farming:bread 1', 'default:apple 9'},
|
||||
{'default:coalblock 9', 'default:tree 99', 'farming:bread 8'},
|
||||
},
|
||||
{ 'Christian', 'Rauchi' },
|
||||
mobf_trader.VILLAGE_TRADER_TEXTURES
|
||||
);
|
||||
|
||||
|
||||
-- someone has to color the wool
|
||||
mobf_trader.village_jobs = {
|
||||
forge = {'blacksmith', 'bronzesmith'},
|
||||
farm_tiny = { 'stonemason', 'stoneminer', 'carpenter', 'toolmaker', 'doormaker', 'furnituremaker', 'stairmaker', 'cooper', 'wheelwright', 'saddler', 'roofer',
|
||||
'iceman', 'potterer', 'dyemaker', 'dyemakerl', 'glassmaker'},
|
||||
-- -- candidates for independent buildings
|
||||
-- 'stonemason', 'iceman', 'potterer', 'dyemaker', 'glassmaker'
|
||||
mill = {'miller'},
|
||||
bakery = {'baker'},
|
||||
school = {'teacher'},
|
||||
outside = {'charachoal'}, -- plus lumberjacks and miners
|
||||
};
|
||||
|
||||
-- TODO: innkeeper - sell drinks, food and beds for restoring health?
|
||||
-- TODO: fisher
|
||||
|
||||
-- animalmaterials: feather, milk, eggs -> something for the females
|
||||
|
||||
-- loam, reet - can be produced by all villagers
|
||||
|
||||
-- TODO: apple
|
||||
-- TODO: gold stuff; mese, diamond
|
||||
|
||||
|
||||
-- TODO nicht sinnvoll: schuster, tuchmacher (evtl. wollhaendler?), weber (auch wolle?), schneider (auch wolle?), maler, barbiere,
|
||||
-- TODO sinnvoll: fischer, schlachter, gerber, schaefer, tuermer (eher in stadt/burg), bader?, spielleute
|
||||
|
||||
-- TODO: jaeger, waechter
|
||||
-- TODO: fahrender haendler
|
||||
|
||||
-- TODO: bei den villages auch ab und an nur mal einen wagen hinstellen
|
||||
-- TODO: neben wagen auch backhaus, wachturm, fischerhuette/loeschteich, kohlenmeiler
|
@ -1,227 +0,0 @@
|
||||
|
||||
mob_village_traders = {}
|
||||
|
||||
-- spawn traders in villages
|
||||
mob_village_traders.part_of_village_spawned = function( village, minp, maxp, data, param2_data, a, cid )
|
||||
-- if mobf_trader is not installed, we can't spawn any mobs;
|
||||
-- if mg_villages is not installed, we do not need to spawn anything
|
||||
if( not( minetest.get_modpath( 'mobf_trader'))
|
||||
or not( minetest.get_modpath( 'mg_villages'))
|
||||
or not( mob_basics )
|
||||
or not( mob_basics.spawn_mob )) then
|
||||
return;
|
||||
end
|
||||
|
||||
-- diffrent villages may have diffrent traders
|
||||
local village_type = village.village_type;
|
||||
|
||||
-- for each building in the village
|
||||
for i,bpos in pairs(village.to_add_data.bpos) do
|
||||
-- get data about the building
|
||||
local building_data = mg_villages.BUILDINGS[ bpos.btype ];
|
||||
|
||||
-- only handle buildings that are at least partly contained in that part of the
|
||||
-- village that got spawned in this mapchunk
|
||||
if( not( bpos.x > maxp.x or bpos.x + bpos.bsizex < minp.x
|
||||
or bpos.z > maxp.z or bpos.z + bpos.bsizez < minp.z )
|
||||
-- the building type determines which kind of traders will live there
|
||||
and building_data
|
||||
and building_data.typ
|
||||
-- avoid spawning them twice
|
||||
and not( bpos.traders )) then
|
||||
|
||||
-- choose traders; the replacements may be relevant:
|
||||
-- wood traders tend to sell the same wood type of which their house is built
|
||||
local traders = mob_village_traders.choose_traders( village_type, building_data.typ, village.to_add_data.replacements );
|
||||
|
||||
-- find spawn positions for all traders in the list
|
||||
local all_pos = mob_village_traders.choose_trader_pos(bpos, minp, maxp, data, param2_data, a, cid, traders);
|
||||
|
||||
-- actually spawn the traders
|
||||
for _,v in ipairs( all_pos ) do
|
||||
mob_basics.spawn_mob( {x=v.x, y=v.y, z=v.z}, v.typ, nil, nil, nil, nil, true );
|
||||
end
|
||||
|
||||
-- store the information about the spawned traders
|
||||
village.to_add_data.bpos[ i ].traders = all_pos;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
mob_village_traders.choose_traders = function( village_type, building_type, replacements )
|
||||
|
||||
if( not( building_type ) or not( village_type )) then
|
||||
return {};
|
||||
end
|
||||
|
||||
-- some jobs are obvious
|
||||
if( building_type == 'mill' ) then
|
||||
return { 'miller' };
|
||||
elseif( building_type == 'bakery' ) then
|
||||
return { 'baker' };
|
||||
elseif( building_type == 'school' ) then
|
||||
return { 'teacher' };
|
||||
elseif( building_type == 'forge' ) then
|
||||
local traders = {'blacksmith', 'bronzesmith' };
|
||||
return { traders[ math.random(#traders)] };
|
||||
elseif( building_type == 'shop' ) then
|
||||
local traders = {'seeds','flowers','misc','default','ore', 'fruit trader', 'wood'};
|
||||
return { traders[ math.random(#traders)] };
|
||||
-- there are no traders for these jobs - they'd require specialized mobs
|
||||
elseif( building_type == 'tower'
|
||||
or building_type == 'church'
|
||||
or building_type == 'secular'
|
||||
or building_type == 'tavern' ) then
|
||||
return {};
|
||||
end
|
||||
|
||||
if( village_type == 'charachoal' ) then
|
||||
return { 'charachoal' };
|
||||
elseif( village_type == 'claytrader' ) then
|
||||
return { 'clay' };
|
||||
end
|
||||
|
||||
local res = {};
|
||||
if( building_type == 'shed'
|
||||
or building_type == 'farm_tiny'
|
||||
or building_type == 'house'
|
||||
or building_type == 'house_large'
|
||||
or building_type=='hut') then
|
||||
local traders = { 'stonemason', 'stoneminer', 'carpenter', 'toolmaker',
|
||||
'doormaker', 'furnituremaker', 'stairmaker', 'cooper', 'wheelwright',
|
||||
'saddler', 'roofer', 'iceman', 'potterer', 'bricklayer', 'dyemaker',
|
||||
'dyemakerl', 'glassmaker' }
|
||||
-- sheds and farms both contain craftmen
|
||||
res = { traders[ math.random( #traders )] };
|
||||
if( building_type == 'shed'
|
||||
or building_type == 'house'
|
||||
or building_type == 'house_large'
|
||||
or building_type == 'hut' ) then
|
||||
return res;
|
||||
end
|
||||
end
|
||||
|
||||
if( building_type == 'field'
|
||||
or building_type == 'farm_full'
|
||||
or building_type == 'farm_tiny' ) then
|
||||
|
||||
local fruit = 'farming:cotton';
|
||||
if( 'farm_full' ) then
|
||||
-- RealTest
|
||||
fruit = 'farming:wheat';
|
||||
if( replacements_group['farming'].traders[ 'farming:soy']) then
|
||||
fruit = 'farming:soy';
|
||||
end
|
||||
if( minetest.get_modpath("mobf") ) then
|
||||
local animal_trader = {'animal_cow', 'animal_sheep', 'animal_chicken', 'animal_exotic'};
|
||||
res[1] = animal_trader[ math.random( #animal_trader )];
|
||||
end
|
||||
return { res[1], replacements_group['farming'].traders[ fruit ]};
|
||||
elseif( #replacements_group['farming'].found > 0 ) then
|
||||
-- get a random fruit to grow
|
||||
fruit = replacements_group['farming'].found[ math.random( #replacements_group['farming'].found) ];
|
||||
return { res[1], replacements_group['farming'].traders[ fruit ]};
|
||||
else
|
||||
return res;
|
||||
end
|
||||
end
|
||||
|
||||
if( building_type == 'pasture' and minetest.get_modpath("mobf")) then
|
||||
local animal_trader = {'animal_cow', 'animal_sheep', 'animal_chicken', 'animal_exotic'};
|
||||
return { animal_trader[ math.random( #animal_trader )] };
|
||||
end
|
||||
|
||||
|
||||
-- TODO: banana,cocoa,rubber from farming_plus?
|
||||
-- TODO: sawmill
|
||||
if( building_type == 'lumberjack' or village_type == 'lumberjack' ) then
|
||||
-- find the wood replacement
|
||||
local wood_replacement = 'default:wood';
|
||||
for _,v in ipairs( replacements ) do
|
||||
if( v and v[1]=='default:wood' ) then
|
||||
wood_replacement = v[2];
|
||||
end
|
||||
end
|
||||
-- lumberjacks are more likely to sell the wood of the type of house they are living in
|
||||
if( wood_replacement and math.random(1,3)==1) then
|
||||
return { replacements_group['wood'].traders[ wood_replacement ]};
|
||||
-- ...but not exclusively
|
||||
elseif( replacements_group['wood'].traders ) then
|
||||
-- construct a list containing all available wood trader types
|
||||
local list = {};
|
||||
for k,v in pairs( replacements_group['wood'].traders ) do
|
||||
list[#list+1] = k;
|
||||
end
|
||||
return { replacements_group['wood'].traders[ list[ math.random( 1,#list )]]};
|
||||
-- fallback
|
||||
else
|
||||
return { 'common_wood'};
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- tent, chateau: places for living at; no special jobs associated
|
||||
-- nore,taoki,medieval,lumberjack,logcabin,canadian,grasshut,tent: further village types
|
||||
|
||||
return res;
|
||||
end
|
||||
|
||||
|
||||
-- chooses trader positions for multiple traders for one particular building
|
||||
mob_village_traders.choose_trader_pos = function(pos, minp, maxp, data, param2_data, a, cid, traders)
|
||||
|
||||
local trader_pos = {};
|
||||
-- determine spawn positions for the mobs
|
||||
for i,tr in ipairs( traders ) do
|
||||
local tries = 0;
|
||||
local found = false;
|
||||
local pt = {x=pos.x, y=pos.y-1, z=pos.z};
|
||||
while( tries < 20 and not(found)) do
|
||||
-- get a random position for the trader
|
||||
pt.x = (pos.x-1)+math.random(0,pos.bsizex+1);
|
||||
pt.z = (pos.z-1)+math.random(0,pos.bsizez+1);
|
||||
-- check if it is inside the area contained in data
|
||||
if (pt.x >= minp.x and pt.x <= maxp.x) and (pt.y >= minp.y and pt.y <= maxp.y) and (pt.z >= minp.z and pt.z <= maxp.z) then
|
||||
|
||||
while( pt.y < maxp.y
|
||||
and (data[ a:index( pt.x, pt.y, pt.z)]~=cid.c_air
|
||||
or data[ a:index( pt.x, pt.y+1, pt.z)]~=cid.c_air )) do
|
||||
pt.y = pt.y + 1;
|
||||
end
|
||||
|
||||
-- check if this position is really suitable? traders standing on the roof are a bit odd
|
||||
local def = minetest.registered_nodes[ minetest.get_name_from_content_id( data[ a:index( pt.x, pt.y-1, pt.z)])];
|
||||
if( not(def) or not(def.drawtype) or def.drawtype=="nodebox" or def.drawtype=="mesh" or def.name=='air') then
|
||||
found = false;
|
||||
elseif( def and def.name ) then
|
||||
found = true;
|
||||
end
|
||||
end
|
||||
tries = tries+1;
|
||||
|
||||
-- check if this position has already been assigned to another trader
|
||||
for j,t in ipairs( trader_pos ) do
|
||||
if( t.x==pt.x and t.y==pt.y and t.z==pt.z ) then
|
||||
found = false;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- there is usually free space around the building; use that for spawning
|
||||
if( found==false ) then
|
||||
if( pt.x < minp.x ) then
|
||||
pt.x = pos.x + pos.bsizex+1;
|
||||
else
|
||||
pt.x = pos.x-1;
|
||||
end
|
||||
pt.z = pos.z-1 + math.random( pos.bsizez+1 );
|
||||
-- let the trader drop down until he finds ground
|
||||
pt.y = pos.y + 20;
|
||||
found = true;
|
||||
end
|
||||
|
||||
table.insert( trader_pos, {x=pt.x, y=pt.y, z=pt.z, typ=tr} );
|
||||
end
|
||||
return trader_pos;
|
||||
end
|