Compare commits
92 Commits
move_physi
...
master
Author | SHA1 | Date |
---|---|---|
Kristian | ed8319e013 | |
Kristian | 6f8bd8a8d7 | |
Kristian | 75899036df | |
Kristian | 8350bbc6ac | |
Kristian | 8d2410f697 | |
Kristian | 7911a18e00 | |
Kristian | 42c5bf0be9 | |
Kristian | 62f31a4649 | |
Kristian | e87c38d653 | |
ancientmarinerdev | 482a6071f5 | |
Michieal | ff7299a444 | |
ancientmarinerdev | 2ed3c1c480 | |
ancientmarinerdev | 111c885417 | |
ancientmarinerdev | 8e1f00d428 | |
ancientmarinerdev | 4fd4425aae | |
ancientmarinerdev | ac4cd2c325 | |
ancientmarinerdev | 01c8009c6a | |
ancientmarinerdev | ef90820f67 | |
ancientmarinerdev | d6d11b9526 | |
ancientmarinerdev | b0264b2736 | |
PrairieWind | b3da85be64 | |
ancientmarinerdev | 3ed32abc4e | |
kay27 | 9db6050638 | |
kay27 | 7ceb953a56 | |
kay27 | 1894d8c5f0 | |
kay27 | 419d61edde | |
PrairieWind | 9820309762 | |
Michieal | f46581905a | |
Michieal | 4f6de581dd | |
ancientmarinerdev | db62631540 | |
ancientmarinerdev | fb30564827 | |
Michieal | 8c355db3ce | |
Michieal | eae08f3010 | |
Michieal | 4701c4d6e7 | |
ancientmarinerdev | 66f368531d | |
PrairieWind | 7cb5c55d68 | |
PrairieWind | 6fd799ac42 | |
ancientmarinerdev | 01bb753549 | |
ancientmarinerdev | 59694ebc7c | |
ancientmarinerdev | 00c4ecf643 | |
ancientmarinerdev | e4db91d35c | |
ancientmarinerdev | 2527479401 | |
ancientmarinerdev | 85f7bbdb80 | |
ancientmarinerdev | 465a919f6b | |
ancientmarinerdev | 325a666c62 | |
ancientmarinerdev | e9b54e85c2 | |
ancientmarinerdev | 4324fe2489 | |
ancientmarinerdev | d6804bf4b7 | |
ancientmarinerdev | 87f04bdd9f | |
ancientmarinerdev | e3307d647b | |
ancientmarinerdev | 29cd73cb84 | |
ancientmarinerdev | 5c0a763b83 | |
ancientmarinerdev | 9b1ceebf0d | |
ancientmarinerdev | 856a60bcc2 | |
𝕵𝖔𝖍𝖆𝖓𝖓𝖊𝖘 𝕱𝖗𝖎𝖙𝖟 | ddd004c0f0 | |
ancientmarinerdev | 609ef220ad | |
ancientmarinerdev | 32a7eb4087 | |
CyberMango | 5e969ba928 | |
CyberMango | 17e02aec3c | |
CyberMango | fb28e192e6 | |
CyberMango | 0f569fdbaa | |
CyberMango | 8a7fcfde82 | |
CyberMango | fb51067c78 | |
ancientmarinerdev | 7ea41a2f21 | |
𝕵𝖔𝖍𝖆𝖓𝖓𝖊𝖘 𝕱𝖗𝖎𝖙𝖟 | 0b1916b807 | |
ancientmarinerdev | 0fca1ce469 | |
ancientmarinerdev | df6d1c026a | |
ancientmarinerdev | f8ae702ce4 | |
ancientmarinerdev | 5faf060122 | |
ancientmarinerdev | 8c648d1fc3 | |
ancientmarinerdev | 46052e5b7e | |
iliekprogrammar | 6430fcf103 | |
iliekprogrammar | 7376b08c61 | |
iliekprogrammar | 2e28a3386b | |
iliekprogrammar | 98dac6dcd7 | |
iliekprogrammar | 3026808a71 | |
test1 | 7c7521ff15 | |
test1 | 50d8e95c16 | |
iliekprogrammar | fc74bd5cfe | |
kabou | 2a37d38f6c | |
kabou | 89821a8329 | |
iliekprogrammar | 3249c13752 | |
iliekprogrammar | 2ea72ccda8 | |
iliekprogrammar | 5237eca31e | |
iliekprogrammar | c2ba70a601 | |
iliekprogrammar | 723fe9c532 | |
iliekprogrammar | 661afed46c | |
AFCMS | 96e83e866c | |
AFCMS | 3bb86fd436 | |
AFCMS | 4acee8e64e | |
AFCMS | bacec2c7e6 | |
AFCMS | a3d459f020 |
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
|
||||
name: "Bug report"
|
||||
about: "File a bug report"
|
||||
labels:
|
||||
|
||||
- unconfirmed
|
||||
- bug
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
|
||||
Please follow our contributing guidelines first:
|
||||
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CONTRIBUTING.md#rules-about-both-bugs-and-feature-requests
|
||||
|
||||
By submitting this issue, you agree to follow our Code of Conduct:
|
||||
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CODE_OF_CONDUCT.md
|
||||
-->
|
||||
|
||||
<!--
|
||||
What version of MineClone2 are you using? We do not provide support for outdated versions of MineClone2.
|
||||
Current latest version is listed here, at the top:
|
||||
https://git.minetest.land/MineClone2/MineClone2/tags
|
||||
-->
|
||||
MineClone2 version:
|
||||
|
||||
### What happened?
|
||||
Report about the bug! Please send large log snippets as an attachement file.
|
||||
|
||||
### What should happen:
|
||||
Tell us what should happen!
|
||||
|
||||
### Steps to reproduce
|
||||
Tell us how we can reproduce the bug!
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
|
||||
name: "Feature request"
|
||||
about: "File a feature request not in Minecraft"
|
||||
labels:
|
||||
|
||||
- "non-Minecraft feature"
|
||||
- "needs discussion"
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Got a new non-Minecraft feature request? Explain to us why we should consider your idea.
|
||||
|
||||
Please follow our contributing guidelines first:
|
||||
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CONTRIBUTING.md#rules-about-both-bugs-and-feature-requests
|
||||
|
||||
By submitting this issue, you agree to follow our Code of Conduct:
|
||||
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CODE_OF_CONDUCT.md
|
||||
-->
|
||||
|
||||
### Feature
|
||||
Tell us about your requested feature not in Minecraft!
|
||||
|
||||
### Why
|
||||
Tell us why should we implement it!
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
|
||||
name: "Missing Feature request"
|
||||
about: "File a missing feature request in Minecraft but not in MineClone2"
|
||||
labels:
|
||||
|
||||
- "missing feature"
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Thanks for taking the time to fill out this missing feature request!
|
||||
|
||||
Please follow our contributing guidelines first:
|
||||
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CONTRIBUTING.md#rules-about-both-bugs-and-feature-requests
|
||||
|
||||
By submitting this issue, you agree to follow our Code of Conduct:
|
||||
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CODE_OF_CONDUCT.md
|
||||
-->
|
||||
|
||||
### Current feature in Minecraft
|
||||
Tell us about the feature currently in Minecraft! What is it like on Minecraft?
|
||||
|
||||
### Current feature in MineClone2
|
||||
Tell us about the feature currently in MineClone2! What is different?
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
|
||||
name: "Pull request"
|
||||
about: "Submit a pull request"
|
||||
labels:
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Please follow our contributing guidelines first:
|
||||
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CONTRIBUTING.md#how-you-can-help-as-a-programmer
|
||||
|
||||
By submitting this pull request, you agree to follow our Code of Conduct:
|
||||
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CODE_OF_CONDUCT.md
|
||||
-->
|
||||
|
||||
Tell us about your pull request! Reference related issues, if necessary
|
||||
|
||||
### Testing
|
||||
Tell us how to test your changes!
|
|
@ -4,3 +4,4 @@
|
|||
*.blend2
|
||||
*.blend3
|
||||
/.idea/
|
||||
.Rproj.user
|
||||
|
|
|
@ -158,7 +158,7 @@ The following features are incomplete:
|
|||
|
||||
* Some monsters and animals
|
||||
* Redstone-related things
|
||||
* Special minecarts
|
||||
* Some special minecarts (hopper and chest minecarts work)
|
||||
* A couple of non-trivial blocks and items
|
||||
|
||||
Bonus features (not found in Minecraft):
|
||||
|
|
|
@ -19,9 +19,9 @@ movement_speed_jump = 6.6
|
|||
movement_speed_climb = 2.35
|
||||
# TODO: Add descend speed (3.0) when available
|
||||
|
||||
movement_liquid_fluidity = 0.88
|
||||
movement_liquid_fluidity = 1.13
|
||||
movement_liquid_fluidity_smooth = 0.5
|
||||
movement_liquid_sink = 16
|
||||
movement_liquid_sink = 23
|
||||
|
||||
movement_gravity = 10.4
|
||||
|
||||
|
|
|
@ -3,26 +3,26 @@ mcl_vars = {}
|
|||
|
||||
mcl_vars.redstone_tick = 0.1
|
||||
|
||||
--- GUI / inventory menu settings
|
||||
-- GUI / inventory menu settings
|
||||
mcl_vars.gui_slots = "listcolors[#9990;#FFF7;#FFF0;#000;#FFF]"
|
||||
|
||||
-- nonbg is added as formspec prepend in mcl_formspec_prepend
|
||||
mcl_vars.gui_nonbg = mcl_vars.gui_slots ..
|
||||
"style_type[image_button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]"..
|
||||
"style_type[button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]"..
|
||||
"style_type[field;textcolor=#323232]"..
|
||||
"style_type[label;textcolor=#323232]"..
|
||||
"style_type[textarea;textcolor=#323232]"..
|
||||
"style_type[checkbox;textcolor=#323232]"
|
||||
mcl_vars.gui_nonbg = table.concat({
|
||||
mcl_vars.gui_slots,
|
||||
"style_type[image_button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]",
|
||||
"style_type[button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]",
|
||||
"style_type[field;textcolor=#323232]",
|
||||
"style_type[label;textcolor=#323232]",
|
||||
"style_type[textarea;textcolor=#323232]",
|
||||
"style_type[checkbox;textcolor=#323232]",
|
||||
})
|
||||
|
||||
-- Background stuff must be manually added by mods (no formspec prepend)
|
||||
mcl_vars.gui_bg_color = "bgcolor[#00000000]"
|
||||
mcl_vars.gui_bg_img = "background9[1,1;1,1;mcl_base_textures_background9.png;true;7]"
|
||||
|
||||
-- Legacy
|
||||
mcl_vars.inventory_header = ""
|
||||
|
||||
-- Tool wield size
|
||||
mcl_vars.tool_wield_scale = { x = 1.8, y = 1.8, z = 1 }
|
||||
mcl_vars.tool_wield_scale = vector.new(1.8, 1.8, 1)
|
||||
|
||||
-- Mapgen variables
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
|
@ -35,55 +35,69 @@ mcl_vars.chunksize = math.max(1, tonumber(minetest.get_mapgen_setting("chunksize
|
|||
mcl_vars.MAP_BLOCKSIZE = math.max(1, minetest.MAP_BLOCKSIZE or 16)
|
||||
mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
|
||||
mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, minetest.MAX_MAP_GENERATION_LIMIT or 31000)
|
||||
|
||||
local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2)
|
||||
|
||||
mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
||||
mcl_vars.chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE
|
||||
|
||||
local central_chunk_min_pos = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
||||
local central_chunk_max_pos = central_chunk_min_pos + mcl_vars.chunk_size_in_nodes - 1
|
||||
local ccfmin = central_chunk_min_pos - mcl_vars.MAP_BLOCKSIZE -- Fullminp/fullmaxp of central chunk, in nodes
|
||||
local ccfmax = central_chunk_max_pos + mcl_vars.MAP_BLOCKSIZE
|
||||
local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) / mcl_vars.MAP_BLOCKSIZE)
|
||||
local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) /
|
||||
mcl_vars.MAP_BLOCKSIZE)
|
||||
local mapgen_limit_min = -mapgen_limit_b * mcl_vars.MAP_BLOCKSIZE
|
||||
local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_vars.MAP_BLOCKSIZE - 1
|
||||
local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / mcl_vars.chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk
|
||||
local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / mcl_vars.chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits.
|
||||
|
||||
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * mcl_vars.chunk_size_in_nodes
|
||||
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * mcl_vars.chunk_size_in_nodes
|
||||
|
||||
---@param x integer
|
||||
---@return integer
|
||||
local function coordinate_to_block(x)
|
||||
return math.floor(x / mcl_vars.MAP_BLOCKSIZE)
|
||||
end
|
||||
|
||||
---@param x integer
|
||||
---@return integer
|
||||
local function coordinate_to_chunk(x)
|
||||
return math.floor((coordinate_to_block(x) - central_chunk_offset) / mcl_vars.chunksize)
|
||||
end
|
||||
|
||||
---@param pos Vector
|
||||
---@return Vector
|
||||
function mcl_vars.pos_to_block(pos)
|
||||
return {
|
||||
x = coordinate_to_block(pos.x),
|
||||
y = coordinate_to_block(pos.y),
|
||||
z = coordinate_to_block(pos.z)
|
||||
}
|
||||
return vector.new(
|
||||
coordinate_to_block(pos.x),
|
||||
coordinate_to_block(pos.y),
|
||||
coordinate_to_block(pos.z)
|
||||
)
|
||||
end
|
||||
|
||||
---@param pos Vector
|
||||
---@return Vector
|
||||
function mcl_vars.pos_to_chunk(pos)
|
||||
return {
|
||||
x = coordinate_to_chunk(pos.x),
|
||||
y = coordinate_to_chunk(pos.y),
|
||||
z = coordinate_to_chunk(pos.z)
|
||||
}
|
||||
return vector.new(
|
||||
coordinate_to_chunk(pos.x),
|
||||
coordinate_to_chunk(pos.y),
|
||||
coordinate_to_chunk(pos.z)
|
||||
)
|
||||
end
|
||||
|
||||
local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / mcl_vars.chunk_size_in_nodes)
|
||||
local k_positive_z = k_positive * 2
|
||||
local k_positive_y = k_positive_z * k_positive_z
|
||||
|
||||
---@param pos Vector
|
||||
---@return integer
|
||||
function mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
local c = mcl_vars.pos_to_chunk(pos)
|
||||
return
|
||||
(c.y + k_positive) * k_positive_y +
|
||||
return (c.y + k_positive) * k_positive_y +
|
||||
(c.z + k_positive) * k_positive_z +
|
||||
c.x + k_positive
|
||||
c.x + k_positive
|
||||
end
|
||||
|
||||
if not superflat and not singlenode then
|
||||
|
@ -117,11 +131,8 @@ elseif singlenode then
|
|||
mcl_vars.mg_bedrock_is_rough = false
|
||||
else
|
||||
-- Classic superflat
|
||||
local ground = minetest.get_mapgen_setting("mgflat_ground_level")
|
||||
ground = tonumber(ground)
|
||||
if not ground then
|
||||
ground = 8
|
||||
end
|
||||
local ground = tonumber(minetest.get_mapgen_setting("mgflat_ground_level")) or 8
|
||||
|
||||
mcl_vars.mg_overworld_min = ground - 3
|
||||
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
||||
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
|
||||
|
@ -181,14 +192,16 @@ minetest.craftitemdef_default.stack_max = 64
|
|||
math.randomseed(os.time())
|
||||
|
||||
local chunks = {} -- intervals of chunks generated
|
||||
|
||||
---@param pos Vector
|
||||
function mcl_vars.add_chunk(pos)
|
||||
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
local prev
|
||||
for i, d in pairs(chunks) do
|
||||
if n <= d[2] then -- we've found it
|
||||
if (n == d[2]) or (n >= d[1]) then return end -- already here
|
||||
if n == d[1]-1 then -- right before:
|
||||
if prev and (prev[2] == n-1) then
|
||||
if n == d[1] - 1 then -- right before:
|
||||
if prev and (prev[2] == n - 1) then
|
||||
prev[2] = d[2]
|
||||
table.remove(chunks, i)
|
||||
return
|
||||
|
@ -196,17 +209,20 @@ function mcl_vars.add_chunk(pos)
|
|||
d[1] = n
|
||||
return
|
||||
end
|
||||
if prev and (prev[2] == n-1) then --join to previous
|
||||
if prev and (prev[2] == n - 1) then --join to previous
|
||||
prev[2] = n
|
||||
return
|
||||
end
|
||||
table.insert(chunks, i, {n, n}) -- insert new interval before i
|
||||
table.insert(chunks, i, { n, n }) -- insert new interval before i
|
||||
return
|
||||
end
|
||||
prev = d
|
||||
end
|
||||
chunks[#chunks+1] = {n, n}
|
||||
chunks[#chunks + 1] = { n, n }
|
||||
end
|
||||
|
||||
---@param pos Vector
|
||||
---@return boolean
|
||||
function mcl_vars.is_generated(pos)
|
||||
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
for i, d in pairs(chunks) do
|
||||
|
@ -217,47 +233,46 @@ function mcl_vars.is_generated(pos)
|
|||
return false
|
||||
end
|
||||
|
||||
-- "Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does.
|
||||
-- p: Position, if it's wrong, {name="error"} node will return.
|
||||
-- force: optional (default: false) - Do the maximum to still read the node within us_timeout.
|
||||
-- us_timeout: optional (default: 244 = 0.000244 s = 1/80/80/80), set it at least to 3000000 to let mapgen to finish its job.
|
||||
--
|
||||
-- returns node definition, eg. {name="air"}. Unfortunately still can return {name="ignore"}.
|
||||
function mcl_vars.get_node(p, force, us_timeout)
|
||||
---"Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does.
|
||||
---@param pos Vector Position, if it's wrong, `{name="error"}` node will return.
|
||||
---@param force? boolean Optional (default: `false`), Do the maximum to still read the node within us_timeout.
|
||||
---@param us_timeout? number Optional (default: `244 = 0.000244 s = 1/80/80/80`), set it at least to `3000000` to let mapgen to finish its job
|
||||
---@return node # Node definition, eg. `{name="air"}`. Unfortunately still can return `{name="ignore"}`.
|
||||
---@nodiscard
|
||||
function mcl_vars.get_node(pos, force, us_timeout)
|
||||
-- check initial circumstances
|
||||
if not p or not p.x or not p.y or not p.z then return {name="error"} end
|
||||
if not pos or not pos.x or not pos.y or not pos.z then return { name = "error" } end
|
||||
|
||||
-- try common way
|
||||
local node = minetest.get_node(p)
|
||||
local node = minetest.get_node(pos)
|
||||
if node.name ~= "ignore" then
|
||||
return node
|
||||
end
|
||||
|
||||
-- copy table to get sure it won't changed by other threads
|
||||
local pos = {x=p.x,y=p.y,z=p.z}
|
||||
-- copy vector to get sure it won't changed by other threads
|
||||
local pos_copy = vector.copy(pos)
|
||||
|
||||
-- try LVM
|
||||
minetest.get_voxel_manip():read_from_map(pos, pos)
|
||||
node = minetest.get_node(pos)
|
||||
minetest.get_voxel_manip():read_from_map(pos_copy, pos_copy)
|
||||
node = minetest.get_node(pos_copy)
|
||||
if node.name ~= "ignore" or not force then
|
||||
return node
|
||||
end
|
||||
|
||||
-- all ways failed - need to emerge (or forceload if generated)
|
||||
local us_timeout = us_timeout or 244
|
||||
if mcl_vars.is_generated(pos) then
|
||||
if mcl_vars.is_generated(pos_copy) then
|
||||
minetest.chat_send_all("IMPOSSIBLE! Please report this to MCL2 issue tracker!")
|
||||
minetest.forceload_block(pos)
|
||||
minetest.forceload_block(pos_copy)
|
||||
else
|
||||
minetest.emerge_area(pos, pos)
|
||||
minetest.emerge_area(pos_copy, pos_copy)
|
||||
end
|
||||
|
||||
local t = minetest.get_us_time()
|
||||
|
||||
node = minetest.get_node(pos)
|
||||
node = minetest.get_node(pos_copy)
|
||||
|
||||
while (not node or node.name == "ignore") and (minetest.get_us_time() - t < us_timeout) do
|
||||
node = minetest.get_node(pos)
|
||||
while (not node or node.name == "ignore") and (minetest.get_us_time() - t < (us_timeout or 244)) do
|
||||
node = minetest.get_node(pos_copy)
|
||||
end
|
||||
|
||||
return node
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# textdomain: mcl_boats
|
||||
Acacia Boat=Akaciebåd
|
||||
Birch Boat=Birkebåd
|
||||
Boat=Båd
|
||||
Boats are used to travel on the surface of water.=Både blier brugt til at rejse på vandoverflader.
|
||||
Dark Oak Boat=Mørk egetræsbåd
|
||||
Jungle Boat=Junglebåd
|
||||
Oak Boat=Egetræsbåd
|
||||
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Use [Sneak] to leave the boat, punch the boat to make it drop as an item.=Højre-klik på en vand for at placere båden. Højre-klik på båden for at gå ombord. Brug [Left] og [Right] til at styre. [Forwards] for at øge hastigheden, og [Backwards] for at sænke farten eller sejle bagud. Brug [Sneak] for at forlade båden, slå båden for at lave den om til en genstand.
|
||||
Spruce Boat=Granbåd
|
||||
Water vehicle=Vandfartøj
|
||||
Sneak to dismount=Snig for at stige ud
|
||||
Obsidian Boat=Obsidianbåd
|
|
@ -0,0 +1,3 @@
|
|||
# textdomain: mcl_falling_nodes
|
||||
@1 was smashed by a falling anvil.=@1 blev smadret af en nedfaldende ambolt.
|
||||
@1 was smashed by a falling block.=@1 blev smadret af en nedfaldende blok.
|
|
@ -7,31 +7,24 @@ local pool = {}
|
|||
local tick = false
|
||||
|
||||
|
||||
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_item_entities",false)
|
||||
local function mcl_log (message)
|
||||
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_item_entities", false)
|
||||
local function mcl_log(message)
|
||||
if LOGGING_ON then
|
||||
mcl_util.mcl_log (message, "[Item Entities]", true)
|
||||
mcl_util.mcl_log(message, "[Item Entities]", true)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
local name
|
||||
name = player:get_player_name()
|
||||
pool[name] = 0
|
||||
pool[player:get_player_name()] = 0
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
local name
|
||||
name = player:get_player_name()
|
||||
pool[name] = nil
|
||||
pool[player:get_player_name()] = nil
|
||||
end)
|
||||
|
||||
|
||||
local has_awards = minetest.get_modpath("awards")
|
||||
|
||||
local mcl_item_entity = {}
|
||||
mcl_item_entity = {}
|
||||
|
||||
--basic settings
|
||||
local item_drop_settings = {} --settings table
|
||||
|
@ -46,22 +39,29 @@ item_drop_settings.random_item_velocity = true --this sets random item velocity
|
|||
item_drop_settings.drop_single_item = false --if true, the drop control drops 1 item instead of the entire stack, and sneak+drop drops the stack
|
||||
-- drop_single_item is disabled by default because it is annoying to throw away items from the intentory screen
|
||||
|
||||
item_drop_settings.magnet_time = 0.75 -- how many seconds an item follows the player before giving up
|
||||
item_drop_settings.magnet_time = 0.75 -- how many seconds an item follows the player before giving up
|
||||
|
||||
local function get_gravity()
|
||||
return tonumber(minetest.settings:get("movement_gravity")) or 9.81
|
||||
end
|
||||
|
||||
local registered_pickup_achievement = {}
|
||||
mcl_item_entity.registered_pickup_achievement = {}
|
||||
|
||||
--TODO: remove limitation of 1 award per itemname
|
||||
---Register an achievement that will be unlocked on pickup.
|
||||
---
|
||||
---TODO: remove limitation of 1 award per itemname
|
||||
---@param itemname string
|
||||
---@param award string
|
||||
function mcl_item_entity.register_pickup_achievement(itemname, award)
|
||||
if not has_awards then
|
||||
minetest.log("warning", "[mcl_item_entity] Trying to register pickup achievement ["..award.."] for ["..itemname.."] while awards missing")
|
||||
elseif registered_pickup_achievement[itemname] then
|
||||
minetest.log("error", "[mcl_item_entity] Trying to register already existing pickup achievement ["..award.."] for ["..itemname.."]")
|
||||
minetest.log("warning",
|
||||
"[mcl_item_entity] Trying to register pickup achievement [" .. award .. "] for [" ..
|
||||
itemname .. "] while awards missing")
|
||||
elseif mcl_item_entity.registered_pickup_achievement[itemname] then
|
||||
minetest.log("error",
|
||||
"[mcl_item_entity] Trying to register already existing pickup achievement [" .. award .. "] for [" .. itemname .. "]")
|
||||
else
|
||||
registered_pickup_achievement[itemname] = award
|
||||
mcl_item_entity.registered_pickup_achievement[itemname] = award
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -74,11 +74,13 @@ mcl_item_entity.register_pickup_achievement("mcl_nether:ancient_debris", "mcl:hi
|
|||
mcl_item_entity.register_pickup_achievement("mcl_end:dragon_egg", "mcl:PickUpDragonEgg")
|
||||
mcl_item_entity.register_pickup_achievement("mcl_armor:elytra", "mcl:skysTheLimit")
|
||||
|
||||
---@param object ObjectRef
|
||||
---@param player ObjectRef
|
||||
local function check_pickup_achievements(object, player)
|
||||
if has_awards then
|
||||
local itemname = ItemStack(object:get_luaentity().itemstring):get_name()
|
||||
local playername = player:get_player_name()
|
||||
for name,award in pairs(registered_pickup_achievement) do
|
||||
for name, award in pairs(mcl_item_entity.registered_pickup_achievement) do
|
||||
if itemname == name or minetest.get_item_group(itemname, name) ~= 0 then
|
||||
awards.unlock(playername, award)
|
||||
end
|
||||
|
@ -86,16 +88,23 @@ local function check_pickup_achievements(object, player)
|
|||
end
|
||||
end
|
||||
|
||||
---@param object ObjectRef
|
||||
---@param luaentity Luaentity
|
||||
---@param ignore_check? boolean
|
||||
local function enable_physics(object, luaentity, ignore_check)
|
||||
if luaentity.physical_state == false or ignore_check == true then
|
||||
luaentity.physical_state = true
|
||||
object:set_properties({
|
||||
physical = true
|
||||
})
|
||||
object:set_acceleration({x=0,y=-get_gravity(),z=0})
|
||||
object:set_acceleration(vector.new(0, -get_gravity(), 0))
|
||||
end
|
||||
end
|
||||
|
||||
---@param object ObjectRef
|
||||
---@param luaentity Luaentity
|
||||
---@param ignore_check? boolean
|
||||
---@param reset_movement? boolean
|
||||
local function disable_physics(object, luaentity, ignore_check, reset_movement)
|
||||
if luaentity.physical_state == true or ignore_check == true then
|
||||
luaentity.physical_state = false
|
||||
|
@ -103,17 +112,16 @@ local function disable_physics(object, luaentity, ignore_check, reset_movement)
|
|||
physical = false
|
||||
})
|
||||
if reset_movement ~= false then
|
||||
object:set_velocity({x=0,y=0,z=0})
|
||||
object:set_acceleration({x=0,y=0,z=0})
|
||||
object:set_velocity(vector.zero())
|
||||
object:set_acceleration(vector.zero())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
minetest.register_globalstep(function(_)
|
||||
tick = not tick
|
||||
|
||||
for _,player in pairs(minetest.get_connected_players()) do
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
if player:get_hp() > 0 or not minetest.settings:get_bool("enable_damage") then
|
||||
|
||||
local name = player:get_player_name()
|
||||
|
@ -125,7 +133,7 @@ minetest.register_globalstep(function(dtime)
|
|||
pos = pos,
|
||||
gain = 0.3,
|
||||
max_hear_distance = 16,
|
||||
pitch = math.random(70,110)/100
|
||||
pitch = math.random(70, 110) / 100
|
||||
})
|
||||
if pool[name] > 6 then
|
||||
pool[name] = 6
|
||||
|
@ -135,15 +143,18 @@ minetest.register_globalstep(function(dtime)
|
|||
end
|
||||
|
||||
|
||||
|
||||
local inv = player:get_inventory()
|
||||
local checkpos = {x=pos.x,y=pos.y + item_drop_settings.player_collect_height,z=pos.z}
|
||||
local checkpos = vector.offset(pos, 0, item_drop_settings.player_collect_height, 0)
|
||||
|
||||
--magnet and collection
|
||||
for _,object in pairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do
|
||||
if not object:is_player() and vector.distance(checkpos, object:get_pos()) < item_drop_settings.radius_magnet and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
|
||||
for _, object in pairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do
|
||||
if not object:is_player() and vector.distance(checkpos, object:get_pos()) < item_drop_settings.radius_magnet and
|
||||
object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer
|
||||
and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
|
||||
|
||||
if object:get_luaentity()._magnet_timer >= 0 and object:get_luaentity()._magnet_timer < item_drop_settings.magnet_time and inv and inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
|
||||
if object:get_luaentity()._magnet_timer >= 0 and
|
||||
object:get_luaentity()._magnet_timer < item_drop_settings.magnet_time and inv and
|
||||
inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
|
||||
|
||||
-- Collection
|
||||
if not object:get_luaentity()._removed then
|
||||
|
@ -158,8 +169,8 @@ minetest.register_globalstep(function(dtime)
|
|||
object:get_luaentity().target = checkpos
|
||||
object:get_luaentity()._removed = true
|
||||
|
||||
object:set_velocity({x=0,y=0,z=0})
|
||||
object:set_acceleration({x=0,y=0,z=0})
|
||||
object:set_velocity(vector.zero())
|
||||
object:set_acceleration(vector.zero())
|
||||
|
||||
object:move_to(checkpos)
|
||||
|
||||
|
@ -179,7 +190,6 @@ minetest.register_globalstep(function(dtime)
|
|||
local entity = object:get_luaentity()
|
||||
entity.collector = player:get_player_name()
|
||||
entity.collected = true
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -194,6 +204,11 @@ end)
|
|||
|
||||
local tmp_id = 0
|
||||
|
||||
---@param drop string|drop_definition
|
||||
---@param toolname string
|
||||
---@param param2 integer
|
||||
---@param paramtype2 paramtype2
|
||||
---@return string[]
|
||||
local function get_drops(drop, toolname, param2, paramtype2)
|
||||
tmp_id = tmp_id + 1
|
||||
local tmp_node_name = "mcl_item_entity:" .. tmp_id
|
||||
|
@ -202,7 +217,7 @@ local function get_drops(drop, toolname, param2, paramtype2)
|
|||
drop = drop,
|
||||
paramtype2 = paramtype2
|
||||
}
|
||||
local drops = minetest.get_node_drops({name = tmp_node_name, param2 = param2}, toolname)
|
||||
local drops = minetest.get_node_drops({ name = tmp_node_name, param2 = param2 }, toolname)
|
||||
minetest.registered_nodes[tmp_node_name] = nil
|
||||
return drops
|
||||
end
|
||||
|
@ -265,7 +280,7 @@ function minetest.handle_node_drops(pos, drops, digger)
|
|||
* table: Drop every itemstring in this table when dug by shears _mcl_silk_touch_drop
|
||||
]]
|
||||
|
||||
local enchantments = tool and mcl_enchanting.get_enchantments(tool, "silk_touch")
|
||||
local enchantments = tool and mcl_enchanting.get_enchantments(tool)
|
||||
|
||||
local silk_touch_drop = false
|
||||
local nodedef = minetest.registered_nodes[dug_node.name]
|
||||
|
@ -294,7 +309,8 @@ function minetest.handle_node_drops(pos, drops, digger)
|
|||
local max_count = fortune_drop.max_count + fortune_level * (fortune_drop.factor or 1)
|
||||
local chance = fortune_drop.chance or fortune_drop.get_chance and fortune_drop.get_chance(fortune_level)
|
||||
if not chance or math.random() < chance then
|
||||
drops = discrete_uniform_distribution(fortune_drop.multiply and drops or fortune_drop.items, min_count, max_count, fortune_drop.cap)
|
||||
drops = discrete_uniform_distribution(fortune_drop.multiply and drops or fortune_drop.items, min_count, max_count,
|
||||
fortune_drop.cap)
|
||||
elseif fortune_drop.override then
|
||||
drops = {}
|
||||
end
|
||||
|
@ -306,13 +322,13 @@ function minetest.handle_node_drops(pos, drops, digger)
|
|||
end
|
||||
|
||||
if digger and mcl_experience.throw_xp and not silk_touch_drop then
|
||||
local experience_amount = minetest.get_item_group(dug_node.name,"xp")
|
||||
local experience_amount = minetest.get_item_group(dug_node.name, "xp")
|
||||
if experience_amount > 0 then
|
||||
mcl_experience.throw_xp(pos, experience_amount)
|
||||
end
|
||||
end
|
||||
|
||||
for _,item in ipairs(drops) do
|
||||
for _, item in ipairs(drops) do
|
||||
local count
|
||||
if type(item) == "string" then
|
||||
count = ItemStack(item):get_count()
|
||||
|
@ -321,7 +337,7 @@ function minetest.handle_node_drops(pos, drops, digger)
|
|||
end
|
||||
local drop_item = ItemStack(item)
|
||||
drop_item:set_count(1)
|
||||
for i=1,count do
|
||||
for i = 1, count do
|
||||
local dpos = table.copy(pos)
|
||||
-- Apply offset for plantlike_rooted nodes because of their special shape
|
||||
if nodedef and nodedef.drawtype == "plantlike_rooted" and nodedef.walkable then
|
||||
|
@ -348,7 +364,7 @@ end
|
|||
function minetest.item_drop(itemstack, dropper, pos)
|
||||
if dropper and dropper:is_player() then
|
||||
local v = dropper:get_look_dir()
|
||||
local p = {x=pos.x, y=pos.y+1.2, z=pos.z}
|
||||
local p = vector.offset(pos, 0, 1.2, 0)
|
||||
local cs = itemstack:get_count()
|
||||
if dropper:get_player_control().sneak then
|
||||
cs = 1
|
||||
|
@ -356,9 +372,9 @@ function minetest.item_drop(itemstack, dropper, pos)
|
|||
local item = itemstack:take_item(cs)
|
||||
local obj = minetest.add_item(p, item)
|
||||
if obj then
|
||||
v.x = v.x*4
|
||||
v.y = v.y*4 + 2
|
||||
v.z = v.z*4
|
||||
v.x = v.x * 4
|
||||
v.y = v.y * 4 + 2
|
||||
v.z = v.z * 4
|
||||
obj:set_velocity(v)
|
||||
-- Force collection delay
|
||||
obj:get_luaentity()._insta_collect = false
|
||||
|
@ -376,16 +392,16 @@ end
|
|||
|
||||
local function cxcz(o, cw, one, zero)
|
||||
if cw < 0 then
|
||||
table.insert(o, { [one]=1, y=0, [zero]=0 })
|
||||
table.insert(o, { [one]=-1, y=0, [zero]=0 })
|
||||
table.insert(o, { [one] = 1, y = 0, [zero] = 0 })
|
||||
table.insert(o, { [one] = -1, y = 0, [zero] = 0 })
|
||||
else
|
||||
table.insert(o, { [one]=-1, y=0, [zero]=0 })
|
||||
table.insert(o, { [one]=1, y=0, [zero]=0 })
|
||||
table.insert(o, { [one] = -1, y = 0, [zero] = 0 })
|
||||
table.insert(o, { [one] = 1, y = 0, [zero] = 0 })
|
||||
end
|
||||
return o
|
||||
end
|
||||
|
||||
local function hopper_take_item (self, pos)
|
||||
local function hopper_take_item(self, pos)
|
||||
--mcl_log("self.itemstring: ".. self.itemstring)
|
||||
--mcl_log("self.itemstring: ".. minetest.pos_to_string(pos))
|
||||
|
||||
|
@ -394,17 +410,17 @@ local function hopper_take_item (self, pos)
|
|||
if objs and self.itemstring then
|
||||
--mcl_log("there is an itemstring. Number of objs: ".. #objs)
|
||||
|
||||
for k,v in pairs(objs) do
|
||||
for k, v in pairs(objs) do
|
||||
local ent = v:get_luaentity()
|
||||
|
||||
-- Don't forget actual hoppers
|
||||
if ent and ent.name == "mcl_minecarts:hopper_minecart" then
|
||||
local taken_items = false
|
||||
|
||||
mcl_log("ent.name: ".. tostring(ent.name))
|
||||
mcl_log("ent pos: ".. tostring(ent.object:get_pos()))
|
||||
mcl_log("ent.name: " .. tostring(ent.name))
|
||||
mcl_log("ent pos: " .. tostring(ent.object:get_pos()))
|
||||
|
||||
local inv = mcl_entity_invs.load_inv(ent,5)
|
||||
local inv = mcl_entity_invs.load_inv(ent, 5)
|
||||
|
||||
if not inv then
|
||||
mcl_log("No inv")
|
||||
|
@ -428,7 +444,7 @@ local function hopper_take_item (self, pos)
|
|||
local items_remaining = current_itemstack:get_count()
|
||||
|
||||
-- This will take part of a floating item stack if no slot can hold the full amount
|
||||
for i = 1, ent._inv_size,1 do
|
||||
for i = 1, ent._inv_size, 1 do
|
||||
local stack = inv:get_stack("main", i)
|
||||
|
||||
mcl_log("i: " .. tostring(i))
|
||||
|
@ -500,13 +516,13 @@ minetest.register_entity(":__builtin:item", {
|
|||
hp_max = 1,
|
||||
physical = true,
|
||||
collide_with_objects = false,
|
||||
collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
|
||||
collisionbox = { -0.3, -0.3, -0.3, 0.3, 0.3, 0.3 },
|
||||
pointable = false,
|
||||
visual = "wielditem",
|
||||
visual_size = {x = 0.4, y = 0.4},
|
||||
textures = {""},
|
||||
spritediv = {x = 1, y = 1},
|
||||
initial_sprite_basepos = {x = 0, y = 0},
|
||||
visual_size = { x = 0.4, y = 0.4 },
|
||||
textures = { "" },
|
||||
spritediv = { x = 1, y = 1 },
|
||||
initial_sprite_basepos = { x = 0, y = 0 },
|
||||
is_visible = false,
|
||||
infotext = "",
|
||||
},
|
||||
|
@ -544,11 +560,11 @@ minetest.register_entity(":__builtin:item", {
|
|||
if vel and vel.x == 0 and vel.z == 0 and self.random_velocity > 0 then
|
||||
local v = self.random_velocity
|
||||
local x = math.random(5, 10) / 10 * v
|
||||
if math.random(0,10) < 5 then x = -x end
|
||||
if math.random(0, 10) < 5 then x = -x end
|
||||
local z = math.random(5, 10) / 10 * v
|
||||
if math.random(0,10) < 5 then z = -z end
|
||||
local y = math.random(2,4)
|
||||
self.object:set_velocity({x=x, y=y, z=z})
|
||||
if math.random(0, 10) < 5 then z = -z end
|
||||
local y = math.random(2, 4)
|
||||
self.object:set_velocity(vector.new(x, y, z))
|
||||
end
|
||||
self.random_velocity = 0
|
||||
end,
|
||||
|
@ -576,7 +592,7 @@ minetest.register_entity(":__builtin:item", {
|
|||
local max_count = stack:get_stack_max()
|
||||
if count > max_count then
|
||||
count = max_count
|
||||
self.itemstring = stack:get_name().." "..max_count
|
||||
self.itemstring = stack:get_name() .. " " .. max_count
|
||||
end
|
||||
local itemtable = stack:to_table()
|
||||
local itemname = nil
|
||||
|
@ -597,9 +613,9 @@ minetest.register_entity(":__builtin:item", {
|
|||
local prop = {
|
||||
is_visible = true,
|
||||
visual = "wielditem",
|
||||
textures = {itemname},
|
||||
visual_size = {x = s, y = s},
|
||||
collisionbox = {-c, -c, -c, c, c, c},
|
||||
textures = { itemname },
|
||||
visual_size = { x = s, y = s },
|
||||
collisionbox = { -c, -c, -c, c, c, c },
|
||||
automatic_rotate = math.pi * 0.5,
|
||||
infotext = description,
|
||||
glow = glow,
|
||||
|
@ -695,9 +711,9 @@ minetest.register_entity(":__builtin:item", {
|
|||
self._forcestart = nil
|
||||
self._forcetimer = 0
|
||||
|
||||
self.object:set_armor_groups({immortal = 1})
|
||||
-- self.object:set_velocity({x = 0, y = 2, z = 0})
|
||||
self.object:set_acceleration({x = 0, y = -get_gravity(), z = 0})
|
||||
self.object:set_armor_groups({ immortal = 1 })
|
||||
-- self.object:set_velocity(vector.new(0, 2, 0))
|
||||
self.object:set_acceleration(vector.new(0, -get_gravity(), 0))
|
||||
self:set_item(self.itemstring)
|
||||
end,
|
||||
|
||||
|
@ -710,9 +726,9 @@ minetest.register_entity(":__builtin:item", {
|
|||
local stack = ItemStack(entity.itemstring)
|
||||
local name = stack:get_name()
|
||||
if own_stack:get_name() ~= name or
|
||||
own_stack:get_meta() ~= stack:get_meta() or
|
||||
own_stack:get_wear() ~= stack:get_wear() or
|
||||
own_stack:get_free_space() == 0 then
|
||||
own_stack:get_meta() ~= stack:get_meta() or
|
||||
own_stack:get_wear() ~= stack:get_wear() or
|
||||
own_stack:get_free_space() == 0 then
|
||||
-- Can not merge different or full stack
|
||||
return false
|
||||
end
|
||||
|
@ -745,8 +761,8 @@ minetest.register_entity(":__builtin:item", {
|
|||
self.object:set_properties({
|
||||
physical = false
|
||||
})
|
||||
self.object:set_velocity({x=0,y=0,z=0})
|
||||
self.object:set_acceleration({x=0,y=0,z=0})
|
||||
self.object:set_velocity(vector.zero())
|
||||
self.object:set_acceleration(vector.zero())
|
||||
return
|
||||
end
|
||||
self.age = self.age + dtime
|
||||
|
@ -761,21 +777,22 @@ minetest.register_entity(":__builtin:item", {
|
|||
-- Delete corrupted item entities. The itemstring MUST be non-empty on its first step,
|
||||
-- otherwise there might have some data corruption.
|
||||
if self.itemstring == "" then
|
||||
minetest.log("warning", "Item entity with empty itemstring found at "..minetest.pos_to_string(self.object:get_pos()).. "! Deleting it now.")
|
||||
minetest.log("warning",
|
||||
"Item entity with empty itemstring found at " .. minetest.pos_to_string(self.object:get_pos()) ..
|
||||
"! Deleting it now.")
|
||||
self._removed = true
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
||||
local p = self.object:get_pos()
|
||||
|
||||
-- If hopper has taken item, it has gone, and no operations should be conducted on this item
|
||||
if hopper_take_item(self, p) then
|
||||
return
|
||||
end
|
||||
|
||||
local node = minetest.get_node_or_nil(p)
|
||||
local in_unloaded = (node == nil)
|
||||
local node = minetest.get_node(p)
|
||||
local in_unloaded = node.name == "ignore"
|
||||
|
||||
if in_unloaded then
|
||||
-- Don't infinetly fall into unloaded map
|
||||
|
@ -785,27 +802,27 @@ minetest.register_entity(":__builtin:item", {
|
|||
|
||||
if self.is_clock then
|
||||
self.object:set_properties({
|
||||
textures = {"mcl_clock:clock_" .. (mcl_worlds.clock_works(p) and mcl_clock.old_time or mcl_clock.random_frame)}
|
||||
textures = { "mcl_clock:clock_" .. (mcl_worlds.clock_works(p) and mcl_clock.old_time or mcl_clock.random_frame) }
|
||||
})
|
||||
end
|
||||
|
||||
local nn = node.name
|
||||
local is_in_water = (minetest.get_item_group(nn, "liquid") ~= 0)
|
||||
local nn_above = minetest.get_node({x=p.x, y=p.y+0.1, z=p.z}).name
|
||||
local nn_above = minetest.get_node(vector.offset(p, 0, 0.1, 0)).name
|
||||
-- make sure it's more or less stationary and is at water level
|
||||
local sleep_threshold = 0.3
|
||||
local is_floating = false
|
||||
local is_stationary = math.abs(self.object:get_velocity().x) < sleep_threshold
|
||||
and math.abs(self.object:get_velocity().y) < sleep_threshold
|
||||
and math.abs(self.object:get_velocity().z) < sleep_threshold
|
||||
and math.abs(self.object:get_velocity().y) < sleep_threshold
|
||||
and math.abs(self.object:get_velocity().z) < sleep_threshold
|
||||
if is_in_water and is_stationary then
|
||||
is_floating = (is_in_water
|
||||
and (minetest.get_item_group(nn_above, "liquid") == 0))
|
||||
end
|
||||
|
||||
if is_floating and self.physical_state == true then
|
||||
self.object:set_velocity({x = 0, y = 0, z = 0})
|
||||
self.object:set_acceleration({x = 0, y = 0, z = 0})
|
||||
self.object:set_velocity(vector.zero())
|
||||
self.object:set_acceleration(vector.zero())
|
||||
disable_physics(self.object, self)
|
||||
end
|
||||
-- If no collector was found for a long enough time, declare the magnet as disabled
|
||||
|
@ -825,7 +842,7 @@ minetest.register_entity(":__builtin:item", {
|
|||
--Wait 2 seconds to allow mob drops to be cooked, & picked up instead of instantly destroyed.
|
||||
if self.age > 2 and minetest.get_item_group(self.itemstring, "fire_immune") == 0 then
|
||||
if dg ~= 2 then
|
||||
minetest.sound_play("builtin_item_lava", {pos = self.object:get_pos(), gain = 0.5})
|
||||
minetest.sound_play("builtin_item_lava", { pos = self.object:get_pos(), gain = 0.5 })
|
||||
end
|
||||
self._removed = true
|
||||
self.object:remove()
|
||||
|
@ -865,7 +882,7 @@ minetest.register_entity(":__builtin:item", {
|
|||
end
|
||||
|
||||
-- Check which one of the 4 sides is free
|
||||
for o=1, #order do
|
||||
for o = 1, #order do
|
||||
local nn = minetest.get_node(vector.add(p, order[o])).name
|
||||
local def = minetest.registered_nodes[nn]
|
||||
if def and def.walkable == false and nn ~= "ignore" then
|
||||
|
@ -875,7 +892,7 @@ minetest.register_entity(":__builtin:item", {
|
|||
end
|
||||
-- If none of the 4 sides is free, shoot upwards
|
||||
if shootdir == nil then
|
||||
shootdir = { x=0, y=1, z=0 }
|
||||
shootdir = vector.new(0, 1, 0)
|
||||
local nn = minetest.get_node(vector.add(p, shootdir)).name
|
||||
if nn == "ignore" then
|
||||
-- Do not push into ignore
|
||||
|
@ -885,7 +902,7 @@ minetest.register_entity(":__builtin:item", {
|
|||
|
||||
-- Set new item moving speed accordingly
|
||||
local newv = vector.multiply(shootdir, 3)
|
||||
self.object:set_acceleration({x = 0, y = 0, z = 0})
|
||||
self.object:set_acceleration(vector.zero())
|
||||
self.object:set_velocity(newv)
|
||||
disable_physics(self.object, self, false, false)
|
||||
|
||||
|
@ -907,10 +924,10 @@ minetest.register_entity(":__builtin:item", {
|
|||
if self._forcetimer > 0 then
|
||||
local cbox = self.object:get_properties().collisionbox
|
||||
local ok = false
|
||||
if self._force.x > 0 and (p.x > (self._forcestart.x + 0.5 + (cbox[4] - cbox[1])/2)) then ok = true
|
||||
elseif self._force.x < 0 and (p.x < (self._forcestart.x + 0.5 - (cbox[4] - cbox[1])/2)) then ok = true
|
||||
elseif self._force.z > 0 and (p.z > (self._forcestart.z + 0.5 + (cbox[6] - cbox[3])/2)) then ok = true
|
||||
elseif self._force.z < 0 and (p.z < (self._forcestart.z + 0.5 - (cbox[6] - cbox[3])/2)) then ok = true end
|
||||
if self._force.x > 0 and (p.x > (self._forcestart.x + 0.5 + (cbox[4] - cbox[1]) / 2)) then ok = true
|
||||
elseif self._force.x < 0 and (p.x < (self._forcestart.x + 0.5 - (cbox[4] - cbox[1]) / 2)) then ok = true
|
||||
elseif self._force.z > 0 and (p.z > (self._forcestart.z + 0.5 + (cbox[6] - cbox[3]) / 2)) then ok = true
|
||||
elseif self._force.z < 0 and (p.z < (self._forcestart.z + 0.5 - (cbox[6] - cbox[3]) / 2)) then ok = true end
|
||||
-- Item was successfully forced out. No more pushing
|
||||
if ok then
|
||||
self._forcetimer = -1
|
||||
|
@ -941,7 +958,7 @@ minetest.register_entity(":__builtin:item", {
|
|||
-- Set new item moving speed into the direciton of the liquid
|
||||
local newv = vector.multiply(vec, f)
|
||||
-- Swap to acceleration instead of a static speed to better mimic MC mechanics.
|
||||
self.object:set_acceleration({x = newv.x, y = -0.22, z = newv.z})
|
||||
self.object:set_acceleration(vector.new(newv.x, -0.22, newv.z))
|
||||
|
||||
self.physical_state = true
|
||||
self._flowing = true
|
||||
|
@ -954,9 +971,10 @@ minetest.register_entity(":__builtin:item", {
|
|||
local cur_vec = self.object:get_velocity()
|
||||
-- apply some acceleration in the opposite direction so it doesn't slide forever
|
||||
local vec = {
|
||||
x = 0 -cur_vec.x*0.9,
|
||||
y = 3 -cur_vec.y*0.9,
|
||||
z = 0 -cur_vec.z*0.9}
|
||||
x = 0 - cur_vec.x * 0.9,
|
||||
y = 3 - cur_vec.y * 0.9,
|
||||
z = 0 - cur_vec.z * 0.9
|
||||
}
|
||||
self.object:set_acceleration(vec)
|
||||
-- slow down the item in water
|
||||
local vel = self.object:get_velocity()
|
||||
|
@ -980,20 +998,20 @@ minetest.register_entity(":__builtin:item", {
|
|||
end
|
||||
|
||||
-- If node is not registered or node is walkably solid and resting on nodebox
|
||||
local nn = minetest.get_node({x=p.x, y=p.y-0.5, z=p.z}).name
|
||||
local nn = minetest.get_node(vector.offset(p, 0, -0.5, 0)).name
|
||||
local def = minetest.registered_nodes[nn]
|
||||
local v = self.object:get_velocity()
|
||||
local is_on_floor = def and (def.walkable
|
||||
and not def.groups.slippery and v.y == 0)
|
||||
|
||||
if not minetest.registered_nodes[nn]
|
||||
or is_floating or is_on_floor then
|
||||
or is_floating or is_on_floor then
|
||||
local own_stack = ItemStack(self.object:get_luaentity().itemstring)
|
||||
-- Merge with close entities of the same item
|
||||
for _, object in pairs(minetest.get_objects_inside_radius(p, 0.8)) do
|
||||
local obj = object:get_luaentity()
|
||||
if obj and obj.name == "__builtin:item"
|
||||
and obj.physical_state == false then
|
||||
and obj.physical_state == false then
|
||||
if self:try_merge_with(own_stack, object, obj) then
|
||||
return
|
||||
end
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# textdomain: mcl_minecarts
|
||||
Minecart=Minevogn
|
||||
Minecarts can be used for a quick transportion on rails.=Minevogne kan bruges til hurtig transport på spor.
|
||||
Minecarts only ride on rails and always follow the tracks. At a T-junction with no straight way ahead, they turn left. The speed is affected by the rail type.=Minevogne kan kun køre på spor, og følger dem altid. Ved et T-kryds uden en vej ligeud drejer de altid til venstre. Farten påvirkes af sportypen.
|
||||
You can place the minecart on rails. Right-click it to enter it. Punch it to get it moving.=Du kan placere minevogne på spor. Højre-klik for at stige ombord.
|
||||
To obtain the minecart, punch it while holding down the sneak key.=For at at få minevognen i din oppakning.
|
||||
A minecart with TNT is an explosive vehicle that travels on rail.=En minevogn med TNT as et eksplosivt fartøj som kører på spor.
|
||||
Place it on rails. Punch it to move it. The TNT is ignited with a flint and steel or when the minecart is on an powered activator rail.=Placér den på spor. Slå den for at flytte den. TNTet bliver antændt med flint og stål eller når minevognen er på et aktiveringsspor.
|
||||
To obtain the minecart and TNT, punch them while holding down the sneak key. You can't do this if the TNT was ignited.=For at få minevognen med TNT i din oppakning skal du slå den mens du holder snigeknappen nede. Du kan ikke gøre dette hvis TNTen er antændt.
|
||||
A minecart with furnace is a vehicle that travels on rails. It can propel itself with fuel.=En minevogn med ovn er et fartøj som kører på spor. Den kan køre af sig selv med brændstof.
|
||||
Place it on rails. If you give it some coal, the furnace will start burning for a long time and the minecart will be able to move itself. Punch it to get it moving.=Placér den på spor. Hvis du putter kul i den vil ovnen brænde i lang tid, og minevognen vil køre af sig selv. Slå den for at sætte den i bevægelse.
|
||||
To obtain the minecart and furnace, punch them while holding down the sneak key.=For at få minevognen med ovn i din oppakning skal du slå den mens du holder snigeknappen nede.
|
||||
Minecart with Chest=Minevogn med kiste
|
||||
Minecart with Furnace=Minevogn med ovn
|
||||
Minecart with Command Block=Minevogn med kommandoblok
|
||||
Minecart with Hopper=Minevogn med tragt
|
||||
Minecart with TNT=Minevogn med TNT
|
||||
Place them on the ground to build your railway, the rails will automatically connect to each other and will turn into curves, T-junctions, crossings and slopes as needed.=Placér dem på jorden for at bygge din jerbane. Sporene kobler sig automatisk sammen med hinanden og laver sving, T-kryds, kryds og skråninger efter behov.
|
||||
Rail=Spor
|
||||
Rails can be used to build transport tracks for minecarts. Normal rails slightly slow down minecarts due to friction.=Spor kan bruges til at bygge jernbaner til minevogne. Normale spor sænker minevognene en smule på grund af friktionsmodstand.
|
||||
Powered Rail=Strømspor
|
||||
Rails can be used to build transport tracks for minecarts. Powered rails are able to accelerate and brake minecarts.=Spor kan bruges til at bygge jernbaner til minevogne. Strømspor kan accelerere eller bremse minevogne.
|
||||
Without redstone power, the rail will brake minecarts. To make this rail accelerate minecarts, power it with redstone power.=Uden redstonekraft vil sporet bremse minevognen. For at accelerere minevognen skal den bruge redstoneskraft.
|
||||
Activator Rail=Aktiveringsspor
|
||||
Rails can be used to build transport tracks for minecarts. Activator rails are used to activate special minecarts.=Spor kan bruges til at bygge jernbaner til minevogne. Aktiveringsspor bruges til at aktivere specielle minevogne.
|
||||
To make this rail activate minecarts, power it with redstone power and send a minecart over this piece of rail.=For at få dette spor til at aktiere minevogne skal du give det redstonekraft og sende en minevogn over dette sporstykke.
|
||||
Detector Rail=Detektorspor
|
||||
Rails can be used to build transport tracks for minecarts. A detector rail is able to detect a minecart above it and powers redstone mechanisms.=Spor kan bruges til at bygge jernbaner til minevogne. Et detektorspor kan opdage en minevogn som kører over det og give kraft til redstonemekanismer.
|
||||
To detect a minecart and provide redstone power, connect it to redstone trails or redstone mechanisms and send any minecart over the rail.=For at opdage en minevogn og give redstonekraft skal den forbindes til redstonestøv eller redstonemekanismer og send en hvilkensomhelst minevogn hen over sporet.
|
||||
Track for minecarts=Spor til minevogne.
|
||||
Speed up when powered, slow down when not powered=Accelerérer når der er strøm, sænk hastigheden når der ikke er strøm.
|
||||
Activates minecarts when powered=Aktieverer minevogne når der er strøm.
|
||||
Emits redstone power when a minecart is detected=Udsender redstonekraft når en minevogn bliver opdaget.
|
||||
Vehicle for fast travel on rails=Fartøj til hurtig kørsel på spor.
|
||||
Can be ignited by tools or powered activator rail=Kan antændes med værktøj eller et aktivatorspor med strøm.
|
||||
Sneak to dismount=Snig for at stige af.
|
|
@ -2,8 +2,6 @@ local mob_class = mcl_mobs.mob_class
|
|||
local mob_class_meta = {__index = mcl_mobs.mob_class}
|
||||
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
|
||||
-- API for Mobs Redo: MineClone 2 Edition (MRM)
|
||||
local MAX_MOB_NAME_LENGTH = 30
|
||||
local DEFAULT_FALL_SPEED = -9.81*1.5
|
||||
|
||||
local PATHFINDING = "gowp"
|
||||
|
||||
|
@ -17,21 +15,9 @@ local function mcl_log (message)
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
-- Invisibility mod check
|
||||
mcl_mobs.invis = {}
|
||||
|
||||
-- localize math functions
|
||||
local atann = math.atan
|
||||
|
||||
local function atan(x)
|
||||
if not x or x ~= x then
|
||||
return 0
|
||||
else
|
||||
return atann(x)
|
||||
end
|
||||
end
|
||||
|
||||
local remove_far = true
|
||||
local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false
|
||||
local spawn_protected = minetest.settings:get_bool("mobs_spawn_protected") ~= false
|
||||
|
@ -297,51 +283,65 @@ function mob_class:mob_activate(staticdata, def, dtime)
|
|||
end
|
||||
end
|
||||
|
||||
-- execute current state (stand, walk, run, attacks)
|
||||
-- returns true if mob has died
|
||||
function mob_class:do_states(dtime)
|
||||
--if self.can_open_doors then check_doors(self) end
|
||||
|
||||
if self.state == "stand" then
|
||||
self:do_states_stand()
|
||||
elseif self.state == PATHFINDING then
|
||||
self:check_gowp(dtime)
|
||||
elseif self.state == "walk" then
|
||||
self:do_states_walk()
|
||||
elseif self.state == "runaway" then
|
||||
-- runaway when punched
|
||||
self:do_states_runaway()
|
||||
elseif self.state == "attack" then
|
||||
-- attack routines (explode, dogfight, shoot, dogshoot)
|
||||
if self:do_states_attack(dtime) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function update_timers (self, dtime)
|
||||
-- knockback timer. set in on_punch
|
||||
if self.pause_timer > 0 then
|
||||
self.pause_timer = self.pause_timer - dtime
|
||||
return true
|
||||
end
|
||||
|
||||
-- attack timer
|
||||
self.timer = self.timer + dtime
|
||||
|
||||
if self.state ~= "attack" and self.state ~= PATHFINDING then
|
||||
if self.timer < 1 then
|
||||
return true
|
||||
end
|
||||
self.timer = 0
|
||||
end
|
||||
|
||||
-- never go over 100
|
||||
if self.timer > 100 then
|
||||
self.timer = 1
|
||||
end
|
||||
end
|
||||
|
||||
-- main mob function
|
||||
function mob_class:on_step(dtime)
|
||||
self.lifetimer = self.lifetimer - dtime
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
if self:check_despawn(pos) then return true end
|
||||
|
||||
local d = 0.85
|
||||
if self:check_dying() then d = 0.92 end
|
||||
|
||||
local v = self.object:get_velocity()
|
||||
if v then
|
||||
--diffuse object velocity
|
||||
self.object:set_velocity({x = v.x*d, y = v.y, z = v.z*d})
|
||||
end
|
||||
if self:check_despawn(pos, dtime) then return true end
|
||||
|
||||
self:slow_mob()
|
||||
if self:falling(pos) then return end
|
||||
|
||||
self:check_suspend()
|
||||
|
||||
self:check_water_flow()
|
||||
|
||||
local yaw = 0
|
||||
if self:is_at_water_danger() and self.state ~= "attack" then
|
||||
if math.random(1, 10) <= 6 then
|
||||
self:set_velocity(0)
|
||||
self.state = "stand"
|
||||
self:set_animation( "stand")
|
||||
yaw = yaw + math.random(-0.5, 0.5)
|
||||
yaw = self:set_yaw( yaw, 8)
|
||||
end
|
||||
else
|
||||
if self.move_in_group ~= false then
|
||||
self:check_herd(dtime)
|
||||
end
|
||||
end
|
||||
|
||||
if self:is_at_cliff_or_danger() then
|
||||
self:set_velocity(0)
|
||||
self.state = "stand"
|
||||
self:set_animation( "stand")
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
yaw = self:set_yaw( yaw + 0.78, 8)
|
||||
end
|
||||
self:env_danger_movement_checks (dtime)
|
||||
|
||||
if not self.fire_resistant then
|
||||
mcl_burning.tick(self.object, dtime, self)
|
||||
|
@ -353,21 +353,17 @@ function mob_class:on_step(dtime)
|
|||
|
||||
if self.state == "die" then return end
|
||||
|
||||
if self.jump_sound_cooloff > 0 then
|
||||
self.jump_sound_cooloff = self.jump_sound_cooloff - dtime
|
||||
end
|
||||
if self.opinion_sound_cooloff > 0 then
|
||||
self.opinion_sound_cooloff = self.opinion_sound_cooloff - dtime
|
||||
end
|
||||
self:follow_flop() -- Mob following code.
|
||||
|
||||
--Mob following code.
|
||||
self:follow_flop()
|
||||
--set animation speed relitive to velocity
|
||||
self:set_animation_speed()
|
||||
self:set_animation_speed() -- set animation speed relitive to velocity
|
||||
self:check_smooth_rotation(dtime)
|
||||
self:check_head_swivel(dtime)
|
||||
|
||||
if self.jump_sound_cooloff > 0 then
|
||||
self.jump_sound_cooloff = self.jump_sound_cooloff - dtime
|
||||
end
|
||||
self:do_jump()
|
||||
|
||||
self:set_armor_texture()
|
||||
self:check_runaway_from()
|
||||
|
||||
|
@ -378,63 +374,26 @@ function mob_class:on_step(dtime)
|
|||
|
||||
-- run custom function (defined in mob lua file)
|
||||
if self.do_custom then
|
||||
|
||||
-- when false skip going any further
|
||||
if self.do_custom(self, dtime) == false then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- knockback timer
|
||||
if self.pause_timer > 0 then
|
||||
if update_timers(self, dtime) then return end
|
||||
|
||||
self.pause_timer = self.pause_timer - dtime
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- attack timer
|
||||
self.timer = self.timer + dtime
|
||||
|
||||
if self.state ~= "attack" and self.state ~= PATHFINDING then
|
||||
if self.timer < 1 then
|
||||
return
|
||||
end
|
||||
self.timer = 0
|
||||
end
|
||||
self:check_particlespawners(dtime)
|
||||
self:check_item_pickup()
|
||||
|
||||
-- never go over 100
|
||||
if self.timer > 100 then
|
||||
self.timer = 1
|
||||
if self.opinion_sound_cooloff > 0 then
|
||||
self.opinion_sound_cooloff = self.opinion_sound_cooloff - dtime
|
||||
end
|
||||
|
||||
-- mob plays random sound at times
|
||||
-- mob plays random sound at times. Should be 120. Zombie and mob farms are ridiculous
|
||||
if math.random(1, 70) == 1 then
|
||||
self:mob_sound("random", true)
|
||||
end
|
||||
|
||||
-- environmental damage timer (every 1 second)
|
||||
self.env_damage_timer = self.env_damage_timer + dtime
|
||||
|
||||
if (self.state == "attack" and self.env_damage_timer > 1)
|
||||
or self.state ~= "attack" then
|
||||
self:check_entity_cramming()
|
||||
self.env_damage_timer = 0
|
||||
|
||||
-- check for environmental damage (water, fire, lava etc.)
|
||||
if self:do_env_damage() then
|
||||
return
|
||||
end
|
||||
|
||||
-- node replace check (cow eats grass etc.)
|
||||
self:replace(pos)
|
||||
end
|
||||
|
||||
if self:do_states(dtime) then
|
||||
return
|
||||
end
|
||||
if self:env_damage (dtime, pos) then return end
|
||||
if self:do_states(dtime) then return end
|
||||
|
||||
if not self.object:get_luaentity() then
|
||||
return false
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
|
||||
local mob_class = mcl_mobs.mob_class
|
||||
|
||||
local MAX_MOB_NAME_LENGTH = 30
|
||||
local HORNY_TIME = 30
|
||||
local HORNY_AGAIN_TIME = 300
|
||||
local CHILD_GROW_TIME = 60*20
|
||||
|
|
|
@ -8,6 +8,18 @@ local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false
|
|||
local stuck_timeout = 3 -- how long before mob gets stuck in place and starts searching
|
||||
local stuck_path_timeout = 10 -- how long will mob follow path before giving up
|
||||
|
||||
local enable_pathfinding = true
|
||||
|
||||
local atann = math.atan
|
||||
local function atan(x)
|
||||
if not x or x ~= x then
|
||||
return 0
|
||||
else
|
||||
return atann(x)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- check if daytime and also if mob is docile during daylight hours
|
||||
function mob_class:day_docile()
|
||||
if self.docile_by_day == false then
|
||||
|
@ -794,3 +806,397 @@ function mob_class:check_aggro(dtime)
|
|||
end
|
||||
self._check_aggro_timer = self._check_aggro_timer + dtime
|
||||
end
|
||||
|
||||
function mob_class:do_states_attack (dtime)
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
|
||||
local s = self.object:get_pos()
|
||||
local p = self.attack:get_pos() or s
|
||||
|
||||
-- stop attacking if player invisible or out of range
|
||||
if not self.attack
|
||||
or not self.attack:get_pos()
|
||||
or not self:object_in_range(self.attack)
|
||||
or self.attack:get_hp() <= 0
|
||||
or (self.attack:is_player() and mcl_mobs.invis[ self.attack:get_player_name() ]) then
|
||||
|
||||
self.state = "stand"
|
||||
self:set_velocity( 0)
|
||||
self:set_animation( "stand")
|
||||
self.attack = nil
|
||||
self.v_start = false
|
||||
self.timer = 0
|
||||
self.blinktimer = 0
|
||||
self.path.way = nil
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- calculate distance from mob and enemy
|
||||
local dist = vector.distance(p, s)
|
||||
|
||||
if self.attack_type == "explode" then
|
||||
|
||||
local vec = {
|
||||
x = p.x - s.x,
|
||||
z = p.z - s.z
|
||||
}
|
||||
|
||||
yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
|
||||
|
||||
if p.x > s.x then yaw = yaw +math.pi end
|
||||
|
||||
yaw = self:set_yaw( yaw, 0, dtime)
|
||||
|
||||
local node_break_radius = self.explosion_radius or 1
|
||||
local entity_damage_radius = self.explosion_damage_radius
|
||||
or (node_break_radius * 2)
|
||||
|
||||
-- start timer when in reach and line of sight
|
||||
if not self.v_start
|
||||
and dist <= self.reach
|
||||
and self:line_of_sight( s, p, 2) then
|
||||
|
||||
self.v_start = true
|
||||
self.timer = 0
|
||||
self.blinktimer = 0
|
||||
self:mob_sound("fuse", nil, false)
|
||||
|
||||
-- stop timer if out of reach or direct line of sight
|
||||
elseif self.allow_fuse_reset
|
||||
and self.v_start
|
||||
and (dist >= self.explosiontimer_reset_radius
|
||||
or not self:line_of_sight( s, p, 2)) then
|
||||
self.v_start = false
|
||||
self.timer = 0
|
||||
self.blinktimer = 0
|
||||
self.blinkstatus = false
|
||||
self:remove_texture_mod("^[brighten")
|
||||
end
|
||||
|
||||
-- walk right up to player unless the timer is active
|
||||
if self.v_start and (self.stop_to_explode or dist < self.reach) then
|
||||
self:set_velocity( 0)
|
||||
else
|
||||
self:set_velocity( self.run_velocity)
|
||||
end
|
||||
|
||||
if self.animation and self.animation.run_start then
|
||||
self:set_animation( "run")
|
||||
else
|
||||
self:set_animation( "walk")
|
||||
end
|
||||
|
||||
if self.v_start then
|
||||
|
||||
self.timer = self.timer + dtime
|
||||
self.blinktimer = (self.blinktimer or 0) + dtime
|
||||
|
||||
if self.blinktimer > 0.2 then
|
||||
|
||||
self.blinktimer = 0
|
||||
|
||||
if self.blinkstatus then
|
||||
self:remove_texture_mod("^[brighten")
|
||||
else
|
||||
self:add_texture_mod("^[brighten")
|
||||
end
|
||||
|
||||
self.blinkstatus = not self.blinkstatus
|
||||
end
|
||||
|
||||
if self.timer > self.explosion_timer then
|
||||
|
||||
local pos = self.object:get_pos()
|
||||
|
||||
if mobs_griefing and not minetest.is_protected(pos, "") then
|
||||
mcl_explosions.explode(mcl_util.get_object_center(self.object), self.explosion_strength, { drop_chance = 1.0 }, self.object)
|
||||
else
|
||||
minetest.sound_play(self.sounds.explode, {
|
||||
pos = pos,
|
||||
gain = 1.0,
|
||||
max_hear_distance = self.sounds.distance or 32
|
||||
}, true)
|
||||
self:entity_physics(pos,entity_damage_radius)
|
||||
mcl_mobs.effect(pos, 32, "mcl_particles_smoke.png", nil, nil, node_break_radius, 1, 0)
|
||||
end
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove()
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
elseif self.attack_type == "dogfight"
|
||||
or (self.attack_type == "dogshoot" and self:dogswitch(dtime) == 2) and (dist >= self.avoid_distance or not self.shooter_avoid_enemy)
|
||||
or (self.attack_type == "dogshoot" and dist <= self.reach and self:dogswitch() == 0) then
|
||||
|
||||
if self.fly
|
||||
and dist > self.reach then
|
||||
|
||||
local p1 = s
|
||||
local me_y = math.floor(p1.y)
|
||||
local p2 = p
|
||||
local p_y = math.floor(p2.y + 1)
|
||||
local v = self.object:get_velocity()
|
||||
|
||||
if self:flight_check( s) then
|
||||
|
||||
if me_y < p_y then
|
||||
|
||||
self.object:set_velocity({
|
||||
x = v.x,
|
||||
y = 1 * self.walk_velocity,
|
||||
z = v.z
|
||||
})
|
||||
|
||||
elseif me_y > p_y then
|
||||
|
||||
self.object:set_velocity({
|
||||
x = v.x,
|
||||
y = -1 * self.walk_velocity,
|
||||
z = v.z
|
||||
})
|
||||
end
|
||||
else
|
||||
if me_y < p_y then
|
||||
|
||||
self.object:set_velocity({
|
||||
x = v.x,
|
||||
y = 0.01,
|
||||
z = v.z
|
||||
})
|
||||
|
||||
elseif me_y > p_y then
|
||||
|
||||
self.object:set_velocity({
|
||||
x = v.x,
|
||||
y = -0.01,
|
||||
z = v.z
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- rnd: new movement direction
|
||||
if self.path.following
|
||||
and self.path.way
|
||||
and self.attack_type ~= "dogshoot" then
|
||||
|
||||
-- no paths longer than 50
|
||||
if #self.path.way > 50
|
||||
or dist < self.reach then
|
||||
self.path.following = false
|
||||
return
|
||||
end
|
||||
|
||||
local p1 = self.path.way[1]
|
||||
|
||||
if not p1 then
|
||||
self.path.following = false
|
||||
return
|
||||
end
|
||||
|
||||
if math.abs(p1.x-s.x) + math.abs(p1.z - s.z) < 0.6 then
|
||||
-- reached waypoint, remove it from queue
|
||||
table.remove(self.path.way, 1)
|
||||
end
|
||||
|
||||
-- set new temporary target
|
||||
p = {x = p1.x, y = p1.y, z = p1.z}
|
||||
end
|
||||
|
||||
local vec = {
|
||||
x = p.x - s.x,
|
||||
z = p.z - s.z
|
||||
}
|
||||
|
||||
yaw = (atan(vec.z / vec.x) + math.pi / 2) - self.rotate
|
||||
|
||||
if p.x > s.x then yaw = yaw + math.pi end
|
||||
|
||||
yaw = self:set_yaw( yaw, 0, dtime)
|
||||
|
||||
-- move towards enemy if beyond mob reach
|
||||
if dist > self.reach then
|
||||
|
||||
-- path finding by rnd
|
||||
if self.pathfinding -- only if mob has pathfinding enabled
|
||||
and enable_pathfinding then
|
||||
|
||||
self:smart_mobs(s, p, dist, dtime)
|
||||
end
|
||||
|
||||
if self:is_at_cliff_or_danger() then
|
||||
|
||||
self:set_velocity( 0)
|
||||
self:set_animation( "stand")
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
yaw = self:set_yaw( yaw + 0.78, 8)
|
||||
else
|
||||
|
||||
if self.path.stuck then
|
||||
self:set_velocity( self.walk_velocity)
|
||||
else
|
||||
self:set_velocity( self.run_velocity)
|
||||
end
|
||||
|
||||
if self.animation and self.animation.run_start then
|
||||
self:set_animation( "run")
|
||||
else
|
||||
self:set_animation( "walk")
|
||||
end
|
||||
end
|
||||
|
||||
else -- rnd: if inside reach range
|
||||
|
||||
self.path.stuck = false
|
||||
self.path.stuck_timer = 0
|
||||
self.path.following = false -- not stuck anymore
|
||||
|
||||
self:set_velocity( 0)
|
||||
|
||||
if not self.custom_attack then
|
||||
|
||||
if self.timer > 1 then
|
||||
|
||||
self.timer = 0
|
||||
|
||||
if self.double_melee_attack
|
||||
and math.random(1, 2) == 1 then
|
||||
self:set_animation( "punch2")
|
||||
else
|
||||
self:set_animation( "punch")
|
||||
end
|
||||
|
||||
local p2 = p
|
||||
local s2 = s
|
||||
|
||||
p2.y = p2.y + .5
|
||||
s2.y = s2.y + .5
|
||||
|
||||
if self:line_of_sight( p2, s2) == true then
|
||||
|
||||
-- play attack sound
|
||||
self:mob_sound("attack")
|
||||
|
||||
-- punch player (or what player is attached to)
|
||||
local attached = self.attack:get_attach()
|
||||
if attached then
|
||||
self.attack = attached
|
||||
end
|
||||
self.attack:punch(self.object, 1.0, {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy = self.damage}
|
||||
}, nil)
|
||||
end
|
||||
end
|
||||
else -- call custom attack every second
|
||||
if self.custom_attack
|
||||
and self.timer > 1 then
|
||||
|
||||
self.timer = 0
|
||||
|
||||
self.custom_attack(self, p)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif self.attack_type == "shoot"
|
||||
or (self.attack_type == "dogshoot" and self:dogswitch(dtime) == 1)
|
||||
or (self.attack_type == "dogshoot" and (dist > self.reach or dist < self.avoid_distance and self.shooter_avoid_enemy) and self:dogswitch() == 0) then
|
||||
|
||||
p.y = p.y - .5
|
||||
s.y = s.y + .5
|
||||
|
||||
local dist = vector.distance(p, s)
|
||||
local vec = {
|
||||
x = p.x - s.x,
|
||||
y = p.y - s.y,
|
||||
z = p.z - s.z
|
||||
}
|
||||
|
||||
yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
|
||||
|
||||
if p.x > s.x then yaw = yaw +math.pi end
|
||||
|
||||
yaw = self:set_yaw( yaw, 0, dtime)
|
||||
|
||||
local stay_away_from_player = vector.new(0,0,0)
|
||||
|
||||
--strafe back and fourth
|
||||
|
||||
--stay away from player so as to shoot them
|
||||
if dist < self.avoid_distance and self.shooter_avoid_enemy then
|
||||
self:set_animation( "shoot")
|
||||
stay_away_from_player=vector.multiply(vector.direction(p, s), 0.33)
|
||||
end
|
||||
|
||||
if self.strafes then
|
||||
if not self.strafe_direction then
|
||||
self.strafe_direction = 1.57
|
||||
end
|
||||
if math.random(40) == 1 then
|
||||
self.strafe_direction = self.strafe_direction*-1
|
||||
end
|
||||
self.acc = vector.add(vector.multiply(vector.rotate_around_axis(vector.direction(s, p), vector.new(0,1,0), self.strafe_direction), 0.3*self.walk_velocity), stay_away_from_player)
|
||||
else
|
||||
self:set_velocity( 0)
|
||||
end
|
||||
|
||||
local p = self.object:get_pos()
|
||||
p.y = p.y + (self.collisionbox[2] + self.collisionbox[5]) / 2
|
||||
|
||||
if self.shoot_interval
|
||||
and self.timer > self.shoot_interval
|
||||
and not minetest.raycast(vector.add(p, vector.new(0,self.shoot_offset,0)), vector.add(self.attack:get_pos(), vector.new(0,1.5,0)), false, false):next()
|
||||
and math.random(1, 100) <= 60 then
|
||||
|
||||
self.timer = 0
|
||||
self:set_animation( "shoot")
|
||||
|
||||
-- play shoot attack sound
|
||||
self:mob_sound("shoot_attack")
|
||||
|
||||
-- Shoot arrow
|
||||
if minetest.registered_entities[self.arrow] then
|
||||
|
||||
local arrow, ent
|
||||
local v = 1
|
||||
if not self.shoot_arrow then
|
||||
self.firing = true
|
||||
minetest.after(1, function()
|
||||
self.firing = false
|
||||
end)
|
||||
arrow = minetest.add_entity(p, self.arrow)
|
||||
ent = arrow:get_luaentity()
|
||||
if ent.velocity then
|
||||
v = ent.velocity
|
||||
end
|
||||
ent.switch = 1
|
||||
ent.owner_id = tostring(self.object) -- add unique owner id to arrow
|
||||
|
||||
-- important for mcl_shields
|
||||
ent._shooter = self.object
|
||||
ent._saved_shooter_pos = self.object:get_pos()
|
||||
end
|
||||
|
||||
local amount = (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) ^ 0.5
|
||||
-- offset makes shoot aim accurate
|
||||
vec.y = vec.y + self.shoot_offset
|
||||
vec.x = vec.x * (v / amount)
|
||||
vec.y = vec.y * (v / amount)
|
||||
vec.z = vec.z * (v / amount)
|
||||
if self.shoot_arrow then
|
||||
vec = vector.normalize(vec)
|
||||
self:shoot_arrow(p, vec)
|
||||
else
|
||||
arrow:set_velocity(vec)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -116,6 +116,7 @@ function mob_class:mob_sound(soundname, is_opinion, fixed_pitch)
|
|||
-- randomize the pitch a bit
|
||||
pitch = pitch + math.random(-10, 10) * 0.005
|
||||
end
|
||||
-- Should be 0.1 to 0.2 for mobs. Cow and zombie farms loud. At least have cool down.
|
||||
minetest.sound_play(sound, {
|
||||
object = self.object,
|
||||
gain = 1.0,
|
||||
|
@ -279,30 +280,55 @@ local function dir_to_pitch(dir)
|
|||
return -math.atan2(-dir.y, xz)
|
||||
end
|
||||
|
||||
function mob_class:check_head_swivel(dtime)
|
||||
if not self.head_swivel or type(self.head_swivel) ~= "string" then return end
|
||||
local final_rotation = vector.new(0,0,0)
|
||||
local oldp,oldr = self.object:get_bone_position(self.head_swivel)
|
||||
|
||||
local function who_are_you_looking_at (self)
|
||||
local pos = self.object:get_pos()
|
||||
|
||||
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 10)) do
|
||||
if obj:is_player() and not self.attack or obj:get_luaentity() and obj:get_luaentity().name == self.name and self ~= obj:get_luaentity() then
|
||||
if not self._locked_object then
|
||||
if math.random(5000/self.curiosity) == 1 or vector.distance(pos,obj:get_pos())<4 and obj:is_player() then
|
||||
self._locked_object = obj
|
||||
end
|
||||
else
|
||||
if math.random(10000/self.curiosity) == 1 then
|
||||
self._locked_object = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local stop_look_at_player_chance = math.random(833/self.curiosity)
|
||||
-- was 10000 - div by 12 for avg entities as outside loop
|
||||
|
||||
local stop_look_at_player = stop_look_at_player_chance == 1
|
||||
|
||||
if self.attack or self.following then
|
||||
self._locked_object = self.attack or self.following
|
||||
elseif self._locked_object then
|
||||
if stop_look_at_player then
|
||||
--minetest.log("Stop look: ".. self.name)
|
||||
self._locked_object = nil
|
||||
end
|
||||
elseif not self._locked_object then
|
||||
if math.random(1, 30) then
|
||||
--minetest.log("Change look check: ".. self.name)
|
||||
local look_at_player_chance = math.random(20/self.curiosity)
|
||||
-- was 5000 but called in loop based on entities. so div by 12 as estimate avg of entities found,
|
||||
-- then div by 20 as less freq lookup
|
||||
|
||||
local look_at_player = look_at_player_chance == 1
|
||||
|
||||
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 8)) do
|
||||
if obj:is_player() and vector.distance(pos,obj:get_pos()) < 4 then
|
||||
--minetest.log("Change look to player: ".. self.name)
|
||||
self._locked_object = obj
|
||||
break
|
||||
elseif obj:is_player() or (obj:get_luaentity() and obj:get_luaentity().name == self.name and self ~= obj:get_luaentity()) then
|
||||
if look_at_player then
|
||||
--minetest.log("Change look to mob: ".. self.name)
|
||||
self._locked_object = obj
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function mob_class:check_head_swivel(dtime)
|
||||
if not self.head_swivel or type(self.head_swivel) ~= "string" then return end
|
||||
|
||||
who_are_you_looking_at (self)
|
||||
|
||||
local final_rotation = vector.new(0,0,0)
|
||||
local oldp,oldr = self.object:get_bone_position(self.head_swivel)
|
||||
|
||||
if self._locked_object and (self._locked_object:is_player() or self._locked_object:get_luaentity()) and self._locked_object:get_hp() > 0 then
|
||||
local _locked_object_eye_height = 1.5
|
||||
|
@ -317,6 +343,7 @@ function mob_class:check_head_swivel(dtime)
|
|||
if self.object:get_attach() then
|
||||
self_rot = self.object:get_attach():get_rotation()
|
||||
end
|
||||
|
||||
if self.rot then
|
||||
local player_pos = self._locked_object:get_pos()
|
||||
local direction_player = vector.direction(vector.add(self.object:get_pos(), vector.new(0, self.head_eye_height*.7, 0)), vector.add(player_pos, vector.new(0, _locked_object_eye_height, 0)))
|
||||
|
@ -345,7 +372,7 @@ function mob_class:check_head_swivel(dtime)
|
|||
elseif not self._locked_object and math.abs(oldr.y) > 3 and math.abs(oldr.x) < 3 then
|
||||
final_rotation = vector.multiply(oldr, 0.9)
|
||||
else
|
||||
final_rotation = vector.new(0,0,0)
|
||||
--final_rotation = vector.new(0,0,0)
|
||||
end
|
||||
|
||||
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), final_rotation)
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# textdomain: mcl_mobs
|
||||
Peaceful mode active! No monsters will spawn.=Fredelig tilstand aktiveret! Ingen monstre vil spawne.
|
||||
This allows you to place a single mob.=Dette gør dig i stand til at placere et enkelt monster.
|
||||
Just place it where you want the mob to appear. Animals will spawn tamed, unless you hold down the sneak key while placing. If you place this on a mob spawner, you change the mob it spawns.=Placér det blot der hvor du ønsker, at monsteret skal komme. Dyr vil spawne tamme, medmindre du holder snige-knappen nede mens du placerer dem. Hvis du placerer denne på et monsterspawn, ændrer du hvilket monster det spawner.
|
||||
You need the “maphack” privilege to change the mob spawner.=Du skal have "maphack" privilegier for at ændre monsterspawneren.
|
||||
Name Tag=Navneskilt
|
||||
A name tag is an item to name a mob.=Et navneskilt bruges til at navngive et monster.
|
||||
Before you use the name tag, you need to set a name at an anvil. Then you can use the name tag to name a mob. This uses up the name tag.=Før du bruger navneskiltet, skal du vælge navnet ved en ambolt. Derefter kan du bruge navneskiltet til at navngive et monster. Dette opbruger navneskiltet.
|
||||
Only peaceful mobs allowed!=Kun fredelige monstre er tilladt!
|
||||
Give names to mobs=Giv navne til monstre
|
||||
Set name at anvil=Vælg navn ved en ambolt.
|
|
@ -4,7 +4,6 @@ local DEFAULT_FALL_SPEED = -9.81*1.5
|
|||
local FLOP_HEIGHT = 6
|
||||
local FLOP_HOR_SPEED = 1.5
|
||||
local PATHFINDING = "gowp"
|
||||
local enable_pathfinding = true
|
||||
|
||||
local node_ice = "mcl_core:ice"
|
||||
local node_snowblock = "mcl_core:snowblock"
|
||||
|
@ -269,6 +268,31 @@ function mob_class:is_at_water_danger()
|
|||
return false
|
||||
end
|
||||
|
||||
function mob_class:env_danger_movement_checks(dtime)
|
||||
local yaw = 0
|
||||
if self:is_at_water_danger() and self.state ~= "attack" then
|
||||
if math.random(1, 10) <= 6 then
|
||||
self:set_velocity(0)
|
||||
self.state = "stand"
|
||||
self:set_animation( "stand")
|
||||
yaw = yaw + math.random(-0.5, 0.5)
|
||||
yaw = self:set_yaw( yaw, 8)
|
||||
end
|
||||
else
|
||||
if self.move_in_group ~= false then
|
||||
self:check_herd(dtime)
|
||||
end
|
||||
end
|
||||
|
||||
if self:is_at_cliff_or_danger() then
|
||||
self:set_velocity(0)
|
||||
self.state = "stand"
|
||||
self:set_animation( "stand")
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
yaw = self:set_yaw( yaw + 0.78, 8)
|
||||
end
|
||||
end
|
||||
|
||||
-- jump if facing a solid node (not fences or gates)
|
||||
function mob_class:do_jump()
|
||||
if not self.jump
|
||||
|
@ -769,591 +793,190 @@ function mob_class:teleport(target)
|
|||
end
|
||||
end
|
||||
|
||||
-- execute current state (stand, walk, run, attacks)
|
||||
-- returns true if mob has died
|
||||
function mob_class:do_states(dtime)
|
||||
--if self.can_open_doors then check_doors(self) end
|
||||
|
||||
function mob_class:do_states_walk()
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
|
||||
if self.state == "stand" then
|
||||
if math.random(1, 4) == 1 then
|
||||
local s = self.object:get_pos()
|
||||
local lp = nil
|
||||
|
||||
-- is there something I need to avoid?
|
||||
if (self.water_damage > 0
|
||||
and self.lava_damage > 0)
|
||||
or self.breath_max ~= -1 then
|
||||
lp = minetest.find_node_near(s, 1, {"group:water", "group:lava"})
|
||||
elseif self.water_damage > 0 then
|
||||
lp = minetest.find_node_near(s, 1, {"group:water"})
|
||||
elseif self.lava_damage > 0 then
|
||||
lp = minetest.find_node_near(s, 1, {"group:lava"})
|
||||
elseif self.fire_damage > 0 then
|
||||
lp = minetest.find_node_near(s, 1, {"group:fire"})
|
||||
end
|
||||
|
||||
local is_in_danger = false
|
||||
if lp then
|
||||
-- If mob in or on dangerous block, look for land
|
||||
if (self:is_node_dangerous(self.standing_in) or
|
||||
self:is_node_dangerous(self.standing_on)) or (self:is_node_waterhazard(self.standing_in) or self:is_node_waterhazard(self.standing_on)) and (not self.fly) then
|
||||
is_in_danger = true
|
||||
|
||||
-- If mob in or on dangerous block, look for land
|
||||
if is_in_danger then
|
||||
-- Better way to find shore - copied from upstream
|
||||
lp = minetest.find_nodes_in_area_under_air(
|
||||
{x = s.x - 5, y = s.y - 0.5, z = s.z - 5},
|
||||
{x = s.x + 5, y = s.y + 1, z = s.z + 5},
|
||||
{"group:solid"})
|
||||
|
||||
lp = #lp > 0 and lp[math.random(#lp)]
|
||||
|
||||
-- did we find land?
|
||||
if lp then
|
||||
|
||||
local vec = {
|
||||
x = lp.x - s.x,
|
||||
z = lp.z - s.z
|
||||
}
|
||||
|
||||
yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
|
||||
|
||||
|
||||
if lp.x > s.x then yaw = yaw +math.pi end
|
||||
|
||||
-- look towards land and move in that direction
|
||||
yaw = self:set_yaw( yaw, 6)
|
||||
self:set_velocity(self.walk_velocity)
|
||||
|
||||
local s = self.object:get_pos()
|
||||
local objs = minetest.get_objects_inside_radius(s, 3)
|
||||
local lp
|
||||
for n = 1, #objs do
|
||||
if objs[n]:is_player() then
|
||||
lp = objs[n]:get_pos()
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- look at any players nearby, otherwise turn randomly
|
||||
if lp and self.look_at_players then
|
||||
|
||||
local vec = {
|
||||
x = lp.x - s.x,
|
||||
z = lp.z - s.z
|
||||
}
|
||||
|
||||
yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
|
||||
|
||||
if lp.x > s.x then yaw = yaw +math.pi end
|
||||
else
|
||||
yaw = yaw + math.random(-0.5, 0.5)
|
||||
end
|
||||
|
||||
yaw = self:set_yaw( yaw, 8)
|
||||
end
|
||||
if self.order == "sit" then
|
||||
self:set_animation( "sit")
|
||||
self:set_velocity(0)
|
||||
else
|
||||
self:set_animation( "stand")
|
||||
self:set_velocity(0)
|
||||
end
|
||||
|
||||
-- npc's ordered to stand stay standing
|
||||
if self.order == "stand" or self.order == "sleep" or self.order == "work" then
|
||||
|
||||
else
|
||||
if self.walk_chance ~= 0
|
||||
and self.facing_fence ~= true
|
||||
and math.random(1, 100) <= self.walk_chance
|
||||
and self:is_at_cliff_or_danger() == false then
|
||||
|
||||
self:set_velocity(self.walk_velocity)
|
||||
self.state = "walk"
|
||||
self:set_animation( "walk")
|
||||
end
|
||||
end
|
||||
|
||||
elseif self.state == PATHFINDING then
|
||||
self:check_gowp(dtime)
|
||||
|
||||
elseif self.state == "walk" then
|
||||
local s = self.object:get_pos()
|
||||
local lp = nil
|
||||
|
||||
-- is there something I need to avoid?
|
||||
if (self.water_damage > 0
|
||||
and self.lava_damage > 0)
|
||||
or self.breath_max ~= -1 then
|
||||
|
||||
lp = minetest.find_node_near(s, 1, {"group:water", "group:lava"})
|
||||
|
||||
elseif self.water_damage > 0 then
|
||||
|
||||
lp = minetest.find_node_near(s, 1, {"group:water"})
|
||||
|
||||
elseif self.lava_damage > 0 then
|
||||
|
||||
lp = minetest.find_node_near(s, 1, {"group:lava"})
|
||||
|
||||
elseif self.fire_damage > 0 then
|
||||
|
||||
lp = minetest.find_node_near(s, 1, {"group:fire"})
|
||||
|
||||
end
|
||||
|
||||
local is_in_danger = false
|
||||
if lp then
|
||||
-- If mob in or on dangerous block, look for land
|
||||
if (self:is_node_dangerous(self.standing_in) or
|
||||
self:is_node_dangerous(self.standing_on)) or (self:is_node_waterhazard(self.standing_in) or self:is_node_waterhazard(self.standing_on)) and (not self.fly) then
|
||||
is_in_danger = true
|
||||
|
||||
-- If mob in or on dangerous block, look for land
|
||||
if is_in_danger then
|
||||
-- Better way to find shore - copied from upstream
|
||||
lp = minetest.find_nodes_in_area_under_air(
|
||||
{x = s.x - 5, y = s.y - 0.5, z = s.z - 5},
|
||||
{x = s.x + 5, y = s.y + 1, z = s.z + 5},
|
||||
{"group:solid"})
|
||||
|
||||
lp = #lp > 0 and lp[math.random(#lp)]
|
||||
|
||||
-- did we find land?
|
||||
if lp then
|
||||
|
||||
local vec = {
|
||||
x = lp.x - s.x,
|
||||
z = lp.z - s.z
|
||||
}
|
||||
|
||||
yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
|
||||
|
||||
|
||||
if lp.x > s.x then yaw = yaw +math.pi end
|
||||
|
||||
-- look towards land and move in that direction
|
||||
yaw = self:set_yaw( yaw, 6)
|
||||
self:set_velocity(self.walk_velocity)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- A danger is near but mob is not inside
|
||||
else
|
||||
else
|
||||
|
||||
-- Randomly turn
|
||||
if math.random(1, 100) <= 30 then
|
||||
yaw = yaw + math.random(-0.5, 0.5)
|
||||
yaw = self:set_yaw( yaw, 8)
|
||||
end
|
||||
-- Randomly turn
|
||||
if math.random(1, 100) <= 30 then
|
||||
yaw = yaw + math.random(-0.5, 0.5)
|
||||
yaw = self:set_yaw( yaw, 8)
|
||||
end
|
||||
end
|
||||
|
||||
yaw = self:set_yaw( yaw, 8)
|
||||
yaw = self:set_yaw( yaw, 8)
|
||||
|
||||
-- otherwise randomly turn
|
||||
elseif math.random(1, 100) <= 30 then
|
||||
yaw = yaw + math.random(-0.5, 0.5)
|
||||
yaw = self:set_yaw( yaw, 8)
|
||||
end
|
||||
elseif math.random(1, 100) <= 30 then
|
||||
yaw = yaw + math.random(-0.5, 0.5)
|
||||
yaw = self:set_yaw( yaw, 8)
|
||||
end
|
||||
|
||||
-- stand for great fall or danger or fence in front
|
||||
local cliff_or_danger = false
|
||||
if is_in_danger then
|
||||
cliff_or_danger = self:is_at_cliff_or_danger()
|
||||
end
|
||||
if self.facing_fence == true
|
||||
or cliff_or_danger
|
||||
or math.random(1, 100) <= 30 then
|
||||
-- stand for great fall or danger or fence in front
|
||||
local cliff_or_danger = false
|
||||
if is_in_danger then
|
||||
cliff_or_danger = self:is_at_cliff_or_danger()
|
||||
end
|
||||
if self.facing_fence == true
|
||||
or cliff_or_danger
|
||||
or math.random(1, 100) <= 30 then
|
||||
|
||||
self:set_velocity(0)
|
||||
self.state = "stand"
|
||||
self:set_animation( "stand")
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
yaw = self:set_yaw( yaw + 0.78, 8)
|
||||
self:set_velocity(0)
|
||||
self.state = "stand"
|
||||
self:set_animation( "stand")
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
yaw = self:set_yaw( yaw + 0.78, 8)
|
||||
else
|
||||
|
||||
self:set_velocity(self.walk_velocity)
|
||||
|
||||
if self:flight_check()
|
||||
and self.animation
|
||||
and self.animation.fly_start
|
||||
and self.animation.fly_end then
|
||||
self:set_animation( "fly")
|
||||
else
|
||||
|
||||
self:set_velocity(self.walk_velocity)
|
||||
|
||||
if self:flight_check()
|
||||
and self.animation
|
||||
and self.animation.fly_start
|
||||
and self.animation.fly_end then
|
||||
self:set_animation( "fly")
|
||||
else
|
||||
self:set_animation( "walk")
|
||||
end
|
||||
end
|
||||
|
||||
-- runaway when punched
|
||||
elseif self.state == "runaway" then
|
||||
|
||||
self.runaway_timer = self.runaway_timer + 1
|
||||
|
||||
-- stop after 5 seconds or when at cliff
|
||||
if self.runaway_timer > 5
|
||||
or self:is_at_cliff_or_danger() then
|
||||
self.runaway_timer = 0
|
||||
self:set_velocity(0)
|
||||
self.state = "stand"
|
||||
self:set_animation( "stand")
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
yaw = self:set_yaw( yaw + 0.78, 8)
|
||||
else
|
||||
self:set_velocity( self.run_velocity)
|
||||
self:set_animation( "run")
|
||||
end
|
||||
|
||||
-- attack routines (explode, dogfight, shoot, dogshoot)
|
||||
elseif self.state == "attack" then
|
||||
|
||||
local s = self.object:get_pos()
|
||||
local p = self.attack:get_pos() or s
|
||||
|
||||
-- stop attacking if player invisible or out of range
|
||||
if not self.attack
|
||||
or not self.attack:get_pos()
|
||||
or not self:object_in_range(self.attack)
|
||||
or self.attack:get_hp() <= 0
|
||||
or (self.attack:is_player() and mcl_mobs.invis[ self.attack:get_player_name() ]) then
|
||||
|
||||
self.state = "stand"
|
||||
self:set_velocity( 0)
|
||||
self:set_animation( "stand")
|
||||
self.attack = nil
|
||||
self.v_start = false
|
||||
self.timer = 0
|
||||
self.blinktimer = 0
|
||||
self.path.way = nil
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- calculate distance from mob and enemy
|
||||
local dist = vector.distance(p, s)
|
||||
|
||||
if self.attack_type == "explode" then
|
||||
|
||||
local vec = {
|
||||
x = p.x - s.x,
|
||||
z = p.z - s.z
|
||||
}
|
||||
|
||||
yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
|
||||
|
||||
if p.x > s.x then yaw = yaw +math.pi end
|
||||
|
||||
yaw = self:set_yaw( yaw, 0, dtime)
|
||||
|
||||
local node_break_radius = self.explosion_radius or 1
|
||||
local entity_damage_radius = self.explosion_damage_radius
|
||||
or (node_break_radius * 2)
|
||||
|
||||
-- start timer when in reach and line of sight
|
||||
if not self.v_start
|
||||
and dist <= self.reach
|
||||
and self:line_of_sight( s, p, 2) then
|
||||
|
||||
self.v_start = true
|
||||
self.timer = 0
|
||||
self.blinktimer = 0
|
||||
self:mob_sound("fuse", nil, false)
|
||||
|
||||
-- stop timer if out of reach or direct line of sight
|
||||
elseif self.allow_fuse_reset
|
||||
and self.v_start
|
||||
and (dist >= self.explosiontimer_reset_radius
|
||||
or not self:line_of_sight( s, p, 2)) then
|
||||
self.v_start = false
|
||||
self.timer = 0
|
||||
self.blinktimer = 0
|
||||
self.blinkstatus = false
|
||||
self:remove_texture_mod("^[brighten")
|
||||
end
|
||||
|
||||
-- walk right up to player unless the timer is active
|
||||
if self.v_start and (self.stop_to_explode or dist < self.reach) then
|
||||
self:set_velocity( 0)
|
||||
else
|
||||
self:set_velocity( self.run_velocity)
|
||||
end
|
||||
|
||||
if self.animation and self.animation.run_start then
|
||||
self:set_animation( "run")
|
||||
else
|
||||
self:set_animation( "walk")
|
||||
end
|
||||
|
||||
if self.v_start then
|
||||
|
||||
self.timer = self.timer + dtime
|
||||
self.blinktimer = (self.blinktimer or 0) + dtime
|
||||
|
||||
if self.blinktimer > 0.2 then
|
||||
|
||||
self.blinktimer = 0
|
||||
|
||||
if self.blinkstatus then
|
||||
self:remove_texture_mod("^[brighten")
|
||||
else
|
||||
self:add_texture_mod("^[brighten")
|
||||
end
|
||||
|
||||
self.blinkstatus = not self.blinkstatus
|
||||
end
|
||||
|
||||
if self.timer > self.explosion_timer then
|
||||
|
||||
local pos = self.object:get_pos()
|
||||
|
||||
if mobs_griefing and not minetest.is_protected(pos, "") then
|
||||
mcl_explosions.explode(mcl_util.get_object_center(self.object), self.explosion_strength, { drop_chance = 1.0 }, self.object)
|
||||
else
|
||||
minetest.sound_play(self.sounds.explode, {
|
||||
pos = pos,
|
||||
gain = 1.0,
|
||||
max_hear_distance = self.sounds.distance or 32
|
||||
}, true)
|
||||
self:entity_physics(pos,entity_damage_radius)
|
||||
mcl_mobs.effect(pos, 32, "mcl_particles_smoke.png", nil, nil, node_break_radius, 1, 0)
|
||||
end
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove()
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
elseif self.attack_type == "dogfight"
|
||||
or (self.attack_type == "dogshoot" and self:dogswitch(dtime) == 2) and (dist >= self.avoid_distance or not self.shooter_avoid_enemy)
|
||||
or (self.attack_type == "dogshoot" and dist <= self.reach and self:dogswitch() == 0) then
|
||||
|
||||
if self.fly
|
||||
and dist > self.reach then
|
||||
|
||||
local p1 = s
|
||||
local me_y = math.floor(p1.y)
|
||||
local p2 = p
|
||||
local p_y = math.floor(p2.y + 1)
|
||||
local v = self.object:get_velocity()
|
||||
|
||||
if self:flight_check( s) then
|
||||
|
||||
if me_y < p_y then
|
||||
|
||||
self.object:set_velocity({
|
||||
x = v.x,
|
||||
y = 1 * self.walk_velocity,
|
||||
z = v.z
|
||||
})
|
||||
|
||||
elseif me_y > p_y then
|
||||
|
||||
self.object:set_velocity({
|
||||
x = v.x,
|
||||
y = -1 * self.walk_velocity,
|
||||
z = v.z
|
||||
})
|
||||
end
|
||||
else
|
||||
if me_y < p_y then
|
||||
|
||||
self.object:set_velocity({
|
||||
x = v.x,
|
||||
y = 0.01,
|
||||
z = v.z
|
||||
})
|
||||
|
||||
elseif me_y > p_y then
|
||||
|
||||
self.object:set_velocity({
|
||||
x = v.x,
|
||||
y = -0.01,
|
||||
z = v.z
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- rnd: new movement direction
|
||||
if self.path.following
|
||||
and self.path.way
|
||||
and self.attack_type ~= "dogshoot" then
|
||||
|
||||
-- no paths longer than 50
|
||||
if #self.path.way > 50
|
||||
or dist < self.reach then
|
||||
self.path.following = false
|
||||
return
|
||||
end
|
||||
|
||||
local p1 = self.path.way[1]
|
||||
|
||||
if not p1 then
|
||||
self.path.following = false
|
||||
return
|
||||
end
|
||||
|
||||
if math.abs(p1.x-s.x) + math.abs(p1.z - s.z) < 0.6 then
|
||||
-- reached waypoint, remove it from queue
|
||||
table.remove(self.path.way, 1)
|
||||
end
|
||||
|
||||
-- set new temporary target
|
||||
p = {x = p1.x, y = p1.y, z = p1.z}
|
||||
end
|
||||
|
||||
local vec = {
|
||||
x = p.x - s.x,
|
||||
z = p.z - s.z
|
||||
}
|
||||
|
||||
yaw = (atan(vec.z / vec.x) + math.pi / 2) - self.rotate
|
||||
|
||||
if p.x > s.x then yaw = yaw + math.pi end
|
||||
|
||||
yaw = self:set_yaw( yaw, 0, dtime)
|
||||
|
||||
-- move towards enemy if beyond mob reach
|
||||
if dist > self.reach then
|
||||
|
||||
-- path finding by rnd
|
||||
if self.pathfinding -- only if mob has pathfinding enabled
|
||||
and enable_pathfinding then
|
||||
|
||||
self:smart_mobs(s, p, dist, dtime)
|
||||
end
|
||||
|
||||
if self:is_at_cliff_or_danger() then
|
||||
|
||||
self:set_velocity( 0)
|
||||
self:set_animation( "stand")
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
yaw = self:set_yaw( yaw + 0.78, 8)
|
||||
else
|
||||
|
||||
if self.path.stuck then
|
||||
self:set_velocity( self.walk_velocity)
|
||||
else
|
||||
self:set_velocity( self.run_velocity)
|
||||
end
|
||||
|
||||
if self.animation and self.animation.run_start then
|
||||
self:set_animation( "run")
|
||||
else
|
||||
self:set_animation( "walk")
|
||||
end
|
||||
end
|
||||
|
||||
else -- rnd: if inside reach range
|
||||
|
||||
self.path.stuck = false
|
||||
self.path.stuck_timer = 0
|
||||
self.path.following = false -- not stuck anymore
|
||||
|
||||
self:set_velocity( 0)
|
||||
|
||||
if not self.custom_attack then
|
||||
|
||||
if self.timer > 1 then
|
||||
|
||||
self.timer = 0
|
||||
|
||||
if self.double_melee_attack
|
||||
and math.random(1, 2) == 1 then
|
||||
self:set_animation( "punch2")
|
||||
else
|
||||
self:set_animation( "punch")
|
||||
end
|
||||
|
||||
local p2 = p
|
||||
local s2 = s
|
||||
|
||||
p2.y = p2.y + .5
|
||||
s2.y = s2.y + .5
|
||||
|
||||
if self:line_of_sight( p2, s2) == true then
|
||||
|
||||
-- play attack sound
|
||||
self:mob_sound("attack")
|
||||
|
||||
-- punch player (or what player is attached to)
|
||||
local attached = self.attack:get_attach()
|
||||
if attached then
|
||||
self.attack = attached
|
||||
end
|
||||
self.attack:punch(self.object, 1.0, {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy = self.damage}
|
||||
}, nil)
|
||||
end
|
||||
end
|
||||
else -- call custom attack every second
|
||||
if self.custom_attack
|
||||
and self.timer > 1 then
|
||||
|
||||
self.timer = 0
|
||||
|
||||
self.custom_attack(self, p)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif self.attack_type == "shoot"
|
||||
or (self.attack_type == "dogshoot" and self:dogswitch(dtime) == 1)
|
||||
or (self.attack_type == "dogshoot" and (dist > self.reach or dist < self.avoid_distance and self.shooter_avoid_enemy) and self:dogswitch() == 0) then
|
||||
|
||||
p.y = p.y - .5
|
||||
s.y = s.y + .5
|
||||
|
||||
local dist = vector.distance(p, s)
|
||||
local vec = {
|
||||
x = p.x - s.x,
|
||||
y = p.y - s.y,
|
||||
z = p.z - s.z
|
||||
}
|
||||
|
||||
yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
|
||||
|
||||
if p.x > s.x then yaw = yaw +math.pi end
|
||||
|
||||
yaw = self:set_yaw( yaw, 0, dtime)
|
||||
|
||||
local stay_away_from_player = vector.new(0,0,0)
|
||||
|
||||
--strafe back and fourth
|
||||
|
||||
--stay away from player so as to shoot them
|
||||
if dist < self.avoid_distance and self.shooter_avoid_enemy then
|
||||
self:set_animation( "shoot")
|
||||
stay_away_from_player=vector.multiply(vector.direction(p, s), 0.33)
|
||||
end
|
||||
|
||||
if self.strafes then
|
||||
if not self.strafe_direction then
|
||||
self.strafe_direction = 1.57
|
||||
end
|
||||
if math.random(40) == 1 then
|
||||
self.strafe_direction = self.strafe_direction*-1
|
||||
end
|
||||
self.acc = vector.add(vector.multiply(vector.rotate_around_axis(vector.direction(s, p), vector.new(0,1,0), self.strafe_direction), 0.3*self.walk_velocity), stay_away_from_player)
|
||||
else
|
||||
self:set_velocity( 0)
|
||||
end
|
||||
|
||||
local p = self.object:get_pos()
|
||||
p.y = p.y + (self.collisionbox[2] + self.collisionbox[5]) / 2
|
||||
|
||||
if self.shoot_interval
|
||||
and self.timer > self.shoot_interval
|
||||
and not minetest.raycast(vector.add(p, vector.new(0,self.shoot_offset,0)), vector.add(self.attack:get_pos(), vector.new(0,1.5,0)), false, false):next()
|
||||
and math.random(1, 100) <= 60 then
|
||||
|
||||
self.timer = 0
|
||||
self:set_animation( "shoot")
|
||||
|
||||
-- play shoot attack sound
|
||||
self:mob_sound("shoot_attack")
|
||||
|
||||
-- Shoot arrow
|
||||
if minetest.registered_entities[self.arrow] then
|
||||
|
||||
local arrow, ent
|
||||
local v = 1
|
||||
if not self.shoot_arrow then
|
||||
self.firing = true
|
||||
minetest.after(1, function()
|
||||
self.firing = false
|
||||
end)
|
||||
arrow = minetest.add_entity(p, self.arrow)
|
||||
ent = arrow:get_luaentity()
|
||||
if ent.velocity then
|
||||
v = ent.velocity
|
||||
end
|
||||
ent.switch = 1
|
||||
ent.owner_id = tostring(self.object) -- add unique owner id to arrow
|
||||
|
||||
-- important for mcl_shields
|
||||
ent._shooter = self.object
|
||||
ent._saved_shooter_pos = self.object:get_pos()
|
||||
end
|
||||
|
||||
local amount = (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) ^ 0.5
|
||||
-- offset makes shoot aim accurate
|
||||
vec.y = vec.y + self.shoot_offset
|
||||
vec.x = vec.x * (v / amount)
|
||||
vec.y = vec.y * (v / amount)
|
||||
vec.z = vec.z * (v / amount)
|
||||
if self.shoot_arrow then
|
||||
vec = vector.normalize(vec)
|
||||
self:shoot_arrow(p, vec)
|
||||
else
|
||||
arrow:set_velocity(vec)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
|
||||
self:set_animation( "walk")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mob_class:do_states_stand()
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
|
||||
if math.random(1, 4) == 1 then
|
||||
|
||||
local s = self.object:get_pos()
|
||||
local objs = minetest.get_objects_inside_radius(s, 3)
|
||||
local lp
|
||||
for n = 1, #objs do
|
||||
if objs[n]:is_player() then
|
||||
lp = objs[n]:get_pos()
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- look at any players nearby, otherwise turn randomly
|
||||
if lp and self.look_at_players then
|
||||
|
||||
local vec = {
|
||||
x = lp.x - s.x,
|
||||
z = lp.z - s.z
|
||||
}
|
||||
|
||||
yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
|
||||
|
||||
if lp.x > s.x then yaw = yaw +math.pi end
|
||||
else
|
||||
yaw = yaw + math.random(-0.5, 0.5)
|
||||
end
|
||||
|
||||
yaw = self:set_yaw( yaw, 8)
|
||||
end
|
||||
if self.order == "sit" then
|
||||
self:set_animation( "sit")
|
||||
self:set_velocity(0)
|
||||
else
|
||||
self:set_animation( "stand")
|
||||
self:set_velocity(0)
|
||||
end
|
||||
|
||||
-- npc's ordered to stand stay standing
|
||||
if self.order == "stand" or self.order == "sleep" or self.order == "work" then
|
||||
|
||||
else
|
||||
if self.walk_chance ~= 0
|
||||
and self.facing_fence ~= true
|
||||
and math.random(1, 100) <= self.walk_chance
|
||||
and self:is_at_cliff_or_danger() == false then
|
||||
|
||||
self:set_velocity(self.walk_velocity)
|
||||
self.state = "walk"
|
||||
self:set_animation( "walk")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mob_class:do_states_runaway()
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
|
||||
self.runaway_timer = self.runaway_timer + 1
|
||||
|
||||
-- stop after 5 seconds or when at cliff
|
||||
if self.runaway_timer > 5
|
||||
or self:is_at_cliff_or_danger() then
|
||||
self.runaway_timer = 0
|
||||
self:set_velocity(0)
|
||||
self.state = "stand"
|
||||
self:set_animation( "stand")
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
yaw = self:set_yaw( yaw + 0.78, 8)
|
||||
else
|
||||
self:set_velocity( self.run_velocity)
|
||||
self:set_animation( "run")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function mob_class:check_smooth_rotation(dtime)
|
||||
-- smooth rotation by ThomasMonroe314
|
||||
if self._turn_to then
|
||||
|
|
|
@ -1,11 +1,24 @@
|
|||
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
|
||||
local mob_class = mcl_mobs.mob_class
|
||||
|
||||
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager",false)
|
||||
local PATHFINDING = "gowp"
|
||||
local enable_pathfinding = true
|
||||
local PATHFINDING_FAIL_THRESHOLD = 100 -- no. of ticks to fail before giving up. 20p/s. 5s helps them get through door
|
||||
local PATHFINDING_FAIL_WAIT = 30 -- how long to wait before trying to path again
|
||||
|
||||
local LOG_MODULE = "[Mobs]"
|
||||
local PATHFINDING = "gowp"
|
||||
|
||||
local one_down = vector.new(0,-1,0)
|
||||
local one_up = vector.new(0,1,0)
|
||||
|
||||
local plane_adjacents = {
|
||||
vector.new(1,0,0),
|
||||
vector.new(-1,0,0),
|
||||
vector.new(0,0,1),
|
||||
vector.new(0,0,-1),
|
||||
}
|
||||
|
||||
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_pathfinding",false)
|
||||
|
||||
local LOG_MODULE = "[Mobs Pathfinding]"
|
||||
local function mcl_log (message)
|
||||
if LOGGING_ON and message then
|
||||
minetest.log(LOG_MODULE .. " " .. message)
|
||||
|
@ -21,7 +34,7 @@ function output_table (wp)
|
|||
end
|
||||
|
||||
function append_paths (wp1, wp2)
|
||||
mcl_log("Start append")
|
||||
--mcl_log("Start append")
|
||||
if not wp1 or not wp2 then
|
||||
mcl_log("Cannot append wp's")
|
||||
return
|
||||
|
@ -31,7 +44,7 @@ function append_paths (wp1, wp2)
|
|||
for _,a in pairs (wp2) do
|
||||
table.insert(wp1, a)
|
||||
end
|
||||
mcl_log("End append")
|
||||
--mcl_log("End append")
|
||||
end
|
||||
|
||||
local function output_enriched (wp_out)
|
||||
|
@ -43,11 +56,12 @@ local function output_enriched (wp_out)
|
|||
|
||||
local action = outy["action"]
|
||||
if action then
|
||||
--mcl_log("Pos ".. i ..":" .. minetest.pos_to_string(outy["pos"]))
|
||||
mcl_log("type: " .. action["type"])
|
||||
mcl_log("action: " .. action["action"])
|
||||
mcl_log("target: " .. minetest.pos_to_string(action["target"]))
|
||||
end
|
||||
mcl_log("failed attempts: " .. outy["failed_attempts"])
|
||||
--mcl_log("failed attempts: " .. outy["failed_attempts"])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -56,34 +70,26 @@ end
|
|||
-- an action, such as to open or close a door where we know that pos requires that action
|
||||
local function generate_enriched_path(wp_in, door_open_pos, door_close_pos, cur_door_pos)
|
||||
local wp_out = {}
|
||||
|
||||
-- TODO Just pass in door position and the index before is open, the index after is close
|
||||
local current_door_index = -1
|
||||
|
||||
for i, cur_pos in pairs(wp_in) do
|
||||
local action = nil
|
||||
|
||||
local one_down = vector.new(0,-1,0)
|
||||
local cur_pos_to_add = vector.add(cur_pos, one_down)
|
||||
if door_open_pos and vector.equals (cur_pos, door_open_pos) then
|
||||
mcl_log ("Door open match")
|
||||
--action = {type = "door", action = "open"}
|
||||
action = {}
|
||||
action["type"] = "door"
|
||||
action["action"] = "open"
|
||||
action["target"] = cur_door_pos
|
||||
action = {type = "door", action = "open", target = cur_door_pos}
|
||||
cur_pos_to_add = vector.add(cur_pos, one_down)
|
||||
elseif door_close_pos and vector.equals(cur_pos, door_close_pos) then
|
||||
mcl_log ("Door close match")
|
||||
--action = {type = "door", action = "closed"}
|
||||
action = {}
|
||||
action["type"] = "door"
|
||||
action["action"] = "close"
|
||||
action["target"] = cur_door_pos
|
||||
action = {type = "door", action = "close", target = cur_door_pos}
|
||||
cur_pos_to_add = vector.add(cur_pos, one_down)
|
||||
elseif cur_door_pos and vector.equals(cur_pos, cur_door_pos) then
|
||||
mcl_log("Current door pos")
|
||||
action = {type = "door", action = "open", target = cur_door_pos}
|
||||
cur_pos_to_add = vector.add(cur_pos, one_down)
|
||||
action = {}
|
||||
action["type"] = "door"
|
||||
action["action"] = "open"
|
||||
action["target"] = cur_door_pos
|
||||
else
|
||||
cur_pos_to_add = cur_pos
|
||||
--mcl_log ("Pos doesn't match")
|
||||
|
@ -101,106 +107,156 @@ local function generate_enriched_path(wp_in, door_open_pos, door_close_pos, cur_
|
|||
return wp_out
|
||||
end
|
||||
|
||||
local plane_adjacents = {
|
||||
vector.new(1,0,0),
|
||||
vector.new(-1,0,0),
|
||||
vector.new(0,0,1),
|
||||
vector.new(0,0,-1),
|
||||
}
|
||||
function mob_class:ready_to_path()
|
||||
mcl_log("Check ready to path")
|
||||
if self._pf_last_failed and (os.time() - self._pf_last_failed) < PATHFINDING_FAIL_WAIT then
|
||||
mcl_log("Not ready to path as last fail is less than threshold: " .. (os.time() - self._pf_last_failed))
|
||||
return false
|
||||
else
|
||||
mcl_log("We are ready to pathfind, no previous fail or we are past threshold")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- This function is used to see if we can path. We could use to check a route, rather than making people move.
|
||||
local function calculate_path_through_door (p, t, target)
|
||||
-- target is the same as t, just 1 square difference. Maybe we don't need target
|
||||
mcl_log("Plot route from mob: " .. minetest.pos_to_string(p) .. ", to target: " .. minetest.pos_to_string(t))
|
||||
local function calculate_path_through_door (p, cur_door_pos, t)
|
||||
if t then
|
||||
mcl_log("Plot route through door from pos: " .. minetest.pos_to_string(p) .. ", to target: " .. minetest.pos_to_string(t))
|
||||
else
|
||||
mcl_log("Plot route through door from pos: " .. minetest.pos_to_string(p))
|
||||
end
|
||||
|
||||
local enriched_path = nil
|
||||
local wp, prospective_wp
|
||||
|
||||
local cur_door_pos = nil
|
||||
local pos_closest_to_door = nil
|
||||
local other_side_of_door = nil
|
||||
|
||||
--Path to door first
|
||||
local wp = minetest.find_path(p,t,150,1,4)
|
||||
if not wp then
|
||||
mcl_log("No direct path. Path through door")
|
||||
if cur_door_pos then
|
||||
mcl_log("Found a door near: " .. minetest.pos_to_string(cur_door_pos))
|
||||
|
||||
-- This could improve. There could be multiple doors. Check you can path from door to target first.
|
||||
local cur_door_pos = minetest.find_node_near(target,16,{"group:door"})
|
||||
if cur_door_pos then
|
||||
mcl_log("Found a door near: " .. minetest.pos_to_string(cur_door_pos))
|
||||
for _,v in pairs(plane_adjacents) do
|
||||
pos_closest_to_door = vector.add(cur_door_pos,v)
|
||||
for _,v in pairs(plane_adjacents) do
|
||||
pos_closest_to_door = vector.add(cur_door_pos,v)
|
||||
other_side_of_door = vector.add(cur_door_pos,-v)
|
||||
|
||||
local n = minetest.get_node(pos_closest_to_door)
|
||||
if n.name == "air" then
|
||||
wp = minetest.find_path(p,pos_closest_to_door,150,1,4)
|
||||
if wp then
|
||||
mcl_log("Found a path to next to door".. minetest.pos_to_string(pos_closest_to_door))
|
||||
other_side_of_door = vector.add(cur_door_pos,-v)
|
||||
mcl_log("Opposite is: ".. minetest.pos_to_string(other_side_of_door))
|
||||
local n = minetest.get_node(pos_closest_to_door)
|
||||
|
||||
if n.name == "air" then
|
||||
mcl_log("We have air space next to door at: " .. minetest.pos_to_string(pos_closest_to_door))
|
||||
|
||||
prospective_wp = minetest.find_path(p,pos_closest_to_door,150,1,4)
|
||||
|
||||
if prospective_wp then
|
||||
mcl_log("Found a path to next to door".. minetest.pos_to_string(pos_closest_to_door))
|
||||
mcl_log("Opposite is: ".. minetest.pos_to_string(other_side_of_door))
|
||||
|
||||
table.insert(prospective_wp, cur_door_pos)
|
||||
|
||||
if t then
|
||||
mcl_log("We have t, lets go from door to target")
|
||||
local wp_otherside_door_to_target = minetest.find_path(other_side_of_door,t,150,1,4)
|
||||
|
||||
if wp_otherside_door_to_target and #wp_otherside_door_to_target > 0 then
|
||||
table.insert(wp, cur_door_pos)
|
||||
append_paths (wp, wp_otherside_door_to_target)
|
||||
enriched_path = generate_enriched_path(wp, pos_closest_to_door, other_side_of_door, cur_door_pos)
|
||||
append_paths (prospective_wp, wp_otherside_door_to_target)
|
||||
|
||||
wp = prospective_wp
|
||||
mcl_log("We have a path from outside door to target")
|
||||
else
|
||||
mcl_log("We cannot path from outside door to target")
|
||||
end
|
||||
break
|
||||
else
|
||||
mcl_log("This block next to door doesn't work.")
|
||||
mcl_log("No t, just add other side of door")
|
||||
table.insert(prospective_wp, other_side_of_door)
|
||||
wp = prospective_wp
|
||||
end
|
||||
|
||||
if wp then
|
||||
enriched_path = generate_enriched_path(wp, pos_closest_to_door, other_side_of_door, cur_door_pos)
|
||||
break
|
||||
end
|
||||
else
|
||||
mcl_log("Block is not air, it is: ".. n.name)
|
||||
mcl_log("Cannot path to this air block next to door.")
|
||||
end
|
||||
|
||||
end
|
||||
else
|
||||
mcl_log("No door found")
|
||||
end
|
||||
else
|
||||
mcl_log("We have a direct route")
|
||||
mcl_log("No door found")
|
||||
end
|
||||
|
||||
if wp and not enriched_path then
|
||||
mcl_log("Wp but not enriched")
|
||||
enriched_path = generate_enriched_path(wp)
|
||||
end
|
||||
return enriched_path
|
||||
end
|
||||
|
||||
local gopath_last = os.time()
|
||||
function mob_class:gopath(target,callback_arrived)
|
||||
if self.state == PATHFINDING then mcl_log("Already pathfinding, don't set another until done.") return end
|
||||
|
||||
if self._pf_last_failed and (os.time() - self._pf_last_failed) < 30 then
|
||||
mcl_log("We are not ready to path as last fail is less than threshold: " .. (os.time() - self._pf_last_failed))
|
||||
return
|
||||
else
|
||||
mcl_log("We are ready to pathfind, no previous fail or we are past threshold")
|
||||
end
|
||||
|
||||
--if os.time() - gopath_last < 5 then
|
||||
-- mcl_log("Not ready to path yet")
|
||||
-- return
|
||||
--end
|
||||
--gopath_last = os.time()
|
||||
if not self:ready_to_path() then return end
|
||||
|
||||
self.order = nil
|
||||
|
||||
local p = self.object:get_pos()
|
||||
local t = vector.offset(target,0,1,0)
|
||||
|
||||
local wp = calculate_path_through_door(p, t, target)
|
||||
--Check direct route
|
||||
local wp = minetest.find_path(p,t,150,1,4)
|
||||
|
||||
if not wp then
|
||||
mcl_log("### No direct path. Path through door closest to target.")
|
||||
local door_near_target = minetest.find_node_near(target, 16, {"group:door"})
|
||||
wp = calculate_path_through_door(p, door_near_target, t)
|
||||
|
||||
if not wp then
|
||||
mcl_log("### No path though door closest to target. Try door closest to origin.")
|
||||
local door_closest = minetest.find_node_near(p, 16, {"group:door"})
|
||||
wp = calculate_path_through_door(p, door_closest, t)
|
||||
|
||||
-- Path through 2 doors
|
||||
if not wp then
|
||||
mcl_log("### Still not wp. Need to path through 2 doors.")
|
||||
local path_through_closest_door = calculate_path_through_door(p, door_closest)
|
||||
|
||||
if path_through_closest_door and #path_through_closest_door > 0 then
|
||||
mcl_log("We have path through first door")
|
||||
mcl_log("Number of pos in path through door: " .. tostring(#path_through_closest_door))
|
||||
|
||||
local pos_after_door_entry = path_through_closest_door[#path_through_closest_door]
|
||||
if pos_after_door_entry then
|
||||
local pos_after_door = vector.add(pos_after_door_entry["pos"], one_up)
|
||||
mcl_log("pos_after_door: " .. minetest.pos_to_string(pos_after_door))
|
||||
local path_after_door = calculate_path_through_door(pos_after_door, door_near_target, t)
|
||||
if path_after_door and #path_after_door > 1 then
|
||||
mcl_log("We have path after first door")
|
||||
table.remove(path_after_door, 1) -- Remove duplicate
|
||||
wp = path_through_closest_door
|
||||
append_paths (wp, path_after_door)
|
||||
else
|
||||
mcl_log("Path after door is not good")
|
||||
end
|
||||
else
|
||||
mcl_log("No pos after door")
|
||||
end
|
||||
else
|
||||
mcl_log("Path through closest door empty or null")
|
||||
end
|
||||
else
|
||||
mcl_log("ok, we have a path through 1 door")
|
||||
end
|
||||
end
|
||||
else
|
||||
wp = generate_enriched_path(wp)
|
||||
mcl_log("We have a direct route")
|
||||
end
|
||||
|
||||
if not wp then
|
||||
mcl_log("Could not calculate path")
|
||||
self._pf_last_failed = os.time()
|
||||
-- Cover for a flaw in pathfind where it chooses the wrong door and gets stuck. Take a break, allow others.
|
||||
-- If cannot path, don't immediately try again
|
||||
end
|
||||
--output_table(wp)
|
||||
|
||||
if wp and #wp > 0 then
|
||||
--output_table(wp)
|
||||
self._target = t
|
||||
self.callback_arrived = callback_arrived
|
||||
local current_location = table.remove(wp,1)
|
||||
|
@ -269,17 +325,7 @@ function mob_class:do_pathfind_action(action)
|
|||
end
|
||||
end
|
||||
|
||||
local gowp_etime = 0
|
||||
|
||||
function mob_class:check_gowp(dtime)
|
||||
gowp_etime = gowp_etime + dtime
|
||||
|
||||
-- 0.1 is optimal.
|
||||
--less frequently = villager will get sent back after passing a point.
|
||||
--more frequently = villager will fail points they shouldn't they just didn't get there yet
|
||||
|
||||
--if gowp_etime < 0.05 then return end
|
||||
--gowp_etime = 0
|
||||
local p = self.object:get_pos()
|
||||
|
||||
-- no destination
|
||||
|
@ -292,7 +338,7 @@ function mob_class:check_gowp(dtime)
|
|||
-- arrived at location, finish gowp
|
||||
local distance_to_targ = vector.distance(p,self._target)
|
||||
--mcl_log("Distance to targ: ".. tostring(distance_to_targ))
|
||||
if distance_to_targ < 2 then
|
||||
if distance_to_targ < 1.8 then
|
||||
mcl_log("Arrived at _target")
|
||||
self.waypoints = nil
|
||||
self._target = nil
|
||||
|
@ -303,6 +349,8 @@ function mob_class:check_gowp(dtime)
|
|||
self.object:set_acceleration({x = 0, y = 0, z = 0})
|
||||
if self.callback_arrived then return self.callback_arrived(self) end
|
||||
return true
|
||||
elseif not self.current_target then
|
||||
mcl_log("Not close enough to targ: ".. tostring(distance_to_targ))
|
||||
end
|
||||
|
||||
-- More pathing to be done
|
||||
|
@ -315,7 +363,7 @@ function mob_class:check_gowp(dtime)
|
|||
-- 0.8 is optimal for 0.025 frequency checks and also 1... Actually. 0.8 is winning
|
||||
-- 0.9 and 1.0 is also good. Stick with unless door open or closing issues
|
||||
if self.waypoints and #self.waypoints > 0 and ( not self.current_target or not self.current_target["pos"] or distance_to_current_target < 0.9 ) then
|
||||
-- We have waypoints, and no current target, or we're at it. We need a new current_target.
|
||||
-- We have waypoints, and are at current_target or have no current target. We need a new current_target.
|
||||
self:do_pathfind_action (self.current_target["action"])
|
||||
|
||||
local failed_attempts = self.current_target["failed_attempts"]
|
||||
|
@ -325,10 +373,11 @@ function mob_class:check_gowp(dtime)
|
|||
self:go_to_pos(self.current_target["pos"])
|
||||
return
|
||||
elseif self.current_target and self.current_target["pos"] then
|
||||
-- No waypoints left, but have current target. Potentially last waypoint to go to.
|
||||
-- No waypoints left, but have current target and not close enough. Potentially last waypoint to go to.
|
||||
|
||||
self.current_target["failed_attempts"] = self.current_target["failed_attempts"] + 1
|
||||
local failed_attempts = self.current_target["failed_attempts"]
|
||||
if failed_attempts >= 50 then
|
||||
if failed_attempts >= PATHFINDING_FAIL_THRESHOLD then
|
||||
mcl_log("Failed to reach position (" .. minetest.pos_to_string(self.current_target["pos"]) .. ") too many times. Abandon route. Times tried: " .. failed_attempts)
|
||||
self.state = "stand"
|
||||
self.current_target = nil
|
||||
|
@ -348,9 +397,22 @@ function mob_class:check_gowp(dtime)
|
|||
-- Is a little sensitive and could take 1 - 7 times. A 10 fail count might be a good exit condition.
|
||||
|
||||
mcl_log("We don't have waypoints or a current target. Let's try to path to target")
|
||||
|
||||
if self.waypoints then
|
||||
mcl_log("WP: " .. tostring(self.waypoints))
|
||||
mcl_log("WP num: " .. tostring(#self.waypoints))
|
||||
else
|
||||
mcl_log("No wp set")
|
||||
end
|
||||
if self.current_target then
|
||||
mcl_log("Current target: " .. tostring(self.current_target))
|
||||
else
|
||||
mcl_log("No current target")
|
||||
end
|
||||
|
||||
local final_wp = minetest.find_path(p,self._target,150,1,4)
|
||||
if final_wp then
|
||||
mcl_log("We might be able to get to target here.")
|
||||
mcl_log("We can get to target here.")
|
||||
-- self.waypoints = final_wp
|
||||
self:go_to_pos(self._target)
|
||||
else
|
||||
|
@ -374,9 +436,9 @@ function mob_class:check_gowp(dtime)
|
|||
self:go_to_pos(self._current_target)
|
||||
else
|
||||
mcl_log("close to current target: ".. minetest.pos_to_string(self.current_target["pos"]))
|
||||
mcl_log("target is: ".. minetest.pos_to_string(self._target))
|
||||
self.current_target = nil
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,8 +5,7 @@ local ENTITY_CRAMMING_MAX = 24
|
|||
local CRAMMING_DAMAGE = 3
|
||||
local DEATH_DELAY = 0.5
|
||||
local DEFAULT_FALL_SPEED = -9.81*1.5
|
||||
local FLOP_HEIGHT = 6
|
||||
local FLOP_HOR_SPEED = 1.5
|
||||
|
||||
local PATHFINDING = "gowp"
|
||||
local mobs_debug = minetest.settings:get_bool("mobs_debug", false)
|
||||
local mobs_drop_items = minetest.settings:get_bool("mobs_drop_items") ~= false
|
||||
|
@ -183,6 +182,17 @@ function mob_class:collision()
|
|||
return({x,z})
|
||||
end
|
||||
|
||||
function mob_class:slow_mob()
|
||||
local d = 0.85
|
||||
if self:check_dying() then d = 0.92 end
|
||||
|
||||
local v = self.object:get_velocity()
|
||||
if v then
|
||||
--diffuse object velocity
|
||||
self.object:set_velocity({x = v.x*d, y = v.y, z = v.z*d})
|
||||
end
|
||||
end
|
||||
|
||||
-- move mob in facing direction
|
||||
function mob_class:set_velocity(v)
|
||||
local c_x, c_y = 0, 0
|
||||
|
@ -778,6 +788,25 @@ function mob_class:do_env_damage()
|
|||
return self:check_for_death("", {type = "unknown"})
|
||||
end
|
||||
|
||||
function mob_class:env_damage (dtime, pos)
|
||||
-- environmental damage timer (every 1 second)
|
||||
self.env_damage_timer = self.env_damage_timer + dtime
|
||||
|
||||
if (self.state == "attack" and self.env_damage_timer > 1)
|
||||
or self.state ~= "attack" then
|
||||
self:check_entity_cramming()
|
||||
self.env_damage_timer = 0
|
||||
|
||||
-- check for environmental damage (water, fire, lava etc.)
|
||||
if self:do_env_damage() then
|
||||
return true
|
||||
end
|
||||
|
||||
-- node replace check (cow eats grass etc.)
|
||||
self:replace(pos)
|
||||
end
|
||||
end
|
||||
|
||||
function mob_class:damage_mob(reason,damage)
|
||||
if not self.health then return end
|
||||
damage = math.floor(damage)
|
||||
|
|
|
@ -244,6 +244,24 @@ local function count_mobs_total(mob_type)
|
|||
return num
|
||||
end
|
||||
|
||||
local function count_mobs_all()
|
||||
local mobs_found = {}
|
||||
local num = 0
|
||||
for _,entity in pairs(minetest.luaentities) do
|
||||
if entity.is_mob then
|
||||
local mob_type = entity.type -- animal / monster / npc
|
||||
local mob_name = entity.name
|
||||
if mobs_found[mob_name] then
|
||||
mobs_found[mob_name] = mobs_found[mob_name] + 1
|
||||
else
|
||||
mobs_found[mob_name] = 1
|
||||
end
|
||||
num = num + 1
|
||||
end
|
||||
end
|
||||
return mobs_found, num
|
||||
end
|
||||
|
||||
local function count_mobs_total_cap(mob_type)
|
||||
local num = 0
|
||||
for _,l in pairs(minetest.luaentities) do
|
||||
|
@ -628,6 +646,9 @@ if mobs_spawn then
|
|||
|
||||
local perlin_noise
|
||||
|
||||
-- Get pos to spawn, x and z are randomised, y is range
|
||||
|
||||
|
||||
local function spawn_a_mob(pos, dimension, y_min, y_max)
|
||||
--create a disconnected clone of the spawn dictionary
|
||||
--prevents memory leak
|
||||
|
@ -722,7 +743,9 @@ if mobs_spawn then
|
|||
end)
|
||||
end
|
||||
|
||||
function mob_class:check_despawn(pos)
|
||||
function mob_class:check_despawn(pos, dtime)
|
||||
self.lifetimer = self.lifetimer - dtime
|
||||
|
||||
-- Despawning: when lifetimer expires, remove mob
|
||||
if remove_far
|
||||
and self.can_despawn == true
|
||||
|
@ -755,5 +778,18 @@ minetest.register_chatcommand("mobstats",{
|
|||
minetest.chat_send_player(n,"total mobs:"..count_mobs_total())
|
||||
minetest.chat_send_player(n,"spawning attempts since server start:"..dbg_spawn_attempts)
|
||||
minetest.chat_send_player(n,"successful spawns since server start:"..dbg_spawn_succ)
|
||||
|
||||
|
||||
local mob_counts, total_mobs = count_mobs_all()
|
||||
if (total_mobs) then
|
||||
minetest.log("action", "Total mobs found: " .. total_mobs)
|
||||
end
|
||||
if mob_counts then
|
||||
for k, v1 in pairs(mob_counts) do
|
||||
minetest.log("action", "k: " .. tostring(k))
|
||||
minetest.log("action", "v1: " .. tostring(v1))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
})
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
# textdomain:mcl_paintings
|
||||
Painting=Maleri
|
|
@ -12,13 +12,13 @@ mcl_mobs.register_mob("mobs_mc:chicken", {
|
|||
description = S("Chicken"),
|
||||
type = "animal",
|
||||
spawn_class = "passive",
|
||||
|
||||
passive = true,
|
||||
runaway = true,
|
||||
hp_min = 4,
|
||||
hp_max = 4,
|
||||
xp_min = 1,
|
||||
xp_max = 3,
|
||||
collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.69, 0.2},
|
||||
runaway = true,
|
||||
floats = 1,
|
||||
head_swivel = "head.control",
|
||||
bone_eye_height = 4,
|
||||
|
|
|
@ -7,6 +7,7 @@ local cow_def = {
|
|||
type = "animal",
|
||||
spawn_class = "passive",
|
||||
passive = true,
|
||||
runaway = true,
|
||||
hp_min = 10,
|
||||
hp_max = 10,
|
||||
xp_min = 1,
|
||||
|
@ -40,7 +41,6 @@ local cow_def = {
|
|||
max = 2,
|
||||
looting = "common",},
|
||||
},
|
||||
runaway = true,
|
||||
sounds = {
|
||||
random = "mobs_mc_cow",
|
||||
damage = "mobs_mc_cow_hurt",
|
||||
|
|
|
@ -259,6 +259,7 @@ mcl_mobs.register_mob("mobs_mc:enderman", {
|
|||
description = S("Enderman"),
|
||||
type = "monster",
|
||||
spawn_class = "passive",
|
||||
can_despawn = true,
|
||||
passive = true,
|
||||
pathfinding = 1,
|
||||
hp_min = 40,
|
||||
|
@ -442,6 +443,7 @@ mcl_mobs.register_mob("mobs_mc:enderman", {
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- TAKE AND PLACE STUFF BEHAVIOUR BELOW.
|
||||
if not mobs_griefing then
|
||||
return
|
||||
|
@ -469,6 +471,7 @@ mcl_mobs.register_mob("mobs_mc:enderman", {
|
|||
local dug = minetest.get_node_or_nil(take_pos)
|
||||
if dug and dug.name == "air" then
|
||||
self._taken_node = node.name
|
||||
self.can_despawn = false
|
||||
local def = minetest.registered_nodes[self._taken_node]
|
||||
-- Update animation and texture accordingly (adds visibly carried block)
|
||||
local block_type
|
||||
|
@ -519,6 +522,7 @@ mcl_mobs.register_mob("mobs_mc:enderman", {
|
|||
if success then
|
||||
local def = minetest.registered_nodes[self._taken_node]
|
||||
-- Update animation accordingly (removes visible block)
|
||||
self.can_despawn = true
|
||||
self.animation = select_enderman_animation("normal")
|
||||
self:set_animation(self.animation.current)
|
||||
if def.sounds and def.sounds.place then
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
# textdomain: mobs_mc
|
||||
Agent=Agent
|
||||
Axolotl=Salamander
|
||||
Bat=Flagermus
|
||||
Blaze=Blaze
|
||||
Chicken=Kylling
|
||||
Cow=Ko
|
||||
Mooshroom=Svamp
|
||||
Creeper=Creeper
|
||||
Ender Dragon=Enderdrage
|
||||
Enderman=Enderman
|
||||
Endermite=Endermide
|
||||
Ghast=Ghast
|
||||
Elder Guardian=Gammel beskytter
|
||||
Guardian=Beskytter
|
||||
Horse=Hest
|
||||
Skeleton Horse=Skelethest
|
||||
Zombie Horse=Zombiehest
|
||||
Donkey=Æsel
|
||||
Mule=Muldyr
|
||||
Iron Golem=Jerngolem
|
||||
Llama=Lama
|
||||
Ocelot=Ozelot
|
||||
Parrot=Papegøje
|
||||
Pig=Gris
|
||||
Polar Bear=Isbjørn
|
||||
Rabbit=Kanin
|
||||
Killer Bunny=Dræberkanin
|
||||
Sheep=Får
|
||||
Shulker=Shulker
|
||||
Silverfish=Sølvfisk
|
||||
Skeleton=Skelet
|
||||
Stray=Omstrejfer
|
||||
Wither Skeleton=Wither-skelet
|
||||
Magma Cube=Magmakube
|
||||
Slime=Slimklump
|
||||
Snow Golem=Snegolem
|
||||
Spider=Edderkop
|
||||
Cave Spider=Huleedderkop
|
||||
Squid=Blæksprutte
|
||||
Vex=Vex
|
||||
Evoker=Fremkalder
|
||||
Illusioner=Illusionist
|
||||
Villager=Landsbyboer
|
||||
Vindicator=Hævner
|
||||
Zombie Villager=Zombie landsbyboer
|
||||
Witch=Heks
|
||||
Wither=Wither
|
||||
Wolf=Ulv
|
||||
Husk=Udtørretskal
|
||||
Zombie=Zombie
|
||||
Zombie Pigman=Zombificeret piglin
|
||||
Farmer=Landmand
|
||||
Fisherman=Fisker
|
||||
Fletcher=Pilemager
|
||||
Shepherd=Fårehyrde
|
||||
Librarian=Bibliotikar
|
||||
Cartographer=Kartograf
|
||||
Armorer=Rustningesmed
|
||||
Leatherworker=Læderarbejder
|
||||
Butcher=Slagter
|
||||
Weapon Smith=Våbensmed
|
||||
Tool Smith=Værktøjssmed
|
||||
Cleric=Gejstlig
|
||||
Nitwit=Tåbe
|
||||
Cod=Torsk
|
||||
Salmon=Laks
|
||||
Dolphin=Delfin
|
||||
Pillager=Plyndrer
|
||||
Tropical fish=Tropisk fisk
|
|
@ -6,6 +6,7 @@ mcl_mobs.register_mob("mobs_mc:pig", {
|
|||
description = S("Pig"),
|
||||
type = "animal",
|
||||
spawn_class = "passive",
|
||||
passive = true,
|
||||
runaway = true,
|
||||
hp_min = 10,
|
||||
hp_max = 10,
|
||||
|
|
|
@ -56,6 +56,7 @@ mcl_mobs.register_mob("mobs_mc:sheep", {
|
|||
description = S("Sheep"),
|
||||
type = "animal",
|
||||
spawn_class = "passive",
|
||||
passive = true,
|
||||
hp_min = 8,
|
||||
hp_max = 8,
|
||||
xp_min = 1,
|
||||
|
|
|
@ -235,7 +235,7 @@ local professions = {
|
|||
librarian = {
|
||||
name = N("Librarian"),
|
||||
texture = "mobs_mc_villager_librarian.png",
|
||||
jobsite = "mcl_books:bookshelf", --FIXME: lectern
|
||||
jobsite = "mcl_lectern:lectern",
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_core:paper", 24, 36 }, E1 },
|
||||
|
@ -641,7 +641,7 @@ function get_activity(tod)
|
|||
else
|
||||
activity = "chill"
|
||||
end
|
||||
mcl_log("Time is " .. tod ..". Activity is: ".. activity)
|
||||
--mcl_log("Time is " .. tod ..". Activity is: ".. activity)
|
||||
return activity
|
||||
|
||||
end
|
||||
|
@ -770,7 +770,7 @@ local function check_bed (entity)
|
|||
local n = minetest.get_node(b)
|
||||
|
||||
local is_bed_bottom = string.find(n.name,"_bottom")
|
||||
mcl_log("" .. tostring(is_bed_bottom))
|
||||
--mcl_log("is bed bottom: " .. tostring(is_bed_bottom))
|
||||
if n and not is_bed_bottom then
|
||||
mcl_log("Where did my bed go?!")
|
||||
entity._bed = nil --the stormtroopers have killed uncle owen
|
||||
|
@ -836,6 +836,7 @@ end
|
|||
|
||||
local function take_bed (entity)
|
||||
if not entity then return end
|
||||
if not entity:ready_to_path() then return end
|
||||
|
||||
local p = entity.object:get_pos()
|
||||
|
||||
|
@ -1059,9 +1060,9 @@ local function look_for_job(self, requested_jobsites)
|
|||
end
|
||||
|
||||
|
||||
|
||||
local function get_a_job(self)
|
||||
if self.order == WORK then self.order = nil end
|
||||
if not self:ready_to_path() then return end
|
||||
|
||||
mcl_log("I'm unemployed or lost my job block and have traded. Can I get a job?")
|
||||
|
||||
|
@ -1135,68 +1136,85 @@ local function validate_jobsite(self)
|
|||
end
|
||||
|
||||
local function do_work (self)
|
||||
--debug_trades(self)
|
||||
if self.child then
|
||||
mcl_log("A child so don't send to work")
|
||||
|
||||
if not self or self.child then
|
||||
mcl_log("No self, or a child so don't work")
|
||||
return
|
||||
end
|
||||
|
||||
--mcl_log("Time for work")
|
||||
local jobsite_node = retrieve_my_jobsite (self)
|
||||
|
||||
-- Don't try if looking_for_work, or gowp possibly
|
||||
if validate_jobsite(self) then
|
||||
--mcl_log("My jobsite is valid. Do i need to travel?")
|
||||
|
||||
local jobsite2 = retrieve_my_jobsite (self)
|
||||
if jobsite_node then
|
||||
local jobsite = self._jobsite
|
||||
|
||||
if self and jobsite2 and self._jobsite then
|
||||
local distance_to_jobsite = vector.distance(self.object:get_pos(),self._jobsite)
|
||||
--mcl_log("Villager: ".. minetest.pos_to_string(self.object:get_pos()) .. ", jobsite: " .. minetest.pos_to_string(self._jobsite) .. ", distance to jobsite: ".. distance_to_jobsite)
|
||||
local distance_to_jobsite = vector.distance(self.object:get_pos(), jobsite)
|
||||
--mcl_log("Villager: ".. minetest.pos_to_string(self.object:get_pos()) .. ", jobsite: " .. minetest.pos_to_string(self._jobsite) .. ", distance to jobsite: ".. distance_to_jobsite)
|
||||
|
||||
if distance_to_jobsite < 2 then
|
||||
if self.state ~= PATHFINDING and self.order ~= WORK then
|
||||
mcl_log("Setting order to work.")
|
||||
self.order = WORK
|
||||
unlock_trades(self)
|
||||
else
|
||||
--mcl_log("Still pathfinding.")
|
||||
end
|
||||
if distance_to_jobsite < 2 then
|
||||
if self.state ~= PATHFINDING and self.order ~= WORK then
|
||||
mcl_log("Setting order to work.")
|
||||
self.order = WORK
|
||||
unlock_trades(self)
|
||||
else
|
||||
mcl_log("Not at job block. Need to commute.")
|
||||
if self.order == WORK then
|
||||
self.order = nil
|
||||
return
|
||||
end
|
||||
self:gopath(jobsite, function(self,jobsite)
|
||||
if not self then
|
||||
--mcl_log("missing self. not good")
|
||||
return false
|
||||
end
|
||||
if not self._jobsite then
|
||||
--mcl_log("Jobsite not valid")
|
||||
return false
|
||||
end
|
||||
if vector.distance(self.object:get_pos(),self._jobsite) < 2 then
|
||||
--mcl_log("Made it to work ok callback!")
|
||||
return true
|
||||
else
|
||||
--mcl_log("Need to walk to work. Not sure we can get here.")
|
||||
end
|
||||
end)
|
||||
--mcl_log("Still pathfinding.")
|
||||
end
|
||||
else
|
||||
mcl_log("Not at job block. Need to commute.")
|
||||
if self.order == WORK then
|
||||
self.order = nil
|
||||
return
|
||||
end
|
||||
self:gopath(jobsite, function(self, jobsite)
|
||||
if not self then
|
||||
--mcl_log("missing self. not good")
|
||||
return false
|
||||
end
|
||||
if not self._jobsite then
|
||||
--mcl_log("Jobsite not valid")
|
||||
return false
|
||||
end
|
||||
if vector.distance(self.object:get_pos(),self._jobsite) < 2 then
|
||||
--mcl_log("Made it to work ok callback!")
|
||||
return true
|
||||
else
|
||||
--mcl_log("Need to walk to work. Not sure we can get here.")
|
||||
end
|
||||
end)
|
||||
end
|
||||
elseif self._profession == "unemployed" or has_traded(self) then
|
||||
get_a_job(self)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local below_vec = vector.new(0, -1, 0)
|
||||
|
||||
local function get_ground_below_floating_object (float_pos)
|
||||
local pos = float_pos
|
||||
repeat
|
||||
mcl_log("Current pos: " .. minetest.pos_to_string(pos))
|
||||
pos = vector.add(pos, below_vec)
|
||||
local node = minetest.get_node(pos)
|
||||
mcl_log("First non air materials: ".. tostring(node.name))
|
||||
until node.name ~= "air"
|
||||
|
||||
-- If pos is 1 below float_pos, then just return float_pos as there is no air below it
|
||||
if pos.y == float_pos.y - 1 then
|
||||
--mcl_log("pos is only 1 lower than float pos so no air below")
|
||||
return float_pos
|
||||
else
|
||||
--mcl_log("pos is more than 1 lower than float pos so air is below")
|
||||
return pos
|
||||
end
|
||||
|
||||
return pos
|
||||
end
|
||||
|
||||
local function go_to_town_bell(self)
|
||||
if self.order == GATHERING then
|
||||
mcl_log("Already gathering")
|
||||
return
|
||||
else
|
||||
mcl_log("Current order" .. self.order)
|
||||
end
|
||||
if self.order == GATHERING then return
|
||||
else mcl_log("Current order" .. self.order) end
|
||||
|
||||
if not self:ready_to_path() then return end
|
||||
|
||||
mcl_log("Go to town bell")
|
||||
|
||||
local looking_for_type={}
|
||||
|
@ -1208,8 +1226,9 @@ local function go_to_town_bell(self)
|
|||
--Ideally should check for closest available. It'll make pathing easier.
|
||||
for _,n in pairs(nn) do
|
||||
mcl_log("Found bell")
|
||||
local target_point = get_ground_below_floating_object(n)
|
||||
|
||||
local gp = self:gopath(n,function(self)
|
||||
local gp = self:gopath(target_point,function(self)
|
||||
if self then
|
||||
self.order = GATHERING
|
||||
mcl_log("Callback has a self")
|
||||
|
@ -1277,22 +1296,45 @@ local function validate_bed(self)
|
|||
end
|
||||
|
||||
local function do_activity (self)
|
||||
-- Maybe just check we're pathfinding first?
|
||||
|
||||
if self.following then
|
||||
mcl_log("Following, so do not do activity.")
|
||||
return
|
||||
end
|
||||
if self.state == PATHFINDING then
|
||||
mcl_log("Pathfinding, so do not do activity.")
|
||||
return
|
||||
end
|
||||
|
||||
if not validate_bed(self) and self.state ~= PATHFINDING then
|
||||
local jobsite_valid = false
|
||||
|
||||
if not mcl_beds.is_night() then
|
||||
if self.order == SLEEP then self.order = nil end
|
||||
mcl_log("Villager has no bed. Currently at location: "..minetest.pos_to_string(self.object:get_pos()))
|
||||
take_bed (self)
|
||||
|
||||
if not validate_jobsite(self) then
|
||||
--debug_trades(self)
|
||||
if self._profession == "unemployed" or has_traded(self) then
|
||||
get_a_job(self)
|
||||
return
|
||||
end
|
||||
else
|
||||
jobsite_valid = true
|
||||
--mcl_log("My jobsite is valid. Do i need to travel?")
|
||||
end
|
||||
else
|
||||
if self.order == WORK then self.order = nil end
|
||||
|
||||
if not validate_bed(self) then
|
||||
if self.order == SLEEP then self.order = nil end
|
||||
mcl_log("Villager at this location has no bed: " .. minetest.pos_to_string(self.object:get_pos()))
|
||||
take_bed (self)
|
||||
end
|
||||
end
|
||||
|
||||
-- Only check in day or during thunderstorm but wandered_too_far code won't work
|
||||
local wandered_too_far = false
|
||||
if check_bed (self) then
|
||||
wandered_too_far = ( self.state ~= PATHFINDING ) and (vector.distance(self.object:get_pos(),self._bed) > 50 )
|
||||
wandered_too_far = vector.distance(self.object:get_pos(),self._bed) > 50
|
||||
end
|
||||
|
||||
if wandered_too_far then
|
||||
|
@ -1300,7 +1342,7 @@ local function do_activity (self)
|
|||
go_home(self, false)
|
||||
elseif get_activity() == SLEEP then
|
||||
go_home(self, true)
|
||||
elseif get_activity() == WORK then
|
||||
elseif get_activity() == WORK and jobsite_valid then
|
||||
do_work(self)
|
||||
elseif get_activity() == GATHERING then
|
||||
go_to_town_bell(self)
|
||||
|
@ -1309,13 +1351,6 @@ local function do_activity (self)
|
|||
self.order = nil
|
||||
end
|
||||
|
||||
-- Daytime is work and play time
|
||||
if not mcl_beds.is_night() then
|
||||
if self.order == SLEEP then self.order = nil end
|
||||
else
|
||||
if self.order == WORK then self.order = nil end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function update_max_tradenum(self)
|
||||
|
@ -1895,8 +1930,6 @@ end)
|
|||
|
||||
--[=======[ MOB REGISTRATION AND SPAWNING ]=======]
|
||||
|
||||
local pick_up = { "mcl_farming:bread", "mcl_farming:carrot_item", "mcl_farming:beetroot_item" , "mcl_farming:potato_item" }
|
||||
|
||||
mcl_mobs.register_mob("mobs_mc:villager", {
|
||||
description = S("Villager"),
|
||||
type = "npc",
|
||||
|
@ -1941,7 +1974,7 @@ mcl_mobs.register_mob("mobs_mc:villager", {
|
|||
head_shake_start = 131, head_shake_end = 141, head_shake_loop = false,
|
||||
head_nod_start = 121, head_nod_end = 131, head_nod_loop = false,
|
||||
},
|
||||
follow = pick_up,
|
||||
follow = { "mcl_farming:bread", "mcl_farming:carrot_item", "mcl_farming:beetroot_item" , "mcl_farming:potato_item" },
|
||||
nofollow = true,
|
||||
view_range = 16,
|
||||
fear_height = 4,
|
||||
|
@ -1951,7 +1984,7 @@ mcl_mobs.register_mob("mobs_mc:villager", {
|
|||
_id = nil,
|
||||
_profession = "unemployed",
|
||||
look_at_player = true,
|
||||
pick_up = pick_up,
|
||||
pick_up = { "mcl_farming:bread", "mcl_farming:carrot_item", "mcl_farming:beetroot_item" , "mcl_farming:potato_item" },
|
||||
can_open_doors = true,
|
||||
on_pick_up = function(self,itementity)
|
||||
local clicker
|
||||
|
@ -1968,6 +2001,7 @@ mcl_mobs.register_mob("mobs_mc:villager", {
|
|||
return it
|
||||
end,
|
||||
on_rightclick = function(self, clicker)
|
||||
--minetest.log("In villager right click")
|
||||
if self.child or self._profession == "unemployed" or self._profession == "nitwit" then
|
||||
self.order = nil
|
||||
return
|
||||
|
|
|
@ -109,6 +109,7 @@ mcl_mobs.register_mob("mobs_mc:villager_zombie", {
|
|||
clicker:set_wielded_item(wielditem)
|
||||
self._curing = math.random(3 * 60, 5 * 60)
|
||||
self.shaking = true
|
||||
self.can_despawn = false
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
|
|
@ -109,7 +109,7 @@ mcl_mobs.register_mob("mobs_mc:zombie", zombie)
|
|||
|
||||
local baby_zombie = table.copy(zombie)
|
||||
baby_zombie.description = S("Baby Zombie")
|
||||
baby_zombie.collisionbox = {-0.25, -0.01, -0.25, 0.25, 1, 0.25}
|
||||
baby_zombie.collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.98, 0.25}
|
||||
baby_zombie.xp_min = 12
|
||||
baby_zombie.xp_max = 12
|
||||
baby_zombie.walk_velocity = 1.2
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# textdomain: lightning
|
||||
Let lightning strike at the specified position or player. No parameter will strike yourself.=Lad lynet slå ned på den angivne position eller spiller. Hvis du ikke skriver et parameter vil lynet ramme dig selv.
|
||||
No position specified and unknown player=Ingen position og ukendt spiller.
|
|
@ -0,0 +1,3 @@
|
|||
# textdomain: mcl_void_damage
|
||||
The void is off-limits to you!=Tomrummet er forbudt område for dig!
|
||||
@1 fell into the endless void.=@1 faldt ned i det uendelige tomrum.
|
|
@ -0,0 +1,8 @@
|
|||
# textdomain: mcl_weather
|
||||
Gives ability to control weather=Gør en i stand til at styre vejret
|
||||
Changes the weather to the specified parameter.=Ændrer vejret til det angivne.
|
||||
Error: No weather specified.=Fejl: Intet vejr angivet.
|
||||
Error: Invalid parameters.=Fejl: Ugyldige parametre.
|
||||
Error: Duration can't be less than 1 second.=Fejl: Vargihed kan ikke være under 1 sekund.
|
||||
Error: Invalid weather specified. Use “clear”, “rain”, “snow” or “thunder”.=Fejl: Ugyldigt vejr angivet. Brug "clear","rain","snow" eller "thunder".
|
||||
Toggles between clear weather and weather with downfall (randomly rain, thunderstorm or snow)=Skifter mellem klart vejr og vejr med nedbør (tilfældigt enten regn, tordenstorm eller sne)
|
|
@ -136,9 +136,16 @@ mcl_weather.skycolor = {
|
|||
local biomesky
|
||||
local biomefog
|
||||
if mg_name ~= "v6" and mg_name ~= "singlenode" then
|
||||
local biome = minetest.get_biome_name(minetest.get_biome_data(player:get_pos()).biome)
|
||||
biomesky = minetest.registered_biomes[biome]._mcl_skycolor
|
||||
biomefog = minetest.registered_biomes[biome]._mcl_fogcolor
|
||||
local biome_index = minetest.get_biome_data(player:get_pos()).biome
|
||||
local biome_name = minetest.get_biome_name(biome_index)
|
||||
local biome = minetest.registered_biomes[biome_name]
|
||||
if biome then
|
||||
--minetest.log("action", string.format("Biome found for number: %s in biome: %s", tostring(biome_index), biome_name))
|
||||
biomesky = biome._mcl_skycolor
|
||||
biomefog = biome._mcl_fogcolor
|
||||
else
|
||||
--minetest.log("action", string.format("No biome for number: %s in biome: %s", tostring(biome_index), biome_name))
|
||||
end
|
||||
end
|
||||
if (mcl_weather.state == "none") then
|
||||
-- Clear weather
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
# textdomain:doc
|
||||
<=<
|
||||
>=>
|
||||
Access to the requested entry has been denied; this entry is secret. You may unlock access by progressing in the game. Figure out on your own how to unlock this entry.=Adgang til det forespurgte blev nægtet; det er hemmeligt. Du kan få adgang ved at nå længere i spillet. Find selv ud af, hvordan du får adgang.
|
||||
All entries read.=Alle indtastninger læst.
|
||||
All help entries revealed!=Alle hjælpeindtastninger afsløret!
|
||||
All help entries are already revealed.=Alle hjælpeindtasterninger er allerede afsløret.
|
||||
Allows you to reveal all hidden help entries with /help_reveal=Gør dig i stand til at afsløre alle skjulte hjælpeindtaster med /help_reveal
|
||||
Category list=Kategoriliste
|
||||
Currently all entries in this category are hidden from you.=Alle indtastninger i denne kategori er i øjeblikket skjult for dig.
|
||||
Unlock new entries by progressing in the game.=Lås nye indtastninger op ved at nå længere i spillet.
|
||||
Help=Hjælp
|
||||
Entry=Indtastning
|
||||
Entry list=Indtastningsliste
|
||||
Error: Access denied.=Fejl: Adgang nægtet.
|
||||
Error: No help available.=Fejl: Igen hjælp tilgængelig.
|
||||
Go to category list=Gå til kategoriliste
|
||||
Go to entry list=Gå til indtastningsliste
|
||||
Help > @1=Hjælp > @1
|
||||
Help > @1 > @2= Hjælp > @1 > @2
|
||||
Help > @1 > (No Entry)=Hjælp > @1 > (Ingen indtasting)
|
||||
Help > (No Category)=Hjælp > (Ingen kategori)
|
||||
Hidden entries: @1=Skjult indtastning: @1
|
||||
Nameless entry (@1)=Unavngiven indtastning (@1)
|
||||
New entries: @1=Nye indtastninger: @1
|
||||
New help entry unlocked: @1 > @2=Ny hjælpeindtastning låst op: @1 > @2
|
||||
No categories have been registered, but they are required to provide help.=Nye kategorier er blevet registreret, men de er påkrævede for at give hjælp.
|
||||
The Documentation System [doc] does not come with help contents on its own, it needs additional mods to add help content. Please make sure such mods are enabled on for this world, and try again.= Dokumentationssystemet [doc] har ikke medfølgende hjælpeindhold, det behøver yderligere mods for at tilføje hjælpeindhold.
|
||||
Number of entries: @1=Antal indtastninger: @1
|
||||
OK=OK
|
||||
Open a window providing help entries about Minetest and more=Åbn et vindue med hjælpeindtastninger om Minetest og mere
|
||||
Please select a category you wish to learn more about:=Vælg venlist en kategori som du ønsker at lære mere om:
|
||||
Recommended mods: doc_basics, doc_items, doc_identifier, doc_encyclopedia.=Anbefalede mods: doc_basics, doc_items, doc_identifier, doc_encyclopedia.
|
||||
Reveal all hidden help entries to you=Afslør alle gemte hjælpeindtastninger for dig.
|
||||
Show entry=Vis indtastning
|
||||
Show category=Vis kategori
|
||||
Show next entry=Vis næste indtastning
|
||||
Show previous entry=Vis forrige indtastning
|
||||
This category does not have any entries.=Denne kategori har ingen indtastninger.
|
||||
This category has the following entries:=Denne kategori har følgende indtastninger:
|
||||
This category is empty.=Denne kategori er tom.
|
||||
This is the help.=Dette er hjælpen.
|
||||
You haven't chosen a category yet. Please choose one in the category list first.=Du har endnu ikke vagt en kategori. Vælg venligst én i kategoriliste før.
|
||||
You haven't chosen an entry yet. Please choose one in the entry list first.=Du har ikke valgt en indtastning endnu. Vælg venligst en fra indtastningslisten først.
|
||||
Collection of help texts=Samling at hjælpetekster.
|
||||
Notify me when new help is available=Giv mig besked når ny hjælp er tilgængelig.
|
||||
Play notification sound when new help is available=Afspil lyd når ny hjælp er tilgængeig.
|
||||
Show previous image=Vis forrige billede
|
||||
Show previous gallery page=Vis forrige galleriside
|
||||
Show next image=Vis næste billede
|
||||
Show next gallery page=Vis næste galleriside
|
|
@ -0,0 +1,18 @@
|
|||
# textdomain:doc_identifier
|
||||
Error: This node, item or object is undefined. This is always an error.=Fejl: Dette knudepunkt, genstand eller objekt er ikke defineret.
|
||||
This can happen for the following reasons:=Dette kan ske af følgende grunde:
|
||||
• The mod which is required for it is not enabled=• Det mod som er krævet er ikke aktiveret
|
||||
• The author of the game or a mod has made a mistake=• Ophavsmanden til spillet eller moddet har lavet en fejltagelse
|
||||
It appears to originate from the mod “@1”, which is enabled.=Det ser ud til at stamme fra moddet "@1" som er aktiveret.
|
||||
It appears to originate from the mod “@1”, which is not enabled!=Det ser ud til at stamme fra moddet "01" som er deaktiveret!
|
||||
Its identifier is “@1”.=Dets identificering er "@1".
|
||||
Lookup Tool=Opslagsværktøj
|
||||
No help entry for this block could be found.=Der kunne ikke findes nogen hjælpeindtastning til denne blok.
|
||||
No help entry for this item could be found.=Der kunne ikke findes nogen hjælpeindtastning til denne genstand.
|
||||
No help entry for this object could be found.=Der kunne ikke findes nogen hjælpeindtastning for stte objekt.
|
||||
OK=OK
|
||||
Punch any block, item or other thing about you wish to learn more about. This will open up the appropriate help entry. The tool comes in two modes which are changed by using. In liquid mode, this tool points to liquids as well while in solid mode this is not the case.=Slå en hvilkensomhelst blok, genstand eller andre ting som du ønsker at vide mere om. Dette vil åbne den relevante hjælpeindtastning. Værktøjet findes i to tilstande som skiftes ved brug. I flydende tilstand vil værktøjet også peje på væsker, mens dette ikke er tilfældet i fast tilstand.
|
||||
This block cannot be identified because the world has not materialized at this point yet. Try again in a few seconds.=Denne blok kan ikke identificeres fordi verdenen ikke har materialiseret sig endnu. Forsøg igen om et par sekunder.
|
||||
This is a player.=Dette er en spiller.
|
||||
This useful little helper can be used to quickly learn more about about one's closer environment. It identifies and analyzes blocks, items and other things and it shows extensive information about the thing on which it is used.=Denne smarte lille hjælper kan bruges til hurtigt at lære mere om omgivelserne. Den identificerer og analyserer blokke, genstande og andre ting, og den viser udtømmende informationer om den ting den bliver brugt på.
|
||||
Show help for pointed thing=Vis hjælp til tingen
|
|
@ -0,0 +1,143 @@
|
|||
# textdomain:doc_items
|
||||
Using it as fuel turns it into: @1.=At bruge det som brændstof laver det om til: @1.
|
||||
@1 seconds=@1 sekunder
|
||||
# Item count times item name
|
||||
@1×@2=@1x@2
|
||||
# Itemname (25%)
|
||||
@1 (@2%)=@1 (@2%)
|
||||
# Itemname (<0.5%)
|
||||
@1 (<0.5%)= @1 (<0.5%)
|
||||
# Itemname (ca. 25%)
|
||||
@1 (ca. @2%)=@1 (ca. @2%)
|
||||
# List separator (e.g. “one, two, three”)
|
||||
, = ,
|
||||
# Final list separator (e.g. “One, two and three”)
|
||||
and = and
|
||||
1 second=1 sekund
|
||||
A transparent block, basically empty space. It is usually left behind after digging something.=En gennemsigtig blok, egentlig bare tom luft. Det efterlades typisk efter at have gravet.
|
||||
Air=Luft
|
||||
Blocks=Blokke
|
||||
Building another block at this block will place it inside and replace it.=At sætte en ny blok ved denne blok vil placere den indeni og erstatte den.
|
||||
Building this block is completely silent.=Det er helt lydløst at bygge denne blok.
|
||||
Collidable: @1=Kan kollidere: @1
|
||||
Description: @1=Beskrivelse: @1
|
||||
Falling blocks can go through this block; they destroy it when doing so.=Faldende blokke kan gå igennem denne blok; de ødelægger den idet i går igennem den.
|
||||
Full punch interval: @1 s=Tid mellem hele slag: @1
|
||||
Hand=Hånd
|
||||
Hold it in your hand, then leftclick to eat it.=Hold det i din hånd, og venstre-klik for at spise det.
|
||||
Hold it in your hand, then leftclick to eat it. But why would you want to do this?=Hold det i din hånd, og venstre-klik for at spise det. Men hvorfor i alverden ville du have lyst til dét?
|
||||
Item reference of all wieldable tools and weapons=Genstandsreference til alt værktøj og alle våden man kan bære.
|
||||
Item reference of blocks and other things which are capable of occupying space=Genstandsreference til blokke og andre ting som kan optage plads.
|
||||
Item reference of items which are neither blocks, tools or weapons (esp. crafting items)=Genstandsreference til genstanse som hverken er blokke, værktøj eller våben (især håndværksmateriale)
|
||||
Liquids can flow into this block and destroy it.=Væsker kan flyde ind i denne blok og ødelægge den.
|
||||
Maximum stack size: @1=Største stakstørrelse: @1
|
||||
Mining level: @1=Udvindingsevneevne: @1
|
||||
Mining ratings:=Udvindelsesvurdering
|
||||
• @1, rating @2: @3 s - @4 s=• @1, vurdering @2: @3 s -@4 s
|
||||
• @1, rating @2: @3 s=• @1, vurdering @2: @3 s
|
||||
Mining times:=Udvindingstider
|
||||
Mining this block is completely silent.=Det er helt lydløst at udvinde denne blok.
|
||||
Miscellaneous items=Diverse genstande
|
||||
No=Nej
|
||||
Pointable: No=Retningsbestemt: Nej
|
||||
Pointable: Only by special items=Retningsbestemt: Kun af særlige genstande
|
||||
Pointable: Yes=Retningsbestemt: Ja
|
||||
Punches with this block don't work as usual; melee combat and mining are either not possible or work differently.=Slag med denne blok virker ikke som normalt; nærkamp og udvinding er enten umulig eller virker anderledes.
|
||||
Punches with this item don't work as usual; melee combat and mining are either not possible or work differently.=Slag med dette objekt virker ikke som normalt; nærkamp og udvinding er enten umulig eller virker anderledes.
|
||||
Punches with this tool don't work as usual; melee combat and mining are either not possible or work differently.=Slag med dette værktøj virker ikke som normalt; nærkamp og udvinding er enten umulig eller virker anderledes.
|
||||
Range: @1=Rækkevidde: @1
|
||||
# Range: <Hand> (<Range>)
|
||||
Range: @1 (@2)=Rækkevidde: @1 (@2)
|
||||
Range: 4=Rækkevidde: 4
|
||||
# Rating used for digging times
|
||||
Rating @1=Vurdering: @1
|
||||
# @1 is minimal rating, @2 is maximum rating
|
||||
Rating @1-@2=Vurdering @1-@2
|
||||
The fall damage on this block is increased by @1%.=Faldskade på denne blok er øget med @1%.
|
||||
The fall damage on this block is reduced by @1%.=Faldskade på denne blok er reduceret med @1%.
|
||||
This block allows light to propagate with a small loss of brightness, and sunlight can even go through losslessly.=Denne blok lader lys sprede sig med et lille tab af styrke, og sollys kan endda gå igennem uden tab.
|
||||
This block allows light to propagate with a small loss of brightness.=Denne blok tillader lys at sprede med et lille tab af styrke.
|
||||
This block allows sunlight to propagate without loss in brightness.=Denne blok tillader sollys at sprede sig uden tab af styrke.
|
||||
This block belongs to the @1 group.=Denne blok tilhører @1gruppen
|
||||
This block belongs to these groups: @1.=Denne blok hører til følgende grupper: @1.
|
||||
This block can be climbed.=Man kan klatre på denne blok.
|
||||
This block can be destroyed by any mining tool immediately.=Denne blok kan ødelægges straks med ethvert udvindingsværktøj.
|
||||
This block can be destroyed by any mining tool in half a second.=Denne blok kan ødelægges på et halvt sekund med ethvert udvindingsværktøj.
|
||||
This block can be mined by any mining tool immediately.=Denne blok kan udvindes straks med ethvert udvindingsværktøj.
|
||||
This block can be mined by any mining tool in half a second.=Denne blok kan udvindes på et halvt sekund med ethvert udvindingsværktøj.
|
||||
This block can be mined by mining tools which match any of the following mining ratings and its toughness level.=Denne blok kan udvindes med ethvert udvindingsværktøj som svarer til en hvilkensomhelst af følgende udvindingsvurderinger og hårdhedsgrad.
|
||||
This block can not be destroyed by ordinary mining tools.=Denne blok kan ikke ødelægges af normalt udvindingsværktøj.
|
||||
This block can not be mined by ordinary mining tools.=Denne blok kan ikke udvindes med normalt udvindingsværktøj.
|
||||
This block can serve as a smelting fuel with a burning time of @1.=Denne blok virker som brændstof til at smelte og har en brændetid på @1.
|
||||
This block causes a damage of @1 hit point per second.=Denne blok giver @1 skade per sekund.
|
||||
This block causes a damage of @1 hit points per second.=Denne blok giver @1 skade per sekund.
|
||||
This block connects to blocks of the @1 group.=Denne blok forbindes til blokke i @1gruppen.
|
||||
This block connects to blocks of the following groups: @1.=Denne blok forbindes til blokke i følgende grupper: @1.
|
||||
This block connects to these blocks: @1.=Denne blok forbindes til disse blokke: @1.
|
||||
This block connects to this block: @1.=Denne blok forbindes til denne blok: @1.
|
||||
This block decreases your breath and causes a drowning damage of @1 hit point every 2 seconds.=Denne blok nedsætter dit åndedræt og giver @1 drukningsskade hvert 2. sekund.
|
||||
This block decreases your breath and causes a drowning damage of @1 hit points every 2 seconds.=Denne blok nedsætter dit åndedræt og giver @1 drukneskade hvert 2. sekund.
|
||||
This block is a light source with a light level of @1.=Denne blok er en lyskilde med lysniveau @1.
|
||||
This block glows faintly with a light level of @1.=Denne blok gløder svagt med et lysniveau på @1.
|
||||
This block is a building block for creating various buildings.=Denne blok er en byggesten til at bygge forskellige bygninger.
|
||||
This block is a liquid with these properties:=Denne blok er en væske med følgende egenskaber:
|
||||
This block is affected by gravity and can fall.=Denne blok påvirkes af tyngdekraften og kan falde ned.
|
||||
This block is completely silent when mined or built.=Denne blok er helt lydløs når den udvindes eller bygges.
|
||||
This block is completely silent when walked on, mined or built.=Denne blok er helt lydløs når den betrædes, udvindes eller bygges.
|
||||
This block is destroyed when a falling block ends up inside it.=Denne blok ødelægges når en nedfaldende blok ender indeni den.
|
||||
This block negates all fall damage.=Denne blok modvirker al faldskade.
|
||||
This block points to liquids.=Denne blok orienteres mod væsker.
|
||||
This block will drop as an item when a falling block ends up inside it.=Denne blok dropper som genstand når en faldende blok ender indeni den.
|
||||
This block will drop as an item when it is not attached to a surrounding block.=Denne blok dropper som genstand når den ikke sidder fast på en tilstødende blok.
|
||||
This block will drop as an item when no collidable block is below it.=Denne blok dropper som genstand når der ikke er en bæredygtig blok under den.
|
||||
This block will drop the following items when mined: @1.=Denne blok dropper følgende genstande når den udvindes: @1.
|
||||
This block will drop the following when mined: @1×@2.=Denne blok dropper følgende når den udvindes: @1x@2.
|
||||
This block will drop the following when mined: @1.=Denne blok dropper følgende når den udvindes: @1.
|
||||
This block will drop the following when mined: @1.=Denne blok dropper følgende når den udvindes: @1.
|
||||
This block will make you bounce off with an elasticity of @1%.=Denne blok får dig til at hoppe af med en elasticitet på @1%.
|
||||
This block will randomly drop one of the following when mined: @1.=Denne blok dropper en vilkårlig af følgende genstande når den udvindes: @1.
|
||||
This block will randomly drop up to @1 drops of the following possible drops when mined: @2.=Denne blok dropper et vilkårligt antal op til @1 af følgende mulige ting når den udvindes: @2.
|
||||
This block won't drop anything when mined.=Denne blok dropper ikke noget når den udvindes.
|
||||
This is a decorational block.=Dette er en pynteblok.
|
||||
This is a melee weapon which deals damage by punching.=Dette er et nærkampsvåben som giver skade ved at slå.
|
||||
Maximum damage per hit:=Højeste skade per slag:
|
||||
This item belongs to the @1 group.=Denne genstand hører til @1gruppen.
|
||||
This item belongs to these groups: @1.=Denne genstand hører til disse grupper: @1.
|
||||
This item can serve as a smelting fuel with a burning time of @1.=Denne genstand virker som brændstof til at smelte og har en brændetid på @1.
|
||||
This item is primarily used for crafting other items.=Denne genstand bruges mest til at lave andre genstande.
|
||||
This item points to liquids.=Denne genstand orienterer sig mod væsker.
|
||||
This tool belongs to the @1 group.=Dette værktøj hører til @1gruppen
|
||||
This tool belongs to these groups: @1.=Dette værktøj hører til disse grupper:
|
||||
This tool can serve as a smelting fuel with a burning time of @1.=Dette værktøj virker som brændstof til at smelte og har en brændetid på @1.
|
||||
This tool is capable of mining.=Dette værktøj kan bruges til udvinding.
|
||||
Maximum toughness levels:=Højeste hårdhedsgrad.
|
||||
This tool points to liquids.=Dette værktøj orienterer sig mod væsker.
|
||||
Tools and weapons=Værktøj og våben
|
||||
Unknown Node=Ukendt knudepunkt
|
||||
Usage help: @1=Hjælp til brug: @1
|
||||
Walking on this block is completely silent.=Det er helt lydløst at gå på denne blok.
|
||||
Whenever you are not wielding any item, you use the hand which acts as a tool with its own capabilities. When you are wielding an item which is not a mining tool or a weapon it will behave as if it would be the hand.=Når du ikke anvender en genstand, bruger du din hånd som fungerer som et værktøj med sine egne egenskaber. Når du anvender en genstand som ikke er et værktøj til udvinding eller våben virker det som om du bruger din hånd.
|
||||
Yes=Ja
|
||||
You can not jump while standing on this block.=Du kan ikke hoppe mens du står på dene blok.
|
||||
any level=hvilketsomhelst level
|
||||
level 0=level 0
|
||||
level 0-@1=level 0-@1
|
||||
unknown=ukendt
|
||||
Unknown item (@1)=ukendt genstand (@1)
|
||||
• @1: @2=
|
||||
• @1: @2 HP=• @1: @2 HP
|
||||
• @1: @2, @3=• @1: @2, @3
|
||||
• Flowing range: @1=• Flydende rækkevidde: @1
|
||||
• No flowing=• Ingen strøm
|
||||
• Not renewable=• Kan ikke genopfriskes
|
||||
• Renewable=• Kan genopfriskes
|
||||
• Viscosity: @1=• Viskositet: @1
|
||||
Itemstring: "@1"=Genstandsstreng: "@1"
|
||||
Durability: @1 uses=Holdbarhed: @1 anvendelser
|
||||
Durability: @1=Holdbarhed: @1
|
||||
Mining durability:=Udvindingsholdbarhed:
|
||||
• @1, level @2: @3 uses=• @1, level @2: @3 anvendelser
|
||||
• @1, level @2: Unlimited=• @1, level @2: Uendelig
|
||||
This block's rotation is affected by the way you place it: Place it on the floor or ceiling for a vertical orientation; place it at the side for a horizontal orientation. Sneaking while placing it leads to a perpendicular orientation instead.=Denne bloks rotation påvirkes af måden du placerer den på: Placér den på gulvet eller loftet for en lodret orientering; placér den på siden for en horisontal orientering. Hvis du sniger dig mens den placeres den vinkelret i stedet.
|
||||
Toughness level: @1=Hårdhedsgrad: @1
|
||||
This block is slippery.=Denne blok er glat.
|
|
@ -0,0 +1,37 @@
|
|||
# textdomain: craftguide
|
||||
Any shulker box=Hvilkensomhelst shulkerboks
|
||||
Any wool=Hvilkensomhelst uld
|
||||
Any wood planks=Hvilkensomhelst træplanker
|
||||
Any wood=Hvilkensomhelst træ
|
||||
Any sand=Hvilkensomhelst sand
|
||||
Any normal sandstone=Hvilkensomhelst normal sandsten
|
||||
Any red sandstone=Hvilkensomhelst rød sandsten
|
||||
Any carpet=HVilketsomhelst tæppe
|
||||
Any dye=Hvilkensomhelst farvestof
|
||||
Any water bucket=Hvilkensomhelst vandpand
|
||||
Any flower=Hvilkensomhelst blomst
|
||||
Any mushroom=Hvilkensomhelst svamp
|
||||
Any wooden slab=Hvilkensomhelst træplade
|
||||
Any wooden stairs=Hvilkensomhelst trætrappe
|
||||
Any coal=Hvilketsomhelst kul
|
||||
Any kind of quartz block=Hvilkensomhelst quartzblok
|
||||
Any kind of purpur block=Hvilkensomhelst pupurblok
|
||||
Any stone bricks=Hvilkensomhelst mursten af sten
|
||||
Any stick=Hvilkensomhelst pind
|
||||
Any item belonging to the @1 group=Hvilkensomhelst genstant i @1gruppen
|
||||
Any item belonging to the groups: @1=Hvilkensomhelst genstand som hører til grupperne: @1
|
||||
Search=Søg
|
||||
Reset=Nulstil
|
||||
Previous page=Forrige side
|
||||
Next page=Næste side
|
||||
Usage @1 of @2=Brug @1 af @2
|
||||
Recipe @1 of @2=Opskrift @1 af @2
|
||||
Burning time: @1=Brændetid: @1
|
||||
Cooking time: @1=Tilberedelsestid: @1
|
||||
Recipe is too big to be displayed (@1×@2)=Formen er for stor til at blive vist (@1x@2)
|
||||
Shapeless=Uformelig
|
||||
Cooking=Madlavning
|
||||
Increase window size=Øg vinduesstørrelsen
|
||||
Decrease window size=Mindsk vinduesstørrelsen
|
||||
No item to show=Ingen genstande at vise
|
||||
Collect items to reveal more recipes=Saml genstande for at afsløre flere opskrifter
|
|
@ -0,0 +1,79 @@
|
|||
# textdomain: mcl_doc
|
||||
Water can flow into this block and cause it to drop as an item.=Der kan flyde vandt i denne blok, hvilket får den til at droppe som en genstand.
|
||||
This block can be turned into dirt with a hoe.=Denne blok kan omdannes til jord med en hakke.
|
||||
This block can be turned into farmland with a hoe.=Denne blok kan omdannes til landbrugsjord med en hakke.
|
||||
This block acts as a soil for all saplings.=Denne blok virker som jord for alle spirer.
|
||||
This block acts as a soil for some saplings.=Denne blok virker som jord for nogle spirer.
|
||||
Sugar canes will grow on this block.=Sukkerrør gror på denne blok.
|
||||
Nether wart will grow on this block.=Nethervorder gror på denne blok.
|
||||
This block quickly decays when there is no wood block of any species within a distance of @1. When decaying, it disappears and may drop one of its regular drops. The block does not decay when the block has been placed by a player.=Denne blok forgår hurtigt når der ikke er træblokke af nogen art af træblokke indenfor en afstand af @1. Når den forgår, forsvinder den, og dropper måske et af sine normale drops. Blokken forgår ikke når den er blevet placeret af en spiller.
|
||||
This block quickly decays and disappears when there is no wood block of any species within a distance of @1. The block does not decay when the block has been placed by a player.=Denne blok forgår hurtigt og forsvinder når der ikke er nogen art af træblokke indenfor en afstand af @1. Blokken forgår ikke når den er blevet placeret af en spiller.
|
||||
This plant can only grow on grass blocks and dirt. To survive, it needs to have an unobstructed view to the sky above or be exposed to a light level of 8 or higher.=Denne plante kan kun gro på græsblokke eller jord. For at overleve, har den brug for direkte udsyn til himlen, eller et lysniveau på 8 eller derover.
|
||||
This plant can grow on grass blocks, podzol, dirt and coarse dirt. To survive, it needs to have an unobstructed view to the sky above or be exposed to a light level of 8 or higher.=Denne plante kan gro på græsblokke, podsol, jord eller grov jord. For at overleve, har den brug for direkte udsyn til himlen, eller et lysniveau på 8 eller derover.
|
||||
This block is flammable.=Denne blok er brændfarlig.
|
||||
This block destroys any item it touches.=Denne blok ødelægger enhver genstand den berør.
|
||||
To eat it, wield it, then rightclick.=For at spise det skal du bære det og højre-klikke.
|
||||
You can eat this even when your hunger bar is full.=Du kan spise dette selvom din sultbjælke er fuld.
|
||||
You cannot eat this when your hunger bar is full.=Du kan ikke spise dette når din sultbjælke er fuld.
|
||||
To drink it, wield it, then rightclick.=For at drikke det skal du bære det og højre-klikke.
|
||||
You cannot drink this when your hunger bar is full.=Du kan ikke drikke dette når din sultbjælke er fuld.
|
||||
To consume it, wield it, then rightclick.=For at indtage det skal du bære det og højre-klikke.
|
||||
You cannot consume this when your hunger bar is full.=Du kan ikke indtage dette når din sultbjælke er fuld.
|
||||
You have to wait for about 2 seconds before you can eat or drink again.=Du er nødt til at vente omkring 2 sekunder før du kan drikke eller spise igen.
|
||||
Hunger points restored: @1=Sultpoint genvundet: @1
|
||||
Saturation points restored: @1%.1f=Mæthedspoint genvundet: @1%.1f
|
||||
This item can be repaired at an anvil with: @1.=Denne genstand kan repareres ved en ambolt med: @1.
|
||||
This item can be repaired at an anvil with any wooden planks.=Denne genstand kan repareres ved en ambolt med hvilkensomhelst træplanke.
|
||||
This item can be repaired at an anvil with any item in the “@1” group.=Denne genstand kan repareres ved en ambolt med hvilkensomhelst genstand i "@1"gruppen
|
||||
This item cannot be renamed at an anvil.=Denne genstand kan ikke omdøbes ved en ambolt.
|
||||
This block crushes any block it falls into.=Denn blok knuser enhver blok den falder ind i.
|
||||
When this block falls deeper than 1 block, it causes damage to any player it hits. The damage dealt is B×2−2 hit points with B @= number of blocks fallen. The damage can never be more than 40 HP.=Denne blok falder dybere end 1 blok, og giver skade til enhver spiller den rammer. Skaden givet er Bx2-2 ned B @= antal faldne blokke.
|
||||
Diamond Pickaxe=Minehakke i diamant
|
||||
Iron Pickaxe=Jernhakke
|
||||
Stone Pickaxe=Stenhakke
|
||||
Golden Pickaxe=Guldhakke
|
||||
Wooden Pickaxe=Træhakke
|
||||
Diamond Axe=Diamantøkse
|
||||
Iron Axe=Jernøkse
|
||||
Stone Axe=Stenøkse
|
||||
Golden Axe=Guldøkse
|
||||
Wooden Axe=Træøkse
|
||||
Diamond Shovel=Diamantskovl
|
||||
Iron Shovel=Jernskovl
|
||||
Stone Shovel=Stenskovl
|
||||
Golden Shovel=Guldskovl
|
||||
Wooden Shovel=Træskovl
|
||||
This block can be mined by any tool instantly.=Denne blok kan udvindes momentant med ethvert værktøj.
|
||||
This block can be mined by:=Denne blok kan udvindes med:
|
||||
Hardness: ∞= Hårdhed:∞
|
||||
Hardness: @1=Hårdhed @1
|
||||
This block will not be destroyed by TNT explosions.=Denne blok ødelægges ikke af TNT-eksplosioner.
|
||||
This block drops itself when mined by shears.=Denne blok dropper sig selv når den udvindes med sakse.
|
||||
@1×@2=@1x@2
|
||||
This blocks drops the following when mined by shears: @1=Denne blok dropper følgende når den udvindes med sakse: @1
|
||||
, =,
|
||||
• Shears=• Sakse
|
||||
• Sword=• Sværd
|
||||
• Hand=• Hånd
|
||||
This is a melee weapon which deals damage by punching.=Dette er et nærkampsvåben som giver skade ved at slå.
|
||||
Maximum damage: @1 HP=Højeste skade: @1
|
||||
Full punch interval: @1 s=Helt interval mellem slag: @1 s
|
||||
This tool is capable of mining.=Dette værktøj kan bruges til udvinding.
|
||||
Mining speed: @1=Udvindingshastighed: @1
|
||||
Painfully slow=Pinagtig langsom
|
||||
Very slow=Meget langsom
|
||||
Slow=Langsom
|
||||
Fast=Hurtig
|
||||
Very fast=Meget hurtig
|
||||
Extremely fast=Ekstremt hurtig
|
||||
Instantaneous=Momentan
|
||||
@1 uses=@1 anvendelser
|
||||
Unlimited uses=Uendelige anvendelser
|
||||
Block breaking strength: @1=Blokkens brudstyrke: @1
|
||||
Mining durability: @1=Udvindingsholdbarhed: @1
|
||||
Armor points: @1=Rustningspoint: @1
|
||||
Armor durability: @1=Rustningens holdbarhed: @1
|
||||
It can be worn on the head.=Den kan bæres på hovedet.
|
||||
It can be worn on the torso.=Den kan bæres på kroppen.
|
||||
It can be worn on the legs.=De kan bæres på benene.
|
||||
It can be worn on the feet.=De kan bæres på fødderne.
|
|
@ -0,0 +1,511 @@
|
|||
# textdomain: mcl_doc_basics
|
||||
Basics=
|
||||
Everything you need to know to get started with playing=
|
||||
Advanced usage=
|
||||
Advanced information which may be nice to know, but is not crucial to gameplay=
|
||||
Quick start=
|
||||
This is a very brief introduction to the basic gameplay:=
|
||||
Basic controls:=
|
||||
• Move mouse to look=
|
||||
• [W], [A], [S] and [D] to move=
|
||||
• [E] to sprint=
|
||||
• [Space] to jump or move upwards=
|
||||
• [Shift] to sneak or move downwards=
|
||||
• Mouse wheel or [1]-[9] to select item=
|
||||
• Left-click to mine blocks or attack=
|
||||
• Recover from swings to deal full damage=
|
||||
• Right-click to build blocks and use things=
|
||||
• [I] for the inventory=
|
||||
• First items in inventory appear in hotbar below=
|
||||
• Lowest row in inventory appears in hotbar below=
|
||||
• [Esc] to close this window=
|
||||
How to play:=
|
||||
• Punch a tree trunk until it breaks and collect wood=
|
||||
• Place the wood into the 2×2 grid (your “crafting grid”) in your inventory menu and craft 4 wood planks=
|
||||
• Place them in a 2×2 shape in the crafting grid to craft a crafting table=
|
||||
• Place the crafting table on the ground=
|
||||
• Rightclick it for a 3×3 crafting grid=
|
||||
• Use the crafting guide (book icon) to learn all the possible crafting recipes=
|
||||
• Craft a wooden pickaxe so you can dig stone=
|
||||
• Different tools break different kinds of blocks. Try them out!=
|
||||
• Read entries in this help to learn the rest=
|
||||
• Continue playing as you wish. There's no goal. Have fun!=
|
||||
Minetest=
|
||||
Minetest is a free software game engine for games based on voxel gameplay, inspired by InfiniMiner, Minecraft, and the like. Minetest was originally created by Perttu Ahola (alias “celeron55”).=
|
||||
The player is thrown into a huge world made out of cubes or blocks. These cubes usually make the landscape they blocks can be removed and placed almost entirely freely. Using the collected items, new tools and other items can be crafted. Games in Minetest can, however, be much more complex than this.=
|
||||
A core feature of Minetest is the built-in modding capability. Mods modify existing gameplay. They can be as simple as adding a few decorational blocks or be very complex by e.g. introducing completely new gameplay concepts, generating a completely different kind of world, and many other things.=
|
||||
Minetest can be played alone or online together with multiple players. Online play will work out of the box with any mods, with no need for additional software as they are entirely provided by the server.=
|
||||
Minetest is usually bundled with a simple default game, named “Minetest Game” (shown in images 1 and 2). You probably already have it. Other games for Minetest can be downloaded from the official Minetest forums <https://forum.minetest.net/viewforum.php?f@=48>.=
|
||||
Minetest as well as Minetest Game are both unfinished at the moment, so please forgive us when not everything works out perfectly.=
|
||||
Sneaking=
|
||||
Sneaking makes you walk slower and prevents you from falling off the edge of a block.=
|
||||
To sneak, hold down the sneak key (default: [Shift]). When you release it, you stop sneaking. Careful: When you release the sneak key at a ledge, you might fall!=
|
||||
• Sneak: [Shift]=
|
||||
Sneaking only works when you stand on solid ground, are not in a liquid and don't climb.=
|
||||
If you jump while holding the sneak key, you also jump slightly higher than usual.=
|
||||
Sneaking might be disabled by mods. In this case, you still walk slower by sneaking, but you will no longer be stopped at ledges.=
|
||||
Controls=
|
||||
These are the default controls:=
|
||||
Basic movement:=
|
||||
• Moving the mouse around: Look around=
|
||||
• W: Move forwards=
|
||||
• A: Move to the left=
|
||||
• D: Move to the right=
|
||||
• S: Move backwards=
|
||||
• E: Sprint=
|
||||
While standing on solid ground:=
|
||||
• Space: Jump=
|
||||
• Shift: Sneak=
|
||||
While on a ladder, swimming in a liquid or fly mode is active=
|
||||
• Space: Move up=
|
||||
• Shift: Move down=
|
||||
Extended movement (requires privileges):=
|
||||
• J: Toggle fast mode, makes you run or fly fast (requires “fast” privilege)=
|
||||
• K: Toggle fly mode, makes you move freely in all directions (requires “fly” privilege)=
|
||||
• H: Toggle noclip mode, makes you go through walls in fly mode (requires “noclip” privilege)=
|
||||
• E: Move even faster when in fast mode=
|
||||
• E: Walk fast in fast mode=
|
||||
World interaction:=
|
||||
• Left mouse button: Punch / mine blocks / take items=
|
||||
• Left mouse button: Punch / mine blocks=
|
||||
• Right mouse button: Build or use pointed block=
|
||||
• Shift+Right mouse button: Build=
|
||||
• Roll mouse wheel: Select next/previous item in hotbar=
|
||||
• Roll mouse wheel / B / N: Select next/previous item in hotbar=
|
||||
• 1-9: Select item in hotbar directly=
|
||||
• Q: Drop item stack=
|
||||
• Shift+Q: Drop 1 item=
|
||||
• I: Show/hide inventory menu=
|
||||
Inventory interaction:=
|
||||
See the entry “Basics > Inventory”.=
|
||||
Camera:=
|
||||
• Z: Zoom=
|
||||
• F7: Toggle camera mode=
|
||||
• F8: Toggle cinematic mode=
|
||||
Interface:=
|
||||
• Esc: Open menu window (pauses in single-player mode) or close window=
|
||||
• F1: Show/hide HUD=
|
||||
• F2: Show/hide chat=
|
||||
• F9: Toggle minimap=
|
||||
• Shift+F9: Toggle minimap rotation mode=
|
||||
• F10: Open/close console/chat log=
|
||||
• F12: Take a screenshot=
|
||||
Server interaction:=
|
||||
• T: Open chat window (chat requires the “shout” privilege)=
|
||||
• /: Start issuing a server command=
|
||||
Technical:=
|
||||
• R: Toggle far view (disables all fog and allows viewing far away, can make game very slow)=
|
||||
• +: Increase minimal viewing distance=
|
||||
• -: Decrease minimal viewing distance=
|
||||
• F3: Enable/disable fog=
|
||||
• F5: Enable/disable debug screen which also shows your coordinates=
|
||||
• F6: Only useful for developers. Enables/disables profiler=
|
||||
• P: Only useful for developers. Writes current stack traces=
|
||||
Players=
|
||||
Players (actually: “player characters”) are the characters which users control.=
|
||||
Players are living beings. They start with a number of health points (HP) and a number of breath points (BP).=
|
||||
Players are capable of walking, sneaking, jumping, climbing, swimming, diving, mining, building, fighting and using tools and blocks.=
|
||||
Players can take damage for a variety of reasons, here are some:=
|
||||
• Taking fall damage=
|
||||
• Touching a block which causes direct damage=
|
||||
• Drowning=
|
||||
• Being attacked by another player=
|
||||
• Being attacked by a computer enemy=
|
||||
At a health of 0, the player dies. The player can just respawn in the world.=
|
||||
Other consequences of death depend on the game. The player could lose all items, or lose the round in a competitive game.=
|
||||
Some blocks reduce breath. While being with the head in a block which causes drowning, the breath points are reduced by 1 for every 2 seconds. When all breath is gone, the player starts to suffer drowning damage. Breath is quickly restored in any other block.=
|
||||
Damage can be disabled on any world. Without damage, players are immortal and health and breath are unimportant.=
|
||||
In multi-player mode, the name of other players is written above their head.=
|
||||
Items=
|
||||
Items are things you can carry along and store in inventories. They can be used for crafting, smelting, building, mining, and more. Types of items include blocks, tools, weapons and items only used for crafting.=
|
||||
An item stack is a collection of items of the same type which fits into a single item slot. Item stacks can be dropped on the ground. Items which drop into the same coordinates will form an item stack.=
|
||||
Dropped item stacks will be collected automatically when you stand close to them.=
|
||||
Items have several properties, including the following:=
|
||||
• Maximum stack size: Number of items which fit on 1 item stack=
|
||||
• Pointing range: How close things must be to be pointed while wielding this item=
|
||||
• Group memberships: See “Basics > Groups”=
|
||||
• May be used for crafting or cooking=
|
||||
Tools=
|
||||
Some items may serve as a tool when wielded. Any item which has some special use which can be directly used by its wielder is considered a tool.=
|
||||
A common subset of tools is mining tools. These are important to break all kinds of blocks. Weapons are a kind of tool. There are of course many other possible tools. Special actions of tools are usually done by left-click or right-click.=
|
||||
When nothing is wielded, players use their hand which may act as tool and weapon.=
|
||||
Mining tools are important to break all kinds of blocks. Weapons are another kind of tool. There are some other more specialized tools. Special actions of tools are usually done by right-click.=
|
||||
When nothing is wielded, players use their hand which may act as tool and weapon. The hand is capable of punching and deals minimum damage.=
|
||||
Many tools will wear off when using them and may eventually get destroyed. The damage is displayed in a damage bar below the tool icon. If no damage bar is shown, the tool is in mint condition. Tools may be repairable by crafting, see “Basics > Crafting”.=
|
||||
Weapons=
|
||||
Some items are usable as a melee weapon when wielded. Weapons share most of the properties of tools.=
|
||||
Melee weapons deal damage by punching players and other animate objects. There are two ways to attack:=
|
||||
• Single punch: Left-click once to deal a single punch=
|
||||
• Quick punching: Hold down the left mouse button to deal quick repeated punches=
|
||||
There are two core attributes of melee weapons:=
|
||||
• Maximum damage: Damage which is dealt after a hit when the weapon was fully recovered=
|
||||
• Full punch interval: Time it takes for fully recovering from a punch=
|
||||
A weapon only deals full damage when it has fully recovered from a previous punch. Otherwise, the weapon will deal only reduced damage. This means, quick punching is very fast, but also deals rather low damage. Note the full punch interval does not limit how fast you can attack.=
|
||||
There is a rule which sometimes makes attacks impossible: Players, animate objects and weapons belong to damage groups. A weapon only deals damage to those who share at least one damage group with it. So if you're using the wrong weapon, you might not deal any damage at all.=
|
||||
Pointing=
|
||||
“Pointing” means looking at something in range with the crosshair. Pointing is needed for interaction, like mining, punching, using, etc. Pointable things include blocks, players, computer enemies and objects.=
|
||||
To point something, it must be in the pointing range (also just called “range”) of your wielded item. There's a default range when you are not wielding anything. A pointed thing will be outlined or highlighted (depending on your settings). Pointing is not possible with the 3rd person front camera.=
|
||||
A few things can not be pointed. Most blocks are pointable. A few blocks, like air, can never be pointed. Other blocks, like liquids can only be pointed by special items.=
|
||||
Camera=
|
||||
There are 3 different views which determine the way you see the world. The modes are:=
|
||||
• 1: First-person view (default)=
|
||||
• 2: Third-person view from behind=
|
||||
• 3: Third-person view from the front=
|
||||
You can change the camera mode by pressing [F7].=
|
||||
You might be able to zoom with [Z] to zoom the view at the crosshair. This allows you to look further.=
|
||||
Zooming is a gameplay feature that might be enabled or disabled by the game. By default, zooming is enabled when in Creative Mode but disabled otherwise.=
|
||||
There is also Cinematic Mode which can be toggled with [F8]. With Cinematic Mode enabled, the camera movements become more smooth. Some players don't like it, it is a matter of taste.=
|
||||
By holding down [Z], you can zoom the view at your crosshair. You need the “zoom” privilege to do this.=
|
||||
• Switch camera mode: [F7]=
|
||||
• Toggle Cinematic Mode: [F8]=
|
||||
• Zoom: [Z]=
|
||||
Blocks=
|
||||
The world of MineClone 2 is made entirely out of blocks (voxels, to be precise). Blocks can be added or removed with the correct tools.=
|
||||
The world is made entirely out of blocks (voxels, to be precise). Blocks can be added or removed with the correct tools.=
|
||||
Blocks can have a wide range of different properties which determine mining times, behavior, looks, shape, and much more. Their properties include:=
|
||||
• Collidable: Collidable blocks can not be passed through; players can walk on them. Non-collidable blocks can be passed through freely=
|
||||
• Pointable: Pointable blocks show a wireframe or a halo box when pointed. But you will just point through non-pointable blocks. Liquids are usually non-pointable but they can be pointed at by some special tools=
|
||||
• Mining properties: By which tools it can be mined, how fast and how much it wears off tools=
|
||||
• Climbable: While you are at a climbable block, you won't fall and you can move up and down with the jump and sneak keys=
|
||||
• Drowning damage: See the entry “Basics > Player”=
|
||||
• Liquids: See the entry “Basics > Liquids”=
|
||||
• Group memberships: Group memberships are used to determine mining properties, crafting, interactions between blocks and more=
|
||||
Mining=
|
||||
Mining (or digging) is the process of breaking blocks to remove them. To mine a block, point it and hold down the left mouse button until it breaks.=
|
||||
Blocks require a mining tool to be mined. Different blocks are mined by different mining tools, and some blocks can not be mined by any tool. Blocks vary in hardness and tools vary in strength. Mining tools will wear off over time. The mining time and the tool wear depend on the block and the mining tool. The fastest way to find out how efficient your mining tools are is by just trying them out on various blocks. Any items you gather by mining will drop on the ground, ready to be collected.=
|
||||
After mining, a block may leave a “drop” behind. This is a number of items you get after mining. Most commonly, you will get the block itself. There are other possibilities for a drop which depends on the block type. The following drops are possible:=
|
||||
• Always drops itself (the usual case)=
|
||||
• Always drops the same items=
|
||||
• Drops items based on probability=
|
||||
• Drops nothing=
|
||||
Building=
|
||||
Almost all blocks can be built (or placed). Building is very simple and has no delay.=
|
||||
To build your wielded block, point at a block in the world and right-click. If this is not possible because the pointed block has a special right-click action, hold down the sneak key before right-clicking.=
|
||||
Blocks can almost always be built at pointable blocks. One exception are blocks attached to the floor; these can only be built on the floor.=
|
||||
Normally, blocks are built in front of the pointed side of the pointed block. A few blocks are different: When you try to build at them, they are replaced.=
|
||||
Liquids=
|
||||
Liquids are special dynamic blocks. Liquids like to spread and flow to their surrounding blocks. Players can swim and drown in them.=
|
||||
Liquids usually come in two forms: In source form (S) and in flowing form (F).=
|
||||
Liquid sources have the shape of a full cube. A liquid source will generate flowing liquids around it from time to time, and, if the liquid is renewable, it also generates liquid sources. A liquid source can sustain itself. As long it is left alone, a liquid source will normally keep its place and does not drain out.=
|
||||
Flowing liquids take a sloped form. Flowing liquids spread around the world until they drain. A flowing liquid can not sustain itself and always comes from a liquid source, either directly or indirectly. Without a liquid source, a flowing liquid will eventually drain out and disappear.=
|
||||
All liquids share the following properties:=
|
||||
• All properties of blocks (including drowning damage)=
|
||||
• Renewability: Renewable liquids can create new sources=
|
||||
• Flowing range: How many flowing liquids are created at maximum per liquid source, it determines how far the liquid will spread. Possible are ranges from 0 to 8. At 0, no flowing liquids will be created. Image 5 shows a liquid of flowing range 2=
|
||||
• Viscosity: How slow players move through it and how slow the liquid spreads=
|
||||
Renewable liquids create new liquid sources at open spaces (image 2). A new liquid source is created when:=
|
||||
• Two renewable liquid blocks of the same type touch each other diagonally=
|
||||
• These blocks are also on the same height=
|
||||
• One of the two “corners” is open space which allows liquids to flow in=
|
||||
When those criteria are met, the open space is filled with a new liquid source of the same type (image 3).=
|
||||
Swimming in a liquid is fairly straightforward: The usual direction keys for basic movement, the jump key for rising and the sneak key for sinking.=
|
||||
The physics for swimming and diving in a liquid are:=
|
||||
• The higher the viscosity, the slower you move=
|
||||
• If you rest, you'll slowly sink=
|
||||
• There is no fall damage for falling into a liquid as such=
|
||||
• If you fall into a liquid, you will be slowed down on impact (but don't stop instantly). Your impact depth is determined by your speed and the liquid viscosity. For a safe high drop into a liquid, make sure there is enough liquid above the ground, otherwise you might hit the ground and take fall damage=
|
||||
Liquids are often not pointable. But some special items are able to point all liquids.=
|
||||
Crafting=
|
||||
Crafting is the task of combining several items to form a new item.=
|
||||
To craft something, you need one or more items, a crafting grid (C) and a crafting recipe. A crafting grid is like a normal inventory which can also be used for crafting. Items need to be put in a certain pattern into the crafting grid. Next to the crafting grid is an output slot (O). Here the result will appear when you placed items correctly. This is just a preview, not the actual item. Crafting grids can come in different sizes which limits the possible recipes you can craft.=
|
||||
To complete the craft, take the result item from the output slot, which will consume items from the crafting grid and creates a new item. It is not possible to place items into the output slot.=
|
||||
A description on how to craft an item is called a “crafting recipe”. You need this knowledge to craft. There are multiple ways to learn crafting recipes. One way is by using a crafting guide, which contains a list of available crafting recipes. Some games provide crafting guides. There are also some mods which you can download online for installing a crafting guide. Another way is by reading the online manual of the game (if one is available).=
|
||||
Crafting recipes consist of at least one input item and exactly one stack of output items. When performing a single craft, it will consume exactly one item from each stack of the crafting grid, unless the crafting recipe defines replacements.=
|
||||
There are multiple types of crafting recipes:=
|
||||
• Shaped (image 2): Items need to be placed in a particular shape=
|
||||
• Shapeless (images 3 and 4): Items need to be placed somewhere in input (both images show the same recipe)=
|
||||
• Cooking: Explained in “Basics > Cooking”=
|
||||
• Repairing (image 5): Place two damaged tools into the crafting grid anywhere to get a tool which is repaired by 5%=
|
||||
In some crafting recipes, some input items do not need to be a concrete item, instead they need to be a member of a group (see “Basics > Groups”). These recipes offer a bit more freedom in the input items. Images 6-8 show the same group-based recipe. Here, 8 items of the “stone” group are required, which is true for all of the shown items.=
|
||||
Rarely, crafting recipes have replacements. This means, whenever you perform a craft, some items in the crafting grid will not be consumed, but instead will be replaced by another item.=
|
||||
Cooking=
|
||||
Cooking (or smelting) is a form of crafting which does not involve a crafting grid. Cooking is done with a special block (like a furnace), an cookable item, a fuel item and time in order to yield a new item.=
|
||||
Each fuel item has a burning time. This is the time a single item of the fuel keeps a furnace burning.=
|
||||
Each cookable item requires time to be cooked. This time is specific to the item type and the item must be “on fire” for the whole cooking time to actually yield the result.=
|
||||
Hotbar=
|
||||
At the bottom of the screen you see some squares. This is called the “hotbar”. The hotbar allows you to quickly access the first items from your player inventory.=
|
||||
You can change the selected item with the mouse wheel or the keyboard.=
|
||||
• Select previous item in hotbar: [Mouse wheel up] or [B]=
|
||||
• Select next item in hotbar: [Mouse wheel down] or [N]=
|
||||
• Select item in hotbar directly: [1]-[9]=
|
||||
The selected item is also your wielded item.=
|
||||
Minimap=
|
||||
If you have a map item in any of your hotbar slots, you can use the minimap.=
|
||||
Press [F9] to make a minimap appear on the top right. The minimap helps you to find your way around the world. Press it again to select different minimap modes and zoom levels. The minimap also shows the positions of other players.=
|
||||
There are 2 minimap modes and 3 zoom levels.=
|
||||
Surface mode (image 1) is a top-down view of the world, roughly resembling the colors of the blocks this world is made of. It only shows the topmost blocks, everything below is hidden, like a satellite photo. Surface mode is useful if you got lost.=
|
||||
Radar mode (image 2) is more complicated. It displays the “denseness” of the area around you and changes with your height. Roughly, the more green an area is, the less “dense” it is. Black areas have many blocks. Use the radar to find caverns, hidden areas, walls and more. The rectangular shapes in image 2 clearly expose the position of a dungeon.=
|
||||
There are also two different rotation modes. In “square mode”, the rotation of the minimap is fixed. If you press [Shift]+[F9] to switch to “circle mode”, the minimap will instead rotate with your looking direction, so “up” is always your looking direction.=
|
||||
In some games, the minimap may be disabled.=
|
||||
• Toggle minimap mode: [F9]=
|
||||
• Toggle minimap rotation mode: [Shift]+[F9]=
|
||||
Inventory=
|
||||
Inventories are used to store item stacks. There are other uses, such as crafting. An inventory consists of a rectangular grid of item slots. Each item slot can either be empty or hold one item stack. Item stacks can be moved freely between most slots.=
|
||||
You have your own inventory which is called your “player inventory”, you can open it with the inventory key (default: [I]). The first inventory slots are also used as slots in your hotbar.=
|
||||
Blocks can also have their own inventory, e.g. chests and furnaces.=
|
||||
Inventory controls:=
|
||||
Taking: You can take items from an occupied slot if the cursor holds nothing.=
|
||||
• Left click: take entire item stack=
|
||||
• Right click: take half from the item stack (rounded up)=
|
||||
• Middle click: take 10 items from the item stack=
|
||||
• Mouse wheel down: take 1 item from the item stack=
|
||||
Putting: You can put items onto a slot if the cursor holds 1 or more items and the slot is either empty or contains an item stack of the same item type.=
|
||||
• Left click: put entire item stack=
|
||||
• Right click: put 1 item of the item stack=
|
||||
• Right click or mouse wheel up: put 1 item of the item stack=
|
||||
• Middle click: put 10 items of the item stack=
|
||||
Exchanging: You can exchange items if the cursor holds 1 or more items and the destination slot is occupied by a different item type.=
|
||||
• Click: exchange item stacks=
|
||||
Throwing away: If you hold an item stack and click with it somewhere outside the menu, the item stack gets thrown away into the environment.=
|
||||
Quick transfer: You can quickly transfer an item stack to/from the player inventory to/from another item's inventory slot like a furnace, chest, or any other item with an inventory slot when that item's inventory is accessed. The target inventory is generally the most relevant inventory in this context.=
|
||||
• Sneak+Left click: Automatically transfer item stack=
|
||||
Online help=
|
||||
You may want to check out these online resources related to MineClone 2.=
|
||||
MineClone 2 download and forum discussion: <https://forum.minetest.net/viewtopic.php?f@=50&t@=16407>=
|
||||
Here you find the most recent version of MineClone 2 and can discuss it.=
|
||||
Bug tracker: <https://github.com/Wuzzy2/MineClone2-Bugs>=
|
||||
Report bugs here.=
|
||||
Minetest links:=
|
||||
You may want to check out these online resources related to Minetest:=
|
||||
Official homepage of Minetest: <https://minetest.net/>=
|
||||
The main place to find the most recent version of Minetest, the engine used by MineClone 2.=
|
||||
The main place to find the most recent version of Minetest.=
|
||||
Community wiki: <https://wiki.minetest.net/>=
|
||||
A community-based documentation website for Minetest. Anyone with an account can edit it! It also features a documentation of Minetest Game.=
|
||||
Minetest forums: <https://forums.minetest.net/>=
|
||||
A web-based discussion platform where you can discuss everything related to Minetest. This is also a place where player-made mods and games are published and discussed. The discussions are mainly in English, but there is also space for discussion in other languages.=
|
||||
Chat: <irc://irc.freenode.net#minetest>=
|
||||
A generic Internet Relay Chat channel for everything related to Minetest where people can meet to discuss in real-time. If you do not understand IRC, see the Community Wiki for help.=
|
||||
Groups=
|
||||
Items, players and objects (animate and inanimate) can be members of any number of groups. Groups serve multiple purposes:=
|
||||
• Crafting recipes: Slots in a crafting recipe may not require a specific item, but instead an item which is a member of a particular group, or multiple groups=
|
||||
• Digging times: Diggable blocks belong to groups which are used to determine digging times. Mining tools are capable of digging blocks belonging to certain groups=
|
||||
• Block behavior: Blocks may show a special behaviour and interact with other blocks when they belong to a particular group=
|
||||
• Damage and armor: Objects and players have armor groups, weapons have damage groups. These groups determine damage. See also: “Basics > Weapons”=
|
||||
• Other uses=
|
||||
In the item help, many important groups are usually mentioned and explained.=
|
||||
Glossary=
|
||||
This is a list of commonly used terms:=
|
||||
Controls:=
|
||||
• Wielding: Holding an item in hand=
|
||||
• Pointing: Looking with the crosshair at something in range=
|
||||
• Dropping: Throwing an item or item stack to the ground=
|
||||
• Punching: Attacking with left-click, is also used on blocks=
|
||||
• Sneaking: Walking slowly while (usually) avoiding to fall over edges=
|
||||
• Climbing: Moving up or down a climbable block=
|
||||
Blocks:=
|
||||
• Block: Cubes that the worlds are made of=
|
||||
• Mining/digging: Using a mining tool to break a block=
|
||||
• Building/placing: Putting a block somewhere=
|
||||
• Drop: Items you get after mining a block=
|
||||
• Using a block: Right-clicking a block to access its special function=
|
||||
Items:=
|
||||
• Item: A single thing that players can possess=
|
||||
• Item stack: A collection of items of the same kind=
|
||||
• Maximum stack size: Maximum amount of items in an item stack=
|
||||
• Slot / inventory slot: Can hold one item stack=
|
||||
• Inventory: Provides several inventory slots for storage=
|
||||
• Player inventory: The main inventory of a player=
|
||||
• Tool: An item which you can use to do special things with when wielding=
|
||||
• Range: How far away things can be to be pointed by an item=
|
||||
• Mining tool: A tool which allows to break blocks=
|
||||
• Craftitem: An item which is (primarily or only) used for crafting=
|
||||
Gameplay:=
|
||||
• “heart”: A single health symbol, indicates 2 HP=
|
||||
• “bubble”: A single breath symbol, indicates 1 BP=
|
||||
• HP: Hit point (equals half 1 “heart”)=
|
||||
• BP: Breath point, indicates breath when diving=
|
||||
• Mob: Computer-controlled enemy=
|
||||
• Crafting: Combining multiple items to create new ones=
|
||||
• Crafting guide: A helper which shows available crafting recipes=
|
||||
• Spawning: Appearing in the world=
|
||||
• Respawning: Appearing again in the world after death=
|
||||
• Group: Puts similar things together, often affects gameplay=
|
||||
• noclip: Allows to fly through walls=
|
||||
Interface=
|
||||
• Hotbar: Inventory slots at the bottom=
|
||||
• Statbar: Indicator made out of half-symbols, used for health and breath=
|
||||
• Minimap: The map or radar at the top right=
|
||||
• Crosshair: Seen in the middle, used to point at things=
|
||||
Online multiplayer:=
|
||||
• PvP: Player vs Player. If active, players can deal damage to each other=
|
||||
• Griefing: Destroying the buildings of other players against their will=
|
||||
• Protection: Mechanism to own areas of the world, which only allows the owners to modify blocks inside=
|
||||
Technical terms:=
|
||||
• Minetest: This game engine=
|
||||
• MineClone 2: What you play right now=
|
||||
• Minetest Game: A game for Minetest by the Minetest developers=
|
||||
• Game: A complete playing experience to be used in Minetest; such as a game or sandbox or similar=
|
||||
• Mod: A single subsystem which adds or modifies functionality; is the basic building block of games and can be used to further enhance or modify them=
|
||||
• Privilege: Allows a player to do something=
|
||||
• Node: Other word for “block”=
|
||||
Settings=
|
||||
There is a large variety of settings to configure Minetest. Pretty much every aspect can be changed that way.=
|
||||
These are a few of the most important gameplay settings:=
|
||||
• Damage enabled (enable_damage): Enables the health and breath attributes for all players. If disabled, players are immortal=
|
||||
• Creative Mode (creative_mode): Enables sandbox-style gameplay focusing on creativity rather than a challenging gameplay. The meaning depends on the game; usual changes are: Reduced dig times, easy access to almost all items, tools never wear off, etc.=
|
||||
• PvP (enable_pvp): Short for “Player vs Player”. If enabled, players can deal damage to each other=
|
||||
For a full list of all available settings, use the “All Settings” dialog in the main menu.=
|
||||
Movement modes=
|
||||
You can enable some special movement modes that change how you move.=
|
||||
Pitch movement mode:=
|
||||
• Description: If this mode is activated, the movement keys will move you relative to your current view pitch (vertical look angle) when you're in a liquid or in fly mode.=
|
||||
• Default key: [L]=
|
||||
• No privilege required=
|
||||
Fast mode:=
|
||||
• Description: Allows you to move much faster. Hold down the the “Use” key [E] to move faster. In the client configuration, you can further customize fast mode.=
|
||||
• Default key: [J]=
|
||||
• Required privilege: fast=
|
||||
Fly mode:=
|
||||
• Description: Gravity doesn't affect you and you can move freely in all directions. Use the jump key to rise and the sneak key to sink.=
|
||||
• Default key: [K]=
|
||||
• Required privilege: fly=
|
||||
Noclip mode:=
|
||||
• Description: Allows you to move through walls. Only works when fly mode is enabled, too.=
|
||||
• Default key: [H]=
|
||||
• Required privilege: noclip=
|
||||
Console=
|
||||
With [F10] you can open and close the console. The main use of the console is to show the chat log and enter chat messages or server commands.=
|
||||
Using the chat or server command key also opens the console, but it is smaller and will be closed after you sent a message.=
|
||||
Use the chat to communicate with other players. This requires you to have the “shout” privilege.=
|
||||
Just type in the message and hit [Enter]. Public chat messages can not begin with “/”.=
|
||||
You can send private messages: Say “/msg <player> <message>” in chat to send “<message>” which can only be seen by <player>.=
|
||||
There are some special controls for the console:=
|
||||
• [F10] Open/close console=
|
||||
• [Enter]: Send message or command=
|
||||
• [Tab]: Try to auto-complete a partially-entered player name=
|
||||
• [Ctrl]+[Left]: Move cursor to the beginning of the previous word=
|
||||
• [Ctrl]+[Right]: Move cursor to the beginning of the next word=
|
||||
• [Ctrl]+[Backspace]: Delete previous word=
|
||||
• [Ctrl]+[Delete]: Delete next word=
|
||||
• [Ctrl]+[U]: Delete all text before the cursor=
|
||||
• [Ctrl]+[K]: Delete all text after the cursor=
|
||||
• [Page up]: Scroll up=
|
||||
• [Page down]: Scroll down=
|
||||
There is also an input history. Minetest saves your previous console inputs which you can quickly access later:=
|
||||
• [Up]: Go to previous entry in history=
|
||||
• [Down]: Go to next entry in history=
|
||||
Server commands=
|
||||
Server commands (also called “chat commands”) are little helpers for advanced users. You don't need to use these commands when playing. But they might come in handy to perform some more technical tasks. Server commands work both in multi-player and single-player mode.=
|
||||
Server commands can be entered by players using the chat to perform a special server action. There are a few commands which can be issued by everyone, but some commands only work if you have certain privileges granted on the server. There is a small set of basic commands which are always available, other commands can be added by mods.=
|
||||
To issue a command, simply type it like a chat message or press Minetest's command key (default: [/]). All commands have to begin with “/”, for example “/mods”. The Minetest command key does the same as the chat key, except that the slash is already entered.=
|
||||
Commands may or may not give a response in the chat log, but errors will generally be shown in the chat. Try it for yourselves: Close this window and type in the “/mods” command. This will give you the list of available mods on this server.=
|
||||
“/help all” is a very important command: You get a list of all available commands on the server, a short explanation and the allowed parameters. This command is also important because the available commands often differ per server.=
|
||||
Commands are followed by zero or more parameters.=
|
||||
In the command reference, you see some placeholders which you need to replace with an actual value. Here's an explanation:=
|
||||
• Text in greater-than and lower-than signs (e.g. “<param>”): Placeholder for a parameter=
|
||||
• Anything in square brackets (e.g. “[text]”) is optional and can be omitted=
|
||||
• Pipe or slash (e.g. “text1 | text2 | text3”): Alternation. One of multiple texts must be used (e.g. “text2”)=
|
||||
• Parenthesis: (e.g. “(word1 word2) | word3”): Groups multiple words together, used for alternations=
|
||||
• Everything else is to be read as literal text=
|
||||
Here are some examples to illustrate the command syntax:=
|
||||
• /mods: No parameters. Just enter “/mods”=
|
||||
• /me <action>: 1 parameter. You have to enter “/me ” followed by any text, e.g. “/me orders pizza”=
|
||||
• /give <name> <ItemString>: Two parameters. Example: “/give Player default:apple”=
|
||||
• /help [all|privs|<cmd>]: Valid inputs are “/help”, “/help all”, “/help privs”, or “/help ” followed by a command name, like “/help time”=
|
||||
• /spawnentity <EntityName> [<X>,<Y>,<Z>]: Valid inputs include “/spawnentity boats:boat” and “/spawnentity boats:boat 0,0,0”=
|
||||
Some final remarks:=
|
||||
• For /give and /giveme, you need an itemstring. This is an internally used unique item identifier which you may find in the item help if you have the “give” or “debug” privilege=
|
||||
• For /spawnentity you need an entity name, which is another identifier=
|
||||
Privileges=
|
||||
Each player has a set of privileges, which differs from server to server. Your privileges determine what you can and can't do. Privileges can be granted and revoked from other players by any player who has the privilege called “privs”.=
|
||||
On a multiplayer server with the default configuration, new players start with the privileges called “interact” and “shout”. The “interact” privilege is required for the most basic gameplay actions such as building, mining, using, etc. The “shout” privilege allows to chat.=
|
||||
There is a small set of core privileges which you'll find on every server, other privileges might be added by mods.=
|
||||
To view your own privileges, issue the server command “/privs”.=
|
||||
Here are a few basic privilege-related commands:=
|
||||
• /privs: Lists your privileges=
|
||||
• /privs <player>: Lists the privileges of <player>=
|
||||
• /help privs: Shows a list and description about all privileges=
|
||||
Players with the “privs” privilege can modify privileges at will:=
|
||||
• /grant <player> <privilege>: Grant <privilege> to <player>=
|
||||
• /revoke <player> <privilege>: Revoke <privilege> from <player>=
|
||||
In single-player mode, you can use “/grantme all” to unlock all abilities.=
|
||||
Light=
|
||||
As the world is entirely block-based, so is the light in the world. Each block has its own brightness. The brightness of a block is expressed in a “light level” which ranges from 0 (total darkness) to 15 (as bright as the sun).=
|
||||
There are two types of light: Sunlight and artificial light.=
|
||||
Artificial light is emitted by luminous blocks. Artificial light has a light level from 1-14.=
|
||||
Sunlight is the brightest light and always goes perfectly straight down from the sky at each time of the day. At night, the sunlight will become moonlight instead, which still provides a small amount of light. The light level of sunlight is 15.=
|
||||
Blocks have 3 levels of transparency:=
|
||||
• Transparent: Sunlight goes through limitless, artificial light goes through with losses=
|
||||
• Semi-transparent: Sunlight and artificial light go through with losses=
|
||||
• Opaque: No light passes through=
|
||||
Artificial light will lose one level of brightness for each transparent or semi-transparent block it passes through, until only darkness remains (image 1).=
|
||||
Sunlight will preserve its brightness as long it only passes fully transparent blocks. When it passes through a semi-transparent block, it turns to artificial light. Image 2 shows the difference.=
|
||||
Note that “transparency” here only means that the block is able to carry brightness from its neighboring blocks. It is possible for a block to be transparent to light but you can't see trough the other side.=
|
||||
Coordinates=
|
||||
The world is a large cube. And because of this, a position in the world can be easily expressed with Cartesian coordinates. That is, for each position in the world, there are 3 values X, Y and Z.=
|
||||
Like this: (5, 45, -12)=
|
||||
This refers to the position where X@=5, Y@=45 and Z@=-12. The 3 letters are called “axes”: Y is for the height. X and Z are for the horizontal position.=
|
||||
The values for X, Y and Z work like this:=
|
||||
• If you go up, Y increases=
|
||||
• If you go down, Y decreases=
|
||||
• If you follow the sun, X increases=
|
||||
• If you go to the reverse direction, X decreases=
|
||||
• Follow the sun, then go right: Z increases=
|
||||
• Follow the sun, then go left: Z decreases=
|
||||
• The side length of a full cube is 1=
|
||||
You can view your current position in the debug screen (open with [F5]).=
|
||||
|
||||
# MCL2 extensions
|
||||
Creative Mode=
|
||||
Enabling Creative Mode in MineClone 2 applies the following changes:=
|
||||
• You keep the things you've placed=
|
||||
• Creative inventory is available to obtain most items easily=
|
||||
• Hand breaks all default blocks instantly=
|
||||
• Greatly increased hand pointing range=
|
||||
• Mined blocks don't drop items=
|
||||
• Items don't get used up=
|
||||
• Tools don't wear off=
|
||||
• You can eat food whenever you want=
|
||||
• You can always use the minimap (including radar mode)=
|
||||
Damage is not affected by Creative Mode, it needs to be disabled separately.=
|
||||
Mobs=
|
||||
Mobs are the living beings in the world. This includes animals and monsters.=
|
||||
Mobs appear randomly throughout the world. This is called “spawning”. Each mob kind appears on particular block types at a given light level. The height also plays a role. Peaceful mobs tend to spawn at daylight while hostile ones prefer darkness. Most mobs can spawn on any solid block but some mobs only spawn on particular blocks (like grass blocks).=
|
||||
Like players, mobs have hit points and sometimes armor points, too (which means you need better weapons to deal any damage at all). Also like players, hostile mobs can attack directly or at a distance. Mobs may drop random items after they die.=
|
||||
Most animals roam the world aimlessly while most hostile mobs hunt players. Animals can be fed, tamed and bred.=
|
||||
Animals=
|
||||
Animals are peaceful beings which roam the world aimlessly. You can feed, tame and breed them.=
|
||||
Feeding:=
|
||||
Each animal has its own taste for food and doesn't just accept any food. To feed, hold an item in your hand and rightclick the animal.=
|
||||
Animals are attraced to the food they like and follow you as long you hold the food item in hand.=
|
||||
Feeding an animal has three uses: Taming, healing and breeding.=
|
||||
Feeding heals animals instantly, depending on the quality of the food item.=
|
||||
Taming:=
|
||||
A few animals can be tamed. You can generally do more things with tamed animals and use other items on them. For example, tame horses can be saddled and tame wolves fight on your side.=
|
||||
Breeding:=
|
||||
When you have fed an animal up to its maximum health, then feed it again, you will activate “Love Mode” and many hearts appear around the animal.=
|
||||
Two animals of the same species will start to breed if they are in Love Mode and close to each other. Soon a baby animal will pop up.=
|
||||
Baby animals:=
|
||||
Baby animals are just like their adult couterparts, but they can't be tamed or bred and don't drop anything when they die. They grow to adults after a short time. When fed, they grow to adults faster.=
|
||||
Hunger=
|
||||
Hunger affects your health and your ability to sprint. Hunger is not in effect when damage is disabled.=
|
||||
Core hunger rules:=
|
||||
• You start with 20/20 hunger points (more points @= less hungry)=
|
||||
• Actions like combat, jumping, sprinting, etc. decrease hunger points=
|
||||
• Food restores hunger points=
|
||||
• If your hunger bar decreases, you're hungry=
|
||||
• At 18-20 hunger points, you regenerate 1 HP every 4 seconds=
|
||||
• At 6 hunger points or less, you can't sprint=
|
||||
• At 0 hunger points, you lose 1 HP every 4 seconds (down to 1 HP)=
|
||||
• Poisonous food decreases your health=
|
||||
Details:=
|
||||
You have 0-20 hunger points, indicated by 20 drumstick half-icons above the hotbar. You also have an invisible attribute: Saturation.=
|
||||
Hunger points reflect how full you are while saturation points reflect how long it takes until you're hungry again.=
|
||||
Each food item increases both your hunger level as well your saturation.=
|
||||
Food with a high saturation boost has the advantage that it will take longer until you get hungry again.=
|
||||
A few food items might induce food poisoning by chance. When you're poisoned, the health and hunger symbols turn sickly green. Food poisoning drains your health by 1 HP per second, down to 1 HP. Food poisoning also drains your saturation. Food poisoning goes away after a while or when you drink milk.=
|
||||
You start with 5 saturation points. The maximum saturation is equal to your current hunger level. So with 20 hunger points your maximum saturation is 20. What this means is that food items which restore many saturation points are more effective the more hunger points you have. This is because at low hunger levels, a lot of the saturation boost will be lost due to the low saturation cap.=
|
||||
If your saturation reaches 0, you're hungry and start to lose hunger points. Whenever you see the hunger bar decrease, it is a good time to eat.=
|
||||
Saturation decreases by doing things which exhaust you (highest exhaustion first):=
|
||||
• Regenerating 1 HP=
|
||||
• Suffering food poisoning=
|
||||
• Sprint-jumping=
|
||||
• Sprinting=
|
||||
• Attacking=
|
||||
• Taking damage=
|
||||
• Swimming=
|
||||
• Jumping=
|
||||
• Mining a block=
|
||||
Other actions, like walking, do not exaust you.=
|
||||
If you have a map item in any of your hotbar slots, you can use the minimap.=
|
|
@ -305,7 +305,7 @@ function awards.unlock(name, award)
|
|||
local one = player:hud_add({
|
||||
hud_elem_type = "image",
|
||||
name = "award_bg",
|
||||
scale = {x = 1, y = 1},
|
||||
scale = {x = 1.25, y = 1},
|
||||
text = background,
|
||||
position = {x = 0.5, y = 0},
|
||||
offset = {x = 0, y = 138},
|
||||
|
@ -329,7 +329,7 @@ function awards.unlock(name, award)
|
|||
scale = {x = 100, y = 20},
|
||||
text = hud_announce,
|
||||
position = {x = 0.5, y = 0},
|
||||
offset = {x = 0, y = 40},
|
||||
offset = {x = 30, y = 40},
|
||||
alignment = {x = 0, y = -1},
|
||||
z_index = 102,
|
||||
})
|
||||
|
@ -340,7 +340,7 @@ function awards.unlock(name, award)
|
|||
scale = {x = 100, y = 20},
|
||||
text = title,
|
||||
position = {x = 0.5, y = 0},
|
||||
offset = {x = 30, y = 100},
|
||||
offset = {x = 35, y = 100},
|
||||
alignment = {x = 0, y = -1},
|
||||
z_index = 102,
|
||||
})
|
||||
|
@ -355,7 +355,7 @@ function awards.unlock(name, award)
|
|||
number = 2,
|
||||
text = icon,
|
||||
position = {x = 0.5, y = 0},
|
||||
offset = {x = -110, y = 62},
|
||||
offset = {x = -138, y = 62},
|
||||
alignment = {x = 0, y = 0},
|
||||
direction = 0,
|
||||
z_index = 102,
|
||||
|
|
|
@ -337,7 +337,7 @@ awards.register_achievement("mcl:fishyBusiness", {
|
|||
|
||||
-- Triggered in mcl_compass
|
||||
awards.register_achievement("mcl:countryLode", {
|
||||
title = S("Country Lode,\nTake Me Home"),
|
||||
title = S("Country Lode, Take Me Home"),
|
||||
description = S("Use a compass on a Lodestone."),
|
||||
icon = "lodestone_side4.png",
|
||||
type = "Advancement",
|
||||
|
|
|
@ -67,7 +67,7 @@ Withering Heights=Les Witherables
|
|||
Summon the wither from the dead.=Invoquez le Wither d'entre les morts.
|
||||
Fishy Business=Merci pour le poisson
|
||||
Catch a fish.@nHint: Catch a fish, salmon, clownfish, or pufferfish.=Attrapez un poisson. \nAstuce : attrapez un poisson, saumon, poisson-clown, ou poisson-globe.
|
||||
Country Lode,@nTake Me Home=Petit Poucet
|
||||
Country Lode, Take Me Home=Petit Poucet
|
||||
Use a compass on a Lodestone.=utiliser une boussole sur une magnétite.
|
||||
Serious Dedication=Sérieux dévouement
|
||||
Use a Netherite Ingot to upgrade a hoe, and then completely reevaluate your life choices.=Utilisez un lingot de netherite pour améliorez une houe, puis réévaluez complètement vos choix de vie.
|
||||
|
|
|
@ -69,7 +69,7 @@ The Cutest Predator=いちばんカワイイ捕食者
|
|||
Catch an Axolotl with a bucket!=バケツでウーパールーパーを捕まえよう!
|
||||
Fishy Business=フィッシー・ビジネス
|
||||
Catch a fish.@nHint: Catch a fish, salmon, clownfish, or pufferfish.=魚を獲ろう。@nヒント:タラ、サケ、クマノミ、フグ等を釣ります。
|
||||
Country Lode,@nTake Me Home=この道ずっとゆけば@n鉱脈につづいてる
|
||||
Country Lode, Take Me Home=この道ずっとゆけば 鉱脈につづいてる
|
||||
Use a compass on a Lodestone.=ロードストーンにコンパスを使おう。
|
||||
Serious Dedication=真摯な取り組み
|
||||
Use a Netherite Ingot to upgrade a hoe, and then completely reevaluate your life choices.=ネザライトインゴットでクワをアップグレードしたら、人生設計の完全な見直しを図ろう。
|
||||
|
|
|
@ -69,7 +69,7 @@ The Cutest Predator=
|
|||
Catch an Axolotl with a bucket!
|
||||
Fishy Business=
|
||||
Catch a fish.@nHint: Catch a fish, salmon, clownfish, or pufferfish.=
|
||||
Country Lode,@nTake Me Home=
|
||||
Country Lode, Take Me Home=
|
||||
Use a compass on a Lodestone.=
|
||||
Serious Dedication=
|
||||
Use a Netherite Ingot to upgrade a hoe, and then completely reevaluate your life choices.=
|
||||
|
|
|
@ -149,6 +149,11 @@ mcl_death_messages = {
|
|||
plain = "@1 went off with a bang",
|
||||
item = "@1 went off with a bang due to a firework fired from @3 by @2", -- order is intentional
|
||||
},
|
||||
sweet_berry = {
|
||||
_translator = S,
|
||||
plain = "@1 died a sweet death",
|
||||
assist = "@1 was poked to death by a sweet berry bush whilst trying to escape @2",
|
||||
},
|
||||
-- Missing snowballs: The Minecraft wiki mentions them but the MC source code does not.
|
||||
},
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# textdomain: mcl_amethyst
|
||||
Amethyst Cluster=Ametystklynge
|
||||
Amethyst Cluster is the final growth of amethyst bud.=En ameystklynge er den sidste udvikling af en ametystspire.
|
||||
Amethyst Shard=Ametystskår
|
||||
An amethyst shard is a crystalline mineral.=Et ametystskår er et krystallisk mineral.
|
||||
Block of Amethyst=Blok af ametyst
|
||||
Budding Amethyst=Spirende ametyst
|
||||
Calcite=Calcedon
|
||||
Calcite can be found as part of amethyst geodes.=Calcedon kan findes som en del af krystalhuler med ametyst.
|
||||
Large Amethyst Bud=Stor ametystknop
|
||||
Large Amethyst Bud is the third growth of amethyst bud.=En stor ametystknop er den trejde udvikling af en ametystspire.
|
||||
Medium Amethyst Bud=Mellem ametystknop
|
||||
Medium Amethyst Bud is the second growth of amethyst bud.=En mellem ametystknop er den anden udvikling af en ametystspire.
|
||||
Small Amethyst Bud=Lille ametystknop
|
||||
Small Amethyst Bud is the first growth of amethyst bud.=En lille ametystknop er den første udvikling af en ametystspire.
|
||||
The Block of Amethyst is a decoration block crafted from amethyst shards.=En blok af ametyst er en udsmykningsblok som kan laves ametystskår.
|
||||
The Budding Amethyst can grow amethyst=Den spirende ametyst kan gro ametyst
|
||||
Tinted Glass=Farvet glas
|
||||
Tinted Glass is a type of glass which blocks lights while it is visually transparent.=Farvet glas er en glastype som er gennemsigtig, men lukker lys ude.
|
|
@ -0,0 +1,16 @@
|
|||
# textdomain: mcl_anvils
|
||||
Set Name=Navngiv
|
||||
Repair and Name=Reparér og navngiv
|
||||
Inventory=Oppakning
|
||||
Anvil=Ambolt
|
||||
The anvil allows you to repair tools and armor, and to give names to items. It has a limited durability, however. Don't let it fall on your head, it could be quite painful!=Ambolten gør dig i stand til at reparere værktøj og rustninger, og til at navngive genstande. Den har dog begrænset holdbarhed. Lad den ikke falde ned i hovedet på dig, det kunne gøre meget ondt!
|
||||
To use an anvil, rightclick it. An anvil has 2 input slots (on the left) and one output slot.=For at bruge ambolten skal du højre-klikke på den. En ambolt har to indgangspladser (til venstre), og én udgangsplads.
|
||||
To rename items, put an item stack in one of the item slots while keeping the other input slot empty. Type in a name, hit enter or “Set Name”, then take the renamed item from the output slot.=For at omdøbe en genstande skal du putte dem i den ene indgangsplads og lade den anden indgangsplads være tom. Skriv et navn, tryk på enter eller "Giv navn", og tag så den omdøbte genstand fra udgangspladsen.
|
||||
There are two possibilities to repair tools (and armor):=Der er to muligheder for at reparere værktøj (og rustninger)
|
||||
• Tool + Tool: Place two tools of the same type in the input slots. The “health” of the repaired tool is the sum of the “health” of both input tools, plus a 12% bonus.=• Værktøj + Værktøj: Placér to stykker værktøj af samme type i indgangspladserne. Holbarheden af det reparerede stykke værktøj er summen af holdbarheden på begge stykker værktøj plus 12% bonus.
|
||||
• Tool + Material: Some tools can also be repaired by combining them with an item that it's made of. For example, iron pickaxes can be repaired with iron ingots. This repairs the tool by 25%.=• Værktøj + Materiale: Noget værktøj kan også repareres ved at kombinere dem med en genstand de er lavet af. For eksempel kan en jernhakke repareres med jernbarre. Dette reparerer værktøjet med 25%.
|
||||
Armor counts as a tool. It is possible to repair and rename a tool in a single step.=Rustninger tæller som værktøj. Det er muligt at reparere og omdøbe værktøj i ét enkelt trin.
|
||||
The anvil has limited durability and 3 damage levels: undamaged, slightly damaged and very damaged. Each time you repair or rename something, there is a 12% chance the anvil gets damaged. Anvils also have a chance of being damaged when they fall by more than 1 block. If a very damaged anvil is damaged again, it is destroyed.=Ambolten har en begrænset holdbarhed og 3 skadeniveauer: Ubeskadiget, let beskadiget og meget beskadiget. Hver gang du reparerer eller omdøber noget er der en 12% chance for, at ambolten bliver beskadiget. Ambolte har også en risiko for at blive beskadiget når de falder mere end én blok ned. Hvis en beskadiget ambolt beskadiges igen bliver den ødelagt.
|
||||
Slightly Damaged Anvil=Let beskadiget ambolt
|
||||
Very Damaged Anvil=Meget beskadiget ambolt
|
||||
Repair and rename items=Reparér og omdøb genstande
|
|
@ -0,0 +1,48 @@
|
|||
# textdomain: mcl_armor
|
||||
This is a piece of equippable armor which reduces the amount of damage you receive.=Dette er et stykke rustning du kan tage på for at reducere den mængde du tager.
|
||||
To equip it, put it on the corresponding armor slot in your inventory menu.=For at tage den på, skal du putte den i den tilsvarende rustningsplads i din oppakningsmenu.
|
||||
Leather Cap=Læderhat
|
||||
Iron Helmet=Jernhjelm
|
||||
Golden Helmet=Guldhjelm
|
||||
Diamond Helmet=Diamanthjelm
|
||||
Chain Helmet=Brynjehjelm
|
||||
Netherite Helmet=Netherritehjelm
|
||||
Leather Tunic=Lædertunika
|
||||
Iron Chestplate=Jernbrystplade
|
||||
Golden Chestplate=Guldbrystplade
|
||||
Diamond Chestplate=Diamantbrystplade
|
||||
Chain Chestplate=Brynjeskjorte
|
||||
Netherite Chestplate=Netheritebrystplade
|
||||
Leather Pants=Læderbukser
|
||||
Iron Leggings=Jernbenplader
|
||||
Golden Leggings=Guldbenplader
|
||||
Diamond Leggings=Diamantbenplader
|
||||
Chain Leggings=Brynjebukser
|
||||
Netherite Leggings=Netheritebenplader
|
||||
Leather Boots=Læderstøvler
|
||||
Iron Boots=Jernstøvler
|
||||
Golden Boots=Guldstøvler
|
||||
Diamond Boots=Diamantstøvler
|
||||
Chain Boots=Brynjestøvler
|
||||
Netherite Boots=Netheritestøvler
|
||||
Elytra=Elytra
|
||||
|
||||
#Translations of enchantements
|
||||
Increases underwater mining speed.=Øger udvindingshastigheden under vand.
|
||||
Blast Protection=Eksplosionsbeskyttelse
|
||||
Reduces explosion damage and knockback.=Reducerer eksplosionsskade og -tilbageslag.
|
||||
Curse of Binding=Bindende forbandelse.
|
||||
Item cannot be removed from armor slots except due to death, breaking or in Creative Mode.=Objektet kan ikke fjernes fra rustninspladser undtagen ved død, hvis den går i stykker ikke i kreativ tilstand.
|
||||
Feather Falling=Fjerfald
|
||||
Reduces fall damage.=Reduerer faldskade.
|
||||
Fire Protection=Ildbeskyttelse
|
||||
Reduces fire damage.=Reducerer ildskade.
|
||||
Shooting consumes no regular arrows.=Det bruger ingen normale pile at skyde.
|
||||
Shoot 3 arrows at the cost of one.=Skyd 3 pile for én pils pris.
|
||||
Projectile Protection=Projektilbeskyttelse
|
||||
Reduces projectile damage.=Reducerer projektilskade
|
||||
Protection=Beskyttelse
|
||||
Reduces most types of damage by 4% for each level.=Reducerer det fleste skadestyper med 4% for hvert level.
|
||||
Thorns=Torne
|
||||
Reflects some of the damage taken when hit, at the cost of reducing durability with each proc.=Reflekterer skade ved træfning, men koster holdbarhed ved hver brug.
|
||||
Aqua Affinity=Vandaffinitet
|
|
@ -0,0 +1,5 @@
|
|||
# textdomain: mcl_armor_stand
|
||||
Armor Stand=Rustningsstativ
|
||||
An armor stand is a decorative object which can display different pieces of armor. Anything which players can wear as armor can also be put on an armor stand.=Et rustningsstativ er en udsmykningsgenstand som kan fremvise forskellige rustninger. Alt hvad spillere kan bære som rusning kan sættes på rustningsstativet.
|
||||
Just place an armor item on the armor stand. To take the top piece of armor from the armor stand, select your hand and use the place key on the armor stand.=Placér blot et rustningsstykke på rustningsstativet. For at take den øverste rustningsstykke skal du vælge din hånd og bruge placér knappen på rustningsstativet.
|
||||
Displays pieces of armor=Fremviser rustningsstykker.
|
|
@ -0,0 +1,36 @@
|
|||
# textdomain: mcl_bamboo
|
||||
|
||||
|
||||
### init.lua ###
|
||||
|
||||
A bamboo button is a redstone component made out of stone which can be pushed to provide redstone power. When pushed, it powers adjacent redstone components for 1 second.=En bambusknap er en rødstenskomponent lavet af sten som giver rødstensenergi når den aktiveres. Når den aktiveres forsyner den tilstøende rødstenskomponenter i 1 sekund.
|
||||
|
||||
A wooden pressure plate is a redstone component which supplies its surrounding blocks with redstone power while any movable object (including dropped items, players and mobs) rests on top of it.=En trætrykplade er en rødstenskomponent som forsyner omkringliggende blokke med rødstensenergi når et bevægeligt objekt (inklusiv tabte genstande, spillere og monstre) er ovenpå den.
|
||||
|
||||
Bamboo=Bambus
|
||||
Bamboo Button=Bambusknap
|
||||
Bamboo Door.=Bambusdør
|
||||
Bamboo Fence=Bambushegn
|
||||
Bamboo Fence Gate=Bambushegnslåge
|
||||
Bamboo Plank=Bambusplanke
|
||||
Bamboo Plank Slab=Bambusplankeplade
|
||||
Bamboo Plank Stair=Bambusplanketrappe
|
||||
Bamboo Pressure Plate=Bambustrykplade
|
||||
Bamboo Sign=Bambusskilt
|
||||
Bamboo Slab=Bambusplade
|
||||
Bamboo Stair=Bambustrappe
|
||||
Bamboo Trapdoor.=Bambusfaldlem
|
||||
Double Bamboo Plank Slab=Dobbelbambusplanke
|
||||
Double Bamboo Slab=Dobbelbambusplade
|
||||
Double Stripped Bamboo Slab=Afbarket dobbelbambus
|
||||
Nether Brick Fence=Netherstenshegn
|
||||
Scaffolding=Stillads
|
||||
Scaffolding (horizontal)=Stillads (horisontal)
|
||||
Scaffolding block used to climb up or out across areas.=Stilladsblok som bruges til at kravle op ad eller på tværs af områder
|
||||
Stripped Bamboo Slab=Afbarket bambusplade
|
||||
Stripped Bamboo Stair=Afbarket bambustrappe
|
||||
|
||||
To open or close the trapdoor, rightclick it or send a redstone signal to it.=Højre-klik eller send rødstensenergi til en faldlem for at åbne eller lukke den,
|
||||
|
||||
Wooden trapdoors are horizontal barriers which can be opened and closed by hand or a redstone signal. They occupy the upper or lower part of a block, depending on how they have been placed. When open, they can be climbed like a ladder.=Træfaldlemme er horisontale barrierer som kan åbnes og lukkes med håndkraft eller med rødstensenergi. De kan udgøre den øverste eller den nederste del af en blok afhængigt af hvordan de placeres. Når de er åbne, kan man bruge dem ligesom en stige.
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
# textdomain: mcl_banners
|
||||
White Banner=Hvidt vanner
|
||||
White=Hvid
|
||||
Grey Banner=Gråt banner
|
||||
Grey=Grå
|
||||
Light Grey Banner=Lysegråt banner
|
||||
Light Grey=Lysegrå
|
||||
Black Banner=Sort banner
|
||||
Black=Sort
|
||||
Red Banner=Rødt banner
|
||||
Red=Rød
|
||||
Yellow Banner=Gult banner
|
||||
Yellow=Gul
|
||||
Green Banner=Grønt banner
|
||||
Green=Grøn
|
||||
Cyan Banner=Cyanblåt banner
|
||||
Cyan=Cyanblå
|
||||
Blue Banner=Blåt banner
|
||||
Blue=Blå
|
||||
Magenta Banner=Magenta banner
|
||||
Magenta=Magenta
|
||||
Orange Banner=Orange banner
|
||||
Orange=Orange
|
||||
Purple Banner=Lilla banner
|
||||
Violet=Lilla
|
||||
Brown Banner=Brunt banner
|
||||
Brown=Brund
|
||||
Pink Banner=Lyserødt banner
|
||||
Pink=Lyserøde
|
||||
Lime Banner=Limegrønt banner
|
||||
Lime=Limegrøn
|
||||
Light Blue Banner=Lyseblåt banner
|
||||
Light Blue=Lyseblå
|
||||
Banners are tall colorful decorative blocks. They can be placed on the floor and at walls. Banners can be emblazoned with a variety of patterns using a lot of dye in crafting.=Bannere er høje, farverige udsmykningsblokke. De kan placeres på gulve og vægge. Bannere kan præges med et væld af mønste ved at bruge meget farvestof ved produktion.
|
||||
Use crafting to draw a pattern on top of the banner. Emblazoned banners can be emblazoned again to combine various patterns. You can draw up to 12 layers on a banner that way. If the banner includes a gradient, only 3 layers are possible.=Brug håndværk til at tegne et mønster på banneret. Prægede bannere kan præges igen for at skabe forskellige mønstre. Du kan lave op til 12 lag ovenpå hinanden. Hvis banneret har en gradient, kan du kun lave 3 lag.
|
||||
You can copy the pattern of a banner by placing two banners of the same color in the crafting grid—one needs to be emblazoned, the other one must be clean. Finally, you can use a banner on a cauldron with water to wash off its top-most layer.=Du kan kopiere menteret på et banner ved at placere to bannere i den samme farve i håndværksgitteret. Det ene skal være præget, det andet rent. Du kan også bruge et banner på en keddel med vand for at vaske det øverste lag af.
|
||||
@1 Bordure=@1 kantbånd
|
||||
@1 Bricks=@1 mursten
|
||||
@1 Roundel=@1 rundstok
|
||||
@1 Creeper Charge=@1 creeper
|
||||
@1 Saltire=@1 saltire
|
||||
@1 Bordure Indented=@1 kantbånd med savtakker
|
||||
@1 Per Bend Inverted=@1 nederste venstre diagnoal halvfarvning
|
||||
@1 Per Bend Sinister Inverted=@1 nederste højre diagonal halvfarvning
|
||||
@1 Per Bend=@1 øverste højre diagonal halvfarvning
|
||||
@1 Per Bend Sinister=@1 øverste venstre diagonal halvfarvning
|
||||
@1 Flower Charge=@1 blomst
|
||||
@1 Gradient=@1 gradvist oppefra
|
||||
@1 Base Gradient=@1 gradvist nedefra
|
||||
@1 Per Fess Inverted=@1 nederste halvdel
|
||||
@1 Per Fess=@1 øverste halvdel
|
||||
@1 Per Pale=@1 venstre halvdel
|
||||
@1 Per Pale Inverted=@1 højre halvdel
|
||||
@1 Thing Charge=Mojang
|
||||
@1 Lozenge=Rhombe
|
||||
@1 Skull Charge=@1 dødningehovde
|
||||
@1 Paly=@1 lodrette striber
|
||||
@1 Base Dexter Canton=@1 nederste højre hjørne
|
||||
@1 Base Sinister Canton=@1 nederste venstre hjørne
|
||||
@1 Chief Dexter Canton=@1 øverste højre hjørne
|
||||
@1 Chief Sinister Canton=@1 øverste venstre hjørne
|
||||
@1 Cross=@1 kryds
|
||||
@1 Base=@1 bundstribe
|
||||
@1 Pale=@1 lodret centerstribe
|
||||
@1 Bend Sinister=@1 diagonal stribe fra nederste venstre hjørne
|
||||
@1 Bend=@1 diagonal stribe fra nederste højre hjørne
|
||||
@1 Pale Dexter=@1 venstrestribe
|
||||
@1 Fess=@1 vandret midterstribe
|
||||
@1 Pale Sinister=@1 højrestribe
|
||||
@1 Chief=@1 topstribe
|
||||
@1 Chevron=@1 bundtrekant
|
||||
@1 Chevron Inverted=@1 toptrekant
|
||||
@1 Base Indented=@1 savtakker i bunden
|
||||
@1 Chief Indented=@1 savtakker i toppen
|
||||
And one additional layer=Og ét yderligere lag
|
||||
And @1 additional layers=Og @1 yderligere lag
|
||||
Paintable decoration=Udsmykning som kan males
|
|
@ -0,0 +1,5 @@
|
|||
# textdomain: mcl_barrels
|
||||
Barrel=Tønde
|
||||
Barrels are containers which provide 27 inventory slots.=Tønder er beholdere som kan give 27 oppakningspladser.
|
||||
To access its inventory, rightclick it. When broken, the items will drop out.=For at tilgå dens indhold kan du højre-klikke. Når den ødelægges falder genstandene ud.
|
||||
27 inventory slots=27 indholdsspladser.
|
|
@ -0,0 +1,6 @@
|
|||
# textdomain: mcl_beacons
|
||||
Beacon=Magisk fyrtårn
|
||||
Beacon:=Magisk fyrtårn:
|
||||
Primary Power:=Primær kraft:
|
||||
Inventory:=Indhold:
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
# textdomain: mcl_beds
|
||||
Beds allow you to sleep at night and make the time pass faster.=Senge giver dig mulighed for at sove om natten, og få tiden til at gå hurtigere.
|
||||
To use a bed, stand close to it and right-click the bed to sleep in it. Sleeping only works when the sun sets, at night or during a thunderstorm. The bed must also be clear of any danger.=For at lægge dig til at sove i en seng skal du stå tæt på den og højre-klikke. Man kan kun sove når solen går ned, om natten eller i tordenvejr.
|
||||
You have heard of other worlds in which a bed would set the start point for your next life. But this world is not one of them.=Du har hørt om andre verdener hvor en seng var udgangspunktet for dit næste liv, men denne verden er ikke en af dem.
|
||||
By using a bed, you set the starting point for your next life. If you die, you will start your next life at this bed, unless it is obstructed or destroyed.=Ved at bruge en sætter du udgangspunktet for dit næste liv. Hvis du dør, vil dit næste liv starte i denne seng, medmindre sengen bliver blokeret eller ødelagt.
|
||||
In this world, going to bed won't skip the night, but it will skip thunderstorms.=I denne verden, springer det ikke natten over at sove, men det springer tordenvejr over.
|
||||
Sleeping allows you to skip the night. The night is skipped when all players in this world went to sleep. The night is skipped after sleeping for a few seconds. Thunderstorms can be skipped in the same manner.=Du kan springe natten over ved at sove. Natten bliver sprunget over hvis alle spillere i verdenen sover. Natten bliver sprunget over efter at have sovet i nogle få sekunder. Tordenvejr kan springes over på samme måde.
|
||||
Bed=Seng
|
||||
Red Bed=Rød seng
|
||||
Blue Bed=Blå seng
|
||||
Cyan Bed=Cyanblå seng
|
||||
Grey Bed=Grå seng
|
||||
Light Grey Bed=Lysegrå seng
|
||||
Black Bed=Sort senge
|
||||
Yellow Bed=Gul senge
|
||||
Green Bed=Grøn seng
|
||||
Magenta Bed=Magenta seng
|
||||
Orange Bed=Orange seng
|
||||
Purple Bed=Lilla seng
|
||||
Brown Bed=Brun seng
|
||||
Pink Bed=Lyserød seng
|
||||
Lime Bed=Limegrøn seng
|
||||
Light Blue Bed=Lyseblå seng
|
||||
White Bed=Hvid seng
|
||||
You can't sleep, the bed's too far away!=Du kan ikke gå i seng, sengen er for langt væk!
|
||||
This bed is already occupied!=Denne seng er optaget!
|
||||
You have to stop moving before going to bed!=Du skal stå stille før du kan gå i seng.
|
||||
You can't sleep now, monsters are nearby!=Du kan ikke lægge dig til at sove nu, der er monstre tæt på!
|
||||
You can't sleep, the bed is obstructed!=Du kan ikke gå i seng, denne seng er blokeret!
|
||||
It's too dangerous to sleep here!=Det er for farligt at sove her!
|
||||
New respawn position set! But you can only sleep at night or during a thunderstorm.=Nyt genopståelsespunt sat! Men du kan kun sover om natten eller under et tordenvejr.
|
||||
You can only sleep at night or during a thunderstorm.=Du kan kun sover om natten eller under et tordenvejr.
|
||||
New respawn position set!=Nyt genopståelsespunkt sat!
|
||||
Leave bed=Forlad seng
|
||||
Abort sleep=Afbryd søvn
|
||||
Players in bed: @1/@2=@1 af @2 spillere er gået i seng.
|
||||
Note: Night skip is disabled.=Bemærk: Det er slået fra at springe natten over.
|
||||
You're sleeping.=Du sover.
|
||||
You will fall asleep when all players are in bed.=Du falder i søvn når alle andre spillere er gået i seng.
|
||||
You will fall asleep when @1% of all players are in bed.=Du falder i søvn når @1% af alle spillere er gået i seng.
|
||||
You're in bed.=Du er gået i seng.
|
||||
Allows you to sleep=Gør dig i stand til at sove.
|
||||
Respawn Anchor=Genopståelsesanker
|
|
@ -0,0 +1,4 @@
|
|||
Beehive=Bistade
|
||||
Artificial bee nest.=Kunstigt bibo.
|
||||
Bee Nest=Bibo
|
||||
A naturally generating block that houses bees and a tasty treat...if you can get it.=En naturligt genereret blok som indeholde bier og velsmagende godter... hvis du kan få fat i dem.
|
|
@ -0,0 +1,2 @@
|
|||
# textdomain: mcl_bells
|
||||
Bell=Klokke
|
|
@ -0,0 +1,28 @@
|
|||
# textdomain: mcl_blackstone
|
||||
Blackstone=Sortsten
|
||||
Polished Blackstone=Poleret sortsten
|
||||
Chiseled Polished Blackstone=Majslet poleret sortsten
|
||||
Polished Blackstone Bricks=Poleret sortsten-mursten
|
||||
Basalt=Basalt
|
||||
Polished Basalt=Poleret basalt
|
||||
Blackstone Slab=Sortstensflise
|
||||
Polished Blackstone Slab=Poleret sortstensflise
|
||||
Chiseled Polished Blackstone Slab=Majslet poleret sortstensflise
|
||||
Polished Blackstone Brick Slab=Poleret sortstens-murstensflise
|
||||
Blackstone Stair=Sortstenstrappe
|
||||
Polished Blackstone Stair=Poleret sortstenstrappe
|
||||
Chiseled Polished Blackstone Stair=Majslet poleret sortstenstrappe
|
||||
Polished Blackstone Brick Stair=Poleret sortstens-murstenstrappe
|
||||
Quartz Bricks=Qvarts-mursten
|
||||
Soul Torch=Sjæleildsfakkel
|
||||
Soul Lantern=Sjældeildslaterne
|
||||
Soul Soil=Sjælejord
|
||||
Eternal Soul Fire=Evig sjæleild
|
||||
Gilded Blackstone=Forgyldt sortsten
|
||||
Nether Gold Ore=Nether guldmalm
|
||||
Smooth Basalt=Glat basalt
|
||||
Blackstone Wall=Sorstensmur
|
||||
Double Blackstone Slab=Dobbelt sortstensflise
|
||||
Polished Double Blackstone Slab=Poleret dobbelt sortstensflise
|
||||
Double Chiseled Polished Blackstone Slab=Dobbelt majslet poleret sortstensflise
|
||||
Double Polished Blackstone Brick Slab=Dobbelt poleret sortstens-murstensflise
|
|
@ -0,0 +1,8 @@
|
|||
# textdomain: mcl_blast_furnace
|
||||
Inventory=Indhold
|
||||
Blast Furnace=Højovn
|
||||
Smelts ores faster than furnace=Smelter malm hurtere end en normal ovn.
|
||||
Use the recipe book to see what you can smelt, what you can use as fuel and how long it will burn.=Brug opskriftsbogen for at se hvad du kan smelte, hvad du kan bruge som brændsel og hvor længe det brænder.
|
||||
Use the furnace to open the furnace menu.\nPlace a furnace fuel in the lower slot and the source material in the upper slot.\nThe furnace will slowly use its fuel to smelt the item.\nThe result will be placed into the output slot at the right side.=Brug ovnen for at åbne ovnmenuen. \nPut ovnbrændsel i den nederste plads og det som skal smeltes i den øverste plads.\nOvnen vil langsom bruge dens brændsel til at smelte genstanden.\nResultatet vil blive puttet i pladsen på højre side.
|
||||
Blast Furnaces smelt several items, mainly ores and armor, using a furnace fuel, into something else.=Højovne kan, ved brug af brændsel, smelte flere genstande, hovedsageligt malm og rustning, og lave dem til noget andet.
|
||||
Active Blast Furnace=Aktiv højovn
|
|
@ -0,0 +1,28 @@
|
|||
# textdomain: mcl_books
|
||||
Book=Bog
|
||||
Books are used to make bookshelves and book and quills.=Bøger bruges til at lave bogreoler og bog og fjerpen
|
||||
“@1”="@1"
|
||||
Copy of “@1”=Kopi af "@1"
|
||||
Copy of Copy of “@1”=Kopi af kopi af "@1"
|
||||
Tattered Book=Flosset bog
|
||||
by @1=af @1
|
||||
# as in “to sign a book”
|
||||
Sign=Underskriv
|
||||
Done=Færdig
|
||||
This item can be used to write down some notes.=Denne genstand kan bruges til at skrive notater.
|
||||
Hold it in the hand, then rightclick to read the current notes and edit then. You can edit the text as often as you like. You can also sign the book which turns it into a written book which you can stack, but it can't be edited anymore.=Hold den i hånden, højre-klik så for at læse og redigere aktuelle notater. Du kan redigere teksten så ofte du har lyst. Du kan også signere bogen hvilken gør den til en skrevet bog som du kan gemme, men som ikke kan redigeres mere.
|
||||
A book can hold up to 4500 characters. The title length is limited to 64 characters.=En bog kan indeholde op til 4500 anslag. Titellængden er begrænset til 64 anslag.
|
||||
Enter book title:=Indtast bogens titel:
|
||||
by @1=af @1
|
||||
Note: The book will no longer be editable after signing=Bemærk: Bogen vil ikke længere kunne redigeres efter signering.
|
||||
Sign and Close=Signér og luk
|
||||
Cancel=Afbryd
|
||||
Nameless Book=Unavngiven bog
|
||||
Written Book=Skrevet bog
|
||||
Written books contain some text written by someone. They can be read and copied, but not edited.=Skrevne bøger indeholder tekst som nogen har skrevet. De kan læses og kopieres, men ikke redigeres.
|
||||
Hold it in your hand, then rightclick to read the book.=Hold den i hånden og højre-klik for at læse bogen.
|
||||
To copy the text of the written book, place it into the crafting grid together with a book and quill (or multiple of those) and craft. The written book will not be consumed. Copies of copies can not be copied.=For at kopiere teksten i den skrevne bog skal du placere den i arbejdsgitteret sammen med en (eller flere) bog og fjerdpen og udfør. Den skrevne bog bliver ikke opbrugt. Kopier kan ikke kopieres.
|
||||
Bookshelf=Bogreol
|
||||
Bookshelves are used for decoration.=Bogreoler bruges til udsmykning.
|
||||
Book and Quill=Bog og fjerdpen
|
||||
Write down some notes=Skriv nogle notater
|
|
@ -3,7 +3,7 @@ local S = minetest.get_translator(minetest.get_current_modname())
|
|||
mcl_cocoas = {}
|
||||
|
||||
-- Place cocoa
|
||||
function mcl_cocoas.place(itemstack, placer, pt, plantname)
|
||||
local function cocoa_place(itemstack, placer, pt, plantname)
|
||||
-- check if pointing at a node
|
||||
if not pt or pt.type ~= "node" then
|
||||
return
|
||||
|
@ -90,7 +90,11 @@ local crop_def = {
|
|||
},
|
||||
},
|
||||
groups = {
|
||||
handy=1,axey=1, cocoa=1, not_in_creative_inventory=1, dig_by_water=1, destroy_by_lava_flow=1, dig_by_piston=1, attached_node_facedir=1,
|
||||
handy = 1, axey = 1,
|
||||
dig_by_water=1, destroy_by_lava_flow=1, dig_by_piston=1,
|
||||
attached_node_facedir=1,
|
||||
not_in_creative_inventory=1,
|
||||
cocoa=1
|
||||
},
|
||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||
on_rotate = false,
|
||||
|
|
|
@ -24,7 +24,6 @@ minetest.register_node("mcl_core:ladder", {
|
|||
paramtype2 = "wallmounted",
|
||||
walkable = true,
|
||||
climbable = true,
|
||||
move_resistance = 1,
|
||||
node_box = {
|
||||
type = "wallmounted",
|
||||
wall_side = { -0.5, -0.5, -0.5, -7/16, 0.5, 0.5 },
|
||||
|
@ -33,15 +32,8 @@ minetest.register_node("mcl_core:ladder", {
|
|||
type = "wallmounted",
|
||||
wall_side = { -0.5, -0.5, -0.5, -7/16, 0.5, 0.5 },
|
||||
},
|
||||
collision_box = {
|
||||
type = "wallmounted",
|
||||
wall_side = { -0.5, -0.5, -0.5, -7/16, 0.5, 0.5 },
|
||||
},
|
||||
stack_max = 64,
|
||||
groups = {
|
||||
handy=1, axey=1, attached_node=1, deco_block=1, dig_by_piston=1,
|
||||
no_fall_damage=1
|
||||
},
|
||||
groups = {handy=1,axey=1, attached_node=1, deco_block=1, dig_by_piston=1},
|
||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||
node_placement_prediction = "",
|
||||
-- Restrict placement of ladders
|
||||
|
@ -107,7 +99,6 @@ minetest.register_node("mcl_core:vine", {
|
|||
paramtype2 = "wallmounted",
|
||||
walkable = false,
|
||||
climbable = true,
|
||||
move_resistance = 1,
|
||||
buildable_to = true,
|
||||
selection_box = {
|
||||
type = "wallmounted",
|
||||
|
@ -116,7 +107,7 @@ minetest.register_node("mcl_core:vine", {
|
|||
groups = {
|
||||
handy = 1, axey = 1, shearsy = 1, swordy = 1, deco_block = 1,
|
||||
dig_by_piston = 1, destroy_by_lava_flow = 1, compostability = 50,
|
||||
flammable = 2, fire_encouragement = 15, fire_flammability = 100, no_fall_damage=1
|
||||
flammable = 2, fire_encouragement = 15, fire_flammability = 100
|
||||
},
|
||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||
drop = "",
|
||||
|
|
|
@ -102,18 +102,14 @@ minetest.register_node("mcl_core:cobweb", {
|
|||
tiles = {"mcl_core_web.png"},
|
||||
inventory_image = "mcl_core_web.png",
|
||||
paramtype = "light",
|
||||
liquid_viscosity = 60,
|
||||
liquid_viscosity = 14,
|
||||
liquidtype = "source",
|
||||
liquid_alternative_flowing = "mcl_core:cobweb",
|
||||
liquid_alternative_source = "mcl_core:cobweb",
|
||||
liquid_renewable = false,
|
||||
liquid_range = 0,
|
||||
walkable = false,
|
||||
groups = {
|
||||
swordy_cobweb=1, shearsy_cobweb=1, fake_liquid=1, disable_jump=1,
|
||||
deco_block=1, dig_by_piston=1, dig_by_water=1,destroy_by_lava_flow=1,
|
||||
no_fall_damage=1
|
||||
},
|
||||
groups = {swordy_cobweb=1, shearsy_cobweb=1, fake_liquid=1, disable_jump=1, deco_block=1, dig_by_piston=1, dig_by_water=1,destroy_by_lava_flow=1,},
|
||||
drop = "mcl_mobitems:string",
|
||||
_mcl_shears_drop = true,
|
||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||
|
|
|
@ -76,10 +76,10 @@ minetest.register_node("mcl_crimson:warped_fungus", {
|
|||
walkable = false,
|
||||
groups = {dig_immediate=3,mushroom=1,attached_node=1,dig_by_water=1,destroy_by_lava_flow=1,dig_by_piston=1,enderman_takable=1,deco_block=1},
|
||||
light_source = 1,
|
||||
selection_box = {
|
||||
--[[ selection_box = {
|
||||
type = "fixed",
|
||||
fixed = { -3/16, -0.5, -3/16, 3/16, -2/16, 3/16 },
|
||||
},
|
||||
},]]
|
||||
node_placement_prediction = "",
|
||||
on_rightclick = function(pos, node, pointed_thing, player, itemstack)
|
||||
if pointed_thing:get_wielded_item():get_name() == "mcl_bone_meal:bone_meal" then
|
||||
|
|
Before Width: | Height: | Size: 293 B After Width: | Height: | Size: 264 B |
Before Width: | Height: | Size: 928 B After Width: | Height: | Size: 532 B |
Before Width: | Height: | Size: 408 B After Width: | Height: | Size: 259 B |
|
@ -275,7 +275,7 @@ local function apply_bone_meal(pointed_thing,user)
|
|||
if n.name == "mcl_farming:sweet_berry_bush_3" then
|
||||
return minetest.add_item(vector.offset(pos,math.random()-0.5,math.random()-0.5,math.random()-0.5),"mcl_farming:sweet_berry")
|
||||
else
|
||||
return mcl_farming:grow_plant("plant_sweet_berry_bush", pos, n, 1, true)
|
||||
return mcl_farming:grow_plant("plant_sweet_berry_bush", pos, n, 0, true)
|
||||
end
|
||||
elseif n.name == "mcl_cocoas:cocoa_1" or n.name == "mcl_cocoas:cocoa_2" then
|
||||
mcl_dye.add_bone_meal_particle(pos)
|
||||
|
|
|
@ -102,22 +102,34 @@ minetest.register_node("mcl_farming:beetroot", {
|
|||
0 seeds: 42.18%
|
||||
1 seed: 14.06%
|
||||
2 seeds: 18.75%
|
||||
3 seeds: 25% ]]
|
||||
3 seeds: 25%
|
||||
|
||||
correction: should always drop at least 1 seed. (1-4 seeds, per the minecraft wiki)
|
||||
--]]
|
||||
max_items = 2,
|
||||
items = {
|
||||
{ items = {"mcl_farming:beetroot_item"}, rarity = 1 },
|
||||
{ items = {"mcl_farming:beetroot_seeds 3"}, rarity = 4 },
|
||||
{ items = {"mcl_farming:beetroot_seeds 2"}, rarity = 4 },
|
||||
{ items = {"mcl_farming:beetroot_seeds 1"}, rarity = 4 },
|
||||
{items = {"mcl_farming:beetroot_item"}},
|
||||
{items = {"mcl_farming:beetroot_seeds 4"}, rarity = 6},
|
||||
{items = {"mcl_farming:beetroot_seeds 3"}, rarity = 4},
|
||||
{items = {"mcl_farming:beetroot_seeds 2"}, rarity = 3},
|
||||
{items = {"mcl_farming:beetroot_seeds"}, rarity = 1},
|
||||
},
|
||||
},
|
||||
|
||||
_mcl_fortune_drop = {
|
||||
discrete_uniform_distribution = true,
|
||||
items = {"mcl_farming:beetroot_item", "mcl_farming:beetroot_seeds"},
|
||||
min_count = 1,
|
||||
max_count = 3,
|
||||
cap = 5,
|
||||
},
|
||||
tiles = {"mcl_farming_beetroot_3.png"},
|
||||
inventory_image = "mcl_farming_beetroot_3.png",
|
||||
wield_image = "mcl_farming_beetroot_3.png",
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5, -0.5, -0.5, 0.5, 3/16, 0.5}
|
||||
{-0.5, -0.5, -0.5, 0.5, 3 / 16, 0.5}
|
||||
},
|
||||
},
|
||||
groups = {dig_immediate=3, not_in_creative_inventory=1,plant=1,attached_node=1,dig_by_water=1,destroy_by_lava_flow=1,dig_by_piston=1,beetroot=4},
|
||||
|
@ -161,7 +173,10 @@ minetest.register_craft({
|
|||
mcl_farming:add_plant("plant_beetroot", "mcl_farming:beetroot", {"mcl_farming:beetroot_0", "mcl_farming:beetroot_1", "mcl_farming:beetroot_2"}, 68, 3)
|
||||
|
||||
if minetest.get_modpath("doc") then
|
||||
for i=1,2 do
|
||||
doc.add_entry_alias("nodes", "mcl_farming:beetroot_0", "nodes", "mcl_farming:beetroot_"..i)
|
||||
for i = 1, 2 do
|
||||
doc.add_entry_alias("nodes", "mcl_farming:beetroot_0", "nodes", "mcl_farming:beetroot_" .. i)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_alias("beetroot_seeds", "mcl_farming:beetroot_seeds")
|
||||
minetest.register_alias("beetroot", "mcl_farming:beetroot_item")
|
||||
|
|
|
@ -89,14 +89,7 @@ minetest.register_craftitem("mcl_farming:carrot_item", {
|
|||
groups = {food = 2, eatable = 3, compostability = 65},
|
||||
_mcl_saturation = 3.6,
|
||||
on_secondary_use = minetest.item_eat(3),
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
local new = mcl_farming:place_seed(itemstack, placer, pointed_thing, "mcl_farming:carrot_1")
|
||||
if new then
|
||||
return new
|
||||
else
|
||||
return minetest.do_item_eat(3, nil, itemstack, placer, pointed_thing)
|
||||
end
|
||||
end,
|
||||
on_place = mcl_farming:get_seed_or_eat_callback("mcl_farming:carrot_1", 3),
|
||||
})
|
||||
|
||||
minetest.register_craftitem("mcl_farming:carrot_item_gold", {
|
||||
|
|
|
@ -95,14 +95,7 @@ minetest.register_craftitem("mcl_farming:potato_item", {
|
|||
_mcl_saturation = 0.6,
|
||||
stack_max = 64,
|
||||
on_secondary_use = minetest.item_eat(1),
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
local new = mcl_farming:place_seed(itemstack, placer, pointed_thing, "mcl_farming:potato_1")
|
||||
if new then
|
||||
return new
|
||||
else
|
||||
return minetest.do_item_eat(1, nil, itemstack, placer, pointed_thing)
|
||||
end
|
||||
end,
|
||||
on_place = mcl_farming:get_seed_or_eat_callback("mcl_farming:potato_1", 1),
|
||||
})
|
||||
|
||||
minetest.register_craftitem("mcl_farming:potato_item_baked", {
|
||||
|
|
|
@ -469,6 +469,21 @@ function mcl_farming:stem_color(startcolor, endcolor, step, step_count)
|
|||
return colorstring
|
||||
end
|
||||
|
||||
--[[Get a callback that either eats the item or plants it.
|
||||
|
||||
Used for on_place callbacks for craft items which are seeds that can also be consumed.
|
||||
]]
|
||||
function mcl_farming:get_seed_or_eat_callback(plantname, hp_change)
|
||||
return function(itemstack, placer, pointed_thing)
|
||||
local new = mcl_farming:place_seed(itemstack, placer, pointed_thing, plantname)
|
||||
if new then
|
||||
return new
|
||||
else
|
||||
return minetest.do_item_eat(hp_change, nil, itemstack, placer, pointed_thing)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "Add growth for unloaded farming plants",
|
||||
name = "mcl_farming:growth",
|
||||
|
|
|
@ -9,6 +9,9 @@ for i=0, 3 do
|
|||
if i > 0 then
|
||||
groups.sweet_berry_thorny = 1
|
||||
end
|
||||
local drop_berries = (i >= 2)
|
||||
local berries_to_drop = drop_berries and {i - 1, i} or nil
|
||||
|
||||
minetest.register_node(node_name, {
|
||||
drawtype = "plantlike",
|
||||
tiles = {texture},
|
||||
|
@ -24,7 +27,14 @@ for i=0, 3 do
|
|||
liquid_renewable = false,
|
||||
liquid_range = 0,
|
||||
walkable = false,
|
||||
drop = (i>=2) and ("mcl_farming:sweet_berry" .. (i==3 and " 3" or "")) or "",
|
||||
-- Dont even create a table if no berries are dropped.
|
||||
drop = not drop_berries and "" or {
|
||||
max_items = 1,
|
||||
items = {
|
||||
{ items = {"mcl_farming:sweet_berry " .. berries_to_drop[1] }, rarity = 2 },
|
||||
{ items = {"mcl_farming:sweet_berry " .. berries_to_drop[2] } }
|
||||
}
|
||||
},
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {-6 / 16, -0.5, -6 / 16, 6 / 16, (-0.30 + (i*0.25)), 6 / 16},
|
||||
|
@ -41,22 +51,20 @@ for i=0, 3 do
|
|||
minetest.record_protection_violation(pos, pn)
|
||||
return itemstack
|
||||
end
|
||||
if mcl_dye and clicker:get_wielded_item():get_name() == "mcl_bone_meal:bone_meal" then
|
||||
if 3 ~= i and mcl_dye and
|
||||
clicker:get_wielded_item():get_name() == "mcl_bone_meal:bone_meal" then
|
||||
mcl_dye.apply_bone_meal({under=pos},clicker)
|
||||
itemstack:take_item()
|
||||
if not minetest.is_creative_enabled(pn) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
return
|
||||
end
|
||||
local stage
|
||||
if node.name:find("_2") then
|
||||
stage = 2
|
||||
elseif node.name:find("_3") then
|
||||
stage = 3
|
||||
end
|
||||
if stage then
|
||||
for i=1,math.random(stage) do
|
||||
minetest.add_item(pos,"mcl_farming:sweet_berry")
|
||||
|
||||
if drop_berries then
|
||||
for j=1, berries_to_drop[math.random(2)] do
|
||||
minetest.add_item(pos, "mcl_farming:sweet_berry")
|
||||
end
|
||||
minetest.swap_node(pos,{name = "mcl_farming:sweet_berry_bush_" .. stage - 1 })
|
||||
minetest.swap_node(pos, {name = "mcl_farming:sweet_berry_bush_1"})
|
||||
end
|
||||
return itemstack
|
||||
end,
|
||||
|
@ -76,8 +84,11 @@ minetest.register_craftitem("mcl_farming:sweet_berry", {
|
|||
minetest.record_protection_violation(pointed_thing.above, pn)
|
||||
return itemstack
|
||||
end
|
||||
if pointed_thing.type == "node" and table.indexof(planton,minetest.get_node(pointed_thing.under).name) ~= -1 and minetest.get_node(pointed_thing.above).name == "air" then
|
||||
minetest.set_node(pointed_thing.above,{name="mcl_farming:sweet_berry_bush_0"})
|
||||
if pointed_thing.type == "node" and
|
||||
table.indexof(planton, minetest.get_node(pointed_thing.under).name) ~= -1 and
|
||||
pointed_thing.above.y > pointed_thing.under.y and
|
||||
minetest.get_node(pointed_thing.above).name == "air" then
|
||||
minetest.set_node(pointed_thing.above, {name="mcl_farming:sweet_berry_bush_0"})
|
||||
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
|
|
|
@ -22,6 +22,8 @@ local DEBUG = false
|
|||
local enable_burger = minetest.settings:get_bool("mcl_enable_hamburger",true)
|
||||
local use_alt = minetest.settings:get_bool("mcl_hamburger_alt_texture",false)
|
||||
|
||||
local HAMBURGER_NAME = "mcl_hamburger:hamburger"
|
||||
|
||||
mcl_hamburger = {}
|
||||
|
||||
if DEBUG then
|
||||
|
@ -32,12 +34,12 @@ end
|
|||
function mcl_hamburger.register_burger_craft(cooked_meat)
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "mcl_hamburger:hamburger",
|
||||
recipe = HAMBURGER_NAME,
|
||||
burntime = 2,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "mcl_hamburger:hamburger",
|
||||
output = HAMBURGER_NAME,
|
||||
recipe = {
|
||||
{ "mcl_farming:bread"},
|
||||
{ cooked_meat }, -- "mcl_mobitems:cooked_beef" for a reg hamburger. Grind up clowns for a Big Mac.
|
||||
|
@ -45,7 +47,7 @@ function mcl_hamburger.register_burger_craft(cooked_meat)
|
|||
},
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "mcl_hamburger:hamburger",
|
||||
output = HAMBURGER_NAME,
|
||||
recipe = {
|
||||
-- "mcl_mobitems:cooked_beef" for a reg hamburger. Grind up clowns for a Big Mac.
|
||||
{ "mcl_farming:bread", cooked_meat, "mcl_farming:bread"},
|
||||
|
@ -72,23 +74,23 @@ if not enable_burger then
|
|||
end
|
||||
|
||||
if use_alt == false then
|
||||
minetest.register_craftitem("mcl_hamburger:hamburger", hamburger_def)
|
||||
minetest.register_craftitem(HAMBURGER_NAME, hamburger_def)
|
||||
else
|
||||
local hamburger_alt = table.copy(hamburger_def)
|
||||
hamburger_alt.inventory_image = "mcl_hamburger_alt.png"
|
||||
hamburger_alt.wield_image = "mcl_hamburger_alt.png"
|
||||
minetest.register_craftitem("mcl_hamburger:hamburger", hamburger_alt)
|
||||
minetest.register_craftitem(HAMBURGER_NAME, hamburger_alt)
|
||||
end
|
||||
|
||||
local function register_achievements()
|
||||
|
||||
awards.register_achievement("mcl_hamburger:hamburger", {
|
||||
awards.register_achievement(HAMBURGER_NAME, {
|
||||
title = S("Burger Time!"),
|
||||
description = S("Craft a Hamburger."),
|
||||
icon = "mcl_hamburger_alt.png",
|
||||
trigger = {
|
||||
type = "craft",
|
||||
item = "mcl_hamburger:hamburger",
|
||||
item = HAMBURGER_NAME,
|
||||
target = 1
|
||||
},
|
||||
type = "Advancement",
|
||||
|
@ -101,19 +103,47 @@ local function register_doc_entry()
|
|||
|
||||
-- register Doc entry
|
||||
if minetest.get_modpath("doc") then
|
||||
doc.add_entry_alias("craftitems", "mcl_hamburger:hamburger", "craftitems", "mcl_hamburger:hamburger")
|
||||
doc.add_entry_alias("craftitems", HAMBURGER_NAME, "craftitems", HAMBURGER_NAME)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if enable_burger then
|
||||
-- make the villagers follow the item
|
||||
minetest.registered_entities["mobs_mc:villager"].nofollow = false
|
||||
-- add it to the follow items.
|
||||
table.insert(minetest.registered_entities["mobs_mc:villager"].follow,"mcl_hamburger:hamburger")
|
||||
-- register the item and crafting recipe.
|
||||
local villager = minetest.registered_entities["mobs_mc:villager"]
|
||||
|
||||
table.insert(villager.follow, HAMBURGER_NAME)
|
||||
|
||||
local original_rightclick = villager.on_rightclick
|
||||
|
||||
local new_on_rightclick = function(self, clicker)
|
||||
--minetest.log("In wrapper function")
|
||||
|
||||
local item = clicker:get_wielded_item()
|
||||
if item:get_name() == HAMBURGER_NAME then
|
||||
if self.nofollow == true then
|
||||
--minetest.log("Turn off nofollow")
|
||||
self.nofollow = false
|
||||
elseif self.nofollow == false then
|
||||
--minetest.log("Turn on nofollow")
|
||||
self.nofollow = true
|
||||
end
|
||||
else
|
||||
--minetest.log("Not holding burger")
|
||||
if self.nofollow == false then
|
||||
--minetest.log("Turn on nofollow")
|
||||
self.nofollow = true
|
||||
end
|
||||
original_rightclick(self, clicker)
|
||||
end
|
||||
--minetest.log("Finishing wrapper")
|
||||
end
|
||||
|
||||
villager.on_rightclick = new_on_rightclick
|
||||
|
||||
mcl_hamburger.register_burger_craft("mcl_mobitems:cooked_beef")
|
||||
-- add in the super cool achievement(s)!
|
||||
minetest.register_alias("hamburger", HAMBURGER_NAME)
|
||||
|
||||
register_achievements()
|
||||
register_doc_entry()
|
||||
end
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright © 2007 Free Software Foundation, Inc. <https://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 <https://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:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
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 <https://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 <https://www.gnu.org/licenses/why-not-lgpl.html>.
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
---
|
||||
# Mineclone2-Lectern
|
||||
---
|
||||
A ground up creation of a lectern to be used in MineClone 2. Requires Minetest and Mineclone2.
|
||||
---
|
||||
|
||||
Created by Michieal (FaerRaven) @ DateTime: 01/07/2023 (07JAN2023)
|
||||
|
||||
* Made for MineClone 2 by Michieal.
|
||||
* Texture made by Michieal; The model borrows the top from NathanS21's (Nathan Salapat) Lectern model; The rest of the
|
||||
lectern model was created by Michieal.
|
||||
* Creation date: 01/07/2023 (07JAN2023)
|
||||
* License for Code: GPL3
|
||||
* License for Media: CC-BY-SA 4
|
|
@ -0,0 +1,131 @@
|
|||
-- Made for MineClone 2 by Michieal.
|
||||
-- Texture made by Michieal; The model borrows the top from NathanS21's (Nathan Salapat) Lectern model; The rest of the
|
||||
-- lectern model was created by Michieal.
|
||||
-- Creation date: 01/07/2023 (07JAN2023)
|
||||
-- License for Code: GPL3
|
||||
-- License for Media: CC-BY-SA 4
|
||||
-- Copyright (C) 2023, Michieal. See: License.txt.
|
||||
|
||||
-- LOCALS
|
||||
local modname = minetest.get_current_modname()
|
||||
local S = minetest.get_translator(modname)
|
||||
local node_sound = mcl_sounds.node_sound_wood_defaults()
|
||||
local pi = 3.1415926
|
||||
|
||||
local lectern_def = {
|
||||
description = S("Lectern"),
|
||||
_tt_help = S("Lecterns not only look good, but are job site blocks for Librarians."),
|
||||
_doc_items_longdesc = S("Lecterns not only look good, but are job site blocks for Librarians."),
|
||||
_doc_items_usagehelp = S("Place the Lectern on a solid node for best results. May attract villagers, so it's best to place outside of where you call 'home'."),
|
||||
sounds = node_sound,
|
||||
paramtype = "light",
|
||||
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
|
||||
paramtype2 = "facedir",
|
||||
drawtype = "mesh",
|
||||
-- visual_scale = 1.0, -- Default is 1.0.
|
||||
mesh = "mcl_lectern_lectern.obj",
|
||||
tiles = {"mcl_lectern_lectern.png", },
|
||||
groups = {handy = 1, axey = 1, flammable = 2, fire_encouragement = 5, fire_flammability = 5, solid = 1},
|
||||
drops = "mcl_lectern:lectern",
|
||||
sunlight_propagates = true,
|
||||
walkable = true,
|
||||
is_ground_content = false,
|
||||
node_placement_prediction = "",
|
||||
_mcl_blast_resistance = 3,
|
||||
_mcl_hardness = 2,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
-- L, T, Ba, R, Bo, F.
|
||||
{-0.32, 0.46, -0.32, 0.32, 0.175, 0.32},
|
||||
{-0.18, 0.175, -0.055, 0.18, -0.37, 0.21},
|
||||
{-0.32, -0.37, -0.32, 0.32, -0.5, 0.32},
|
||||
}
|
||||
},
|
||||
collision_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
-- L, T, Ba, R, Bo, F.
|
||||
{-0.32, 0.46, -0.32, 0.32, 0.175, 0.32},
|
||||
{-0.18, 0.175, -0.055, 0.18, -0.37, 0.21},
|
||||
{-0.32, -0.37, -0.32, 0.32, -0.5, 0.32},
|
||||
}
|
||||
},
|
||||
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
local above = pointed_thing.above
|
||||
local under = pointed_thing.under
|
||||
|
||||
local pos = under
|
||||
local pname = placer:get_player_name()
|
||||
if minetest.is_protected(pos, pname) then
|
||||
minetest.record_protection_violation(pos, pname)
|
||||
return
|
||||
end
|
||||
|
||||
-- Use pointed node's on_rightclick function first, if present
|
||||
local node = minetest.get_node(pointed_thing.under)
|
||||
if placer and not placer:get_player_control().sneak then
|
||||
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
|
||||
end
|
||||
end
|
||||
local dir = vector.subtract(under, above)
|
||||
local wdir = minetest.dir_to_wallmounted(dir)
|
||||
local fdir = minetest.dir_to_facedir(dir)
|
||||
if wdir == 0 then
|
||||
return itemstack
|
||||
-- IE., no Hanging Lecterns for you!
|
||||
end
|
||||
if wdir == 1 then
|
||||
-- (only make standing nodes...)
|
||||
-- Determine the rotation based on player's yaw
|
||||
local yaw = pi * 2 - placer:get_look_horizontal()
|
||||
|
||||
-- Convert to 16 dir.
|
||||
local rotation_level = math.round((yaw / (pi * 2)) * 16)
|
||||
|
||||
-- put the rotation level within bounds.
|
||||
if rotation_level > 15 then
|
||||
rotation_level = 0
|
||||
elseif rotation_level < 0 then
|
||||
rotation_level = 15
|
||||
end
|
||||
|
||||
fdir = math.floor(rotation_level / 4) -- collapse that to 4 dir.
|
||||
local lectern_node = ItemStack(itemstack)
|
||||
-- Place the node!
|
||||
local _, success = minetest.item_place_node(lectern_node, placer, pointed_thing, fdir)
|
||||
if not success then
|
||||
return itemstack
|
||||
end
|
||||
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
end
|
||||
return itemstack
|
||||
end,
|
||||
}
|
||||
|
||||
minetest.register_node("mcl_lectern:lectern", lectern_def)
|
||||
mcl_wip.register_wip_item("mcl_lectern:lectern")
|
||||
|
||||
-- April Fools setup
|
||||
local date = os.date("*t")
|
||||
if (date.month == 4 and date.day == 1) then
|
||||
minetest.override_item("mcl_lectern:lectern", {waving = 2})
|
||||
else
|
||||
minetest.override_item("mcl_lectern:lectern", {waving = 0})
|
||||
end
|
||||
|
||||
minetest.register_craft({
|
||||
output = "mcl_lectern:lectern",
|
||||
recipe = {
|
||||
{"group:slab", "group:slab", "group:slab"},
|
||||
{"", "mcl_books:bookshelf", ""},
|
||||
{"", "group:slab", ""},
|
||||
}
|
||||
})
|
||||
|
||||
-- Base Aliases.
|
||||
minetest.register_alias("lectern", "mcl_lectern:lectern")
|
|
@ -0,0 +1,3 @@
|
|||
name = mcl_lectern
|
||||
depends = mcl_core, mcl_sounds, mcl_tools
|
||||
author = Michieal
|
|
@ -0,0 +1,223 @@
|
|||
# Blender 3.5.0 Alpha
|
||||
# www.blender.org
|
||||
mtllib mcl_lectern_lectern.mtl
|
||||
o Lectern_Cube.012
|
||||
v 0.179604 0.312500 -0.062500
|
||||
v -0.179604 0.312500 -0.062500
|
||||
v 0.179604 0.363193 0.205629
|
||||
v -0.179604 0.363193 0.205629
|
||||
v 0.179604 -0.375000 -0.062500
|
||||
v -0.179604 -0.375000 -0.062500
|
||||
v 0.179604 -0.375000 0.205629
|
||||
v -0.179604 -0.375000 0.205629
|
||||
v 0.311850 -0.500000 0.312500
|
||||
v 0.311850 -0.375000 0.312500
|
||||
v -0.311649 -0.500000 0.312500
|
||||
v -0.311649 -0.375000 0.312500
|
||||
v 0.311850 -0.500000 -0.312500
|
||||
v 0.311850 -0.375000 -0.312500
|
||||
v -0.311649 -0.500000 -0.312500
|
||||
v -0.311649 -0.375000 -0.312500
|
||||
v 0.312500 0.186356 -0.272278
|
||||
v 0.312500 0.245087 -0.293654
|
||||
v 0.312500 0.400118 0.315030
|
||||
v 0.312500 0.458849 0.293654
|
||||
v -0.312500 0.186356 -0.272278
|
||||
v -0.312500 0.245087 -0.293654
|
||||
v -0.312500 0.400118 0.315030
|
||||
v -0.312500 0.458849 0.293654
|
||||
v 0.312500 0.207732 -0.213547
|
||||
v 0.312500 0.266463 -0.234923
|
||||
v -0.312500 0.207732 -0.213547
|
||||
v -0.312500 0.266463 -0.234923
|
||||
v -0.312500 0.325194 -0.256299
|
||||
v -0.312500 0.303817 -0.315030
|
||||
v 0.312500 0.303817 -0.315030
|
||||
v 0.312500 0.325194 -0.256299
|
||||
v 0.151506 0.084133 0.146440
|
||||
v -0.157381 0.084133 0.146440
|
||||
v -0.157381 -0.203113 0.146441
|
||||
v 0.151506 -0.203113 0.146441
|
||||
v 0.151523 0.084130 -0.062500
|
||||
v -0.157397 0.084130 -0.062500
|
||||
v 0.151523 -0.203120 -0.062500
|
||||
v -0.157397 -0.203120 -0.062500
|
||||
v 0.151768 0.044855 0.077978
|
||||
v 0.064092 -0.203638 0.077978
|
||||
v 0.151797 0.044842 -0.062023
|
||||
v 0.064120 -0.203654 -0.062023
|
||||
v 0.028419 -0.191051 0.077979
|
||||
v 0.116095 0.057441 0.077979
|
||||
v 0.116124 0.057428 -0.062022
|
||||
v 0.028447 -0.191068 -0.062022
|
||||
vn 1.0000 -0.0000 -0.0000
|
||||
vn -0.0000 -0.0000 1.0000
|
||||
vn -0.0000 -0.0000 -1.0000
|
||||
vn -1.0000 -0.0000 -0.0000
|
||||
vn -0.0000 1.0000 -0.0000
|
||||
vn -0.0000 0.3420 0.9397
|
||||
vn -0.0000 -0.3420 -0.9397
|
||||
vn -0.0000 -0.9397 0.3420
|
||||
vn -0.0000 0.9397 -0.3420
|
||||
vn -0.0000 -1.0000 -0.0000
|
||||
vn -1.0000 -0.0000 -0.0001
|
||||
vn 1.0000 -0.0000 -0.0001
|
||||
vn 0.9430 -0.3327 0.0002
|
||||
vn -0.9430 0.3327 -0.0002
|
||||
vn 0.3327 0.9430 -0.0000
|
||||
vn -0.3327 -0.9430 -0.0000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.343750 -0.000000
|
||||
vt 0.312500 0.000000
|
||||
vt -0.000000 -0.000000
|
||||
vt 0.312500 0.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.312500 0.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.000000 0.437500
|
||||
vt 0.343750 0.625000
|
||||
vt 0.312500 0.437500
|
||||
vt -0.000000 0.625000
|
||||
vt 0.312500 0.437500
|
||||
vt 0.000000 0.437500
|
||||
vt 0.312500 0.437500
|
||||
vt 0.000000 0.437500
|
||||
vt 0.312500 0.593750
|
||||
vt 0.000000 0.593750
|
||||
vt 0.312500 0.656250
|
||||
vt 0.000000 0.656250
|
||||
vt 1.000000 1.000000
|
||||
vt 0.000000 0.593750
|
||||
vt 0.312500 0.593750
|
||||
vt 0.000000 0.656250
|
||||
vt 0.312500 0.656250
|
||||
vt 1.000000 0.437500
|
||||
vt 0.000000 0.593750
|
||||
vt 0.312500 0.593750
|
||||
vt 0.000000 0.656250
|
||||
vt 0.312500 0.656250
|
||||
vt 0.437500 1.000000
|
||||
vt 0.000000 0.593750
|
||||
vt 0.312500 0.593750
|
||||
vt 0.000000 0.656250
|
||||
vt 0.312500 0.656250
|
||||
vt 0.437500 0.437500
|
||||
vt 0.125000 1.000000
|
||||
vt 0.125000 0.687500
|
||||
vt 0.062500 0.687500
|
||||
vt 0.187500 1.000000
|
||||
vt 0.125000 1.000000
|
||||
vt 0.312500 1.000000
|
||||
vt 0.437500 1.000000
|
||||
vt 0.062500 1.000000
|
||||
vt 0.250000 1.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 0.125000 0.687500
|
||||
vt 0.062500 0.687500
|
||||
vt 0.187500 0.687500
|
||||
vt 0.312500 0.687500
|
||||
vt 0.437500 0.437500
|
||||
vt 0.125000 1.000000
|
||||
vt 0.250000 0.687500
|
||||
vt 1.000000 0.437500
|
||||
vt 0.062500 1.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 0.062500 1.000000
|
||||
vt 0.125000 0.718750
|
||||
vt 0.437500 1.000000
|
||||
vt 0.062500 0.718750
|
||||
vt 1.000000 0.437500
|
||||
vt 0.062500 0.687500
|
||||
vt 0.125000 0.718750
|
||||
vt 0.437500 0.437500
|
||||
vt 0.062500 0.718750
|
||||
vt 0.437500 0.687500
|
||||
vt -0.000000 0.718750
|
||||
vt 0.375000 0.687500
|
||||
vt -0.000000 0.687500
|
||||
vt 0.312500 0.687500
|
||||
vt 0.250000 0.687500
|
||||
vt 0.312500 1.000000
|
||||
vt -0.000000 0.687500
|
||||
vt 0.250000 1.000000
|
||||
vt 0.375000 1.000000
|
||||
vt -0.000000 0.718750
|
||||
vt 0.687500 0.375000
|
||||
vt 0.312500 0.375000
|
||||
vt 0.687500 0.375000
|
||||
vt 0.312500 0.000000
|
||||
vt 0.312500 0.375000
|
||||
vt 0.687500 0.000000
|
||||
vt 0.687500 0.375000
|
||||
vt 0.312500 0.375000
|
||||
vt 0.312500 0.218750
|
||||
vt 0.687500 -0.000000
|
||||
vt 0.031250 0.218750
|
||||
vt 0.312500 -0.000000
|
||||
vt 0.687500 -0.000000
|
||||
vt 0.312500 0.468750
|
||||
vt 0.687500 -0.000000
|
||||
vt 0.312500 -0.000000
|
||||
vt 0.031250 0.468750
|
||||
vt 0.312500 -0.000000
|
||||
vt 0.937500 -0.000000
|
||||
vt 0.937500 0.437500
|
||||
vt 0.937500 0.437500
|
||||
vt 1.000000 0.437500
|
||||
vt 0.687500 0.000000
|
||||
vt 0.937500 0.218750
|
||||
vt 0.750000 0.000000
|
||||
vt 0.687500 0.437500
|
||||
vt 0.750000 0.437500
|
||||
vt 1.000000 0.218750
|
||||
vt 0.937500 0.000000
|
||||
vt 1.000000 0.437500
|
||||
vt 0.937500 0.437500
|
||||
vt 0.937500 0.437500
|
||||
vt 1.000000 -0.000000
|
||||
vt 1.000000 0.437500
|
||||
vt 0.687500 0.437500
|
||||
vt 1.000000 0.218750
|
||||
vt 0.687500 0.000000
|
||||
vt 0.687500 0.000000
|
||||
vt 0.687500 0.437500
|
||||
vt 0.937500 0.218750
|
||||
s 0
|
||||
usemtl Material
|
||||
f 1/1/1 3/5/1 7/13/1 5/9/1
|
||||
f 3/6/2 4/7/2 8/15/2 7/14/2
|
||||
f 9/17/2 10/19/2 12/24/2 11/22/2
|
||||
f 36/82/3 35/80/3 34/78/3 33/77/3
|
||||
f 8/16/4 4/8/4 2/3/4 6/11/4
|
||||
f 11/23/4 12/25/4 16/34/4 15/32/4
|
||||
f 15/33/3 16/35/3 14/29/3 13/27/3
|
||||
f 13/28/1 14/30/1 10/20/1 9/18/1
|
||||
f 16/36/5 12/26/5 10/21/5 14/31/5
|
||||
f 25/58/1 26/60/1 20/44/1 19/41/1
|
||||
f 19/42/6 20/45/6 24/53/6 23/50/6
|
||||
f 27/63/4 28/65/4 22/48/4 21/47/4
|
||||
f 21/47/7 22/49/7 18/40/7 17/37/7
|
||||
f 22/48/4 28/65/4 29/67/4 30/69/4
|
||||
f 25/56/8 19/43/8 23/51/8 27/61/8
|
||||
f 17/37/8 25/57/8 27/62/8 21/47/8
|
||||
f 24/54/9 20/46/9 26/59/9 28/64/9
|
||||
f 23/52/4 24/55/4 28/65/4 27/63/4
|
||||
f 17/38/1 18/39/1 26/60/1 25/58/1
|
||||
f 29/68/9 32/75/9 31/72/9 30/70/9
|
||||
f 28/66/6 26/59/6 32/75/6 29/68/6
|
||||
f 26/60/1 18/39/1 31/73/1 32/76/1
|
||||
f 18/40/7 22/49/7 30/71/7 31/74/7
|
||||
f 37/85/3 38/87/3 2/4/3 1/2/3
|
||||
f 39/90/3 37/85/3 1/2/3 5/10/3
|
||||
f 40/93/3 39/90/3 5/10/3 6/12/3
|
||||
f 38/87/3 40/93/3 6/12/3 2/4/3
|
||||
f 33/77/10 34/78/10 38/88/10 37/86/10
|
||||
f 35/81/5 36/83/5 39/91/5 40/94/5
|
||||
f 36/84/11 33/77/11 37/86/11 39/92/11
|
||||
f 34/79/12 35/81/12 40/94/12 38/89/12
|
||||
f 44/102/13 43/99/13 41/95/13 42/97/13
|
||||
f 45/105/14 46/108/14 47/111/14 48/114/14
|
||||
f 41/95/2 46/109/2 45/106/2 42/97/2
|
||||
f 43/100/15 47/112/15 46/110/15 41/96/15
|
||||
f 44/103/3 48/115/3 47/113/3 43/101/3
|
||||
f 42/98/16 45/107/16 48/116/16 44/104/16
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -79,19 +79,27 @@ function settlements.create_site_plan(maxp, minp, pr)
|
|||
local settlement_info = {}
|
||||
local building_all_info
|
||||
local possible_rotations = {"0", "90", "180", "270"}
|
||||
|
||||
-- find center of chunk
|
||||
local center = {
|
||||
x=math.floor((minp.x+maxp.x)/2),
|
||||
y=maxp.y,
|
||||
z=math.floor((minp.z+maxp.z)/2)
|
||||
}
|
||||
|
||||
-- find center_surface of chunk
|
||||
local center_surface , surface_material = settlements.find_surface(center, true)
|
||||
local chunks = {}
|
||||
chunks[mcl_vars.get_chunk_number(center)] = true
|
||||
|
||||
-- go build settlement around center
|
||||
if not center_surface then return false end
|
||||
if not center_surface then
|
||||
minetest.log("action", "Cannot build village at: " .. minetest.pos_to_string(center))
|
||||
return false
|
||||
else
|
||||
minetest.log("action", "Village built.")
|
||||
--minetest.log("action", "Build village at: " .. minetest.pos_to_string(center) .. " with surface material: " .. surface_material)
|
||||
end
|
||||
|
||||
-- initialize all settlement_info table
|
||||
local count_buildings, number_of_buildings, number_built = settlements.initialize_settlement_info(pr)
|
||||
|
@ -190,6 +198,7 @@ local function construct_node(p1, p2, name)
|
|||
end
|
||||
|
||||
local function spawn_iron_golem(pos)
|
||||
--minetest.log("action", "Attempt to spawn iron golem.")
|
||||
local p = minetest.find_node_near(pos,50,"mcl_core:grass_path")
|
||||
if p then
|
||||
local l=minetest.add_entity(p,"mobs_mc:iron_golem"):get_luaentity()
|
||||
|
@ -200,6 +209,7 @@ local function spawn_iron_golem(pos)
|
|||
end
|
||||
|
||||
local function spawn_villagers(minp,maxp)
|
||||
--minetest.log("action", "Attempt to spawn villagers.")
|
||||
local beds=minetest.find_nodes_in_area(vector.offset(minp,-20,-20,-20),vector.offset(maxp,20,20,20),{"mcl_beds:bed_red_bottom"})
|
||||
for _,bed in pairs(beds) do
|
||||
local m = minetest.get_meta(bed)
|
||||
|
@ -235,23 +245,6 @@ end
|
|||
function settlements.place_schematics(settlement_info, pr)
|
||||
local building_all_info
|
||||
|
||||
--attempt to place one belltower in the center of the village - this doesn't always work out great but it's a lot better than doing it first or last.
|
||||
local belltower = table.remove(settlement_info,math.floor(#settlement_info/2))
|
||||
if belltower then
|
||||
mcl_structures.place_schematic(
|
||||
vector.offset(belltower["pos"],0,0,0),
|
||||
settlements.modpath.."/schematics/belltower.mts",
|
||||
belltower["rotation"],
|
||||
nil,
|
||||
true,
|
||||
nil,
|
||||
function(p1, p2, size, rotation, pr)
|
||||
spawn_iron_golem(p1)
|
||||
end,
|
||||
pr
|
||||
)
|
||||
end
|
||||
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
local is_last = i == #settlement_info
|
||||
|
||||
|
@ -262,6 +255,9 @@ function settlements.place_schematics(settlement_info, pr)
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
local pos = settlement_info[i]["pos"]
|
||||
local rotation = settlement_info[i]["rotat"]
|
||||
-- get building node material for better integration to surrounding
|
||||
|
@ -313,8 +309,11 @@ function settlements.place_schematics(settlement_info, pr)
|
|||
|
||||
-- format schematic string
|
||||
local schematic = loadstring(schem_lua)()
|
||||
|
||||
local is_belltower = building_all_info["name"] == "belltower"
|
||||
|
||||
-- build foundation for the building an make room above
|
||||
-- place schematic
|
||||
|
||||
mcl_structures.place_schematic(
|
||||
pos,
|
||||
schematic,
|
||||
|
@ -323,8 +322,12 @@ function settlements.place_schematics(settlement_info, pr)
|
|||
true,
|
||||
nil,
|
||||
function(p1, p2, size, rotation, pr)
|
||||
init_nodes(p1, p2, size, rotation, pr)
|
||||
spawn_villagers(p1,p2)
|
||||
if is_belltower then
|
||||
spawn_iron_golem(p1)
|
||||
else
|
||||
init_nodes(p1, p2, size, rotation, pr)
|
||||
spawn_villagers(p1,p2)
|
||||
end
|
||||
end,
|
||||
pr
|
||||
)
|
||||
|
|
|
@ -52,6 +52,7 @@ schem_path = settlements.modpath.."/schematics/"
|
|||
local basic_pseudobiome_villages = minetest.settings:get_bool("basic_pseudobiome_villages", true)
|
||||
|
||||
settlements.schematic_table = {
|
||||
{name = "belltower", mts = schem_path.."belltower.mts", hwidth = 5, hdepth = 5, hheight = 9, hsize = 14, max_num = 0 , rplc = basic_pseudobiome_villages },
|
||||
{name = "large_house", mts = schem_path.."large_house.mts", hwidth = 12, hdepth = 12, hheight = 9, hsize = 14, max_num = 0.08 , rplc = basic_pseudobiome_villages },
|
||||
{name = "blacksmith", mts = schem_path.."blacksmith.mts", hwidth = 8, hdepth = 11, hheight = 13, hsize = 13, max_num = 0.055, rplc = basic_pseudobiome_villages },
|
||||
{name = "butcher", mts = schem_path.."butcher.mts", hwidth = 12, hdepth = 8, hheight = 10, hsize = 14, max_num = 0.03 , rplc = basic_pseudobiome_villages },
|
||||
|
|
|
@ -40,22 +40,32 @@ function settlements.find_surface(pos, wait)
|
|||
-- go through nodes an find surface
|
||||
while cnt < cnt_max do
|
||||
-- Check Surface_node and Node above
|
||||
--
|
||||
if settlements.surface_mat[surface_node.name] then
|
||||
if surface_node and settlements.surface_mat[surface_node.name] then
|
||||
local surface_node_plus_1 = get_node({ x=p6.x, y=p6.y+1, z=p6.z})
|
||||
if surface_node_plus_1 and surface_node and
|
||||
(string.find(surface_node_plus_1.name,"air") or
|
||||
string.find(surface_node_plus_1.name,"snow") or
|
||||
string.find(surface_node_plus_1.name,"fern") or
|
||||
string.find(surface_node_plus_1.name,"flower") or
|
||||
string.find(surface_node_plus_1.name,"bush") or
|
||||
string.find(surface_node_plus_1.name,"tree") or
|
||||
string.find(surface_node_plus_1.name,"grass"))
|
||||
|
||||
if surface_node_plus_1 then
|
||||
|
||||
local surface_node_minus_1 = get_node({ x=p6.x, y=p6.y-1, z=p6.z})
|
||||
local is_leaf_below = minetest.get_item_group(surface_node_minus_1, "leaves") ~= 0 or
|
||||
string.find(surface_node_minus_1.name,"leaves")
|
||||
|
||||
if not is_leaf_below and ((string.find(surface_node_plus_1.name,"air") or
|
||||
string.find(surface_node_plus_1.name,"fern") or
|
||||
string.find(surface_node_plus_1.name,"flower") or
|
||||
string.find(surface_node_plus_1.name,"bush") or
|
||||
string.find(surface_node_plus_1.name,"tree") or
|
||||
string.find(surface_node_plus_1.name,"grass")) or
|
||||
string.find(surface_node_plus_1.name,"snow"))
|
||||
then
|
||||
settlements.debug("find_surface7: " ..surface_node.name.. " " .. surface_node_plus_1.name)
|
||||
settlements.debug("find_surface success: " ..surface_node.name.. " " .. surface_node_plus_1.name)
|
||||
settlements.debug("node below: " .. tostring(surface_node_minus_1.name))
|
||||
settlements.debug("node below leaves group: " .. tostring(minetest.get_item_group(surface_node_minus_1, "leaves")))
|
||||
return p6, surface_node.name
|
||||
else
|
||||
settlements.debug("find_surface2: wrong surface+1")
|
||||
end
|
||||
else
|
||||
settlements.debug("find_surface2: wrong surface+1")
|
||||
settlements.debug("find_surface8: missing node or plus_1")
|
||||
end
|
||||
else
|
||||
settlements.debug("find_surface3: wrong surface "..surface_node.name.." at pos "..minetest.pos_to_string(p6))
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
local mcl_skins_enabled = minetest.global_exists("mcl_skins")
|
||||
|
||||
-- This is a fake node that should never be placed in the world
|
||||
---This is a fake node that should never be placed in the world
|
||||
---@type node_definition
|
||||
local node_def = {
|
||||
description = "",
|
||||
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
|
||||
visual_scale = 1,
|
||||
wield_scale = {x=1,y=1,z=1},
|
||||
use_texture_alpha = "opaque",
|
||||
paramtype = "light",
|
||||
drawtype = "mesh",
|
||||
node_placement_prediction = "",
|
||||
|
@ -16,7 +14,7 @@ local node_def = {
|
|||
minetest.remove_node(pos)
|
||||
end,
|
||||
drop = "",
|
||||
on_drop = function() return "" end,
|
||||
on_drop = function(_, _, _) return ItemStack() end,
|
||||
groups = { dig_immediate = 3, not_in_creative_inventory = 1 },
|
||||
range = minetest.registered_items[""].range
|
||||
}
|
||||
|
@ -29,20 +27,20 @@ if mcl_skins_enabled then
|
|||
local female = table.copy(node_def)
|
||||
female._mcl_hand_id = skin.id
|
||||
female.mesh = "mcl_meshhand_female.b3d"
|
||||
female.tiles = {skin.texture}
|
||||
female.tiles = { skin.texture }
|
||||
minetest.register_node("mcl_meshhand:" .. skin.id, female)
|
||||
else
|
||||
local male = table.copy(node_def)
|
||||
male._mcl_hand_id = skin.id
|
||||
male.mesh = "mcl_meshhand.b3d"
|
||||
male.tiles = {skin.texture}
|
||||
male.tiles = { skin.texture }
|
||||
minetest.register_node("mcl_meshhand:" .. skin.id, male)
|
||||
end
|
||||
end
|
||||
else
|
||||
node_def._mcl_hand_id = "hand"
|
||||
node_def.mesh = "mcl_meshhand.b3d"
|
||||
node_def.tiles = {"character.png"}
|
||||
node_def.tiles = { "character.png" }
|
||||
minetest.register_node("mcl_meshhand:hand", node_def)
|
||||
end
|
||||
|
||||
|
@ -54,6 +52,6 @@ if mcl_skins_enabled then
|
|||
end)
|
||||
else
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
player:get_inventory():set_stack("hand", 1, "mcl_meshhand:hand")
|
||||
player:get_inventory():set_stack("hand", 1, ItemStack("mcl_meshhand:hand"))
|
||||
end)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
local pianowtune = "diminixed-pianowtune01"
|
||||
local end_tune = "diminixed-ambientwip"
|
||||
local nether_tune = "horizonchris96-traitor"
|
||||
|
||||
local dimension_to_base_track = {
|
||||
["overworld"] = pianowtune,
|
||||
["nether"] = nether_tune,
|
||||
["end"] = end_tune,
|
||||
}
|
||||
|
||||
local listeners = {}
|
||||
|
||||
local weather_state
|
||||
|
||||
local function stop_music_for_listener_name(listener_name)
|
||||
if not listener_name then return end
|
||||
local listener = listeners[listener_name]
|
||||
if not listener then return end
|
||||
local handle = listener.handle
|
||||
if not handle then return end
|
||||
minetest.sound_stop(handle)
|
||||
listeners[listener_name].handle = nil
|
||||
end
|
||||
|
||||
local function stop()
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
local player_name = player:get_player_name()
|
||||
stop_music_for_listener_name(player_name)
|
||||
end
|
||||
end
|
||||
|
||||
local function play()
|
||||
local new_weather_state = mcl_weather.get_weather()
|
||||
local was_good_weather = weather_state == "none" or weather_state == "clear"
|
||||
weather_state = new_weather_state
|
||||
local is_good_weather = weather_state == "none" or weather_state == "clear"
|
||||
local is_weather_changed = weather_state ~= new_weather_state
|
||||
local time = minetest.get_timeofday()
|
||||
if time < 0.25 or time >= 0.75 then
|
||||
stop()
|
||||
minetest.after(10, play)
|
||||
return
|
||||
end
|
||||
local day_count = minetest.get_day_count()
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
local player_name = player:get_player_name()
|
||||
local hp = player:get_hp()
|
||||
local pos = player:get_pos()
|
||||
local dimension = mcl_worlds.pos_to_dimension(pos)
|
||||
|
||||
local listener = listeners[player_name]
|
||||
local old_hp = listener and listener.hp
|
||||
local old_dimension = listener and listener.dimension
|
||||
|
||||
local is_dimension_changed = old_dimension and (old_dimension ~= dimension) or false
|
||||
local is_hp_changed = old_hp and (math.abs(old_hp - hp) > 0.00001) or false
|
||||
local handle = listener and listener.handle
|
||||
|
||||
local track = dimension_to_base_track[dimension]
|
||||
|
||||
if is_hp_changed
|
||||
or is_dimension_changed
|
||||
or (dimension == "overworld" and (is_weather_changed or not is_good_weather))
|
||||
or not track
|
||||
then
|
||||
stop_music_for_listener_name(player_name)
|
||||
if not listeners[player_name] then
|
||||
listeners[player_name] = {}
|
||||
end
|
||||
listeners[player_name].hp = hp
|
||||
listeners[player_name].dimension = dimension
|
||||
elseif not handle and (not listener or (listener.day_count ~= day_count)) then
|
||||
local spec = {
|
||||
name = track,
|
||||
gain = 0.3,
|
||||
pitch = 1.0,
|
||||
}
|
||||
local parameters = {
|
||||
to_player = player_name,
|
||||
gain = 1.0,
|
||||
fade = 0.0,
|
||||
pitch = 1.0,
|
||||
}
|
||||
handle = minetest.sound_play(spec, parameters, false)
|
||||
listeners[player_name] = {
|
||||
spec = spec,
|
||||
parameters = parameters,
|
||||
handle = handle,
|
||||
hp = hp,
|
||||
dimension = dimension,
|
||||
day_count = day_count,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
minetest.after(7, play)
|
||||
end
|
||||
|
||||
minetest.after(15, play)
|
||||
|
||||
minetest.register_on_joinplayer(function(player, last_login)
|
||||
local player_name = player:get_player_name()
|
||||
stop_music_for_listener_name(player_name)
|
||||
end)
|
||||
|
||||
minetest.register_on_respawnplayer(function(player)
|
||||
local player_name = player:get_player_name()
|
||||
stop_music_for_listener_name(player_name)
|
||||
end)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
name = mcl_music
|
||||
author = diminixed, horizonchris96, kay27
|
||||
description = Mod check some conditions and plays music
|
||||
depends = mcl_player, mcl_weather, mcl_worlds
|
|
@ -717,14 +717,19 @@ mcl_damage.register_modifier(function(obj, damage, reason)
|
|||
end
|
||||
if minetest.get_item_group(node.name, "water") ~= 0 then
|
||||
return 0
|
||||
elseif minetest.get_item_group(node.name, "no_fall_damage") ~= 0 then
|
||||
return 0
|
||||
elseif node.name == "mcl_portals:portal_end" then
|
||||
end
|
||||
if node.name == "mcl_portals:portal_end" then
|
||||
if mcl_portals and mcl_portals.end_teleport then
|
||||
mcl_portals.end_teleport(obj)
|
||||
end
|
||||
return 0
|
||||
end
|
||||
if node.name == "mcl_core:cobweb" then
|
||||
return 0
|
||||
end
|
||||
if node.name == "mcl_core:vine" then
|
||||
return 0
|
||||
end
|
||||
end
|
||||
pos = vector.add(pos, step)
|
||||
node = minetest.get_node(pos)
|
||||
|
|