forked from VoxeLibre/VoxeLibre
Compare commits
265 Commits
breath_rew
...
master
Author | SHA1 | Date |
---|---|---|
kno10 | 253a06fa08 | |
kno10 | dcfd31d17a | |
teknomunk | c34aecfcab | |
Mikita Wiśniewski | 9cb4f51468 | |
kno10 | d264ba70d8 | |
Mikita Wiśniewski | 513413afc7 | |
kno10 | 011be754ca | |
teknomunk | eea96867c4 | |
the-real-herowl | cd2ee49591 | |
seventeenthShulker | de3b34f5ea | |
seventeenthShulker | e2bcd129c1 | |
seventeenthShulker | 79e8452f62 | |
the-real-herowl | b239549774 | |
teknomunk | 0b62c827aa | |
teknomunk | 626bdd13d8 | |
teknomunk | 31a3788ce1 | |
teknomunk | e65370b845 | |
teknomunk | 6c50e0a82b | |
teknomunk | 8ef08128b1 | |
teknomunk | 15efd00a29 | |
teknomunk | fa3df0d8c6 | |
teknomunk | c41ce8ba59 | |
teknomunk | 4d58f63485 | |
teknomunk | fa09b65010 | |
teknomunk | d8d39ffd52 | |
teknomunk | b6aafedf25 | |
Mikita Wiśniewski | 178cb9340d | |
kno10 | f219e5f4ae | |
kno10 | 66b7a52d47 | |
WillConker | ce5eb8d88d | |
the-real-herowl | 6eb0d3c9d9 | |
teknomunk | 1707eef672 | |
SmallJoker | fb3e9dae84 | |
SmallJoker | 7f5b19cda8 | |
the-real-herowl | 7f372d066e | |
kno10 | f9290c6493 | |
kno10 | 52124bd201 | |
Mikita Wiśniewski | 19d662dee4 | |
the-real-herowl | 2be54212b7 | |
kno10 | 7d763b7257 | |
kno10 | bdd3ae2cd8 | |
kno10 | 2e1df31399 | |
kno10 | 382a35bb44 | |
kno10 | 0752ed17d8 | |
kno10 | 72c7489976 | |
kno10 | 71881154e9 | |
kno10 | 6c38823606 | |
kno10 | dd4898b319 | |
JoseDouglas26 | 38822aba0a | |
kno10 | d85febdb15 | |
Mikita Wiśniewski | fb4a6b0e7b | |
the-real-herowl | dd4f3d21eb | |
William Goodspeed | 2f25bc5277 | |
William Goodspeed | 5d0d93db0a | |
kno10 | ebee85db7e | |
kno10 | 593a095a5f | |
teknomunk | e9bf509c85 | |
kno10 | 444c491e14 | |
the-real-herowl | 05bfe5513f | |
codiac | 562a9d6d98 | |
cora | 0e4b8d9c27 | |
the-real-herowl | 93165a042b | |
teknomunk | 3e85736404 | |
teknomunk | f10827d0d6 | |
teknomunk | f9cd2500c0 | |
teknomunk | 64c04a2f0a | |
kno10 | ecfa42d51d | |
kno10 | 2dadfda76b | |
the-real-herowl | d888e832ae | |
teknomunk | 8e37f34b93 | |
teknomunk | 88be86ab4b | |
teknomunk | 316d5bf197 | |
teknomunk | bc00b8d11b | |
teknomunk | 0743112317 | |
teknomunk | 0a83c73fe0 | |
teknomunk | 8a3ef9d4c8 | |
teknomunk | 757d6761b2 | |
teknomunk | 15003b1c55 | |
teknomunk | 485bce3df6 | |
teknomunk | 66a3fcb33c | |
teknomunk | 38585154cd | |
teknomunk | 161655e87c | |
teknomunk | b072557a6a | |
teknomunk | 157d72b593 | |
teknomunk | 76b28a4fc5 | |
teknomunk | 92d823deaf | |
teknomunk | c65bd27ad8 | |
teknomunk | 398eb35858 | |
teknomunk | 763902a877 | |
teknomunk | 140d9014a0 | |
teknomunk | 043dc4487c | |
teknomunk | cf6ee14e13 | |
teknomunk | be69fdef8d | |
teknomunk | 6935bc2a18 | |
teknomunk | 37d6ba392c | |
teknomunk | 07bebe6c46 | |
teknomunk | 63036c8d41 | |
teknomunk | 45b8d36f73 | |
teknomunk | a44d8f43db | |
teknomunk | 55b5dee827 | |
teknomunk | adf64e81cd | |
teknomunk | 2b44abbceb | |
teknomunk | e9632b5317 | |
teknomunk | df42751ae6 | |
teknomunk | 576662d719 | |
teknomunk | 6b13612318 | |
teknomunk | 8861ad935b | |
teknomunk | 66a6d213ba | |
teknomunk | 7fc7758b62 | |
teknomunk | 7aa8a4dd11 | |
teknomunk | ec56e4ec1b | |
teknomunk | 3193bb5d93 | |
kno10 | 573269afab | |
kno10 | 12214c5bd6 | |
the-real-herowl | 6dad5afec5 | |
the-real-herowl | 508811d3b3 | |
SmokeyDope | 411cb2b9b9 | |
kno10 | 8fd736e0fd | |
kno10 | d2b96b6142 | |
the-real-herowl | a3cc105fa1 | |
teknomunk | 5b039f1855 | |
teknomunk | 7e832dc641 | |
the-real-herowl | 91cecca135 | |
JoseDouglas26 | 95653a0676 | |
JoseDouglas26 | b141f7c0a4 | |
the-real-herowl | cf9bbb0551 | |
teknomunk | aea9e6d182 | |
teknomunk | 09307292bc | |
teknomunk | e407e2e290 | |
teknomunk | 87a48270f5 | |
teknomunk | 21a88be2b2 | |
teknomunk | 37ff699a23 | |
teknomunk | 18266137b2 | |
teknomunk | 3667feddd3 | |
teknomunk | dc074ff555 | |
teknomunk | 0e1a2cbc1e | |
teknomunk | cb097d9bcd | |
Wbjitscool | cd213b75f7 | |
teknomunk | ef58a9809a | |
teknomunk | 3b01fe20ba | |
teknomunk | d34c804ebf | |
teknomunk | 03faa7764d | |
teknomunk | 207c86b813 | |
teknomunk | cf4b1dbd1d | |
teknomunk | 7811e23611 | |
teknomunk | 24ff7347b2 | |
teknomunk | 820848fb2e | |
teknomunk | f2a638f8e9 | |
teknomunk | 161dd7d379 | |
the-real-herowl | d0e8b4141d | |
cora | 15fa3ff775 | |
WillConker | 11168f226a | |
teknomunk | 2ad59c6df9 | |
the-real-herowl | 948da34755 | |
WillConker | 406e0e8169 | |
the-real-herowl | 09aba760cf | |
William Goodspeed | a6136ad158 | |
William Goodspeed | 77bcf6cff3 | |
WillConker | 293eb6d021 | |
the-real-herowl | 1c5f7d05fe | |
seventeenthShulker | f8fcd9954f | |
seventeenthShulker | 8b9666137d | |
seventeenthShulker | b3087118fa | |
seventeenthShulker | b79a19f4d6 | |
seventeenthShulker | b0b5cc1265 | |
seventeenthShulker | b237c4642d | |
seventeenthShulker | 49b2491b70 | |
seventeenthShulker | 0408f9c3d8 | |
seventeenthShulker | cbafdfa585 | |
seventeenthShulker | 2312989503 | |
seventeenthShulker | 1471ad7181 | |
seventeenthShulker | 38d7609173 | |
seventeenthShulker | 5bce56cdd6 | |
seventeenthShulker | 7a05c32198 | |
seventeenthShulker | ff386e395f | |
the-real-herowl | a687ef19f6 | |
William Goodspeed | c03f9abd18 | |
William Goodspeed | 9657c9d8bb | |
blitzdoughnuts | 95aadd40b9 | |
THE-NERD2 | 86e3446407 | |
William Goodspeed | ee4d1efaa5 | |
kno10 | 5e6e4967f0 | |
kno10 | df60ec947d | |
kno10 | 02cb0818a1 | |
kno10 | 77382d930e | |
the-real-herowl | 5e366a8916 | |
WillConker | 6c614d8376 | |
WillConker | a785be59d9 | |
cora | f23014005f | |
cora | c2098d777f | |
cora | dc07eea590 | |
tacotexmex | 3460e27468 | |
OgelGames | 0012bdb71e | |
kno10 | b8d7139792 | |
WillConker | cddc1982be | |
kno10 | 9595b0df59 | |
WillConker | ff21d1eab1 | |
WillConker | 9d5b46c28a | |
kno10 | 80a6a6efb0 | |
the-real-herowl | 32148262e1 | |
Mikita Wiśniewski | 567d112942 | |
Mikita Wiśniewski | 347305eaea | |
Mikita Wiśniewski | 508bc19f6a | |
Mikita Wiśniewski | c1e9e4b1a2 | |
Mikita Wiśniewski | 7bf15642ca | |
Mikita Wiśniewski | f1fa6240bb | |
Mikita Wiśniewski | c5bc6ff189 | |
Mikita Wiśniewski | 70e903b716 | |
Mikita Wiśniewski | 209b24a2fb | |
cora | ac05f8bad6 | |
Mikita Wiśniewski | 76cff76d91 | |
Mikita Wiśniewski | 49b6d09985 | |
Mikita Wiśniewski | a66c35a9ea | |
Mikita Wiśniewski | a28e55160f | |
Mikita Wiśniewski | 6bbb6b8dec | |
Mikita Wiśniewski | b4b5bf8391 | |
Mikita Wiśniewski | 16dd8694a6 | |
Jürgen Rühle | 7a5ee4e6e2 | |
Jürgen Rühle | d0d9600709 | |
cora | 709b73295c | |
Mikita Wiśniewski | 1d77017ca9 | |
Mikita Wiśniewski | d6d64d8837 | |
Mikita Wiśniewski | e771f0e3ff | |
Mikita Wiśniewski | b10bfe27ce | |
Mikita Wiśniewski | d5b3a6f658 | |
JoseDouglas26 | f7ee3b59d7 | |
the-real-herowl | 1745b6d400 | |
teknomunk | bb9ed4498b | |
teknomunk | 94981d9c09 | |
teknomunk | 7ae05d9c06 | |
teknomunk | 177e8f4b9d | |
the-real-herowl | 026ea5940c | |
the-real-herowl | be9fece0d3 | |
the-real-herowl | 27f8a008c3 | |
the-real-herowl | 8bbceddbc2 | |
the-real-herowl | 6e70c760d6 | |
the-real-herowl | 53802b270d | |
teknomunk | 3928e12634 | |
teknomunk | 304550d90c | |
teknomunk | 0a2336ad82 | |
teknomunk | 75a767a0ab | |
teknomunk | 7e0afd7e21 | |
teknomunk | 15fa925aae | |
teknomunk | 4935f5fdda | |
teknomunk | 41032ec999 | |
teknomunk | d64ee18f75 | |
teknomunk | 1942384fe5 | |
teknomunk | 9b50dd6565 | |
teknomunk | a88951ac6a | |
teknomunk | bc343769ee | |
seventeenthShulker | 8aa65f85f2 | |
qoheniac | e27e70a91b | |
JoseDouglas26 | 744b47088b | |
Mikita Wiśniewski | 6654c86fb2 | |
the-real-herowl | 72435933e4 | |
the-real-herowl | 35e14dd415 | |
the-real-herowl | 173f8a0bca | |
teknomunk | 1f32b47208 | |
SmokeyDope | bf67fd52e1 | |
WillConker | fd4e1484af | |
teknomunk | 1b0deae026 | |
teknomunk | 313c1f558b | |
teknomunk | 5cafa97dd1 | |
teknomunk | ddab68b87c | |
JoseDouglas26 | 2dafbae64b |
|
@ -13,16 +13,17 @@ labels:
|
|||
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
|
||||
https://git.minetest.land/VoxeLibre/VoxeLibre/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
|
||||
https://git.minetest.land/VoxeLibre/VoxeLibre/src/branch/master/CODE_OF_CONDUCT.md
|
||||
-->
|
||||
|
||||
<!--
|
||||
What version of VoxeLibre are you using? We do not provide support for outdated versions of VoxeLibre.
|
||||
"/ver" command will output the version you're running.
|
||||
Current latest version is listed here, at the top:
|
||||
https://git.minetest.land/MineClone2/MineClone2/tags
|
||||
https://git.minetest.land/VoxeLibre/VoxeLibre/tags
|
||||
-->
|
||||
VoxeLibre version:
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
|
||||
name: "Feature request"
|
||||
about: "File a feature request not in Minecraft"
|
||||
about: "File a feature request"
|
||||
labels:
|
||||
|
||||
- "non-Minecraft feature"
|
||||
|
@ -10,17 +10,17 @@ labels:
|
|||
---
|
||||
|
||||
<!--
|
||||
Got a new non-Minecraft feature request? Explain to us why we should consider your idea.
|
||||
Got a new 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
|
||||
https://git.minetest.land/VoxeLibre/VoxeLibre/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
|
||||
https://git.minetest.land/VoxeLibre/VoxeLibre/src/branch/master/CODE_OF_CONDUCT.md
|
||||
-->
|
||||
|
||||
### Feature
|
||||
Tell us about your requested feature not in Minecraft!
|
||||
Tell us about your requested feature!
|
||||
|
||||
### Why
|
||||
Tell us why should we implement it!
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
---
|
||||
|
||||
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 VoxeLibre
|
||||
Tell us about the feature currently in VoxeLibre! What is different?
|
|
@ -8,13 +8,13 @@ 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
|
||||
https://git.minetest.land/VoxeLibre/VoxeLibre/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
|
||||
https://git.minetest.land/VoxeLibre/VoxeLibre/src/branch/master/CODE_OF_CONDUCT.md
|
||||
-->
|
||||
|
||||
Tell us about your pull request! Reference related issues, if necessary
|
||||
Tell us about your pull request! Reference related issues, if necessary.
|
||||
|
||||
### Testing
|
||||
Tell us how to test your changes!
|
||||
|
|
|
@ -20,10 +20,8 @@
|
|||
* epCode
|
||||
* chmodsayshello
|
||||
* MrRar
|
||||
* FossFanatic
|
||||
* SmokeyDope
|
||||
* Faerraven / Michieal
|
||||
* Codiac
|
||||
* rudzik8
|
||||
* teknomunk
|
||||
|
||||
|
@ -36,6 +34,8 @@
|
|||
* NO11
|
||||
* SumianVoice
|
||||
* PrairieWind
|
||||
* FossFanatic
|
||||
* Codiac
|
||||
|
||||
## Contributors
|
||||
* RandomLegoBrick
|
||||
|
@ -140,6 +140,7 @@
|
|||
* SOS-Games
|
||||
* Bram
|
||||
* qoheniac
|
||||
* WillConker
|
||||
|
||||
## Music
|
||||
* Jordach for the jukebox music compilation from Big Freaking Dig
|
||||
|
|
3
LEGAL.md
3
LEGAL.md
|
@ -46,6 +46,9 @@ Armor trim models were created by Aeonix_Aeon
|
|||
Source: <https://www.curseforge.com/minecraft/texture-packs/ozocraft-remix>
|
||||
License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)
|
||||
|
||||
Charcoal block texture was created by [blitzdoughnuts](https://gitlab.com/ApplemunchFromDaDead), based on the Pixel Perfection coal block.
|
||||
License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)
|
||||
|
||||
The main menu images are released under: [CC0](https://creativecommons.org/publicdomain/zero/1.0/)
|
||||
|
||||
All other files, unless mentioned otherwise, fall under:
|
||||
|
|
|
@ -83,7 +83,7 @@ The VoxeLibre repository is hosted at Mesehub. To contribute or report issues, h
|
|||
* Discord: <https://discord.gg/xE4z8EEpDC>
|
||||
* YouTube: <https://www.youtube.com/channel/UClI_YcsXMF3KNeJtoBfnk9A>
|
||||
* ContentDB: <https://content.minetest.net/packages/wuzzy/mineclone2/>
|
||||
* OpenCollective: <https://opencollective.com/mineclone2>
|
||||
* OpenCollective: <https://opencollective.com/voxelibre>
|
||||
* Mastodon: <https://fosstodon.org/@VoxeLibre>
|
||||
* Lemmy: <https://lemm.ee/c/voxelibre>
|
||||
* Matrix space: <https://app.element.io/#/room/#voxelibre:matrix.org>
|
||||
|
|
|
@ -117,10 +117,6 @@ end
|
|||
-- Array of unique hardness values for each group which affects dig time.
|
||||
local hardness_values = get_hardness_values_for_groups()
|
||||
|
||||
-- Map indexed by hardness values which return the index of that value in
|
||||
-- hardness_value. Used for quick lookup.
|
||||
local hardness_lookup = get_hardness_lookup_for_groups(hardness_values)
|
||||
|
||||
--[[local function compute_creativetimes(group)
|
||||
local creativetimes = {}
|
||||
|
||||
|
@ -186,6 +182,7 @@ local function add_groupcaps(toolname, groupcaps, groupcaps_def, efficiency)
|
|||
local mult = capsdef.speed or 1
|
||||
local uses = capsdef.uses
|
||||
local def = mcl_autogroup.registered_diggroups[g]
|
||||
assert(def, toolname .. " has unknown diggroup '" .. dump(g) .. "'")
|
||||
local max_level = def.levels and #def.levels or 1
|
||||
|
||||
assert(capsdef.level, toolname .. ' is missing level for ' .. g)
|
||||
|
@ -313,6 +310,13 @@ function mcl_autogroup.get_wear(toolname, diggroup)
|
|||
end
|
||||
|
||||
local function overwrite()
|
||||
-- Refresh, now that all groups are known.
|
||||
hardness_values = get_hardness_values_for_groups()
|
||||
|
||||
-- Map indexed by hardness values which return the index of that value in
|
||||
-- hardness_value. Used for quick lookup.
|
||||
local hardness_lookup = get_hardness_lookup_for_groups(hardness_values)
|
||||
|
||||
for nname, ndef in pairs(minetest.registered_nodes) do
|
||||
local newgroups = table.copy(ndef.groups)
|
||||
if (nname ~= "ignore" and ndef.diggable) then
|
||||
|
@ -374,4 +378,5 @@ local function overwrite()
|
|||
end
|
||||
end
|
||||
|
||||
overwrite()
|
||||
-- Make sure all tools and groups are registered
|
||||
minetest.register_on_mods_loaded(overwrite)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
name = _mcl_autogroup
|
||||
depends = mcl_autogroup
|
||||
author = ryvnf
|
||||
description = VoxeLibre core mod which automatically adds groups to all items. Very important for digging times.
|
||||
|
|
|
@ -2,33 +2,33 @@
|
|||
Simple flow functions.
|
||||
|
||||
## flowlib.is_touching(realpos, nodepos, radius)
|
||||
Return true if a sphere of <radius> at <realpos> collide with node at <nodepos>.
|
||||
Return true if a sphere of `radius` at `realpos` collide with node at `nodepos`.
|
||||
* realpos: position
|
||||
* nodepos: position
|
||||
* radius: number
|
||||
|
||||
## flowlib.is_water(pos)
|
||||
Return true if node at <pos> is water, false overwise.
|
||||
Return true if node at `pos` is water, false otherwise.
|
||||
* pos: position
|
||||
|
||||
## flowlib.node_is_water(node)
|
||||
Return true if <node> is water, false overwise.
|
||||
Return true if `node` is water, false otherwise.
|
||||
* node: node
|
||||
|
||||
## flowlib.is_lava(pos)
|
||||
Return true if node at <pos> is lava, false overwise.
|
||||
Return true if node at `pos` is lava, false otherwise.
|
||||
* pos: position
|
||||
|
||||
## flowlib.node_is_lava(node)
|
||||
Return true if <node> is lava, false overwise.
|
||||
Return true if `node` is lava, false otherwise.
|
||||
* node: node
|
||||
|
||||
## flowlib.is_liquid(pos)
|
||||
Return true if node at <pos> is liquid, false overwise.
|
||||
Return true if node at `pos` is liquid, false otherwise.
|
||||
* pos: position
|
||||
|
||||
## flowlib.node_is_liquid(node)
|
||||
Return true if <node> is liquid, false overwise.
|
||||
Return true if `node` is liquid, false otherwise.
|
||||
* node: node
|
||||
|
||||
## flowlib.quick_flow(pos, node)
|
||||
|
@ -37,9 +37,9 @@ Return direction where the water is flowing (to be use to push mobs, items...).
|
|||
* node: node
|
||||
|
||||
## flowlib.move_centre(pos, realpos, node, radius)
|
||||
Return the pos of the nearest not water block near from <pos> in a sphere of <radius> at <realpos>.
|
||||
WARNING: This function is never used in mcl2, use at your own risk. The informations described here may be wrong.
|
||||
Return the pos of the nearest not water block near from `pos` in a sphere of `radius` at `realpos`.
|
||||
WARNING: This function is never used in VL, use at your own risk. The informations described here may be wrong.
|
||||
* pos: position
|
||||
* realpos: position, position of the entity
|
||||
* node: node
|
||||
* radius: number
|
||||
* radius: number
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# mcl_autogroup
|
||||
This mod emulate digging times from mc.
|
||||
This mod emulates digging times from MC.
|
||||
|
||||
## mcl_autogroup.can_harvest(nodename, toolname, player)
|
||||
Return true if <nodename> can be dig with <toolname> by <player>.
|
||||
Return true if `nodename` can be dig with `toolname` by <player>.
|
||||
* nodename: string, valid nodename
|
||||
* toolname: (optional) string, valid toolname
|
||||
* player: (optinal) ObjectRef, valid player
|
||||
|
@ -14,7 +14,7 @@ WARNING: This function can only be called after mod initialization.
|
|||
* efficiency: (optional) integer, the efficiency level the tool is enchanted with (default 0)
|
||||
|
||||
## mcl_autogroup.get_wear(toolname, diggroup)
|
||||
Return the max wear of <toolname> with <diggroup>
|
||||
Return the max wear of `toolname` with `diggroup`
|
||||
WARNING: This function can only be called after mod initialization.
|
||||
* toolname: string, name of the tool used
|
||||
* diggroup: string, the name of the diggroup the tool is used on
|
||||
|
@ -25,4 +25,4 @@ WARNING: This function can only be called after mod initialization.
|
|||
* level: (optional) string, if specified it is an array containing the names of the different digging levels the digging group supports
|
||||
|
||||
## mcl_autogroup.registered_diggroups
|
||||
List of registered diggroups, indexed by name.
|
||||
List of registered diggroups, indexed by name.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# mcl_colors
|
||||
Mod providing global table containing legacity minecraft colors to be used in mods.
|
||||
Mod providing global table containing legacy Minecraft colors to be used in mods.
|
||||
|
||||
## mcl_colors.*
|
||||
Colors by upper name, in hex value.
|
||||
|
|
|
@ -6,10 +6,10 @@ WARNING: Not using it inside your mods may cause strange bugs (using the native
|
|||
|
||||
## Callbacks
|
||||
|
||||
To modify the amount of damage made by something:
|
||||
To modify the amount of damage dealt by something:
|
||||
|
||||
```lua
|
||||
--obj: an ObjectRef
|
||||
mcl_damage.register_modifier(function(obj, damage, reason)
|
||||
end, 0)
|
||||
```
|
||||
```
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
## mcl_events
|
||||
### Registering Events
|
||||
`mlc_events.register_event("name",def)`
|
||||
# mcl_events
|
||||
|
||||
#### Event Definition
|
||||
{
|
||||
## Registering Events
|
||||
|
||||
`mcl_events.register_event("name", def)`
|
||||
|
||||
### Event Definition
|
||||
|
||||
```
|
||||
{
|
||||
stage = 0,
|
||||
max_stage = 1,
|
||||
percent = 100,
|
||||
|
@ -22,6 +26,8 @@
|
|||
cond_complete = function(event) end,
|
||||
--return true if event finished successfully
|
||||
}
|
||||
```
|
||||
|
||||
### Debugging
|
||||
* /event_start <event> -- starts the given event at the current player coordinates
|
||||
## Debugging
|
||||
|
||||
* /event_start `event` -- starts the given event at the current player coordinates
|
||||
|
|
|
@ -3,13 +3,13 @@ This mod provide helper functions to create explosions.
|
|||
|
||||
## mcl_explosions.explode(pos, strength, info, puncher)
|
||||
* pos: position, initial position of the explosion
|
||||
* strenght: number, radius of the explosion
|
||||
* strength: number, radius of the explosion
|
||||
* info: table, explosion informations:
|
||||
* drop_chance: number, if specified becomes the drop chance of all nodes in the explosion (default: 1.0 / strength)
|
||||
* max_blast_resistance: int, if specified the explosion will treat all non-indestructible nodes as having a blast resistance of no more than this value
|
||||
* sound: bool, if true, the explosion will play a sound (default: true)
|
||||
* particles: bool, if true, the explosion will create particles (default: true)
|
||||
* fire: bool, if true, 1/3 nodes become fire (default: false)
|
||||
* fire: bool, if true, 1/3 of nodes become fire (default: false)
|
||||
* griefing: bool, if true, the explosion will destroy nodes (default: true)
|
||||
* grief_protected: bool, if true, the explosion will also destroy nodes which have been protected (default: false)
|
||||
* puncher: (optional) entity, will be used as source for damage done by the explosion
|
||||
* puncher: (optional) entity, will be used as source for damage done by the explosion
|
||||
|
|
|
@ -48,6 +48,20 @@ function table.pairs_by_keys(t, f)
|
|||
return iter
|
||||
end
|
||||
|
||||
-- Removes one element randomly selected from the array section of the table and
|
||||
-- returns it, or nil if there are no elements in the array section of the table
|
||||
function table.remove_random_element(table)
|
||||
local count = #table
|
||||
if count == 0 then return nil end
|
||||
|
||||
local idx = math.random(count)
|
||||
local res = table[idx]
|
||||
table[idx] = table[count]
|
||||
table[count] = nil
|
||||
count = count - 1
|
||||
return res
|
||||
end
|
||||
|
||||
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_default", false)
|
||||
local LOG_MODULE = "[MCL2]"
|
||||
function mcl_util.mcl_log(message, module, bypass_default_logger)
|
||||
|
@ -1103,3 +1117,17 @@ function mcl_util.is_it_christmas()
|
|||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_util.to_bool(val)
|
||||
if not val then return false end
|
||||
return true
|
||||
end
|
||||
|
||||
if not vector.in_area then
|
||||
-- backport from minetest 5.8, can be removed when the minimum version is 5.8
|
||||
vector.in_area = function(pos, min, max)
|
||||
return (pos.x >= min.x) and (pos.x <= max.x) and
|
||||
(pos.y >= min.y) and (pos.y <= max.y) and
|
||||
(pos.z >= min.z) and (pos.z <= max.z)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,20 +5,21 @@ This mod provides utility functions about positions and dimensions.
|
|||
This function returns:
|
||||
|
||||
* true, true: if pos is in deep void (deadly)
|
||||
* true, false: if the pos is in void (non deadly)
|
||||
* false, false: owerwise
|
||||
* true, false: if the pos is in void (non-deadly)
|
||||
* false, false: otherwise
|
||||
|
||||
Params:
|
||||
|
||||
* pos: position
|
||||
|
||||
## mcl_worlds.y_to_layer(y)
|
||||
This function is used to calculate the minetest y layer and dimension of the given <y> minecraft layer.
|
||||
This function is used to calculate the Minetest y layer and dimension of the given y Minecraft layer.
|
||||
Mainly used for ore generation.
|
||||
Takes an Y coordinate as input and returns:
|
||||
Takes a Y coordinate as input and returns:
|
||||
|
||||
* The corresponding Minecraft layer (can be `nil` if void)
|
||||
* The corresponding Minecraft dimension ("overworld", "nether" or "end") or "void" if y is in the void
|
||||
|
||||
* The corresponding Minecraft layer (can be nil if void)
|
||||
* The corresponding Minecraft dimension ("overworld", "nether" or "end") or "void" if <y> is in the void
|
||||
If the Y coordinate is not located in any dimension, it will return: nil, "void"
|
||||
|
||||
Params:
|
||||
|
@ -26,7 +27,7 @@ Params:
|
|||
* y: int
|
||||
|
||||
## mcl_worlds.pos_to_dimension(pos)
|
||||
This function return the Minecraft dimension of <pos> ("overworld", "nether" or "end") or "void" if <y> is in the void.
|
||||
This function return the Minecraft dimension of pos ("overworld", "nether" or "end") or "void" if y is in the void.
|
||||
|
||||
* pos: position
|
||||
|
||||
|
@ -38,31 +39,32 @@ mc_dimension can be "overworld", "nether", "end" (default: "overworld").
|
|||
* mc_dimension: string
|
||||
|
||||
## mcl_worlds.has_weather(pos)
|
||||
Returns true if <pos> can have weather, false owerwise.
|
||||
Returns true if pos can have weather, false otherwise.
|
||||
Weather can be only in the overworld.
|
||||
|
||||
* pos: position
|
||||
|
||||
## mcl_worlds.has_dust(pos)
|
||||
Returns true if <pos> can have nether dust, false owerwise.
|
||||
Returns true if pos can have nether dust, false otherwise.
|
||||
Nether dust can be only in the nether.
|
||||
|
||||
* pos: position
|
||||
|
||||
## mcl_worlds.compass_works(pos)
|
||||
Returns true if compasses are working at <pos>, false owerwise.
|
||||
In mc, you cant use compass in the nether and the end.
|
||||
Returns true if compasses are working at pos, false otherwise.
|
||||
In MC, you cant use compass in the nether and the end.
|
||||
|
||||
* pos: position
|
||||
|
||||
## mcl_worlds.compass_works(pos)
|
||||
Returns true if clock are working at <pos>, false owerwise.
|
||||
In mc, you cant use clock in the nether and the end.
|
||||
Returns true if clock are working at pos, false otherwise.
|
||||
In MC, you cant use clock in the nether and the end.
|
||||
|
||||
* pos: position
|
||||
|
||||
## mcl_worlds.register_on_dimension_change(function(player, dimension, last_dimension))
|
||||
Register a callback function func(player, dimension).
|
||||
|
||||
It will be called whenever a player changes between dimensions.
|
||||
The void counts as dimension.
|
||||
|
||||
|
@ -75,7 +77,7 @@ The void counts as dimension.
|
|||
Table containing all function registered with mcl_worlds.register_on_dimension_change()
|
||||
|
||||
## mcl_worlds.dimension_change(player, dimension)
|
||||
Notify this mod of a dimension change of <player> to <dimension>
|
||||
Notify this mod of a dimension change of player to dimension
|
||||
|
||||
* player: player, player who changed the dimension
|
||||
* dimension: string, new dimension ("overworld", "nether", "end", "void")
|
||||
|
|
|
@ -10,3 +10,14 @@ Rightclick on a water source to place the boat. Rightclick the boat to enter it.
|
|||
Spruce Boat=Fichtenboot
|
||||
Water vehicle=Wasserfahrzeug
|
||||
Sneak to dismount=Zum Aussteigen schleichen
|
||||
Obsidian Boat=Obsidianboot
|
||||
Mangrove Boat=
|
||||
Cherry Boat=Kirschholzboot
|
||||
Oak Chest Boat=Eichentruhenboot
|
||||
Spruce Chest Boat=
|
||||
Birch Chest Boat=Birkentruhenboot
|
||||
Jungle Chest Boat=Dschungeltruhenboot
|
||||
Acacia Chest Boat=
|
||||
Dark Oak Chest Boat=
|
||||
Mangrove Chest Boat=
|
||||
Cherry Chest Boat=
|
||||
|
|
|
@ -29,7 +29,7 @@ local function make_drop(pos, liquid, sound, interval, texture)
|
|||
pt.expirationtime = t
|
||||
|
||||
pt.texture = "[combine:2x2:" ..
|
||||
-math.random(1, 16) .. "," .. -math.random(1, 16) .. "=" .. texture
|
||||
math.random(-14, 0) .. "," .. math.random(-14, 0) .. "=" .. texture
|
||||
|
||||
minetest.add_particle(pt)
|
||||
|
||||
|
|
|
@ -136,6 +136,7 @@ local function try_object_pickup(player, inv, object, checkpos)
|
|||
-- Destroy entity
|
||||
-- This just prevents this section to be run again because object:remove() doesn't remove the item immediately.
|
||||
le.target = checkpos
|
||||
le.itemstring = ""
|
||||
le._removed = true
|
||||
|
||||
-- Stop the object
|
||||
|
@ -320,6 +321,7 @@ function minetest.handle_node_drops(pos, drops, digger)
|
|||
if tool and nodedef._mcl_fortune_drop and enchantments.fortune then
|
||||
local fortune_level = enchantments.fortune
|
||||
local fortune_drop = nodedef._mcl_fortune_drop
|
||||
local simple_drop = nodedef._mcl_fortune_drop.drop_without_fortune
|
||||
if fortune_drop.discrete_uniform_distribution then
|
||||
local min_count = fortune_drop.min_count
|
||||
local max_count = fortune_drop.max_count + fortune_level * (fortune_drop.factor or 1)
|
||||
|
@ -335,6 +337,12 @@ function minetest.handle_node_drops(pos, drops, digger)
|
|||
local drop = get_fortune_drops(fortune_drop, fortune_level)
|
||||
drops = get_drops(drop, tool:get_name(), dug_node.param2, nodedef.paramtype2)
|
||||
end
|
||||
|
||||
if simple_drop then
|
||||
for _, item in pairs(simple_drop) do
|
||||
table.insert(drops, item)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if digger and mcl_experience.throw_xp and not silk_touch_drop then
|
||||
|
@ -957,6 +965,7 @@ minetest.register_entity(":__builtin:item", {
|
|||
self.random_velocity = 0
|
||||
self:set_item(own_stack:to_string())
|
||||
|
||||
entity.itemstring = ""
|
||||
entity._removed = true
|
||||
object:remove()
|
||||
return true
|
||||
|
|
|
@ -18,7 +18,7 @@ mcl_mobs.invis = {}
|
|||
local remove_far = true
|
||||
|
||||
local mobs_debug = minetest.settings:get_bool("mobs_debug", false) -- Shows helpful debug info above each mob
|
||||
local spawn_logging = minetest.settings:get_bool("mcl_logging_mobs_spawn",true)
|
||||
local spawn_logging = minetest.settings:get_bool("mcl_logging_mobs_spawn", false)
|
||||
|
||||
local MAPGEN_LIMIT = mcl_vars.mapgen_limit
|
||||
local MAPGEN_MOB_LIMIT = MAPGEN_LIMIT - 90
|
||||
|
@ -150,6 +150,11 @@ function mob_class:mob_activate(staticdata, def, dtime)
|
|||
local tmp = minetest.deserialize(staticdata)
|
||||
|
||||
if tmp then
|
||||
-- Patch incorrectly converted mobs
|
||||
if tmp.base_mesh ~= minetest.registered_entities[self.name].mesh then
|
||||
mcl_mobs.strip_staticdata(tmp)
|
||||
end
|
||||
|
||||
for _,stat in pairs(tmp) do
|
||||
self[_] = stat
|
||||
end
|
||||
|
@ -383,7 +388,7 @@ end
|
|||
|
||||
|
||||
|
||||
local function on_step_work (self, dtime)
|
||||
local function on_step_work(self, dtime, moveresult)
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
|
||||
|
@ -397,7 +402,7 @@ local function on_step_work (self, dtime)
|
|||
-- Do we abandon out of here now?
|
||||
end
|
||||
|
||||
if self:falling(pos) then return end
|
||||
if self:falling(pos, moveresult) then return end
|
||||
if self:step_damage (dtime, pos) then return end
|
||||
|
||||
if self.state == "die" then return end
|
||||
|
@ -497,11 +502,11 @@ end
|
|||
|
||||
|
||||
-- main mob function
|
||||
function mob_class:on_step(dtime)
|
||||
function mob_class:on_step(dtime, moveresult)
|
||||
if not DEVELOPMENT then
|
||||
-- Removed as bundled Lua (5.1 doesn't support xpcall)
|
||||
--local status, retVal = xpcall(on_step_work, on_step_error_handler, self, dtime)
|
||||
local status, retVal = pcall(on_step_work, self, dtime)
|
||||
local status, retVal = pcall(on_step_work, self, dtime, moveresult)
|
||||
if status then
|
||||
return retVal
|
||||
else
|
||||
|
@ -516,7 +521,7 @@ function mob_class:on_step(dtime)
|
|||
log_error (dump(retVal), dump(pos), dump(self))
|
||||
end
|
||||
else
|
||||
return on_step_work (self, dtime)
|
||||
return on_step_work (self, dtime, moveresult)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ end
|
|||
|
||||
-- Spawn a child
|
||||
function mcl_mobs.spawn_child(pos, mob_type)
|
||||
local child = minetest.add_entity(pos, mob_type)
|
||||
local child = mcl_mobs.spawn(pos, mob_type)
|
||||
if not child then
|
||||
return
|
||||
end
|
||||
|
@ -285,6 +285,7 @@ function mob_class:check_breeding()
|
|||
end
|
||||
|
||||
local child = mcl_mobs.spawn_child(pos, parent1.name)
|
||||
if not child then return end
|
||||
|
||||
local ent_c = child:get_luaentity()
|
||||
|
||||
|
|
|
@ -802,34 +802,37 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
|
|||
end
|
||||
|
||||
-- alert others to the attack
|
||||
local objs = minetest.get_objects_inside_radius(hitter:get_pos(), self.view_range)
|
||||
local obj = nil
|
||||
local alert_pos = hitter:get_pos()
|
||||
if alert_pos then
|
||||
local objs = minetest.get_objects_inside_radius(alert_pos, self.view_range)
|
||||
local obj = nil
|
||||
|
||||
for n = 1, #objs do
|
||||
for n = 1, #objs do
|
||||
|
||||
obj = objs[n]:get_luaentity()
|
||||
obj = objs[n]:get_luaentity()
|
||||
|
||||
if obj then
|
||||
-- only alert members of same mob or friends
|
||||
if obj.group_attack
|
||||
and obj.state ~= "attack"
|
||||
and obj.owner ~= name then
|
||||
if obj.name == self.name then
|
||||
obj:do_attack(hitter)
|
||||
elseif type(obj.group_attack) == "table" then
|
||||
for i=1, #obj.group_attack do
|
||||
if obj.group_attack[i] == self.name then
|
||||
obj._aggro = true
|
||||
obj:do_attack(hitter)
|
||||
break
|
||||
if obj then
|
||||
-- only alert members of same mob or friends
|
||||
if obj.group_attack
|
||||
and obj.state ~= "attack"
|
||||
and obj.owner ~= name then
|
||||
if obj.name == self.name then
|
||||
obj:do_attack(hitter)
|
||||
elseif type(obj.group_attack) == "table" then
|
||||
for i=1, #obj.group_attack do
|
||||
if obj.group_attack[i] == self.name then
|
||||
obj._aggro = true
|
||||
obj:do_attack(hitter)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- have owned mobs attack player threat
|
||||
if obj.owner == name and obj.owner_loyal then
|
||||
obj:do_attack(self.object)
|
||||
-- have owned mobs attack player threat
|
||||
if obj.owner == name and obj.owner_loyal then
|
||||
obj:do_attack(self.object)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -342,13 +342,33 @@ function mcl_mobs.register_mob(name, def)
|
|||
minetest.register_entity(name, setmetatable(final_def,mcl_mobs.mob_class_meta))
|
||||
end -- END mcl_mobs.register_mob function
|
||||
|
||||
|
||||
local STRIP_FIELDS = { "mesh", "base_size", "textures", "base_mesh", "base_texture" }
|
||||
function mcl_mobs.strip_staticdata(unpacked_staticdata)
|
||||
-- Strip select fields from the staticdata to prevent conversion issues
|
||||
for i = 1,#STRIP_FIELDS do
|
||||
unpacked_staticdata[STRIP_FIELDS[i]] = nil
|
||||
end
|
||||
end
|
||||
function mcl_mobs.register_conversion(old_name, new_name)
|
||||
minetest.register_entity(old_name, {
|
||||
on_activate = function(self, staticdata, dtime)
|
||||
local obj = minetest.add_entity(self.object:get_pos(), new_name, staticdata)
|
||||
local hook = (obj:get_luaentity() or {})._on_after_convert
|
||||
if hook then hook(obj) end
|
||||
self.object:remove()
|
||||
local unpacked_staticdata = minetest.deserialize(staticdata)
|
||||
mcl_mobs.strip_staticdata(unpacked_staticdata)
|
||||
staticdata = minetest.serialize(unpacked_staticdata)
|
||||
|
||||
local old_object = self.object
|
||||
if not old_object then return end
|
||||
|
||||
local pos = old_object:get_pos()
|
||||
if not pos then return end
|
||||
old_object:remove()
|
||||
|
||||
local new_object = minetest.add_entity(pos, new_name, staticdata)
|
||||
if not new_object then return end
|
||||
|
||||
local hook = (new_object:get_luaentity() or {})._on_after_convert
|
||||
if hook then hook(new_object) end
|
||||
end,
|
||||
_convert_to = new_name,
|
||||
})
|
||||
|
@ -508,7 +528,7 @@ end
|
|||
-- Note: This also introduces the “spawn_egg” group:
|
||||
-- * spawn_egg=1: Spawn egg (generic mob, no metadata)
|
||||
-- * spawn_egg=2: Spawn egg (captured/tamed mob, metadata)
|
||||
function mcl_mobs.register_egg(mob, desc, background_color, overlay_color, addegg, no_creative)
|
||||
function mcl_mobs.register_egg(mob_id, desc, background_color, overlay_color, addegg, no_creative)
|
||||
|
||||
local grp = {spawn_egg = 1}
|
||||
|
||||
|
@ -519,7 +539,7 @@ function mcl_mobs.register_egg(mob, desc, background_color, overlay_color, addeg
|
|||
|
||||
local invimg = "(spawn_egg.png^[multiply:" .. background_color ..")^(spawn_egg_overlay.png^[multiply:" .. overlay_color .. ")"
|
||||
if old_spawn_icons then
|
||||
local mobname = mob:gsub("mobs_mc:","")
|
||||
local mobname = mob_id:gsub("mobs_mc:","")
|
||||
local fn = "mobs_mc_spawn_icon_"..mobname..".png"
|
||||
if mcl_util.file_exists(minetest.get_modpath("mobs_mc").."/textures/"..fn) then
|
||||
invimg = fn
|
||||
|
@ -531,7 +551,7 @@ function mcl_mobs.register_egg(mob, desc, background_color, overlay_color, addeg
|
|||
end
|
||||
|
||||
-- register old stackable mob egg
|
||||
minetest.register_craftitem(mob, {
|
||||
minetest.register_craftitem(mob_id, {
|
||||
|
||||
description = desc,
|
||||
inventory_image = invimg,
|
||||
|
@ -541,7 +561,6 @@ function mcl_mobs.register_egg(mob, desc, background_color, overlay_color, addeg
|
|||
_doc_items_usagehelp = S("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."),
|
||||
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
|
||||
local pos = pointed_thing.above
|
||||
|
||||
-- am I clicking on something with existing on_rightclick function?
|
||||
|
@ -551,11 +570,12 @@ function mcl_mobs.register_egg(mob, desc, background_color, overlay_color, addeg
|
|||
return def.on_rightclick(pointed_thing.under, under, placer, itemstack)
|
||||
end
|
||||
|
||||
local mob_name = itemstack:get_name()
|
||||
|
||||
if pos and within_limits(pos, 0) and not minetest.is_protected(pos, placer:get_player_name()) then
|
||||
local name = placer:get_player_name()
|
||||
local privs = minetest.get_player_privs(name)
|
||||
|
||||
|
||||
if under.name == "mcl_mobspawners:spawner" then
|
||||
if minetest.is_protected(pointed_thing.under, name) then
|
||||
minetest.record_protection_violation(pointed_thing.under, name)
|
||||
|
@ -572,26 +592,35 @@ function mcl_mobs.register_egg(mob, desc, background_color, overlay_color, addeg
|
|||
--minetest.log("min light: " .. mob_light_lvl[1])
|
||||
--minetest.log("max light: " .. mob_light_lvl[2])
|
||||
|
||||
mcl_mobspawners.setup_spawner(pointed_thing.under, itemstack:get_name(), mob_light_lvl[1], mob_light_lvl[2])
|
||||
-- Handle egg conversion
|
||||
local convert_to = (minetest.registered_entities[mob_name] or {})._convert_to
|
||||
if convert_to then mob_name = convert_to end
|
||||
|
||||
mcl_mobspawners.setup_spawner(pointed_thing.under, mob_name, mob_light_lvl[1], mob_light_lvl[2])
|
||||
if not minetest.is_creative_enabled(name) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
|
||||
if not minetest.registered_entities[mob] then
|
||||
if not minetest.registered_entities[mob_name] then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
if minetest.settings:get_bool("only_peaceful_mobs", false)
|
||||
and minetest.registered_entities[mob].type == "monster" then
|
||||
and minetest.registered_entities[mob_name].type == "monster" then
|
||||
minetest.chat_send_player(name, S("Only peaceful mobs allowed!"))
|
||||
return itemstack
|
||||
end
|
||||
|
||||
pos.y = pos.y - 0.5
|
||||
pos.y = pos.y - 1
|
||||
local mob = mcl_mobs.spawn(pos, mob_name)
|
||||
if not mob then
|
||||
pos.y = pos.y + 1
|
||||
mob = mcl_mobs.spawn(pos, mob_name)
|
||||
if not mob then return end
|
||||
end
|
||||
|
||||
local mob = minetest.add_entity(pos, mob)
|
||||
local entityname = itemstack:get_name()
|
||||
minetest.log("action", "Player " ..name.." spawned "..entityname.." at "..minetest.pos_to_string(pos))
|
||||
local ent = mob:get_luaentity()
|
||||
|
@ -622,5 +651,4 @@ function mcl_mobs.register_egg(mob, desc, background_color, overlay_color, addeg
|
|||
return itemstack
|
||||
end,
|
||||
})
|
||||
|
||||
end
|
||||
|
|
|
@ -258,6 +258,18 @@ function mcl_mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
|||
end
|
||||
end
|
||||
|
||||
-- Stop!
|
||||
local s = get_sign(entity.v)
|
||||
|
||||
entity.v = entity.v - 0.02 * s
|
||||
|
||||
if s ~= get_sign(entity.v) then
|
||||
|
||||
entity.object:set_velocity({x = 0, y = 0, z = 0})
|
||||
entity.v = 0
|
||||
return
|
||||
end
|
||||
|
||||
-- if not moving then set animation and return
|
||||
if entity.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then
|
||||
|
||||
|
@ -273,18 +285,6 @@ function mcl_mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
|||
mcl_mobs:set_animation(entity, moving_anim)
|
||||
end
|
||||
|
||||
-- Stop!
|
||||
local s = get_sign(entity.v)
|
||||
|
||||
entity.v = entity.v - 0.02 * s
|
||||
|
||||
if s ~= get_sign(entity.v) then
|
||||
|
||||
entity.object:set_velocity({x = 0, y = 0, z = 0})
|
||||
entity.v = 0
|
||||
return
|
||||
end
|
||||
|
||||
-- enforce speed limit forward and reverse
|
||||
local max_spd = entity.max_speed_reverse
|
||||
|
||||
|
|
|
@ -362,7 +362,7 @@ function mob_class:env_danger_movement_checks(player_in_active_range)
|
|||
self.state = "stand"
|
||||
self:set_animation( "stand")
|
||||
end
|
||||
yaw = yaw + math.random(-0.5, 0.5)
|
||||
yaw = yaw + math.random() - 0.5
|
||||
yaw = self:set_yaw( yaw, 8)
|
||||
return
|
||||
end
|
||||
|
@ -788,9 +788,9 @@ function mob_class:flop()
|
|||
if self.object:get_velocity().y < 0.1 then
|
||||
self:mob_sound("flop")
|
||||
self.object:set_velocity({
|
||||
x = math.random(-FLOP_HOR_SPEED, FLOP_HOR_SPEED),
|
||||
x = (math.random()-0.5) * 2 * FLOP_HOR_SPEED,
|
||||
y = FLOP_HEIGHT,
|
||||
z = math.random(-FLOP_HOR_SPEED, FLOP_HOR_SPEED),
|
||||
z = (math.random()-0.5) * 2 * FLOP_HOR_SPEED,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
@ -920,7 +920,7 @@ function mob_class:do_states_walk()
|
|||
|
||||
-- Randomly turn
|
||||
if math.random(1, 100) <= 30 then
|
||||
yaw = yaw + math.random(-0.5, 0.5)
|
||||
yaw = yaw + math.random() - 0.5
|
||||
yaw = self:set_yaw( yaw, 8)
|
||||
end
|
||||
end
|
||||
|
@ -929,7 +929,7 @@ function mob_class:do_states_walk()
|
|||
|
||||
-- otherwise randomly turn
|
||||
elseif math.random(1, 100) <= 30 then
|
||||
yaw = yaw + math.random(-0.5, 0.5)
|
||||
yaw = yaw + math.random() - 0.5
|
||||
yaw = self:set_yaw( yaw, 8)
|
||||
end
|
||||
|
||||
|
@ -989,7 +989,7 @@ function mob_class:do_states_stand(player_in_active_range)
|
|||
|
||||
if lp.x > s.x then yaw = yaw +math.pi end
|
||||
else
|
||||
yaw = yaw + math.random(-0.5, 0.5)
|
||||
yaw = yaw + math.random() - 0.5
|
||||
end
|
||||
|
||||
yaw = self:set_yaw( yaw, 8)
|
||||
|
|
|
@ -692,14 +692,10 @@ function mob_class:do_env_damage()
|
|||
local nodef3 = minetest.registered_nodes[self.standing_under]
|
||||
|
||||
-- rain
|
||||
if self.rain_damage > 0 then
|
||||
if mcl_weather.rain.raining and mcl_weather.is_outdoor(pos) then
|
||||
self.health = self.health - self.rain_damage
|
||||
|
||||
if self:check_for_death("rain", {type = "environment",
|
||||
pos = pos, node = self.standing_in}) then
|
||||
return true
|
||||
end
|
||||
if self.rain_damage > 0 and mcl_weather.rain.raining and mcl_weather.is_outdoor(pos) then
|
||||
self.health = self.health - self.rain_damage
|
||||
if self:check_for_death("rain", {type = "environment", pos = pos, node = self.standing_in}) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -707,14 +703,10 @@ function mob_class:do_env_damage()
|
|||
|
||||
-- water damage
|
||||
if self.water_damage > 0 and nodef.groups.water then
|
||||
if self.water_damage ~= 0 then
|
||||
self.health = self.health - self.water_damage
|
||||
mcl_mobs.effect(pos, 5, "mcl_particles_smoke.png", nil, nil, 1, nil)
|
||||
|
||||
if self:check_for_death("water", {type = "environment",
|
||||
pos = pos, node = self.standing_in}) then
|
||||
return true
|
||||
end
|
||||
self.health = self.health - self.water_damage
|
||||
mcl_mobs.effect(pos, 5, "mcl_particles_smoke.png", nil, nil, 1, nil)
|
||||
if self:check_for_death("water", {type = "environment", pos = pos, node = self.standing_in}) then
|
||||
return true
|
||||
end
|
||||
elseif self.lava_damage > 0 and (nodef.groups.lava) then
|
||||
-- lava damage
|
||||
|
@ -730,91 +722,69 @@ function mob_class:do_env_damage()
|
|||
end
|
||||
elseif self.fire_damage > 0 and (nodef2.groups.fire) then
|
||||
-- magma damage
|
||||
if self.fire_damage ~= 0 then
|
||||
self.health = self.health - self.fire_damage
|
||||
|
||||
if self:check_for_death("fire", {type = "environment",
|
||||
pos = pos, node = self.standing_in}) then
|
||||
return true
|
||||
end
|
||||
self.health = self.health - self.fire_damage
|
||||
if self:check_for_death("fire", {type = "environment", pos = pos, node = self.standing_in}) then
|
||||
return true
|
||||
end
|
||||
elseif self.fire_damage > 0 and (nodef.groups.fire) then
|
||||
-- fire damage
|
||||
if self.fire_damage ~= 0 then
|
||||
self.health = self.health - self.fire_damage
|
||||
mcl_mobs.effect(pos, 5, "fire_basic_flame.png", nil, nil, 1, nil)
|
||||
mcl_burning.set_on_fire(self.object, 5)
|
||||
|
||||
if self:check_for_death("fire", {type = "environment",
|
||||
pos = pos, node = self.standing_in}) then
|
||||
return true
|
||||
end
|
||||
self.health = self.health - self.fire_damage
|
||||
mcl_mobs.effect(pos, 5, "fire_basic_flame.png", nil, nil, 1, nil)
|
||||
mcl_burning.set_on_fire(self.object, 5)
|
||||
if self:check_for_death("fire", {type = "environment", pos = pos, node = self.standing_in}) then
|
||||
return true
|
||||
end
|
||||
elseif nodef.damage_per_second ~= 0 and not nodef.groups.lava and not nodef.groups.fire then
|
||||
-- damage_per_second node check
|
||||
self.health = self.health - nodef.damage_per_second
|
||||
mcl_mobs.effect(pos, 5, "mcl_particles_smoke.png")
|
||||
|
||||
if self:check_for_death("dps", {type = "environment",
|
||||
pos = pos, node = self.standing_in}) then
|
||||
if self:check_for_death("dps", {type = "environment", pos = pos, node = self.standing_in}) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- Cactus damage
|
||||
local near = minetest.find_node_near(pos, 1, "mcl_core:cactus", true)
|
||||
if not near and near ~= nil then
|
||||
near = find_node_near({x=pos.x, y=pos.y-1, z=pos.z}, 1, "mcl_core:cactus", true)
|
||||
end
|
||||
if near then
|
||||
-- is mob touching the cactus?
|
||||
local dist = vector.distance(pos, near)
|
||||
local dist_feet = vector.distance({x=pos.x, y=pos.y-1, z=pos.z}, near)
|
||||
local large_mob = false
|
||||
local medium_mob = false
|
||||
if self.name == "mobs_mc:ender_dragon" or
|
||||
self.name == "mobs_mc:ghast" or
|
||||
self.name == "mobs_mc:guardian_elder" or
|
||||
self.name == "mobs_mc:slime_big" or
|
||||
self.name == "mobs_mc:magma_cube_big" or
|
||||
self.name == "mobs_mc:wither" then
|
||||
|
||||
large_mob = true
|
||||
elseif self.name == "mobs_mc:hoglin" or
|
||||
self.name == "mobs_mc:zoglin" or
|
||||
self.name == "mobs_mc:horse" or
|
||||
self.name == "mobs_mc:skeleton_horse" or
|
||||
self.name == "mobs_mc:zombie_horse" or
|
||||
self.name == "mobs_mc:donkey" or
|
||||
self.name == "mobs_mc:mule" or
|
||||
self.name == "mobs_mc:iron_golem" or
|
||||
self.name == "mobs_mc:polar_bear" or
|
||||
self.name == "mobs_mc:spider" or
|
||||
self.name == "mobs_mc:cave_spider" or
|
||||
self.name == "mobs_mc:strider" then
|
||||
|
||||
medium_mob = true
|
||||
if self.standing_on == "mcl_core:cactus" or self.standing_in == "mcl_core:cactus" or self.standing_under == "mcl_core:cactus" then
|
||||
self:damage_mob("cactus", 2)
|
||||
if self:check_for_death("cactus", {type = "environment", pos = pos, node = self.standing_in}) then
|
||||
return true
|
||||
end
|
||||
if (not large_mob and not medium_mob and (dist < 1.03 or dist_feet < 1.6)) or (medium_mob and (dist < 1.165 or dist_feet < 1.73)) or (large_mob and (dist < 1.25 or dist_feet < 1.9)) then
|
||||
if self.health ~= 0 then
|
||||
else
|
||||
local near = minetest.find_node_near(pos, 1, "mcl_core:cactus")
|
||||
if near then
|
||||
-- is mob touching the cactus?
|
||||
local dist = vector.distance(pos, near)
|
||||
local threshold = 1.04 -- small mobs
|
||||
-- medium mobs
|
||||
if self.name == "mobs_mc:spider" or
|
||||
self.name == "mobs_mc:iron_golem" or
|
||||
self.name == "mobs_mc:horse" or
|
||||
self.name == "mobs_mc:donkey" or
|
||||
self.name == "mobs_mc:mule" or
|
||||
self.name == "mobs_mc:polar_bear" or
|
||||
self.name == "mobs_mc:cave_spider" or
|
||||
self.name == "mobs_mc:skeleton_horse" or
|
||||
self.name == "mobs_mc:zombie_horse" or
|
||||
self.name == "mobs_mc:strider" or
|
||||
self.name == "mobs_mc:hoglin" or
|
||||
self.name == "mobs_mc:zoglin" then
|
||||
threshold = 1.165
|
||||
elseif self.name == "mobs_mc:slime_big" or
|
||||
self.name == "mobs_mc:magma_cube_big" or
|
||||
self.name == "mobs_mc:ghast" or
|
||||
self.name == "mobs_mc:guardian_elder" or
|
||||
self.name == "mobs_mc:wither" or
|
||||
self.name == "mobs_mc:ender_dragon" then
|
||||
threshold = 1.25
|
||||
end
|
||||
if dist < threshold then
|
||||
self:damage_mob("cactus", 2)
|
||||
|
||||
if self:check_for_death("cactus", {type = "environment",
|
||||
pos = pos, node = self.standing_in}) then
|
||||
if self:check_for_death("cactus", {type = "environment", pos = pos, node = self.standing_in}) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- is mob standing on the cactus?
|
||||
if self.standing_on == "mcl_core:cactus" or self.standing_in == "mcl_core:cactus" or self.standing_under == "mcl_core:cactus" then
|
||||
self:damage_mob("cactus", 2)
|
||||
|
||||
if self:check_for_death("cactus", {type = "environment",
|
||||
pos = pos, node = self.standing_in}) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- Drowning damage
|
||||
if self.breath_max ~= -1 then
|
||||
|
@ -957,7 +927,8 @@ end
|
|||
|
||||
-- falling and fall damage
|
||||
-- returns true if mob died
|
||||
function mob_class:falling(pos)
|
||||
function mob_class:falling(pos, moveresult)
|
||||
if moveresult and moveresult.touching_ground then return false end
|
||||
|
||||
if self.fly and self.state ~= "die" then
|
||||
return
|
||||
|
|
|
@ -10,20 +10,22 @@ local overworld_sky_threshold = tonumber(minetest.settings:get("mcl_mobs_overwor
|
|||
local overworld_passive_threshold = tonumber(minetest.settings:get("mcl_mobs_overworld_passive_threshold")) or 7
|
||||
|
||||
local get_node = minetest.get_node
|
||||
local get_item_group = minetest.get_item_group
|
||||
local get_node_light = minetest.get_node_light
|
||||
local find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air
|
||||
local mt_get_biome_name = minetest.get_biome_name
|
||||
local get_objects_inside_radius = minetest.get_objects_inside_radius
|
||||
local get_connected_players = minetest.get_connected_players
|
||||
local registered_nodes = minetest.registered_nodes
|
||||
|
||||
local math_min = math.min
|
||||
local math_max = math.max
|
||||
local math_random = math.random
|
||||
local math_floor = math.floor
|
||||
local math_ceil = math.ceil
|
||||
local math_cos = math.cos
|
||||
local math_sin = math.sin
|
||||
local math_round = function(x) return (x > 0) and math_floor(x + 0.5) or math_ceil(x - 0.5) end
|
||||
local math_sqrt = math.sqrt
|
||||
local math_abs = math.abs
|
||||
|
||||
local vector_distance = vector.distance
|
||||
local vector_new = vector.new
|
||||
|
@ -33,19 +35,15 @@ local table_copy = table.copy
|
|||
local table_remove = table.remove
|
||||
local pairs = pairs
|
||||
|
||||
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_spawning", false)
|
||||
local function mcl_log (message, property)
|
||||
if LOGGING_ON then
|
||||
if property then
|
||||
message = message .. ": " .. dump(property)
|
||||
end
|
||||
mcl_util.mcl_log (message, "[Mobs spawn]", true)
|
||||
end
|
||||
local logging = minetest.settings:get_bool("mcl_logging_mobs_spawn", false)
|
||||
local function mcl_log(message, property)
|
||||
if property then message = message .. ": " .. dump(property) end
|
||||
mcl_util.mcl_log(message, "[Mobs spawn]", true)
|
||||
end
|
||||
if not logging then mcl_log = function() end end
|
||||
|
||||
local dbg_spawn_attempts = 0
|
||||
local dbg_spawn_succ = 0
|
||||
local dbg_spawn_counts = {}
|
||||
|
||||
local remove_far = true
|
||||
|
||||
|
@ -54,8 +52,10 @@ local FIND_SPAWN_POS_RETRIES = 16
|
|||
local FIND_SPAWN_POS_RETRIES_SUCCESS_RESPIN = 8
|
||||
|
||||
local MOB_SPAWN_ZONE_INNER = 24
|
||||
local MOB_SPAWN_ZONE_INNER_SQ = MOB_SPAWN_ZONE_INNER^2 -- squared
|
||||
local MOB_SPAWN_ZONE_MIDDLE = 32
|
||||
local MOB_SPAWN_ZONE_OUTER = 128
|
||||
local MOB_SPAWN_ZONE_OUTER_SQ = MOB_SPAWN_ZONE_OUTER^2 -- squared
|
||||
|
||||
-- range for mob count
|
||||
local MOB_CAP_INNER_RADIUS = 32
|
||||
|
@ -95,170 +95,6 @@ mcl_log("Percentage of hostile spawns are group: " .. hostile_group_percentage_s
|
|||
--do mobs spawn?
|
||||
local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false
|
||||
local spawn_protected = minetest.settings:get_bool("mobs_spawn_protected") ~= false
|
||||
local logging = minetest.settings:get_bool("mcl_logging_mobs_spawn",true)
|
||||
|
||||
-- THIS IS THE BIG LIST OF ALL BIOMES - used for programming/updating mobs
|
||||
-- Also used for missing parameter
|
||||
-- Please update the list when adding new biomes!
|
||||
|
||||
local list_of_all_biomes = {
|
||||
|
||||
-- underground:
|
||||
|
||||
"FlowerForest_underground",
|
||||
"JungleEdge_underground",
|
||||
"ColdTaiga_underground",
|
||||
"IcePlains_underground",
|
||||
"IcePlainsSpikes_underground",
|
||||
"MegaTaiga_underground",
|
||||
"Taiga_underground",
|
||||
"ExtremeHills+_underground",
|
||||
"JungleM_underground",
|
||||
"ExtremeHillsM_underground",
|
||||
"JungleEdgeM_underground",
|
||||
"MangroveSwamp_underground",
|
||||
|
||||
-- ocean:
|
||||
|
||||
"RoofedForest_ocean",
|
||||
"JungleEdgeM_ocean",
|
||||
"BirchForestM_ocean",
|
||||
"BirchForest_ocean",
|
||||
"IcePlains_deep_ocean",
|
||||
"Jungle_deep_ocean",
|
||||
"Savanna_ocean",
|
||||
"MesaPlateauF_ocean",
|
||||
"ExtremeHillsM_deep_ocean",
|
||||
"Savanna_deep_ocean",
|
||||
"SunflowerPlains_ocean",
|
||||
"Swampland_deep_ocean",
|
||||
"Swampland_ocean",
|
||||
"MegaSpruceTaiga_deep_ocean",
|
||||
"ExtremeHillsM_ocean",
|
||||
"JungleEdgeM_deep_ocean",
|
||||
"SunflowerPlains_deep_ocean",
|
||||
"BirchForest_deep_ocean",
|
||||
"IcePlainsSpikes_ocean",
|
||||
"Mesa_ocean",
|
||||
"StoneBeach_ocean",
|
||||
"Plains_deep_ocean",
|
||||
"JungleEdge_deep_ocean",
|
||||
"SavannaM_deep_ocean",
|
||||
"Desert_deep_ocean",
|
||||
"Mesa_deep_ocean",
|
||||
"ColdTaiga_deep_ocean",
|
||||
"Plains_ocean",
|
||||
"MesaPlateauFM_ocean",
|
||||
"Forest_deep_ocean",
|
||||
"JungleM_deep_ocean",
|
||||
"FlowerForest_deep_ocean",
|
||||
"MushroomIsland_ocean",
|
||||
"MegaTaiga_ocean",
|
||||
"StoneBeach_deep_ocean",
|
||||
"IcePlainsSpikes_deep_ocean",
|
||||
"ColdTaiga_ocean",
|
||||
"SavannaM_ocean",
|
||||
"MesaPlateauF_deep_ocean",
|
||||
"MesaBryce_deep_ocean",
|
||||
"ExtremeHills+_deep_ocean",
|
||||
"ExtremeHills_ocean",
|
||||
"MushroomIsland_deep_ocean",
|
||||
"Forest_ocean",
|
||||
"MegaTaiga_deep_ocean",
|
||||
"JungleEdge_ocean",
|
||||
"MesaBryce_ocean",
|
||||
"MegaSpruceTaiga_ocean",
|
||||
"ExtremeHills+_ocean",
|
||||
"Jungle_ocean",
|
||||
"RoofedForest_deep_ocean",
|
||||
"IcePlains_ocean",
|
||||
"FlowerForest_ocean",
|
||||
"ExtremeHills_deep_ocean",
|
||||
"MesaPlateauFM_deep_ocean",
|
||||
"Desert_ocean",
|
||||
"Taiga_ocean",
|
||||
"BirchForestM_deep_ocean",
|
||||
"Taiga_deep_ocean",
|
||||
"JungleM_ocean",
|
||||
"MangroveSwamp_ocean",
|
||||
"MangroveSwamp_deep_ocean",
|
||||
|
||||
-- water or beach?
|
||||
|
||||
"MesaPlateauFM_sandlevel",
|
||||
"MesaPlateauF_sandlevel",
|
||||
"MesaBryce_sandlevel",
|
||||
"Mesa_sandlevel",
|
||||
|
||||
-- beach:
|
||||
|
||||
"FlowerForest_beach",
|
||||
"Forest_beach",
|
||||
"StoneBeach",
|
||||
"ColdTaiga_beach_water",
|
||||
"Taiga_beach",
|
||||
"Savanna_beach",
|
||||
"Plains_beach",
|
||||
"ExtremeHills_beach",
|
||||
"ColdTaiga_beach",
|
||||
"Swampland_shore",
|
||||
"MushroomIslandShore",
|
||||
"JungleM_shore",
|
||||
"Jungle_shore",
|
||||
"BambooJungleM_shore",
|
||||
"BambooJungle_shore",
|
||||
"MangroveSwamp_shore",
|
||||
|
||||
-- dimension biome:
|
||||
|
||||
"Nether",
|
||||
"BasaltDelta",
|
||||
"CrimsonForest",
|
||||
"WarpedForest",
|
||||
"SoulsandValley",
|
||||
"End",
|
||||
|
||||
-- Overworld regular:
|
||||
|
||||
"Mesa",
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
"Taiga",
|
||||
"ExtremeHills",
|
||||
"ExtremeHillsM",
|
||||
"ExtremeHills+_snowtop",
|
||||
"Jungle",
|
||||
"Savanna",
|
||||
"BirchForest",
|
||||
"MegaSpruceTaiga",
|
||||
"MegaTaiga",
|
||||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"Desert",
|
||||
"ColdTaiga",
|
||||
"MushroomIsland",
|
||||
"IcePlainsSpikes",
|
||||
"SunflowerPlains",
|
||||
"IcePlains",
|
||||
"RoofedForest",
|
||||
"ExtremeHills+_snowtop",
|
||||
"MesaPlateauFM_grasstop",
|
||||
"JungleEdgeM",
|
||||
"JungleM",
|
||||
"BirchForestM",
|
||||
"MesaPlateauF",
|
||||
"MesaPlateauFM",
|
||||
"MesaPlateauF_grasstop",
|
||||
"MesaBryce",
|
||||
"JungleEdge",
|
||||
"SavannaM",
|
||||
"MangroveSwamp",
|
||||
"BambooJungle",
|
||||
"BambooJungleEdge",
|
||||
"BambooJungleEdgeM",
|
||||
"BambooJungleM",
|
||||
}
|
||||
|
||||
-- count how many mobs are in an area
|
||||
local function count_mobs(pos,r,mob_type)
|
||||
|
@ -287,11 +123,7 @@ local function count_mobs_total(mob_type)
|
|||
end
|
||||
|
||||
local function count_mobs_add_entry (mobs_list, mob_cat)
|
||||
if mobs_list[mob_cat] then
|
||||
mobs_list[mob_cat] = mobs_list[mob_cat] + 1
|
||||
else
|
||||
mobs_list[mob_cat] = 1
|
||||
end
|
||||
mobs_list[mob_cat] = (mobs_list[mob_cat] or 0) + 1
|
||||
end
|
||||
|
||||
--categorise_by can be name or type or spawn_class
|
||||
|
@ -450,7 +282,7 @@ function mcl_mobs:spawn_setup(def)
|
|||
|
||||
local dimension = def.dimension or "overworld"
|
||||
local type_of_spawning = def.type_of_spawning or "ground"
|
||||
local biomes = def.biomes or list_of_all_biomes
|
||||
local biomes = def.biomes or nil
|
||||
local min_light = def.min_light or 0
|
||||
local max_light = def.max_light or (minetest.LIGHT_MAX + 1)
|
||||
local chance = def.chance or 1000
|
||||
|
@ -601,71 +433,40 @@ function mcl_mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_
|
|||
spawn_dictionary[key]["check_position"] = check_position
|
||||
end
|
||||
|
||||
-- Calculate the inverse of a piecewise linear function f(x). Line segments are represented as two
|
||||
-- adjacent points specified as { x, f(x) }. At least 2 points are required. If there are most solutions,
|
||||
-- the one with a lower x value will be chosen.
|
||||
local function inverse_pwl(fx, f)
|
||||
if fx < f[1][2] then
|
||||
return f[1][1]
|
||||
end
|
||||
|
||||
for i=2,#f do
|
||||
local x0,fx0 = unpack(f[i-1])
|
||||
local x1,fx1 = unpack(f[i ])
|
||||
if fx < fx1 then
|
||||
return (fx - fx0) * (x1 - x0) / (fx1 - fx0) + x0
|
||||
end
|
||||
end
|
||||
|
||||
return f[#f][1]
|
||||
end
|
||||
|
||||
local SPAWN_DISTANCE_CDF_PWL = {
|
||||
{0.000,0.00},
|
||||
{0.083,0.40},
|
||||
{0.416,0.75},
|
||||
{1.000,1.00},
|
||||
}
|
||||
|
||||
local two_pi = 2 * math.pi
|
||||
local function get_next_mob_spawn_pos(pos)
|
||||
-- Select a distance such that distances closer to the player are selected much more often than
|
||||
-- those further away from the player.
|
||||
local fx = (math_random(1,10000)-1) / 10000
|
||||
local x = inverse_pwl(fx, SPAWN_DISTANCE_CDF_PWL)
|
||||
local distance = x * (MOB_SPAWN_ZONE_OUTER - MOB_SPAWN_ZONE_INNER) + MOB_SPAWN_ZONE_INNER
|
||||
-- those further away from the player. This does produce a concentration at INNER (24 blocks)
|
||||
local distance = math_random()^2 * (MOB_SPAWN_ZONE_OUTER - MOB_SPAWN_ZONE_INNER) + MOB_SPAWN_ZONE_INNER
|
||||
--print("Using spawn distance of "..tostring(distance).." fx="..tostring(fx)..",x="..tostring(x))
|
||||
|
||||
-- TODO Floor xoff and zoff and add 0.5 so it tries to spawn in the middle of the square. Less failed attempts.
|
||||
-- Use spherical coordinates https://en.wikipedia.org/wiki/Spherical_coordinate_system#Cartesian_coordinates
|
||||
local theta = math_random() * two_pi
|
||||
local phi = math_random() * two_pi
|
||||
local xoff = math_round(distance * math_sin(theta) * math_cos(phi))
|
||||
local yoff = math_round(distance * math_cos(theta))
|
||||
local zoff = math_round(distance * math_sin(theta) * math_sin(phi))
|
||||
-- Choose a random direction. Rejection sampling is simple and fast (1-2 tries usually)
|
||||
local xoff, yoff, zoff, dd
|
||||
repeat
|
||||
xoff, yoff, zoff = math_random() * 2 - 1, math_random() * 2 - 1, math_random() * 2 - 1
|
||||
dd = xoff*xoff + yoff*yoff + zoff*zoff
|
||||
until (dd <= 1 and dd >= 1e-6) -- outside of uniform ball, retry
|
||||
dd = distance / math_sqrt(dd) -- distance scaling factor
|
||||
xoff, yoff, zoff = xoff * dd, yoff * dd, zoff * dd
|
||||
local goal_pos = vector.offset(pos, xoff, yoff, zoff)
|
||||
|
||||
if not ( math.abs(goal_pos.x) <= SPAWN_MAPGEN_LIMIT and math.abs(pos.y) <= SPAWN_MAPGEN_LIMIT and math.abs(goal_pos.z) <= SPAWN_MAPGEN_LIMIT ) then
|
||||
if not (math_abs(goal_pos.x) <= SPAWN_MAPGEN_LIMIT and math_abs(goal_pos.y) <= SPAWN_MAPGEN_LIMIT and math_abs(goal_pos.z) <= SPAWN_MAPGEN_LIMIT) then
|
||||
mcl_log("Pos outside mapgen limits: " .. minetest.pos_to_string(goal_pos))
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Calculate upper/lower y limits
|
||||
local R1 = MOB_SPAWN_ZONE_OUTER
|
||||
local d = vector_distance( pos, vector.new( goal_pos.x, pos.y, goal_pos.z ) ) -- distance from player to projected point on horizontal plane
|
||||
local y1 = math_sqrt( R1*R1 - d*d ) -- absolue value of distance to outer sphere
|
||||
local d2 = xoff*xoff + zoff*zoff -- squared distance in x,z plane only
|
||||
local y1 = math_sqrt(MOB_SPAWN_ZONE_OUTER_SQ - d2) -- absolue value of distance to outer sphere
|
||||
|
||||
local y_min
|
||||
local y_max
|
||||
if d >= MOB_SPAWN_ZONE_INNER then
|
||||
local y_min, y_max
|
||||
if d2 >= MOB_SPAWN_ZONE_INNER_SQ then
|
||||
-- Outer region, y range has both ends on the outer sphere
|
||||
y_min = pos.y - y1
|
||||
y_max = pos.y + y1
|
||||
else
|
||||
-- Inner region, y range spans between inner and outer spheres
|
||||
local R2 = MOB_SPAWN_ZONE_INNER
|
||||
local y2 = math_sqrt( R2*R2 - d*d )
|
||||
if goal_pos.y > pos. y then
|
||||
local y2 = math_sqrt(MOB_SPAWN_ZONE_INNER_SQ - d2)
|
||||
if goal_pos.y > pos.y then
|
||||
-- Upper hemisphere
|
||||
y_min = pos.y + y2
|
||||
y_max = pos.y + y1
|
||||
|
@ -675,16 +476,9 @@ local function get_next_mob_spawn_pos(pos)
|
|||
y_max = pos.y - y2
|
||||
end
|
||||
end
|
||||
y_min = math_round(y_min)
|
||||
y_max = math_round(y_max)
|
||||
|
||||
-- Limit total range of check to 32 nodes (maximum of 3 map blocks)
|
||||
if y_max > goal_pos.y + 16 then
|
||||
y_max = goal_pos.y + 16
|
||||
end
|
||||
if y_min < goal_pos.y - 16 then
|
||||
y_min = goal_pos.y - 16
|
||||
end
|
||||
y_min = math_max(math_floor(y_min), goal_pos.y - 16)
|
||||
y_max = math_min(math_ceil(y_max), goal_pos.y + 16)
|
||||
|
||||
-- Ask engine for valid spawn locations
|
||||
local spawning_position_list = find_nodes_in_area_under_air(
|
||||
|
@ -716,12 +510,12 @@ end
|
|||
|
||||
--a simple helper function for mob_spawn
|
||||
local function biome_check(biome_list, biome_goal)
|
||||
if not biome_goal then return false end
|
||||
for _, data in pairs(biome_list) do
|
||||
if data == biome_goal then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
@ -736,8 +530,8 @@ local function get_water_spawn(p)
|
|||
end
|
||||
end
|
||||
|
||||
local function has_room(self,pos)
|
||||
local cb = self.collisionbox
|
||||
local function has_room(self, pos)
|
||||
local cb = self.spawnbox or self.collisionbox
|
||||
local nodes = {}
|
||||
if self.fly_in then
|
||||
local t = type(self.fly_in)
|
||||
|
@ -748,18 +542,74 @@ local function has_room(self,pos)
|
|||
end
|
||||
end
|
||||
table.insert(nodes,"air")
|
||||
local x = cb[4] - cb[1]
|
||||
local y = cb[5] - cb[2]
|
||||
local z = cb[6] - cb[3]
|
||||
local r = math.ceil(x * y * z)
|
||||
local p1 = vector.offset(pos,cb[1],cb[2],cb[3])
|
||||
local p2 = vector.offset(pos,cb[4],cb[5],cb[6])
|
||||
local n = #minetest.find_nodes_in_area(p1,p2,nodes) or 0
|
||||
if r > n then
|
||||
minetest.log("warning","[mcl_mobs] No room for mob "..self.name.." at "..minetest.pos_to_string(vector.round(pos)))
|
||||
return false
|
||||
|
||||
-- Calculate area to check for room
|
||||
local cb_height = cb[5] - cb[2]
|
||||
local p1 = vector.new(
|
||||
math.round(pos.x + cb[1]),
|
||||
math.floor(pos.y),
|
||||
math.round(pos.z + cb[3]))
|
||||
local p2 = vector.new(
|
||||
math.round(pos.x + cb[4]),
|
||||
math.ceil(p1.y + cb_height) - 1,
|
||||
math.round(pos.z + cb[6]))
|
||||
|
||||
-- Check if the entire spawn volume is free
|
||||
local dx = p2.x - p1.x + 1
|
||||
local dy = p2.y - p1.y + 1
|
||||
local dz = p2.z - p1.z + 1
|
||||
local found_nodes = minetest.find_nodes_in_area(p1,p2,nodes) or 0
|
||||
local n = #found_nodes
|
||||
if n == dx * dy * dz then
|
||||
return true
|
||||
end
|
||||
return true
|
||||
|
||||
-- If we don't have an implementation of get_node_boxes, we can't check for sub-node space
|
||||
if not minetest.get_node_boxes then return false end
|
||||
|
||||
-- Check if it's possible for a sub-node space check to succeed
|
||||
local needed_in_bottom_section = dx * ( dy - 1) * dz
|
||||
if n < needed_in_bottom_section then return false end
|
||||
|
||||
-- Make sure the entire volume except for the top level is free before checking the top layer
|
||||
if dy > 1 then
|
||||
-- Remove nodes in the top layer from the count
|
||||
for i = 1,#found_nodes do
|
||||
if found_nodes[i].y == p2.y then
|
||||
n = n - 1
|
||||
end
|
||||
end
|
||||
|
||||
-- If the entire volume except the top layer isn't air (or nodes) then we can't spawn this mob here
|
||||
if n < needed_in_bottom_section then return false end
|
||||
end
|
||||
|
||||
-- Check the top layer to see if we have enough space to spawn in
|
||||
local top_layer_height = 1
|
||||
local processed = {}
|
||||
for x = p1.x,p2.x do
|
||||
for z = p1.z,p2.z do
|
||||
local test_pos = vector.new(x,p2.y,z)
|
||||
local node = minetest.get_node(test_pos) or { name = "ignore" }
|
||||
local cache_name = string.format("%s-%d", node.name, node.param2)
|
||||
if not processed[cache_name] then
|
||||
-- Calculate node bounding box and select the lowest y value
|
||||
local boxes = minetest.get_node_boxes("collision_box", test_pos, node)
|
||||
for i = 1,#boxes do
|
||||
local box = boxes[i]
|
||||
local y_test = box[2] + 0.5
|
||||
if y_test < top_layer_height then top_layer_height = y_test end
|
||||
|
||||
local y_test = box[5] + 0.5
|
||||
if y_test < top_layer_height then top_layer_height = y_test end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if top_layer_height + dy - 1 >= cb_height then return true end
|
||||
|
||||
-- We don't have room
|
||||
return false
|
||||
end
|
||||
|
||||
mcl_mobs.custom_biomecheck = nil
|
||||
|
@ -768,119 +618,92 @@ function mcl_mobs.register_custom_biomecheck(custom_biomecheck)
|
|||
mcl_mobs.custom_biomecheck = custom_biomecheck
|
||||
end
|
||||
|
||||
|
||||
local function get_biome_name(pos)
|
||||
if mcl_mobs.custom_biomecheck then
|
||||
return mcl_mobs.custom_biomecheck (pos)
|
||||
else
|
||||
local gotten_biome = minetest.get_biome_data(pos)
|
||||
|
||||
if not gotten_biome then
|
||||
return
|
||||
end
|
||||
|
||||
gotten_biome = mt_get_biome_name(gotten_biome.biome)
|
||||
--minetest.log ("biome: " .. dump(gotten_biome))
|
||||
|
||||
return gotten_biome
|
||||
end
|
||||
if mcl_mobs.custom_biomecheck then return mcl_mobs.custom_biomecheck(pos) end
|
||||
local gotten_biome = minetest.get_biome_data(pos)
|
||||
return gotten_biome and mt_get_biome_name(gotten_biome.biome)
|
||||
end
|
||||
|
||||
local function spawn_check(pos, spawn_def)
|
||||
if not spawn_def or not pos then return end
|
||||
|
||||
dbg_spawn_attempts = dbg_spawn_attempts + 1
|
||||
|
||||
local dimension = mcl_worlds.pos_to_dimension(pos)
|
||||
local mob_def = minetest.registered_entities[spawn_def.name]
|
||||
local mob_type = mob_def.type
|
||||
local gotten_node = get_node(pos).name
|
||||
if not gotten_node then return end
|
||||
|
||||
local biome_name = get_biome_name(pos)
|
||||
if not biome_name then return end
|
||||
|
||||
local is_ground = minetest.get_item_group(gotten_node,"solid") ~= 0
|
||||
if not is_ground then
|
||||
if spawn_def.dimension ~= dimension then return end -- wrong dimension
|
||||
-- find ground node below spawn position
|
||||
local node_name = get_node(pos).name
|
||||
local node_def = registered_nodes[node_name]
|
||||
if node_def and not node_def.groups.solid then -- try node one below instead
|
||||
pos.y = pos.y - 1
|
||||
gotten_node = get_node(pos).name
|
||||
is_ground = minetest.get_item_group(gotten_node,"solid") ~= 0
|
||||
node_name = get_node(pos).name
|
||||
node_def = registered_nodes[node_name]
|
||||
end
|
||||
if not node_def or not node_def.groups then return end
|
||||
-- do not spawn on bedrock
|
||||
if node_name == "mcl_core:bedrock" then return end
|
||||
pos.y = pos.y + 1
|
||||
local is_water = get_item_group(gotten_node, "water") ~= 0
|
||||
local is_lava = get_item_group(gotten_node, "lava") ~= 0
|
||||
local is_leaf = get_item_group(gotten_node, "leaves") ~= 0
|
||||
local is_bedrock = gotten_node == "mcl_core:bedrock"
|
||||
local is_grass = minetest.get_item_group(gotten_node,"grass_block") ~= 0
|
||||
-- check spawn height
|
||||
if pos.y < spawn_def.min_height or pos.y > spawn_def.max_height then return end
|
||||
mcl_log("spawn_check#1 position checks passed")
|
||||
|
||||
if pos.y >= spawn_def.min_height
|
||||
and pos.y <= spawn_def.max_height
|
||||
and spawn_def.dimension == dimension
|
||||
and biome_check(spawn_def.biomes, biome_name) then
|
||||
-- do not spawn ground mobs on leaves
|
||||
if spawn_def.type_of_spawning == "ground" and (not node_def.groups.solid or node_def.groups.leaves) then return end
|
||||
-- water mobs only on water
|
||||
if spawn_def.type_of_spawning == "water" and not node_def.groups.water then return end
|
||||
-- lava mobs only on lava
|
||||
if spawn_def.type_of_spawning == "lava" and not node_def.groups.lava then return end
|
||||
-- farm animals on grass only
|
||||
if is_farm_animal(spawn_def.name) and not node_def.groups.grass_block then return end
|
||||
|
||||
mcl_log("Spawn level 1 check - Passed")
|
||||
if (is_ground or spawn_def.type_of_spawning ~= "ground")
|
||||
and (spawn_def.type_of_spawning ~= "ground" or not is_leaf)
|
||||
and (not is_farm_animal(spawn_def.name) or is_grass)
|
||||
and (spawn_def.type_of_spawning ~= "water" or is_water)
|
||||
and not is_bedrock
|
||||
and has_room(mob_def,pos)
|
||||
and (spawn_def.check_position and spawn_def.check_position(pos) or spawn_def.check_position == nil)
|
||||
and ( not spawn_protected or not minetest.is_protected(pos, "") ) then
|
||||
---- More expensive calls:
|
||||
-- check the biome
|
||||
if spawn_def.biomes and not biome_check(spawn_def.biomes, get_biome_name(pos)) then return end
|
||||
-- check if there is enough room
|
||||
local mob_def = minetest.registered_entities[spawn_def.name]
|
||||
if not has_room(mob_def,pos) then return end
|
||||
-- additional checks (slime etc.)
|
||||
if spawn_def.check_position and not spawn_def.check_position(pos) then return end
|
||||
if spawn_protected and minetest.is_protected(pos, "") then return end
|
||||
mcl_log("spawn_check#2 advanced checks passed")
|
||||
|
||||
mcl_log("Spawn level 2 check - Passed")
|
||||
local gotten_light = get_node_light(pos)
|
||||
-- check light thresholds
|
||||
local gotten_light = get_node_light(pos)
|
||||
-- old lighting
|
||||
if not modern_lighting then return gotten_light >= spawn_def.min_light and gotten_light <= spawn_def.max_light end
|
||||
|
||||
if modern_lighting then
|
||||
local my_node = get_node(pos)
|
||||
local sky_light = minetest.get_natural_light(pos)
|
||||
local art_light = minetest.get_artificial_light(my_node.param1)
|
||||
|
||||
if mob_def.spawn_check then
|
||||
return mob_def.spawn_check(pos, gotten_light, art_light, sky_light)
|
||||
elseif mob_type == "monster" then
|
||||
if dimension == "nether" then
|
||||
if art_light <= nether_threshold then
|
||||
return true
|
||||
end
|
||||
elseif dimension == "end" then
|
||||
if art_light <= end_threshold then
|
||||
return true
|
||||
end
|
||||
elseif dimension == "overworld" then
|
||||
if art_light <= overworld_threshold and sky_light <= overworld_sky_threshold then
|
||||
return true
|
||||
end
|
||||
end
|
||||
else
|
||||
-- passive threshold is apparently the same in all dimensions ...
|
||||
if gotten_light > overworld_passive_threshold then
|
||||
return true
|
||||
end
|
||||
end
|
||||
else
|
||||
if gotten_light >= spawn_def.min_light and gotten_light <= spawn_def.max_light then
|
||||
return true
|
||||
end
|
||||
local sky_light = minetest.get_natural_light(pos)
|
||||
local art_light = minetest.get_artificial_light(get_node(pos).param1)
|
||||
if mob_def.spawn_check then
|
||||
return mob_def.spawn_check(pos, gotten_light, art_light, sky_light)
|
||||
end
|
||||
if mob_def.type == "monster" then
|
||||
if dimension == "nether" then
|
||||
if art_light <= nether_threshold then
|
||||
return true
|
||||
end
|
||||
elseif dimension == "end" then
|
||||
if art_light <= end_threshold then
|
||||
return true
|
||||
end
|
||||
elseif dimension == "overworld" then
|
||||
if art_light <= overworld_threshold and sky_light <= overworld_sky_threshold then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
return false
|
||||
-- passive threshold is apparently the same in all dimensions ...
|
||||
return gotten_light > overworld_passive_threshold
|
||||
end
|
||||
|
||||
function mcl_mobs.spawn(pos,id)
|
||||
if not pos or not id then return false end
|
||||
local def = minetest.registered_entities[id] or minetest.registered_entities["mobs_mc:"..id] or minetest.registered_entities["extra_mobs:"..id]
|
||||
if not def or (def.can_spawn and not def.can_spawn(pos)) or not def.is_mob then
|
||||
return false
|
||||
end
|
||||
if not dbg_spawn_counts[def.name] then
|
||||
dbg_spawn_counts[def.name] = 1
|
||||
else
|
||||
dbg_spawn_counts[def.name] = dbg_spawn_counts[def.name] + 1
|
||||
end
|
||||
if not def or not def.is_mob or (def.can_spawn and not def.can_spawn(pos)) then return false end
|
||||
if not has_room(def, pos) then return false end
|
||||
return minetest.add_entity(pos, def.name)
|
||||
end
|
||||
|
||||
|
||||
local function spawn_group(p,mob,spawn_on,amount_to_spawn)
|
||||
local nn= minetest.find_nodes_in_area_under_air(vector.offset(p,-5,-3,-5),vector.offset(p,5,3,5),spawn_on)
|
||||
local o
|
||||
|
@ -997,7 +820,7 @@ if mobs_spawn then
|
|||
mob_total_wide = 0
|
||||
end
|
||||
|
||||
local cap_space_wide = math.max(type_cap - mob_total_wide, 0)
|
||||
local cap_space_wide = math_max(type_cap - mob_total_wide, 0)
|
||||
|
||||
mcl_log("mob_type", mob_type)
|
||||
mcl_log("cap_space_wide", cap_space_wide)
|
||||
|
@ -1005,10 +828,10 @@ if mobs_spawn then
|
|||
local cap_space_available = 0
|
||||
if mob_type == "hostile" then
|
||||
mcl_log("cap_space_global", cap_space_hostile)
|
||||
cap_space_available = math.min(cap_space_hostile, cap_space_wide)
|
||||
cap_space_available = math_min(cap_space_hostile, cap_space_wide)
|
||||
else
|
||||
mcl_log("cap_space_global", cap_space_non_hostile)
|
||||
cap_space_available = math.min(cap_space_non_hostile, cap_space_wide)
|
||||
cap_space_available = math_min(cap_space_non_hostile, cap_space_wide)
|
||||
end
|
||||
|
||||
local mob_total_close = mob_counts_close[mob_type]
|
||||
|
@ -1017,8 +840,8 @@ if mobs_spawn then
|
|||
mob_total_close = 0
|
||||
end
|
||||
|
||||
local cap_space_close = math.max(close_zone_cap - mob_total_close, 0)
|
||||
cap_space_available = math.min(cap_space_available, cap_space_close)
|
||||
local cap_space_close = math_max(close_zone_cap - mob_total_close, 0)
|
||||
cap_space_available = math_min(cap_space_available, cap_space_close)
|
||||
|
||||
mcl_log("cap_space_close", cap_space_close)
|
||||
mcl_log("cap_space_available", cap_space_available)
|
||||
|
@ -1145,7 +968,7 @@ if mobs_spawn then
|
|||
|
||||
local amount_to_spawn = math.random(group_min, spawn_in_group)
|
||||
mcl_log("Spawning quantity: " .. amount_to_spawn)
|
||||
amount_to_spawn = math.min(amount_to_spawn, cap_space_available)
|
||||
amount_to_spawn = math_min(amount_to_spawn, cap_space_available)
|
||||
mcl_log("throttled spawning quantity: " .. amount_to_spawn)
|
||||
|
||||
if logging then
|
||||
|
@ -1196,8 +1019,8 @@ if mobs_spawn then
|
|||
local players = get_connected_players()
|
||||
local total_mobs, total_non_hostile, total_hostile = count_mobs_total_cap()
|
||||
|
||||
local cap_space_hostile = math.max(mob_cap.global_hostile - total_hostile, 0)
|
||||
local cap_space_non_hostile = math.max(mob_cap.global_non_hostile - total_non_hostile, 0)
|
||||
local cap_space_hostile = math_max(mob_cap.global_hostile - total_hostile, 0)
|
||||
local cap_space_non_hostile = math_max(mob_cap.global_non_hostile - total_non_hostile, 0)
|
||||
mcl_log("global cap_space_hostile", cap_space_hostile)
|
||||
mcl_log("global cap_space_non_hostile", cap_space_non_hostile)
|
||||
|
||||
|
@ -1274,7 +1097,6 @@ end
|
|||
minetest.register_chatcommand("mobstats",{
|
||||
privs = { debug = true },
|
||||
func = function(n,param)
|
||||
--minetest.chat_send_player(n,dump(dbg_spawn_counts))
|
||||
local pos = minetest.get_player_by_name(n):get_pos()
|
||||
minetest.chat_send_player(n,"mobs: within 32 radius of player/total loaded :"..count_mobs(pos,MOB_CAP_INNER_RADIUS) .. "/" .. count_mobs_total())
|
||||
minetest.chat_send_player(n,"spawning attempts since server start:" .. dbg_spawn_succ .. "/" .. dbg_spawn_attempts)
|
||||
|
|
|
@ -95,8 +95,8 @@ mcl_mobs.register_mob("mobs_mc:blaze", {
|
|||
end
|
||||
local pos = self.object:get_pos()
|
||||
minetest.add_particle({
|
||||
pos = {x=pos.x+math.random(-0.7,0.7)*math.random()/2,y=pos.y+math.random(0.7,1.2),z=pos.z+math.random(-0.7,0.7)*math.random()/2},
|
||||
velocity = {x=0, y=math.random(1,1), z=0},
|
||||
pos = {x=pos.x+(math.random()*0.7-0.35)*math.random(),y=pos.y+0.7+math.random()*0.5,z=pos.z+(math.random()*0.7-0.35)*math.random()},
|
||||
velocity = {x=0, y=1, z=0},
|
||||
expirationtime = math.random(),
|
||||
size = math.random(1, 4),
|
||||
collisiondetection = true,
|
||||
|
@ -110,8 +110,8 @@ mcl_mobs.register_mob("mobs_mc:blaze", {
|
|||
},
|
||||
})
|
||||
minetest.add_particle({
|
||||
pos = {x=pos.x+math.random(-0.7,0.7)*math.random()/2,y=pos.y+math.random(0.7,1.2),z=pos.z+math.random(-0.7,0.7)*math.random()/2},
|
||||
velocity = {x=0, y=math.random(1,1), z=0},
|
||||
pos = {x=pos.x+(math.random()*0.7-0.35)*math.random(),y=pos.y+0.7+math.random()*0.5,z=pos.z+(math.random()*0.7-0.35)*math.random()},
|
||||
velocity = {x=0, y=1, z=0},
|
||||
expirationtime = math.random(),
|
||||
size = math.random(1, 4),
|
||||
collisiondetection = true,
|
||||
|
@ -125,8 +125,8 @@ mcl_mobs.register_mob("mobs_mc:blaze", {
|
|||
},
|
||||
})
|
||||
minetest.add_particle({
|
||||
pos = {x=pos.x+math.random(-0.7,0.7)*math.random()/2,y=pos.y+math.random(0.7,1.2),z=pos.z+math.random(-0.7,0.7)*math.random()/2},
|
||||
velocity = {x=0, y=math.random(1,1), z=0},
|
||||
pos = {x=pos.x+(math.random()*0.7-0.35)*math.random(),y=pos.y+0.7+math.random()*0.5,z=pos.z+(math.random()*0.7-0.35)*math.random()},
|
||||
velocity = {x=0, y=1, z=0},
|
||||
expirationtime = math.random(),
|
||||
size = math.random(1, 4),
|
||||
collisiondetection = true,
|
||||
|
|
|
@ -84,7 +84,7 @@ local cod = {
|
|||
self.object:set_bone_position("body", vector.new(0,1,0), vector.new(degrees(dir_to_pitch(self.object:get_velocity())) * -1 + 90,0,0))
|
||||
if minetest.get_item_group(self.standing_in, "water") ~= 0 then
|
||||
if self.object:get_velocity().y < 5 then
|
||||
self.object:add_velocity({ x = 0 , y = math.random(-.007, .007), z = 0 })
|
||||
self.object:add_velocity({ x = 0 , y = math.random()*.014-.007, z = 0 })
|
||||
end
|
||||
end
|
||||
--]]
|
||||
|
|
|
@ -81,16 +81,16 @@ local dolphin = {
|
|||
reach = 2,
|
||||
damage = 2.5,
|
||||
attack_type = "dogfight",
|
||||
--[[ this is supposed to make them jump out the water but doesn't appear to work very well
|
||||
do_custom = function(self,dtime)
|
||||
--[[ this is supposed to make them jump out the water but doesn't appear to work very well
|
||||
self.object:set_bone_position("body", vector.new(0,1,0), vector.new(degrees(dir_to_pitch(self.object:get_velocity())) * -1 + 90,0,0))
|
||||
if minetest.get_item_group(self.standing_in, "water") ~= 0 then
|
||||
if self.object:get_velocity().y < 5 then
|
||||
self.object:add_velocity({ x = 0 , y = math.random(-.007, .007), z = 0 })
|
||||
self.object:add_velocity({ x = 0 , y = math.random()*.014-.007, z = 0 })
|
||||
end
|
||||
end
|
||||
--]]
|
||||
end,
|
||||
--]]
|
||||
}
|
||||
|
||||
mcl_mobs.register_mob("mobs_mc:dolphin", dolphin)
|
||||
|
|
|
@ -4,21 +4,17 @@
|
|||
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
local BEAM_CHECK_FREQUENCY = 2
|
||||
local BEAM_CHECK_FREQUENCY = 1
|
||||
local POS_CHECK_FREQUENCY = 15
|
||||
local HEAL_AMMOUNT = 37
|
||||
local HEAL_INTERVAL = 1
|
||||
local HEAL_AMOUNT = 2
|
||||
|
||||
local function heal(self)
|
||||
local o = self.object
|
||||
self.health = math.min(self.hp_max,self.health + HEAL_AMMOUNT)
|
||||
end
|
||||
local function check_beam(self)
|
||||
for _, obj in ipairs(minetest.get_objects_inside_radius(self.object:get_pos(), 80)) do
|
||||
local luaentity = obj:get_luaentity()
|
||||
if luaentity and luaentity.name == "mcl_end:crystal" then
|
||||
if luaentity.beam then
|
||||
if luaentity.beam == self.beam then
|
||||
heal(self)
|
||||
break
|
||||
end
|
||||
else
|
||||
|
@ -106,7 +102,6 @@ mcl_mobs.register_mob("mobs_mc:enderdragon", {
|
|||
},
|
||||
ignores_nametag = true,
|
||||
do_custom = function(self,dtime)
|
||||
mcl_bossbars.update_boss(self.object, "Ender Dragon", "light_purple")
|
||||
if self._pos_timer == nil or self._pos_timer > POS_CHECK_FREQUENCY then
|
||||
self._pos_timer = 0
|
||||
check_pos(self)
|
||||
|
@ -115,8 +110,20 @@ mcl_mobs.register_mob("mobs_mc:enderdragon", {
|
|||
self._beam_timer = 0
|
||||
check_beam(self)
|
||||
end
|
||||
|
||||
self._beam_timer = self._beam_timer + dtime
|
||||
self._pos_timer = self._pos_timer + dtime
|
||||
|
||||
if self.beam ~= nil then
|
||||
-- heal
|
||||
self._heal_timer = (self._heal_timer or 0) + dtime
|
||||
if self._heal_timer > HEAL_INTERVAL then
|
||||
self.health = math.min(self.hp_max,self.health + HEAL_AMOUNT)
|
||||
self._heal_timer = self._heal_timer - HEAL_INTERVAL
|
||||
end
|
||||
end
|
||||
|
||||
mcl_bossbars.update_boss(self.object, "Ender Dragon", "light_purple")
|
||||
end,
|
||||
on_die = function(self, pos, cmi_cause)
|
||||
if self._portal_pos then
|
||||
|
|
|
@ -83,8 +83,8 @@ mcl_mobs.register_mob("mobs_mc:iron_golem", {
|
|||
stand_speed = 15, walk_speed = 15, run_speed = 25, punch_speed = 15,
|
||||
stand_start = 0, stand_end = 0,
|
||||
walk_start = 0, walk_end = 40,
|
||||
run_start = 0, run_end = 40,
|
||||
punch_start = 40, punch_end = 50,
|
||||
run_start = 40, run_end = 80,
|
||||
punch_start = 80, punch_end = 90,
|
||||
},
|
||||
jump = true,
|
||||
do_custom = function(self, dtime)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name = mobs_mc
|
||||
author = maikerumine
|
||||
description = Adds Minecraft-like monsters and animals.
|
||||
depends = mcl_init, mcl_particles, mcl_mobs, mcl_wip, mcl_core, mcl_util
|
||||
depends = mcl_init, mcl_particles, mcl_mobs, mcl_wip, mcl_core, mcl_util, mcl_entity_invs
|
||||
optional_depends = default, mcl_tnt, mcl_bows, mcl_throwing, mcl_fishing, bones, mesecons_materials, doc_items, mcl_worlds
|
||||
|
|
|
@ -360,7 +360,7 @@ piglin_brute.xp_min = 20
|
|||
piglin_brute.xp_max = 20
|
||||
piglin_brute.hp_min = 50
|
||||
piglin_brute.hp_max = 50
|
||||
piglin_brute.fire_resistant = 1
|
||||
piglin_brute.fire_resistant = false
|
||||
piglin_brute.do_custom = function()
|
||||
return
|
||||
end
|
||||
|
@ -371,8 +371,8 @@ piglin_brute.on_rightclick = function()
|
|||
return
|
||||
end
|
||||
piglin_brute.attacks_monsters = true
|
||||
piglin_brute.lava_damage = 0
|
||||
piglin_brute.fire_damage = 0
|
||||
piglin_brute.lava_damage = 4
|
||||
piglin_brute.fire_damage = 2
|
||||
piglin_brute.attack_animals = true
|
||||
piglin_brute.mesh = "extra_mobs_sword_piglin.b3d"
|
||||
piglin_brute.textures = {"extra_mobs_piglin_brute.png", "default_tool_goldaxe.png", "extra_mobs_trans.png"}
|
||||
|
|
|
@ -52,7 +52,7 @@ local salmon = {
|
|||
makes_footstep_sound = false,
|
||||
swim = true,
|
||||
fly = true,
|
||||
fly_in = "mcl_core:water_source",
|
||||
fly_in = { "mcl_core:water_source", "mclx_core:river_water_source" },
|
||||
breathes_in_water = true,
|
||||
jump = false,
|
||||
view_range = 16,
|
||||
|
|
|
@ -103,6 +103,7 @@ local skeleton = {
|
|||
return true
|
||||
end,
|
||||
ignited_by_sunlight = true,
|
||||
floats = 0,
|
||||
view_range = 16,
|
||||
fear_height = 4,
|
||||
attack_type = "dogshoot",
|
||||
|
|
|
@ -94,6 +94,7 @@ mcl_mobs.register_mob("mobs_mc:witherskeleton", {
|
|||
dogshoot_switch = 1,
|
||||
dogshoot_count_max =0.5,
|
||||
fear_height = 4,
|
||||
floats = 0,
|
||||
harmed_by_heal = true,
|
||||
fire_resistant = true,
|
||||
dealt_effect = {
|
||||
|
|
|
@ -1,112 +1,31 @@
|
|||
--License for code WTFPL and otherwise stated in readmes
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
local MAPBLOCK_SIZE = 16
|
||||
|
||||
local seed = minetest.get_mapgen_setting("seed")
|
||||
|
||||
local slime_chunk_match
|
||||
local MAPBLOCK_SIZE = 16 -- size for slime chunk logic
|
||||
local SEED_OFFSET = 362 -- module specific seed
|
||||
local world_seed = (minetest.get_mapgen_setting("seed") + SEED_OFFSET) % 4294967296
|
||||
-- slime density, where default N=10 is every 10th chunk
|
||||
local slime_ratio = tonumber(minetest.settings:get("slime_ratio")) or 10
|
||||
-- use 3D chunking instead of 2d chunks
|
||||
local slime_3d_chunks = minetest.settings:get_bool("slime_3d_chunks", false)
|
||||
-- maximum light level, for slimes in caves only, not magma/swamps
|
||||
local slime_max_light = (tonumber(minetest.settings:get("slime_max_light")) or minetest.LIGHT_MAX) + 1
|
||||
-- maximum light level for swamp spawning
|
||||
local swamp_light_max = 7
|
||||
-- maximum height to spawn in slime chunks
|
||||
local slime_chunk_spawn_max = mcl_worlds.layer_to_y(40)
|
||||
local x_modifier
|
||||
local z_modifier
|
||||
|
||||
local function split_by_char (inputstr, sep, limit)
|
||||
if sep == nil then
|
||||
sep = "%d"
|
||||
end
|
||||
local t = {}
|
||||
|
||||
local i = 0
|
||||
for str in string.gmatch(inputstr, "(["..sep.."])") do
|
||||
i = i --+ 1
|
||||
table.insert(t, tonumber(str))
|
||||
if limit and i >= limit then
|
||||
break
|
||||
end
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
--Seed: "16002933932875202103" == random seed
|
||||
--Seed: "1807191622654296300" == cheese
|
||||
--Seed: "1" = 1
|
||||
local function process_seed (seed)
|
||||
--minetest.log("seed: " .. seed)
|
||||
|
||||
local split_chars = split_by_char(tostring(seed), nil, 10)
|
||||
|
||||
slime_chunk_match = split_chars[1]
|
||||
x_modifier = split_chars[2]
|
||||
z_modifier = split_chars[3]
|
||||
|
||||
--minetest.log("x_modifier: " .. tostring(x_modifier))
|
||||
--minetest.log("z_modifier: " .. tostring(z_modifier))
|
||||
--minetest.log("slime_chunk_match: " .. tostring(slime_chunk_match))
|
||||
end
|
||||
|
||||
local processed = process_seed (seed)
|
||||
|
||||
|
||||
local function convert_to_chunk_value (co_ord, modifier)
|
||||
local converted = math.floor(math.abs(co_ord) / MAPBLOCK_SIZE)
|
||||
|
||||
if modifier then
|
||||
converted = (converted + modifier)
|
||||
end
|
||||
converted = converted % 10
|
||||
|
||||
--minetest.log("co_ord: " .. co_ord)
|
||||
--minetest.log("converted: " .. converted)
|
||||
return converted
|
||||
end
|
||||
|
||||
assert(convert_to_chunk_value(-16) == 1, "Incorrect convert_to_chunk_value result")
|
||||
assert(convert_to_chunk_value(-15) == 0, "Incorrect convert_to_chunk_value result")
|
||||
assert(convert_to_chunk_value(-1) == 0, "Incorrect convert_to_chunk_value result")
|
||||
assert(convert_to_chunk_value(0) == 0, "Incorrect convert_to_chunk_value result")
|
||||
assert(convert_to_chunk_value(1) == 0, "Incorrect convert_to_chunk_value result")
|
||||
assert(convert_to_chunk_value(15) == 0, "Incorrect convert_to_chunk_value result")
|
||||
assert(convert_to_chunk_value(16) == 1, "Incorrect convert_to_chunk_value result")
|
||||
assert(convert_to_chunk_value(31) == 1, "Incorrect convert_to_chunk_value result")
|
||||
assert(convert_to_chunk_value(32) == 2, "Incorrect convert_to_chunk_value result")
|
||||
assert(convert_to_chunk_value(1599) == 9, "Incorrect convert_to_chunk_value result")
|
||||
assert(convert_to_chunk_value(1600) == 0, "Incorrect convert_to_chunk_value result")
|
||||
|
||||
assert(convert_to_chunk_value(0,9) == 9, "Incorrect convert_to_chunk_value result")
|
||||
assert(convert_to_chunk_value(16,5) == 6, "Incorrect convert_to_chunk_value result")
|
||||
assert(convert_to_chunk_value(1599,4) == 3, "Incorrect convert_to_chunk_value result")
|
||||
|
||||
local function calculate_chunk_value (pos, x_mod, z_mod)
|
||||
local chunk_val = math.abs(convert_to_chunk_value(pos.x, x_mod) - convert_to_chunk_value(pos.z, z_mod)) % 10
|
||||
return chunk_val
|
||||
end
|
||||
|
||||
assert(calculate_chunk_value(vector.new(0,0,0)) == 0, "calculate_chunk_value failed")
|
||||
assert(calculate_chunk_value(vector.new(0,0,0), 1, 1) == 0, "calculate_chunk_value failed")
|
||||
assert(calculate_chunk_value(vector.new(0,0,0), 2, 1) == 1, "calculate_chunk_value failed")
|
||||
assert(calculate_chunk_value(vector.new(64,0,16)) == (4-1), "calculate_chunk_value failed")
|
||||
assert(calculate_chunk_value(vector.new(16,0,64)) == (3), "calculate_chunk_value failed")
|
||||
assert(calculate_chunk_value(vector.new(-160,0,-160)) == 0, "calculate_chunk_value failed")
|
||||
local floor = math.floor
|
||||
local max = math.max
|
||||
|
||||
local function is_slime_chunk(pos)
|
||||
if not pos then return end
|
||||
|
||||
local chunk_val = calculate_chunk_value (pos, x_modifier, z_modifier)
|
||||
local slime_chunk = chunk_val == slime_chunk_match
|
||||
|
||||
--minetest.log("x: " ..pos.x .. ", z:" .. pos.z)
|
||||
|
||||
--minetest.log("seed slime_chunk_match: " .. tostring(slime_chunk_match))
|
||||
--minetest.log("chunk_val: " .. tostring(chunk_val))
|
||||
--minetest.log("Is slime chunk: " .. tostring(slime_chunk))
|
||||
return slime_chunk
|
||||
if not pos then return end -- no position given
|
||||
if slime_ratio == 0 then return end -- no slime chunks
|
||||
if slime_ratio <= 1 then return true end -- slime everywhere
|
||||
local bpos = vector.new(floor(pos.x / MAPBLOCK_SIZE), slime_3d_chunks and floor(pos.y / MAPBLOCK_SIZE) or 0, floor(pos.z / MAPBLOCK_SIZE))
|
||||
return PcgRandom(minetest.hash_node_position(bpos) + world_seed):next(0,1e9)/1e9 * slime_ratio < 1
|
||||
end
|
||||
|
||||
local check_position = function (pos)
|
||||
return is_slime_chunk(pos)
|
||||
end
|
||||
|
||||
|
||||
-- Returns a function that spawns children in a circle around pos.
|
||||
-- To be used as on_die callback.
|
||||
-- self: mob reference
|
||||
|
@ -116,19 +35,15 @@ end
|
|||
-- eject_speed: Initial speed of child mob away from "mother" mob
|
||||
local spawn_children_on_die = function(child_mob, spawn_distance, eject_speed)
|
||||
return function(self, pos)
|
||||
local posadd, newpos, dir
|
||||
if not eject_speed then
|
||||
eject_speed = 1
|
||||
end
|
||||
eject_speed = eject_speed or 1
|
||||
local mndef = minetest.registered_nodes[minetest.get_node(pos).name]
|
||||
local mother_stuck = mndef and mndef.walkable
|
||||
local angle = math.random(0, math.pi*2)
|
||||
local angle = math.random() * math.pi * 2
|
||||
local children = {}
|
||||
local spawn_count = math.random(2, 4)
|
||||
for i = 1, spawn_count do
|
||||
dir = vector.new(math.cos(angle), 0, math.sin(angle))
|
||||
posadd = vector.normalize(dir) * spawn_distance
|
||||
newpos = pos + posadd
|
||||
local dir = vector.new(math.cos(angle), 0, math.sin(angle))
|
||||
local newpos = pos + dir * spawn_distance
|
||||
-- If child would end up in a wall, use position of the "mother", unless
|
||||
-- the "mother" was stuck as well
|
||||
if not mother_stuck then
|
||||
|
@ -138,12 +53,14 @@ local spawn_children_on_die = function(child_mob, spawn_distance, eject_speed)
|
|||
eject_speed = eject_speed * 0.5
|
||||
end
|
||||
end
|
||||
local mob = minetest.add_entity(newpos, child_mob)
|
||||
if not mother_stuck then
|
||||
mob:set_velocity(dir * eject_speed)
|
||||
local mob = mcl_mobs.spawn(newpos, child_mob)
|
||||
if mob then
|
||||
if not mother_stuck then
|
||||
mob:set_velocity(dir * eject_speed)
|
||||
end
|
||||
mob:set_yaw(angle - math.pi/2)
|
||||
table.insert(children, mob)
|
||||
end
|
||||
mob:set_yaw(angle - math.pi/2)
|
||||
table.insert(children, mob)
|
||||
angle = angle + (math.pi*2) / spawn_count
|
||||
end
|
||||
-- If mother was murdered, children attack the killer after 1 second
|
||||
|
@ -162,16 +79,12 @@ local spawn_children_on_die = function(child_mob, spawn_distance, eject_speed)
|
|||
end
|
||||
end
|
||||
|
||||
local swamp_light_max = 7
|
||||
|
||||
-- two different rules, underground slime chunks and regular swamp spawning
|
||||
local function slime_spawn_check(pos, environmental_light, artificial_light, sky_light)
|
||||
local maxlight = swamp_light_max
|
||||
|
||||
if pos.y <= slime_chunk_spawn_max and is_slime_chunk(pos) then
|
||||
maxlight = minetest.LIGHT_MAX + 1
|
||||
return max(artificial_light, sky_light) <= slime_max_light
|
||||
end
|
||||
|
||||
return math.max(artificial_light, sky_light) <= maxlight
|
||||
return max(artificial_light, sky_light) <= swamp_light_max
|
||||
end
|
||||
|
||||
-- Slime
|
||||
|
@ -322,13 +235,13 @@ mcl_mobs:spawn_specific(
|
|||
"ground",
|
||||
cave_biomes,
|
||||
0,
|
||||
minetest.LIGHT_MAX+1,
|
||||
slime_max_light,
|
||||
30,
|
||||
1000,
|
||||
4,
|
||||
cave_min,
|
||||
cave_max,
|
||||
nil, nil, check_position)
|
||||
nil, nil, is_slime_chunk)
|
||||
|
||||
mcl_mobs:spawn_specific(
|
||||
"mobs_mc:slime_tiny",
|
||||
|
@ -349,13 +262,13 @@ mcl_mobs:spawn_specific(
|
|||
"ground",
|
||||
cave_biomes,
|
||||
0,
|
||||
minetest.LIGHT_MAX+1,
|
||||
slime_max_light,
|
||||
30,
|
||||
1000,
|
||||
4,
|
||||
cave_min,
|
||||
cave_max,
|
||||
nil, nil, check_position)
|
||||
nil, nil, is_slime_chunk)
|
||||
|
||||
mcl_mobs:spawn_specific(
|
||||
"mobs_mc:slime_small",
|
||||
|
@ -376,13 +289,13 @@ mcl_mobs:spawn_specific(
|
|||
"ground",
|
||||
cave_biomes,
|
||||
0,
|
||||
minetest.LIGHT_MAX+1,
|
||||
slime_max_light,
|
||||
30,
|
||||
1000,
|
||||
4,
|
||||
cave_min,
|
||||
cave_max,
|
||||
nil, nil, check_position)
|
||||
nil, nil, is_slime_chunk)
|
||||
|
||||
mcl_mobs:spawn_specific(
|
||||
"mobs_mc:slime_big",
|
||||
|
@ -559,3 +472,4 @@ mcl_mobs:non_spawn_specific("mobs_mc:magma_cube_big","overworld",0, minetest.LIG
|
|||
mcl_mobs.register_egg("mobs_mc:slime_big", S("Slime"), "#52a03e", "#7ebf6d")
|
||||
|
||||
-- FIXME: add spawn eggs for small and tiny slimes and magma cubes
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ local spider = {
|
|||
curiosity = 10,
|
||||
head_yaw="z",
|
||||
collisionbox = {-0.7, -0.01, -0.7, 0.7, 0.89, 0.7},
|
||||
spawnbox = {-1.2, -0.01, -1.2, 1.2, 0.89, 1.2},
|
||||
visual = "mesh",
|
||||
mesh = "mobs_mc_spider.b3d",
|
||||
textures = {
|
||||
|
|
|
@ -97,7 +97,7 @@ local tropical_fish = {
|
|||
makes_footstep_sound = false,
|
||||
swim = true,
|
||||
fly = true,
|
||||
fly_in = "mcl_core:water_source",
|
||||
fly_in = { "mcl_core:water_source", "mclx_core:river_water_source" },
|
||||
breathes_in_water = true,
|
||||
jump = false,
|
||||
view_range = 16,
|
||||
|
|
|
@ -818,7 +818,7 @@ local function find_closest_bed (self)
|
|||
|
||||
if (owned_by and owned_by == self._id) then
|
||||
mcl_log("Clear as already owned by me.")
|
||||
bed_meta:set_string("villager", nil)
|
||||
bed_meta:set_string("villager", "")
|
||||
owned_by = nil
|
||||
end
|
||||
|
||||
|
@ -1049,14 +1049,18 @@ local function has_summon_participants(self)
|
|||
end
|
||||
|
||||
local function summon_golem(self)
|
||||
vector.offset(self.object:get_pos(),-10,-10,-10)
|
||||
local nn = minetest.find_nodes_in_area_under_air(vector.offset(self.object:get_pos(),-10,-10,-10),vector.offset(self.object:get_pos(),10,10,10),{"group:solid","group:water"})
|
||||
table.shuffle(nn)
|
||||
for _,n in pairs(nn) do
|
||||
local up = minetest.find_nodes_in_area(vector.offset(n,0,1,0),vector.offset(n,0,3,0),{"air"})
|
||||
if up and #up >= 3 then
|
||||
local pos = self.object:get_pos()
|
||||
local p1 = vector.offset(pos, -10, -10, -10)
|
||||
local p2 = vector.offset(pos, 10, 10, 10)
|
||||
local nn = minetest.find_nodes_in_area_under_air(p1, p2,{"group:solid","group:water"})
|
||||
while #nn > 0 do
|
||||
local n = table.remove_random_element(nn)
|
||||
n.y = n.y + 1
|
||||
|
||||
local summon = mcl_mobs.spawn(n, "mobs_mc:iron_golem")
|
||||
if summon then
|
||||
minetest.sound_play("mcl_portals_open_end_portal", {pos=n, gain=0.5, max_hear_distance = 16}, true)
|
||||
return minetest.add_entity(vector.offset(n,0,1,0),"mobs_mc:iron_golem")
|
||||
return summon
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1279,7 +1283,7 @@ local function validate_jobsite(self)
|
|||
mcl_log("Jobsite far, so resettle: " .. tostring(resettle))
|
||||
if resettle then
|
||||
local m = minetest.get_meta(self._jobsite)
|
||||
m:set_string("villager", nil)
|
||||
m:set_string("villager", "")
|
||||
remove_job (self)
|
||||
return false
|
||||
end
|
||||
|
@ -1421,7 +1425,7 @@ local function validate_bed(self)
|
|||
mcl_log("Bed far, so resettle: " .. tostring(resettle))
|
||||
if resettle then
|
||||
mcl_log("Resettled. Ditch bed.")
|
||||
m:set_string("villager", nil)
|
||||
m:set_string("villager", "")
|
||||
self._bed = nil
|
||||
bed_valid = false
|
||||
return false
|
||||
|
@ -1431,7 +1435,7 @@ local function validate_bed(self)
|
|||
mcl_log("Player owner: " .. owned_by_player)
|
||||
if owned_by_player ~= "" then
|
||||
mcl_log("Player owns this. Villager won't take this.")
|
||||
m:set_string("villager", nil)
|
||||
m:set_string("villager", "")
|
||||
self._bed = nil
|
||||
bed_valid = false
|
||||
return false
|
||||
|
@ -2300,13 +2304,13 @@ mcl_mobs.register_mob("mobs_mc:villager", {
|
|||
local bed = self._bed
|
||||
if bed then
|
||||
local bed_meta = minetest.get_meta(bed)
|
||||
bed_meta:set_string("villager", nil)
|
||||
bed_meta:set_string("villager", "")
|
||||
mcl_log("Died, so bye bye bed")
|
||||
end
|
||||
local jobsite = self._jobsite
|
||||
if jobsite then
|
||||
local jobsite_meta = minetest.get_meta(jobsite)
|
||||
jobsite_meta:set_string("villager", nil)
|
||||
jobsite_meta:set_string("villager", "")
|
||||
mcl_log("Died, so bye bye jobsite")
|
||||
end
|
||||
|
||||
|
|
|
@ -55,14 +55,16 @@ mcl_mobs.register_mob("mobs_mc:evoker", {
|
|||
basepos.y = basepos.y + 1
|
||||
for i=1, r do
|
||||
local spawnpos = vector.add(basepos, minetest.yaw_to_dir(pr:next(0,360)))
|
||||
local vex = minetest.add_entity(spawnpos, "mobs_mc:vex")
|
||||
local ent = vex:get_luaentity()
|
||||
local vex = mcl_mobs.spawn(spawnpos, "mobs_mc:vex")
|
||||
if vex then
|
||||
local ent = vex:get_luaentity()
|
||||
|
||||
-- Mark vexes as summoned and start their life clock (they take damage it reaches 0)
|
||||
ent._summoned = true
|
||||
ent._lifetimer = pr:next(33, 108)
|
||||
-- Mark vexes as summoned and start their life clock (they take damage it reaches 0)
|
||||
ent._summoned = true
|
||||
ent._lifetimer = pr:next(33, 108)
|
||||
|
||||
table.insert(spawned_vexes[self],ent)
|
||||
table.insert(spawned_vexes[self],ent)
|
||||
end
|
||||
end
|
||||
end,
|
||||
passive = false,
|
||||
|
|
|
@ -134,6 +134,7 @@ mcl_mobs.register_mob("mobs_mc:villager_zombie", {
|
|||
end,
|
||||
sunlight_damage = 2,
|
||||
ignited_by_sunlight = true,
|
||||
floats = 0,
|
||||
view_range = 16,
|
||||
fear_height = 4,
|
||||
harmed_by_heal = true,
|
||||
|
|
|
@ -96,6 +96,7 @@ local zombie = {
|
|||
},
|
||||
ignited_by_sunlight = true,
|
||||
sunlight_damage = 2,
|
||||
floats = 0,
|
||||
view_range = 16,
|
||||
attack_type = "dogfight",
|
||||
harmed_by_heal = true,
|
||||
|
|
|
@ -19,7 +19,6 @@ local set_node = minetest.set_node
|
|||
local sound_play = minetest.sound_play
|
||||
local add_particlespawner = minetest.add_particlespawner
|
||||
local after = minetest.after
|
||||
local add_entity = minetest.add_entity
|
||||
local get_objects_inside_radius = minetest.get_objects_inside_radius
|
||||
local get_item_group = minetest.get_item_group
|
||||
|
||||
|
@ -165,7 +164,7 @@ function lightning.strike_func(pos, pos2, objects)
|
|||
|
||||
-- Events caused by the lightning strike: Fire, damage, mob transformations, rare skeleton spawn
|
||||
|
||||
pos2.y = pos2.y + 1/2
|
||||
pos2.y = pos2.y + 1
|
||||
local skeleton_lightning = false
|
||||
if rng:next(1,100) <= 3 then
|
||||
skeleton_lightning = true
|
||||
|
@ -174,14 +173,14 @@ function lightning.strike_func(pos, pos2, objects)
|
|||
if get_node(pos2).name == "air" then
|
||||
-- Low chance for a lightning to spawn skeleton horse + skeletons
|
||||
if skeleton_lightning then
|
||||
add_entity(pos2, "mobs_mc:skeleton_horse")
|
||||
mcl_mobs.spawn(pos2, "mobs_mc:skeleton_horse")
|
||||
|
||||
local angle, posadd
|
||||
angle = math.random(0, math.pi*2)
|
||||
angle = math.random() * math.pi * 2
|
||||
for i=1,3 do
|
||||
posadd = { x=math.cos(angle),y=0,z=math.sin(angle) }
|
||||
posadd = vector.normalize(posadd)
|
||||
local mob = add_entity(vector.add(pos2, posadd), "mobs_mc:skeleton")
|
||||
local mob = mcl_mobs.spawn(vector.add(pos2, posadd), "mobs_mc:skeleton")
|
||||
if mob then
|
||||
mob:set_yaw(angle-math.pi/2)
|
||||
end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name = mcl_void_damage
|
||||
author = Wuzzy
|
||||
description = Deal damage to entities stuck in the deep void
|
||||
depends = mcl_worlds
|
||||
depends = mcl_worlds, mcl_spawn
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name = mcl_weather
|
||||
author = xeranas
|
||||
description = Weather and sky handling: Rain, snow, thunderstorm, End and Nether ambience
|
||||
depends = mcl_init, mcl_worlds
|
||||
depends = mcl_init, mcl_worlds, mcl_playerinfo, mcl_util
|
||||
optional_depends = lightning
|
||||
|
|
|
@ -60,13 +60,15 @@ end
|
|||
-- set skybox based on time (uses skycolor api)
|
||||
function mcl_weather.rain.set_sky_box()
|
||||
if mcl_weather.state == "rain" then
|
||||
mcl_weather.skycolor.add_layer(
|
||||
"weather-pack-rain-sky",
|
||||
{{r=0, g=0, b=0},
|
||||
{r=85, g=86, b=98},
|
||||
{r=135, g=135, b=151},
|
||||
{r=85, g=86, b=98},
|
||||
{r=0, g=0, b=0}})
|
||||
if mcl_weather.skycolor.current_layer_name() ~= "weather-pack-rain-sky" then
|
||||
mcl_weather.skycolor.add_layer(
|
||||
"weather-pack-rain-sky",
|
||||
{{r=0, g=0, b=0},
|
||||
{r=85, g=86, b=98},
|
||||
{r=135, g=135, b=151},
|
||||
{r=85, g=86, b=98},
|
||||
{r=0, g=0, b=0}})
|
||||
end
|
||||
mcl_weather.skycolor.active = true
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
player:set_clouds({color="#5D5D5FE8"})
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
local mods_loaded = false
|
||||
-- Constants
|
||||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
local NIGHT_VISION_RATIO = 0.45
|
||||
|
||||
local MINIMUM_LIGHT_LEVEL = 0.2
|
||||
-- Settings
|
||||
local minimum_update_interval = { 250e3 }
|
||||
|
||||
local water_color = "#3F76E4"
|
||||
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
-- Module state
|
||||
local mods_loaded = false
|
||||
|
||||
function mcl_weather.set_sky_box_clear(player, sky, fog)
|
||||
local pos = player:get_pos()
|
||||
if minetest.get_item_group(minetest.get_node(vector.new(pos.x,pos.y+1.5,pos.z)).name, "water") ~= 0 then return end
|
||||
-- Make sure the player's head isn't in water before changing the skybox
|
||||
local node_head = mcl_playerinfo[player:get_player_name()].node_head
|
||||
if minetest.get_item_group(node_head, "water") ~= 0 then return end
|
||||
|
||||
local sc = {
|
||||
day_sky = "#7BA4FF",
|
||||
day_horizon = "#C0D8FF",
|
||||
|
@ -38,8 +42,10 @@ function mcl_weather.set_sky_box_clear(player, sky, fog)
|
|||
end
|
||||
|
||||
function mcl_weather.set_sky_color(player, def)
|
||||
local pos = player:get_pos()
|
||||
if minetest.get_item_group(minetest.get_node(vector.offset(pos, 0, 1.5, 0)).name, "water") ~= 0 then return end
|
||||
-- Make sure the player's head isn't in water before changing the skybox
|
||||
local node_head = mcl_playerinfo[player:get_player_name()].node_head
|
||||
if minetest.get_item_group(node_head, "water") ~= 0 then return end
|
||||
|
||||
player:set_sky({
|
||||
type = def.type,
|
||||
sky_color = def.sky_color,
|
||||
|
@ -47,25 +53,7 @@ function mcl_weather.set_sky_color(player, def)
|
|||
})
|
||||
end
|
||||
|
||||
-- Function to work out light modifier at different times
|
||||
-- Noon is brightest, midnight is darkest, 0600 and 18000 is in the middle of this
|
||||
local function get_light_modifier(time)
|
||||
-- 0.1 = 0.2
|
||||
-- 0.4 = 0.8
|
||||
-- 0.5 = 1
|
||||
-- 0.6 = 0.8
|
||||
-- 0.9 = 0.2
|
||||
|
||||
local light_multiplier = time * 2
|
||||
if time > 0.5 then
|
||||
light_multiplier = 2 * (1 - time)
|
||||
else
|
||||
light_multiplier = time / 0.5
|
||||
end
|
||||
return light_multiplier
|
||||
end
|
||||
|
||||
mcl_weather.skycolor = {
|
||||
local skycolor = {
|
||||
-- Should be activated before do any effect.
|
||||
active = true,
|
||||
|
||||
|
@ -85,319 +73,205 @@ mcl_weather.skycolor = {
|
|||
-- number of colors while constructing gradient of user given colors
|
||||
max_val = 1000,
|
||||
|
||||
NIGHT_VISION_RATIO = NIGHT_VISION_RATIO,
|
||||
|
||||
-- Table for tracking layer order
|
||||
layer_names = {},
|
||||
|
||||
-- To layer to colors table
|
||||
add_layer = function(layer_name, layer_color, instant_update)
|
||||
mcl_weather.skycolor.colors[layer_name] = layer_color
|
||||
table.insert(mcl_weather.skycolor.layer_names, layer_name)
|
||||
mcl_weather.skycolor.force_update = true
|
||||
end,
|
||||
|
||||
current_layer_name = function()
|
||||
return mcl_weather.skycolor.layer_names[#mcl_weather.skycolor.layer_names]
|
||||
end,
|
||||
|
||||
-- Retrieve layer from colors table
|
||||
retrieve_layer = function()
|
||||
local last_layer = mcl_weather.skycolor.current_layer_name()
|
||||
return mcl_weather.skycolor.colors[last_layer]
|
||||
end,
|
||||
|
||||
-- Remove layer from colors table
|
||||
remove_layer = function(layer_name)
|
||||
for k, name in pairs(mcl_weather.skycolor.layer_names) do
|
||||
if name == layer_name then
|
||||
table.remove(mcl_weather.skycolor.layer_names, k)
|
||||
mcl_weather.skycolor.force_update = true
|
||||
return
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
-- Wrapper for updating day/night ratio that respects night vision
|
||||
override_day_night_ratio = function(player, ratio)
|
||||
local meta = player:get_meta()
|
||||
local has_night_vision = meta:get_int("night_vision") == 1
|
||||
local has_darkness = meta:get_int("darkness") == 1
|
||||
local is_visited_shepherd = meta:get_int("mcl_shepherd:special") == 1
|
||||
local arg
|
||||
if has_darkness and not is_visited_shepherd then
|
||||
if has_night_vision then arg = 0.1
|
||||
else arg = 0 end
|
||||
else
|
||||
-- Apply night vision only for dark sky
|
||||
local is_dark = minetest.get_timeofday() > 0.8 or minetest.get_timeofday() < 0.2 or mcl_weather.state ~= "none"
|
||||
local pos = player:get_pos()
|
||||
local dim = mcl_worlds.pos_to_dimension(pos)
|
||||
if (has_night_vision or is_visited_shepherd) and is_dark and dim ~= "nether" and dim ~= "end" then
|
||||
if ratio == nil then
|
||||
arg = NIGHT_VISION_RATIO
|
||||
else
|
||||
arg = math.max(ratio, NIGHT_VISION_RATIO)
|
||||
end
|
||||
else
|
||||
arg = ratio
|
||||
end
|
||||
end
|
||||
player:override_day_night_ratio(arg)
|
||||
end,
|
||||
|
||||
-- Update sky color. If players not specified update sky for all players.
|
||||
update_sky_color = function(players)
|
||||
-- Override day/night ratio as well
|
||||
players = mcl_weather.skycolor.utils.get_players(players)
|
||||
for _, player in ipairs(players) do
|
||||
local pos = player:get_pos()
|
||||
local dim = mcl_worlds.pos_to_dimension(pos)
|
||||
local has_weather = (mcl_worlds.has_weather(pos) and (mcl_weather.state == "snow" or mcl_weather.state =="rain" or mcl_weather.state == "thunder") and mcl_weather.has_snow(pos)) or ((mcl_weather.state =="rain" or mcl_weather.state == "thunder") and mcl_weather.has_rain(pos))
|
||||
local checkname = minetest.get_node(vector.new(pos.x,pos.y+1.5,pos.z)).name
|
||||
if minetest.get_item_group(checkname, "water") ~= 0 then
|
||||
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 water_color = biome._mcl_waterfogcolor end
|
||||
if not biome then water_color = "#3F76E4" end
|
||||
if checkname == "mclx_core:river_water_source" or checkname == "mclx_core:river_water_flowing" then water_color = "#0084FF" end
|
||||
player:set_sky({ type = "regular",
|
||||
sky_color = {
|
||||
day_sky = water_color,
|
||||
day_horizon = water_color,
|
||||
dawn_sky = water_color,
|
||||
dawn_horizon = water_color,
|
||||
night_sky = water_color,
|
||||
night_horizon = water_color,
|
||||
indoors = water_color,
|
||||
fog_sun_tint = water_color,
|
||||
fog_moon_tint = water_color,
|
||||
fog_tint_type = "custom"
|
||||
},
|
||||
clouds = false,
|
||||
})
|
||||
end
|
||||
if dim == "overworld" then
|
||||
local biomesky
|
||||
local biomefog
|
||||
if mg_name ~= "v6" and mg_name ~= "singlenode" then
|
||||
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
|
||||
mcl_weather.set_sky_box_clear(player,biomesky,biomefog)
|
||||
player:set_sun({visible = true, sunrise_visible = true})
|
||||
player:set_moon({visible = true})
|
||||
player:set_stars({visible = true})
|
||||
mcl_weather.skycolor.override_day_night_ratio(player, nil)
|
||||
elseif not has_weather then
|
||||
local day_color = mcl_weather.skycolor.get_sky_layer_color(0.15)
|
||||
local dawn_color = mcl_weather.skycolor.get_sky_layer_color(0.27)
|
||||
local night_color = mcl_weather.skycolor.get_sky_layer_color(0.1)
|
||||
mcl_weather.set_sky_color(player, {
|
||||
type = "regular",
|
||||
sky_color = {
|
||||
day_sky = day_color,
|
||||
day_horizon = day_color,
|
||||
dawn_sky = dawn_color,
|
||||
dawn_horizon = dawn_color,
|
||||
night_sky = night_color,
|
||||
night_horizon = night_color,
|
||||
},
|
||||
clouds = true,
|
||||
})
|
||||
player:set_sun({visible = false, sunrise_visible = false})
|
||||
player:set_moon({visible = false})
|
||||
player:set_stars({visible = false})
|
||||
elseif has_weather then
|
||||
-- Weather skies
|
||||
local day_color = mcl_weather.skycolor.get_sky_layer_color(0.5)
|
||||
local dawn_color = mcl_weather.skycolor.get_sky_layer_color(0.75)
|
||||
local night_color = mcl_weather.skycolor.get_sky_layer_color(0)
|
||||
mcl_weather.set_sky_color(player, {
|
||||
type = "regular",
|
||||
sky_color = {
|
||||
day_sky = day_color,
|
||||
day_horizon = day_color,
|
||||
dawn_sky = dawn_color,
|
||||
dawn_horizon = dawn_color,
|
||||
night_sky = night_color,
|
||||
night_horizon = night_color,
|
||||
},
|
||||
clouds = true,
|
||||
})
|
||||
player:set_sun({visible = false, sunrise_visible = false})
|
||||
player:set_moon({visible = false})
|
||||
player:set_stars({visible = false})
|
||||
|
||||
local light_factor = mcl_weather.get_current_light_factor()
|
||||
if mcl_weather.skycolor.current_layer_name() == "lightning" then
|
||||
mcl_weather.skycolor.override_day_night_ratio(player, 1)
|
||||
elseif light_factor then
|
||||
local time = minetest.get_timeofday()
|
||||
local light_multiplier = get_light_modifier(time)
|
||||
local new_light = math.max(light_factor * light_multiplier, MINIMUM_LIGHT_LEVEL)
|
||||
mcl_weather.skycolor.override_day_night_ratio(player, new_light)
|
||||
else
|
||||
mcl_weather.skycolor.override_day_night_ratio(player, nil)
|
||||
end
|
||||
end
|
||||
elseif dim == "end" then
|
||||
local biomesky = "#000000"
|
||||
local biomefog = "#A080A0"
|
||||
if mg_name ~= "v6" and mg_name ~= "singlenode" then
|
||||
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 -- The End biomes seemingly don't use the fog colour, despite having this value according to the wiki. The sky colour is seemingly used for both sky and fog?
|
||||
else
|
||||
--minetest.log("action", string.format("No biome for number: %s in biome: %s", tostring(biome_index), biome_name))
|
||||
end
|
||||
end
|
||||
local t = "mcl_playerplus_end_sky.png"
|
||||
player:set_sky({ type = "skybox",
|
||||
base_color = biomesky,
|
||||
textures = {t,t,t,t,t,t},
|
||||
clouds = false,
|
||||
})
|
||||
player:set_sun({visible = false , sunrise_visible = false})
|
||||
player:set_moon({visible = false})
|
||||
player:set_stars({visible = false})
|
||||
mcl_weather.skycolor.override_day_night_ratio(player, 0.5)
|
||||
elseif dim == "nether" then
|
||||
local biomesky = "#6EB1FF"
|
||||
local biomefog = "#330808"
|
||||
if mg_name ~= "v6" and mg_name ~= "singlenode" then
|
||||
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 -- The Nether biomes seemingly don't use the sky colour, despite having this value according to the wiki. The fog colour is used for both sky and fog.
|
||||
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
|
||||
mcl_weather.set_sky_color(player, {
|
||||
type = "regular",
|
||||
sky_color = {
|
||||
day_sky = biomefog,
|
||||
day_horizon = biomefog,
|
||||
dawn_sky = biomefog,
|
||||
dawn_horizon = biomefog,
|
||||
night_sky = biomefog,
|
||||
night_horizon = biomefog,
|
||||
indoors = biomefog,
|
||||
fog_sun_tint = biomefog,
|
||||
fog_moon_tint = biomefog,
|
||||
fog_tint_type = "custom"
|
||||
},
|
||||
clouds = false,
|
||||
})
|
||||
player:set_sun({visible = false , sunrise_visible = false})
|
||||
player:set_moon({visible = false})
|
||||
player:set_stars({visible = false})
|
||||
mcl_weather.skycolor.override_day_night_ratio(player, nil)
|
||||
elseif dim == "void" then
|
||||
player:set_sky({ type = "plain",
|
||||
base_color = "#000000",
|
||||
clouds = false,
|
||||
})
|
||||
player:set_sun({visible = false, sunrise_visible = false})
|
||||
player:set_moon({visible = false})
|
||||
player:set_stars({visible = false})
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
-- Returns current layer color in {r, g, b} format
|
||||
get_sky_layer_color = function(timeofday)
|
||||
if #mcl_weather.skycolor.layer_names == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- min timeofday value 0; max timeofday value 1. So sky color gradient range will be between 0 and 1 * mcl_weather.skycolor.max_val.
|
||||
local rounded_time = math.floor(timeofday * mcl_weather.skycolor.max_val)
|
||||
local color = mcl_weather.skycolor.utils.convert_to_rgb(mcl_weather.skycolor.min_val, mcl_weather.skycolor.max_val, rounded_time, mcl_weather.skycolor.retrieve_layer())
|
||||
return color
|
||||
end,
|
||||
|
||||
utils = {
|
||||
convert_to_rgb = function(minval, maxval, current_val, colors)
|
||||
local max_index = #colors - 1
|
||||
local val = (current_val-minval) / (maxval-minval) * max_index + 1.0
|
||||
local index1 = math.floor(val)
|
||||
local index2 = math.min(math.floor(val)+1, max_index + 1)
|
||||
local f = val - index1
|
||||
local c1 = colors[index1]
|
||||
local c2 = colors[index2]
|
||||
return {r=math.floor(c1.r + f*(c2.r - c1.r)), g=math.floor(c1.g + f*(c2.g-c1.g)), b=math.floor(c1.b + f*(c2.b - c1.b))}
|
||||
end,
|
||||
|
||||
-- Simply getter. Ether returns user given players list or get all connected players if none provided
|
||||
get_players = function(players)
|
||||
if players == nil or #players == 0 then
|
||||
if mods_loaded then
|
||||
players = minetest.get_connected_players()
|
||||
elseif players == nil then
|
||||
players = {}
|
||||
end
|
||||
end
|
||||
return players
|
||||
end,
|
||||
|
||||
-- Returns first player sky color. I assume that all players are in same color layout.
|
||||
get_current_bg_color = function()
|
||||
local players = mcl_weather.skycolor.utils.get_players(nil)
|
||||
if players[1] then
|
||||
return players[1]:get_sky(true).sky_color
|
||||
end
|
||||
return nil
|
||||
end
|
||||
},
|
||||
|
||||
utils = {},
|
||||
}
|
||||
mcl_weather.skycolor = skycolor
|
||||
local skycolor_utils = skycolor.utils
|
||||
|
||||
-- Add layer to colors table
|
||||
function skycolor.add_layer(layer_name, layer_color, instant_update)
|
||||
skycolor.colors[layer_name] = layer_color
|
||||
table.insert(skycolor.layer_names, layer_name)
|
||||
skycolor.force_update = true
|
||||
end
|
||||
|
||||
function skycolor.current_layer_name()
|
||||
return skycolor.layer_names[#skycolor.layer_names]
|
||||
end
|
||||
|
||||
-- Retrieve layer from colors table
|
||||
function skycolor.retrieve_layer()
|
||||
local last_layer = skycolor.current_layer_name()
|
||||
return skycolor.colors[last_layer]
|
||||
end
|
||||
|
||||
-- Remove layer from colors table
|
||||
function skycolor.remove_layer(layer_name)
|
||||
for k, name in pairs(skycolor.layer_names) do
|
||||
if name == layer_name then
|
||||
table.remove(skycolor.layer_names, k)
|
||||
skycolor.force_update = true
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Wrapper for updating day/night ratio that respects night vision
|
||||
function skycolor.override_day_night_ratio(player, ratio)
|
||||
player._skycolor_day_night_ratio = ratio
|
||||
skycolor.update_player_sky_color(player)
|
||||
player._skycolor_day_night_ratio = nil
|
||||
end
|
||||
|
||||
local skycolor_filters = {}
|
||||
skycolor.filters = skycolor_filters
|
||||
dofile(modpath.."/skycolor/water.lua")
|
||||
dofile(modpath.."/skycolor/dimensions.lua")
|
||||
dofile(modpath.."/skycolor/effects.lua")
|
||||
|
||||
local function get_skycolor_info(player)
|
||||
local player_name = player:get_player_name()
|
||||
|
||||
local info = mcl_playerinfo[player_name] or {}
|
||||
|
||||
local skycolor_data = info.skycolor
|
||||
if not skycolor_data then
|
||||
skycolor_data = {}
|
||||
info.skycolor = skycolor_data
|
||||
end
|
||||
|
||||
return skycolor_data
|
||||
end
|
||||
|
||||
local water_sky = skycolor.water_sky
|
||||
function skycolor.update_player_sky_color(player)
|
||||
-- Don't update more than once every 250 milliseconds
|
||||
local skycolor_data = get_skycolor_info(player)
|
||||
local last_update = skycolor_data.last_update or 0
|
||||
local now_us = minetest.get_us_time()
|
||||
if (now_us - last_update) < minimum_update_interval[1] then return end
|
||||
skycolor_data.last_update = now_us
|
||||
|
||||
local sky_data = {
|
||||
day_night_ratio = player._skycolor_day_night_ratio
|
||||
}
|
||||
|
||||
for i = 1,#skycolor_filters do
|
||||
skycolor_filters[i](player, sky_data)
|
||||
end
|
||||
|
||||
assert(sky_data.sky)
|
||||
player:set_sky(sky_data.sky)
|
||||
|
||||
if sky_data.sun then player:set_sun(sky_data.sun) end
|
||||
if sky_data.moon then player:set_moon(sky_data.moon) end
|
||||
if sky_data.stars then player:set_stars(sky_data.stars) end
|
||||
player:override_day_night_ratio(sky_data.day_night_ratio)
|
||||
end
|
||||
|
||||
-- Update sky color. If players not specified update sky for all players.
|
||||
function skycolor.update_sky_color(players)
|
||||
-- Override day/night ratio as well
|
||||
players = skycolor_utils.get_players(players)
|
||||
local update = skycolor.update_player_sky_color
|
||||
for _, player in ipairs(players) do
|
||||
update(player)
|
||||
end
|
||||
end
|
||||
|
||||
-- Returns current layer color in {r, g, b} format
|
||||
function skycolor.get_sky_layer_color(timeofday)
|
||||
if #skycolor.layer_names == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- min timeofday value 0; max timeofday value 1. So sky color gradient range will be between 0 and 1 * skycolor.max_val
|
||||
local rounded_time = math.floor(timeofday * skycolor.max_val)
|
||||
return skycolor_utils.convert_to_rgb(
|
||||
skycolor.min_val, skycolor.max_val,
|
||||
rounded_time, skycolor.retrieve_layer()
|
||||
)
|
||||
end
|
||||
|
||||
function skycolor_utils.convert_to_rgb(minval, maxval, current_val, colors)
|
||||
-- Clamp current_val to valid range
|
||||
current_val = math.min(minval, current_val)
|
||||
current_val = math.max(maxval, current_val)
|
||||
|
||||
-- Rescale current_val from a number between minval and maxval to a number between 1 and #colors
|
||||
local scaled_value = (current_val - minval) / (maxval - minval) * (#colors - 1) + 1.0
|
||||
|
||||
-- Get the first color's values
|
||||
local index1 = math.floor(scaled_value)
|
||||
local color1 = colors[index1]
|
||||
local frac1 = scaled_value - index1
|
||||
|
||||
-- Get the second color's values
|
||||
local index2 = math.min(index1 + 1, #colors) -- clamp to maximum color index (will occur if index1 == #colors)
|
||||
local frac2 = 1.0 - frac1
|
||||
local color2 = colors[index2]
|
||||
|
||||
-- Interpolate between color1 and color2
|
||||
return {
|
||||
r = math.floor(frac1 * color1.r + frac2 * color2.r),
|
||||
g = math.floor(frac1 * color1.g + frac2 * color2.g),
|
||||
b = math.floor(frac1 * color1.b + frac2 * color2.b),
|
||||
}
|
||||
end
|
||||
|
||||
-- Simple getter. Either returns user given players list or get all connected players if none provided
|
||||
function skycolor_utils.get_players(players)
|
||||
if players == nil or #players == 0 then
|
||||
if mods_loaded then
|
||||
players = minetest.get_connected_players()
|
||||
elseif players == nil then
|
||||
players = {}
|
||||
end
|
||||
end
|
||||
return players
|
||||
end
|
||||
|
||||
-- Returns the sky color of the first player, which is done assuming that all players are in same color layout.
|
||||
function skycolor_utils.get_current_bg_color()
|
||||
local players = skycolor_utils.get_players(nil)
|
||||
if players[1] then
|
||||
return players[1]:get_sky(true).sky_color
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local timer = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
if mcl_weather.skycolor.active ~= true or #minetest.get_connected_players() == 0 then
|
||||
if skycolor.active ~= true or #minetest.get_connected_players() == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
if mcl_weather.skycolor.force_update then
|
||||
mcl_weather.skycolor.update_sky_color()
|
||||
mcl_weather.skycolor.force_update = false
|
||||
if skycolor.force_update then
|
||||
skycolor.update_sky_color()
|
||||
skycolor.force_update = false
|
||||
return
|
||||
end
|
||||
|
||||
-- regular updates based on iterval
|
||||
timer = timer + dtime;
|
||||
if timer >= mcl_weather.skycolor.update_interval then
|
||||
mcl_weather.skycolor.update_sky_color()
|
||||
if timer >= skycolor.update_interval then
|
||||
skycolor.update_sky_color()
|
||||
timer = 0
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
local function initsky(player)
|
||||
|
||||
if player.set_lighting then
|
||||
player:set_lighting({ shadows = { intensity = tonumber(minetest.settings:get("mcl_default_shadow_intensity") or 0.33) } })
|
||||
player:set_lighting({
|
||||
shadows = { intensity = 0.33 },
|
||||
volumetric_light = { strength = 0.45 },
|
||||
exposure = {
|
||||
luminance_min = -3.5,
|
||||
luminance_max = -2.5,
|
||||
exposure_correction = 0.35,
|
||||
speed_dark_bright = 1500,
|
||||
speed_bright_dark = 700,
|
||||
},
|
||||
saturation = 1.1,
|
||||
})
|
||||
end
|
||||
|
||||
if (mcl_weather.skycolor.active) then
|
||||
if (skycolor.active) then
|
||||
mcl_weather.skycolor.force_update = true
|
||||
end
|
||||
|
||||
|
@ -408,7 +282,7 @@ minetest.register_on_joinplayer(initsky)
|
|||
minetest.register_on_respawnplayer(initsky)
|
||||
|
||||
mcl_worlds.register_on_dimension_change(function(player)
|
||||
mcl_weather.skycolor.update_sky_color({player})
|
||||
skycolor.update_sky_color({player})
|
||||
end)
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
local MINIMUM_LIGHT_LEVEL = 0.2
|
||||
local VALID_SNOW_WEATHER_STATES = { snow = true, rain = true, thunder = true }
|
||||
local VALID_RAIN_WEATHER_STATES = { rain = true, thunder = true }
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
|
||||
local dimension_handlers = {}
|
||||
mcl_weather.skycolor.dimension_handlers = dimension_handlers
|
||||
|
||||
-- Function to work out light modifier at different times
|
||||
-- Noon is brightest, midnight is darkest, 0600 and 1800 is in the middle of this
|
||||
local function get_light_modifier(time)
|
||||
-- 0.1 = 0.2
|
||||
-- 0.4 = 0.8
|
||||
-- 0.5 = 1
|
||||
-- 0.6 = 0.8
|
||||
-- 0.9 = 0.2
|
||||
|
||||
local light_multiplier = time * 2
|
||||
if time > 0.5 then
|
||||
light_multiplier = 2 * (1 - time)
|
||||
else
|
||||
light_multiplier = time / 0.5
|
||||
end
|
||||
return light_multiplier
|
||||
end
|
||||
|
||||
function dimension_handlers.overworld(player, sky_data)
|
||||
local pos = player:get_pos()
|
||||
|
||||
local biomesky
|
||||
local biomefog
|
||||
if mg_name ~= "v6" and mg_name ~= "singlenode" then
|
||||
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
|
||||
biomesky = biome._mcl_skycolor
|
||||
biomefog = biome._mcl_fogcolor
|
||||
end
|
||||
end
|
||||
|
||||
-- Use overworld defaults
|
||||
local day_color = mcl_weather.skycolor.get_sky_layer_color(0.15)
|
||||
local dawn_color = mcl_weather.skycolor.get_sky_layer_color(0.27)
|
||||
local night_color = mcl_weather.skycolor.get_sky_layer_color(0.1)
|
||||
sky_data.sky = {
|
||||
type = "regular",
|
||||
sky_color = {
|
||||
day_sky = day_color,
|
||||
day_horizon = day_color,
|
||||
dawn_sky = dawn_color,
|
||||
dawn_horizon = dawn_color,
|
||||
night_sky = night_color,
|
||||
night_horizon = night_color,
|
||||
},
|
||||
clouds = true,
|
||||
}
|
||||
sky_data.sun = {visible = true, sunrise_visible = true}
|
||||
sky_data.moon = {visible = true}
|
||||
sky_data.stars = {visible = true}
|
||||
|
||||
if mcl_weather.state == "none" then
|
||||
-- Clear weather
|
||||
mcl_weather.set_sky_box_clear(player,biomesky,biomefog)
|
||||
return
|
||||
end
|
||||
|
||||
-- Check if we currently have weather that affects the sky color
|
||||
local has_weather = mcl_worlds.has_weather(pos) and (
|
||||
mcl_weather.has_snow(pos) and VALID_SNOW_WEATHER_STATES[mcl_weather.state] or
|
||||
mcl_weather.has_rain(pos) and VALID_RAIN_WEATHER_STATES[mcl_weather.state]
|
||||
)
|
||||
if has_weather then
|
||||
-- Weather skies
|
||||
local day_color = mcl_weather.skycolor.get_sky_layer_color(0.5)
|
||||
local dawn_color = mcl_weather.skycolor.get_sky_layer_color(0.75)
|
||||
local night_color = mcl_weather.skycolor.get_sky_layer_color(0)
|
||||
sky_data.sky = {
|
||||
type = "regular",
|
||||
sky_color = {
|
||||
day_sky = day_color,
|
||||
day_horizon = day_color,
|
||||
dawn_sky = dawn_color,
|
||||
dawn_horizon = dawn_color,
|
||||
night_sky = night_color,
|
||||
night_horizon = night_color,
|
||||
},
|
||||
clouds = true,
|
||||
}
|
||||
sky_data.sun = {visible = false, sunrise_visible = false}
|
||||
sky_data.moon = {visible = false}
|
||||
sky_data.stars = {visible = false}
|
||||
|
||||
local light_factor = mcl_weather.get_current_light_factor()
|
||||
if mcl_weather.skycolor.current_layer_name() == "lightning" then
|
||||
sky_data.day_night_ratio = 1
|
||||
elseif light_factor then
|
||||
local time = minetest.get_timeofday()
|
||||
local light_multiplier = get_light_modifier(time)
|
||||
local new_light = math.max(light_factor * light_multiplier, MINIMUM_LIGHT_LEVEL)
|
||||
sky_data.day_night_ratio = new_light
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- This can't be function dimension_handlers.end() due to lua syntax
|
||||
dimension_handlers["end"] = function(player, sky_data)
|
||||
local biomesky = "#000000"
|
||||
local biomefog = "#A080A0"
|
||||
if mg_name ~= "v6" and mg_name ~= "singlenode" then
|
||||
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
|
||||
biomesky = biome._mcl_skycolor
|
||||
biomefog = biome._mcl_fogcolor -- The End biomes seemingly don't use the fog colour, despite having this value according to the wiki. The sky colour is seemingly used for both sky and fog?
|
||||
end
|
||||
end
|
||||
local t = "mcl_playerplus_end_sky.png"
|
||||
sky_data.sky = { type = "skybox",
|
||||
base_color = biomesky,
|
||||
textures = {t,t,t,t,t,t},
|
||||
clouds = false,
|
||||
}
|
||||
sky_data.sun = {visible = false , sunrise_visible = false}
|
||||
sky_data.moon = {visible = false}
|
||||
sky_data.stars = {visible = false}
|
||||
sky_data.day_night_ratio = 0.5
|
||||
end
|
||||
|
||||
function dimension_handlers.nether(player, sky_data)
|
||||
local biomesky = "#6EB1FF"
|
||||
local biomefog = "#330808"
|
||||
if mg_name ~= "v6" and mg_name ~= "singlenode" then
|
||||
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
|
||||
-- The Nether biomes seemingly don't use the sky colour, despite having this value according to the wiki.
|
||||
-- The fog colour is used for both sky and fog.
|
||||
biomesky = biome._mcl_skycolor
|
||||
biomefog = biome._mcl_fogcolor
|
||||
end
|
||||
end
|
||||
sky_data.sky = {
|
||||
type = "regular",
|
||||
sky_color = {
|
||||
day_sky = biomefog,
|
||||
day_horizon = biomefog,
|
||||
dawn_sky = biomefog,
|
||||
dawn_horizon = biomefog,
|
||||
night_sky = biomefog,
|
||||
night_horizon = biomefog,
|
||||
indoors = biomefog,
|
||||
fog_sun_tint = biomefog,
|
||||
fog_moon_tint = biomefog,
|
||||
fog_tint_type = "custom"
|
||||
},
|
||||
clouds = false,
|
||||
}
|
||||
sky_data.sun = {visible = false , sunrise_visible = false}
|
||||
sky_data.moon = {visible = false}
|
||||
sky_data.stars = {visible = false}
|
||||
end
|
||||
|
||||
function dimension_handlers.void(player, sky_data)
|
||||
sky_data.sky = { type = "plain",
|
||||
base_color = "#000000",
|
||||
clouds = false,
|
||||
}
|
||||
sky_data.sun = {visible = false, sunrise_visible = false}
|
||||
sky_data.moon = {visible = false}
|
||||
sky_data.stars = {visible = false}
|
||||
end
|
||||
|
||||
local function dimension(player, sky_data)
|
||||
local pos = player:get_pos()
|
||||
local dim = mcl_worlds.pos_to_dimension(pos)
|
||||
|
||||
local handler = dimension_handlers[dim]
|
||||
if handler then return handler(player, sky_data) end
|
||||
end
|
||||
table.insert(mcl_weather.skycolor.filters, dimension)
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
local DIM_ALLOW_NIGHT_VISION = {
|
||||
overworld = true,
|
||||
void = true,
|
||||
}
|
||||
|
||||
local NIGHT_VISION_RATIO = mcl_weather.skycolor.NIGHT_VISION_RATIO
|
||||
local effects_handlers = {}
|
||||
local has_mcl_potions = mcl_util.to_bool(minetest.get_modpath("mcl_potions"))
|
||||
|
||||
function effects_handlers.darkness(player, meta, effect, sky_data)
|
||||
-- No darkness effect if is a visited shepherd
|
||||
if meta:get_int("mcl_shepherd:special") == 1 then return end
|
||||
|
||||
-- High stars
|
||||
sky_data.stars = {visible = false}
|
||||
|
||||
-- Minor visibility if the player has the night vision effect
|
||||
if mcl_potions.has_effect(player, "night_vision") then
|
||||
sky_data.day_night_ratio = 0.1
|
||||
else
|
||||
sky_data.day_night_ratio = 0
|
||||
end
|
||||
end
|
||||
|
||||
function effects_handlers.night_vision(player, meta, effect, sky_data)
|
||||
-- Apply night vision only for dark sky
|
||||
if not (minetest.get_timeofday() > 0.8 or minetest.get_timeofday() < 0.2 or mcl_weather.state ~= "none") then return end
|
||||
|
||||
-- Only some dimensions allow night vision
|
||||
local pos = player:get_pos()
|
||||
local dim = mcl_worlds.pos_to_dimension(pos)
|
||||
if not DIM_ALLOW_NIGHT_VISION[dim] then return end
|
||||
|
||||
-- Apply night vision
|
||||
sky_data.day_night_ratio = math.max(sky_data.day_night_ratio or 0, NIGHT_VISION_RATIO)
|
||||
end
|
||||
|
||||
local function effects(player, sky_data)
|
||||
if not has_mcl_potions then return end
|
||||
|
||||
local meta = player:get_meta()
|
||||
for name,effect in pairs(mcl_potions.registered_effects) do
|
||||
local effect_data = mcl_potions.get_effect(player, name)
|
||||
if effect_data then
|
||||
local hook = effect.mcl_weather_skycolor or effects_handlers[name]
|
||||
if hook then hook(player, meta, effect_data, sky_data) end
|
||||
end
|
||||
end
|
||||
|
||||
-- Handle night vision for shepherd
|
||||
if meta:get_int("mcl_shepherd:special") == 1 then
|
||||
return effects_handlers.night_vision(player, meta, {}, sky_data)
|
||||
end
|
||||
end
|
||||
table.insert(mcl_weather.skycolor.filters, effects)
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
local DEFAULT_WATER_COLOR = "#3F76E4"
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
|
||||
local function water_sky(player, sky_data)
|
||||
local water_color = DEFAULT_WATER_COLOR
|
||||
|
||||
local checkname = mcl_playerinfo[player:get_player_name()].node_head
|
||||
if minetest.get_item_group(checkname, "water") == 0 then return end
|
||||
|
||||
local pos = player:get_pos()
|
||||
local biome = nil
|
||||
if mg_name ~= "v6" and mg_name ~= "singlenode" then
|
||||
local biome_index = minetest.get_biome_data(pos).biome
|
||||
local biome_name = minetest.get_biome_name(biome_index)
|
||||
biome = minetest.registered_biomes[biome_name]
|
||||
end
|
||||
if biome then water_color = biome._mcl_waterfogcolor end
|
||||
if not biome then water_color = DEFAULT_WATER_COLOR end
|
||||
|
||||
if checkname == "mclx_core:river_water_source" or checkname == "mclx_core:river_water_flowing" then water_color = "#0084FF" end
|
||||
|
||||
sky_data.sky = { type = "regular",
|
||||
sky_color = {
|
||||
day_sky = water_color,
|
||||
day_horizon = water_color,
|
||||
dawn_sky = water_color,
|
||||
dawn_horizon = water_color,
|
||||
night_sky = water_color,
|
||||
night_horizon = water_color,
|
||||
indoors = water_color,
|
||||
fog_sun_tint = water_color,
|
||||
fog_moon_tint = water_color,
|
||||
fog_tint_type = "custom"
|
||||
},
|
||||
clouds = true,
|
||||
}
|
||||
end
|
||||
table.insert(mcl_weather.skycolor.filters, water_sky)
|
||||
|
|
@ -10,6 +10,10 @@ mcl_weather.thunder = {
|
|||
init_done = false,
|
||||
}
|
||||
|
||||
lightning.register_on_strike(function(pos, pos2, objects)
|
||||
if not mcl_weather.has_rain(pos) then return nil, true end
|
||||
end)
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
if mcl_weather.get_weather() ~= "thunder" then
|
||||
return false
|
||||
|
|
|
@ -678,6 +678,7 @@ local function make_formspec(name)
|
|||
image_button[2.4,0.12;0.8,0.8;craftguide_search_icon.png;search;]
|
||||
image_button[3.05,0.12;0.8,0.8;craftguide_clear_icon.png;clear;]
|
||||
field_close_on_enter[filter;false]
|
||||
field_enter_after_edit[filter;true]
|
||||
]]
|
||||
|
||||
fs[#fs + 1] = fmt([[ tooltip[search;%s]
|
||||
|
|
|
@ -126,6 +126,9 @@ S("• I: Show/hide inventory menu").."\n\n"..
|
|||
S("Inventory interaction:").."\n"..
|
||||
S("See the entry “Basics > Inventory”.").."\n\n"..
|
||||
|
||||
S("Hunger/Eating:").."\n"..
|
||||
S("• While holding food, hold the right mouse button (PC) or double-tap and hold the second tap (Android) to eat").."\n\n"..
|
||||
|
||||
S("Camera:").."\n"..
|
||||
S("• Z: Zoom").."\n"..
|
||||
S("• F7: Toggle camera mode").."\n\n"..
|
||||
|
|
|
@ -78,6 +78,8 @@ World interaction:=
|
|||
• I: Show/hide inventory menu=
|
||||
Inventory interaction:=
|
||||
See the entry “Basics > Inventory”.=
|
||||
Hunger/Eating:=
|
||||
• While holding food, hold the right mouse button (PC) or double-tap and hold the second tap (Android) to eat=
|
||||
Camera:=
|
||||
• Z: Zoom=
|
||||
• F7: Toggle camera mode=
|
||||
|
|
|
@ -37,6 +37,8 @@ end
|
|||
-- Digging capabilities of tool
|
||||
tt.register_snippet(function(itemstring, toolcaps, itemstack)
|
||||
local def = minetest.registered_items[itemstring]
|
||||
if not def then return end
|
||||
|
||||
if not toolcaps then
|
||||
return
|
||||
end
|
||||
|
@ -165,6 +167,8 @@ end)]]
|
|||
-- Food
|
||||
tt.register_snippet(function(itemstring)
|
||||
local def = minetest.registered_items[itemstring]
|
||||
if not def then return end
|
||||
|
||||
local desc
|
||||
if def._tt_food then
|
||||
desc = S("Food item")
|
||||
|
@ -179,6 +183,8 @@ end)
|
|||
-- Node info
|
||||
tt.register_snippet(function(itemstring)
|
||||
local def = minetest.registered_items[itemstring]
|
||||
if not def then return end
|
||||
|
||||
local desc = ""
|
||||
|
||||
-- Health-related node facts
|
||||
|
|
|
@ -64,6 +64,8 @@ end)
|
|||
|
||||
tt.register_snippet(function(itemstring)
|
||||
local def = minetest.registered_items[itemstring]
|
||||
if not def then return end
|
||||
|
||||
local s = ""
|
||||
if def.groups.eatable and def.groups.eatable > 0 then
|
||||
s = s .. S("Hunger points: +@1", def.groups.eatable)
|
||||
|
@ -89,6 +91,8 @@ end)
|
|||
|
||||
tt.register_snippet(function(itemstring)
|
||||
local def = minetest.registered_items[itemstring]
|
||||
if not def then return end
|
||||
|
||||
if def.groups.place_flowerlike == 1 then
|
||||
return S("Grows on grass blocks or dirt")
|
||||
elseif def.groups.place_flowerlike == 2 then
|
||||
|
@ -98,6 +102,8 @@ end)
|
|||
|
||||
tt.register_snippet(function(itemstring)
|
||||
local def = minetest.registered_items[itemstring]
|
||||
if not def then return end
|
||||
|
||||
if def.groups.flammable then
|
||||
return S("Flammable")
|
||||
end
|
||||
|
@ -127,6 +133,8 @@ end)
|
|||
tt.register_snippet(function(itemstring, _, itemstack)
|
||||
if not itemstack then return end
|
||||
local def = itemstack:get_definition()
|
||||
if not def then return end
|
||||
|
||||
if def.groups._mcl_potion ~= 1 then return end
|
||||
|
||||
local s = ""
|
||||
|
|
|
@ -20,23 +20,12 @@ dofile(minetest.get_modpath(minetest.get_current_modname()).."/snippets.lua")
|
|||
-- Apply item description updates
|
||||
|
||||
local function apply_snippets(desc, itemstring, toolcaps, itemstack)
|
||||
local first = true
|
||||
-- Apply snippets
|
||||
for s=1, #tt.registered_snippets do
|
||||
local str, snippet_color = tt.registered_snippets[s](itemstring, toolcaps, itemstack)
|
||||
if snippet_color == nil then
|
||||
snippet_color = tt.COLOR_DEFAULT
|
||||
end
|
||||
if str then
|
||||
if first then
|
||||
first = false
|
||||
end
|
||||
desc = desc .. "\n"
|
||||
if snippet_color then
|
||||
desc = desc .. minetest.colorize(snippet_color, str)
|
||||
else
|
||||
desc = desc .. str
|
||||
end
|
||||
if snippet_color == nil then snippet_color = tt.COLOR_DEFAULT end
|
||||
desc = desc .. "\n" .. (snippet_color and minetest.colorize(snippet_color, str) or str)
|
||||
end
|
||||
end
|
||||
return desc
|
||||
|
@ -67,10 +56,7 @@ function tt.reload_itemstack_description(itemstack)
|
|||
if def and def._mcl_generate_description then
|
||||
def._mcl_generate_description(itemstack)
|
||||
elseif should_change(itemstring, def) then
|
||||
local toolcaps
|
||||
if def.tool_capabilities then
|
||||
toolcaps = itemstack:get_tool_capabilities()
|
||||
end
|
||||
local toolcaps = def.tool_capabilities and itemstack:get_tool_capabilities()
|
||||
local orig_desc = def._tt_original_description or def.description
|
||||
if meta:get_string("name") ~= "" then
|
||||
orig_desc = minetest.colorize(tt.NAME_COLOR, meta:get_string("name"))
|
||||
|
@ -78,17 +64,13 @@ function tt.reload_itemstack_description(itemstack)
|
|||
local potency = meta:get_int("mcl_potions:potion_potent")
|
||||
local plus = meta:get_int("mcl_potions:potion_plus")
|
||||
if potency > 0 then
|
||||
local sym_potency = mcl_util.to_roman(potency+1)
|
||||
orig_desc = orig_desc.. " ".. sym_potency
|
||||
orig_desc = orig_desc .. " " .. mcl_util.to_roman(potency+1)
|
||||
end
|
||||
if plus > 0 then
|
||||
local sym_plus = " "
|
||||
local i = plus
|
||||
while i>0 do
|
||||
i = i - 1
|
||||
sym_plus = sym_plus.. "+"
|
||||
orig_desc = orig_desc .. " "
|
||||
for i = 1, plus do
|
||||
orig_desc = orig_desc .. "+"
|
||||
end
|
||||
orig_desc = orig_desc.. sym_plus
|
||||
end
|
||||
end
|
||||
local desc = apply_snippets(orig_desc, itemstring, toolcaps or def.tool_capabilities, itemstack)
|
||||
|
|
|
@ -3,9 +3,7 @@
|
|||
-- Custom text (_tt_help)
|
||||
tt.register_snippet(function(itemstring)
|
||||
local def = minetest.registered_items[itemstring]
|
||||
if def._tt_help then
|
||||
return def._tt_help
|
||||
end
|
||||
return def and def._tt_help or nil
|
||||
end)
|
||||
|
||||
|
||||
|
|
|
@ -330,9 +330,16 @@ function hb.change_hudbar(player, identifier, new_value, new_max_value, new_icon
|
|||
|
||||
local name = player:get_player_name()
|
||||
local hudtable = hb.get_hudtable(identifier)
|
||||
|
||||
-- hb.change_hudbar may be called with a non-existing hudbar like hunger.
|
||||
if hudtable == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
if not hudtable.hudstate[name] then
|
||||
return false
|
||||
end
|
||||
|
||||
local value_changed, max_changed = false, false
|
||||
|
||||
if new_value then
|
||||
|
|
|
@ -22,10 +22,8 @@ return {
|
|||
"epCode",
|
||||
"chmodsayshello",
|
||||
"MrRar",
|
||||
"FossFanatic ",
|
||||
"SmokeyDope",
|
||||
"Faerraven / Michieal",
|
||||
"Codiac",
|
||||
"rudzik8",
|
||||
"teknomunk",
|
||||
}},
|
||||
|
@ -38,6 +36,8 @@ return {
|
|||
"NO11",
|
||||
"SumianVoice",
|
||||
"PrairieWind",
|
||||
"FossFanatic",
|
||||
"Codiac",
|
||||
}},
|
||||
{S("Contributors"), 0x52FF00, {
|
||||
"RandomLegoBrick",
|
||||
|
@ -142,6 +142,7 @@ return {
|
|||
"SOS-Games",
|
||||
"Bram",
|
||||
"qoheniac",
|
||||
"WillConker",
|
||||
}},
|
||||
{S("Music"), 0xA60014, {
|
||||
"Jordach for the jukebox music compilation from Big Freaking Dig",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name = mcl_death_messages
|
||||
author = 4Evergreen4
|
||||
description = Shows messages in chat when a player dies.
|
||||
depends = mcl_colors
|
||||
depends = mcl_colors, mcl_damage
|
||||
|
|
|
@ -5,3 +5,4 @@ Error: Too many parameters!=Fehler: Zu viele Parameter!
|
|||
Error: Incorrect value of XP=Fehler: Ungültiger EP-Wert
|
||||
Error: Player not found=Fehler: Spieler nicht gefunden
|
||||
Added @1 XP to @2, total: @3, experience level: @4=@1 EP an @2 gegeben, gesamt: @3, Erfahrungsstufe: @4
|
||||
Bottle o' Enchanting=Erfahrungsfläschchen
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
local size_min, size_max = 20, 59
|
||||
local delta_size = size_max - size_min
|
||||
-- Constants
|
||||
local size_min = 20 / 100 -- minimum size, prescaled
|
||||
local size_max = 59 / 100 -- maximum size, prescaled
|
||||
local delta_size = (size_max - size_min) / 10 -- Size change for each XP size level
|
||||
local max_orb_age = 300 -- seconds
|
||||
local gravity = vector.new(0, -((tonumber(minetest.settings:get("movement_gravity"))) or 9.81), 0)
|
||||
|
||||
local size_to_xp = {
|
||||
-- min and max XP amount for a given size
|
||||
{-32768, 2}, -- 1
|
||||
{ 3, 6}, -- 2
|
||||
{ 7, 16}, -- 3
|
||||
|
@ -16,24 +21,20 @@ local size_to_xp = {
|
|||
}
|
||||
|
||||
local function xp_to_size(xp)
|
||||
local i, l = 1, #size_to_xp
|
||||
xp = xp or 0
|
||||
|
||||
while xp > size_to_xp[i][1] and i < l do
|
||||
i = i + 1
|
||||
-- Find the size for the xp amount
|
||||
for i=1,11 do
|
||||
local bucket = size_to_xp[i]
|
||||
if xp >= bucket[1] and xp <= bucket[2] then
|
||||
return (i - 1) * delta_size + size_min
|
||||
end
|
||||
end
|
||||
|
||||
return ((i - 1) / (l - 1) * delta_size + size_min) / 100
|
||||
-- Fallback is the minimum size
|
||||
return size_min
|
||||
end
|
||||
|
||||
local max_orb_age = 300 -- seconds
|
||||
local gravity = vector.new(0, -((tonumber(minetest.settings:get("movement_gravity"))) or 9.81), 0)
|
||||
|
||||
local collector, pos, pos2
|
||||
local direction, distance, player_velocity, goal
|
||||
local currentvel, acceleration, multiplier, velocity
|
||||
local node, vel, def
|
||||
local is_moving, is_slippery, slippery, slip_factor
|
||||
local size
|
||||
local function xp_step(self, dtime)
|
||||
--if item set to be collected then only execute go to player
|
||||
if self.collected == true then
|
||||
|
@ -41,33 +42,32 @@ local function xp_step(self, dtime)
|
|||
self.collected = false
|
||||
return
|
||||
end
|
||||
collector = minetest.get_player_by_name(self.collector)
|
||||
|
||||
local collector = minetest.get_player_by_name(self.collector)
|
||||
if collector and collector:get_hp() > 0 and vector.distance(self.object:get_pos(),collector:get_pos()) < 7.25 then
|
||||
self.object:set_acceleration(vector.new(0,0,0))
|
||||
self.disable_physics(self)
|
||||
--get the variables
|
||||
pos = self.object:get_pos()
|
||||
pos2 = collector:get_pos()
|
||||
local pos = self.object:get_pos()
|
||||
local pos2 = collector:get_pos()
|
||||
|
||||
player_velocity = collector:get_velocity() or collector:get_player_velocity()
|
||||
local player_velocity = collector:get_velocity() or collector:get_player_velocity()
|
||||
|
||||
pos2.y = pos2.y + 0.8
|
||||
|
||||
direction = vector.direction(pos,pos2)
|
||||
distance = vector.distance(pos2,pos)
|
||||
multiplier = distance
|
||||
local direction = vector.direction(pos,pos2)
|
||||
local distance = vector.distance(pos2,pos)
|
||||
local multiplier = distance
|
||||
if multiplier < 1 then
|
||||
multiplier = 1
|
||||
end
|
||||
goal = vector.multiply(direction,multiplier)
|
||||
currentvel = self.object:get_velocity()
|
||||
local currentvel = self.object:get_velocity()
|
||||
|
||||
if distance > 1 then
|
||||
multiplier = 20 - distance
|
||||
velocity = vector.multiply(direction,multiplier)
|
||||
goal = velocity
|
||||
acceleration = vector.new(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
|
||||
self.object:add_velocity(vector.add(acceleration,player_velocity))
|
||||
local velocity = vector.multiply(direction, multiplier)
|
||||
local acceleration = vector.new(velocity.x - currentvel.x, velocity.y - currentvel.y, velocity.z - currentvel.z)
|
||||
self.object:add_velocity(vector.add(acceleration, player_velocity))
|
||||
elseif distance < 0.8 then
|
||||
mcl_experience.add_xp(collector, self._xp)
|
||||
self.object:remove()
|
||||
|
@ -75,28 +75,26 @@ local function xp_step(self, dtime)
|
|||
return
|
||||
else
|
||||
self.collector = nil
|
||||
self.enable_physics(self)
|
||||
self:enable_physics()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Age orbs
|
||||
self.age = self.age + dtime
|
||||
if self.age > max_orb_age then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
||||
pos = self.object:get_pos()
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
|
||||
if pos then
|
||||
node = minetest.get_node_or_nil({
|
||||
x = pos.x,
|
||||
y = pos.y -0.25,
|
||||
z = pos.z
|
||||
})
|
||||
else
|
||||
return
|
||||
end
|
||||
-- Get the node directly below the XP orb
|
||||
local node = minetest.get_node_or_nil({
|
||||
x = pos.x,
|
||||
y = pos.y - 0.25, -- Orb collision box is +/-0.2, so go a bit below that
|
||||
z = pos.z
|
||||
})
|
||||
|
||||
-- Remove nodes in 'ignore'
|
||||
if node and node.name == "ignore" then
|
||||
|
@ -109,18 +107,18 @@ local function xp_step(self, dtime)
|
|||
end
|
||||
|
||||
-- Slide on slippery nodes
|
||||
vel = self.object:get_velocity()
|
||||
def = node and minetest.registered_nodes[node.name]
|
||||
is_moving = (def and not def.walkable) or
|
||||
local vel = self.object:get_velocity()
|
||||
local def = node and minetest.registered_nodes[node.name]
|
||||
local is_moving = (def and not def.walkable) or
|
||||
vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
|
||||
is_slippery = false
|
||||
local is_slippery = false
|
||||
|
||||
if def and def.walkable then
|
||||
slippery = minetest.get_item_group(node.name, "slippery")
|
||||
local slippery = minetest.get_item_group(node.name, "slippery")
|
||||
is_slippery = slippery ~= 0
|
||||
if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then
|
||||
-- Horizontal deceleration
|
||||
slip_factor = 4.0 / (slippery + 4)
|
||||
local slip_factor = 4.0 / (slippery + 4)
|
||||
self.object:set_acceleration({
|
||||
x = -vel.x * slip_factor,
|
||||
y = 0,
|
||||
|
@ -160,7 +158,6 @@ minetest.register_entity("mcl_experience:orb", {
|
|||
initial_sprite_basepos = {x = 0, y = 0},
|
||||
is_visible = true,
|
||||
pointable = false,
|
||||
static_save = false,
|
||||
},
|
||||
moving_state = true,
|
||||
slippery_state = false,
|
||||
|
@ -191,7 +188,7 @@ minetest.register_entity("mcl_experience:orb", {
|
|||
-- This was a minetest bug for a while: https://github.com/minetest/minetest/issues/14420
|
||||
local xp = tonumber(staticdata) or 0
|
||||
self._xp = xp
|
||||
size = xp_to_size(xp)
|
||||
local size = xp_to_size(xp)
|
||||
|
||||
self.object:set_properties({
|
||||
visual_size = {x = size, y = size},
|
||||
|
@ -199,6 +196,9 @@ minetest.register_entity("mcl_experience:orb", {
|
|||
})
|
||||
self.object:set_sprite({x=1,y=math.random(1,14)}, 14, 0.05, false)
|
||||
end,
|
||||
get_staticdata = function(self)
|
||||
return tostring(self._xp or 0)
|
||||
end,
|
||||
|
||||
enable_physics = function(self)
|
||||
if not self.physical_state then
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
## mcl_info
|
||||
An api to make custom entries in the mcl2 debug hud.
|
||||
An API to make custom entries in the VL debug hud.
|
||||
|
||||
### mcl_info.register_debug_field(name,defintion)
|
||||
Debug field defintion example:
|
||||
|
||||
```
|
||||
{
|
||||
level = 3,
|
||||
--show with debug level 3 and upwards
|
||||
|
@ -13,6 +15,7 @@ Debug field defintion example:
|
|||
-- It should output a string and determines
|
||||
-- the content of the debug field.
|
||||
}
|
||||
```
|
||||
|
||||
### mcl_info.registered_debug_fields
|
||||
Table the debug definitions are stored in. Do not modify this directly. If you need to overwrite a field just set it again with mcl_info.register_debug_field().
|
||||
|
|
|
@ -32,4 +32,5 @@ mcl_inventory.register_survival_inventory_tab({
|
|||
-- Returns true by default
|
||||
access = function(player)
|
||||
end,
|
||||
})
|
||||
```
|
||||
|
|
|
@ -8,7 +8,7 @@ Show a hud message of `type` to player `player` with `data` as params.
|
|||
|
||||
The element will stay for the per-player param `stay` or `data.stay` (in gametick which is 1/20 second).
|
||||
|
||||
Here is a usage exemple:
|
||||
Here is a usage example:
|
||||
|
||||
```lua
|
||||
--show a title in the HUD with minecraft color "gold"
|
||||
|
@ -35,7 +35,7 @@ Basicaly run `mcl_title.remove(player, type)` for every type.
|
|||
|
||||
## mcl_title.params_set(player, params)
|
||||
|
||||
Allow mods to set `stay` and upcomming `fadeIn`/`fadeOut` params.
|
||||
Allow mods to set `stay` and upcoming `fadeIn`/`fadeOut` params.
|
||||
|
||||
```lua
|
||||
mcl_title.params_set(player, {stay = 600}) --elements with no 'data.stay' field will stay during 30s (600/20)
|
||||
|
@ -43,8 +43,8 @@ mcl_title.params_set(player, {stay = 600}) --elements with no 'data.stay' field
|
|||
|
||||
## mcl_title.params_get(player)
|
||||
|
||||
Get `stay` and upcomming `fadeIn` and `fadeOut` params of a player as a table.
|
||||
Get `stay` and upcoming `fadeIn` and `fadeOut` params of a player as a table.
|
||||
|
||||
```lua
|
||||
mcl_title.params_get(player)
|
||||
```
|
||||
```
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name = mcl_title
|
||||
description = Add an API to add in HUD title
|
||||
depends = mcl_colors
|
||||
description = Add an API to add in HUD title
|
||||
depends = mcl_colors, mcl_util
|
||||
author = AFCMS
|
|
@ -113,8 +113,8 @@ mesecon.register_node("mcl_observers:observer", {
|
|||
sounds = mcl_sounds.node_sound_stone_defaults(),
|
||||
paramtype2 = "facedir",
|
||||
on_rotate = false,
|
||||
_mcl_blast_resistance = 3.5,
|
||||
_mcl_hardness = 3.5,
|
||||
_mcl_blast_resistance = 3,
|
||||
_mcl_hardness = 3,
|
||||
}, {
|
||||
description = S("Observer"),
|
||||
_tt_help = S("Emits redstone pulse when block in front changes"),
|
||||
|
@ -172,8 +172,8 @@ mesecon.register_node("mcl_observers:observer_down", {
|
|||
sounds = mcl_sounds.node_sound_stone_defaults(),
|
||||
groups = {pickaxey=1, material_stone=1, not_opaque=1, not_in_creative_inventory=1 },
|
||||
on_rotate = false,
|
||||
_mcl_blast_resistance = 3.5,
|
||||
_mcl_hardness = 3.5,
|
||||
_mcl_blast_resistance = 3,
|
||||
_mcl_hardness = 3,
|
||||
drop = "mcl_observers:observer_off",
|
||||
}, {
|
||||
tiles = {
|
||||
|
@ -224,8 +224,8 @@ mesecon.register_node("mcl_observers:observer_up", {
|
|||
sounds = mcl_sounds.node_sound_stone_defaults(),
|
||||
groups = {pickaxey=1, material_stone=1, not_opaque=1, not_in_creative_inventory=1 },
|
||||
on_rotate = false,
|
||||
_mcl_blast_resistance = 3.5,
|
||||
_mcl_hardness = 3.5,
|
||||
_mcl_blast_resistance = 3,
|
||||
_mcl_hardness = 3,
|
||||
drop = "mcl_observers:observer_off",
|
||||
}, {
|
||||
tiles = {
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# textdomain: mcl_target
|
||||
Target=Zielscheibe
|
||||
A target is a block that provides a temporary redstone charge when hit by a projectile.=
|
||||
Throw a projectile on the target to activate it.=
|
|
@ -2,13 +2,19 @@
|
|||
Use the button to push it.=Benutzen Sie den Knopf, um ihn zu drücken.
|
||||
Stone Button=Steinknopf
|
||||
A stone 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.=Ein Steinknopf ist eine Redstonekomponente aus Stein. Er kann gedrückt werden, um ein Redstonesignal zu senden. Im gedrückten Zustand versorgt er benachbarte Redstonekomponenten für 1 Sekunde mit Redstoneenergie.
|
||||
Polished Blackstone Button=Polierter Schwarzsteinknopf
|
||||
A polished blackstone button is a redstone component made out of polished blackstone which can be pushed to provide redstone power. When pushed, it powers adjacent redstone components for 1 second.=
|
||||
Oak Button=Eichenknopf
|
||||
Acacia Button=Akazienknopf
|
||||
Birch Button=Birkenknopf
|
||||
Dark Oak Button=Schwarzeichenknopf
|
||||
Spruce Button=Fichtenknopf
|
||||
Jungle Button=Dschungelknopf
|
||||
Mangrove Button=
|
||||
Crimson Button=Karmesinholzknopf
|
||||
Warped Button=Wirrholzknopf
|
||||
A wooden button is a redstone component made out of wood which can be pushed to provide redstone power. When pushed, it powers adjacent redstone components for 1.5 seconds. Wooden buttons may also be pushed by arrows.=Ein Holzknopf ist eine Redstonekomponente aus Holz. Er kann gedrückt werden, um ein Redstonesignal zu senden. Im gedrückten Zustand versorgt er benachbarte Redstonekomponenten für 1,5 Sekunden mit Redstoneenergie. Holzknöpfe können auch von Pfeilen gedrückt werden.
|
||||
Provides redstone power when pushed=Gibt Redstoneenergie, wenn gedrückt
|
||||
Push duration: @1s=Druckdauer: @1s
|
||||
Pushable by arrow=Drückbar von Pfeilen
|
||||
A button is a redstone component which can be pushed to provide redstone power. When pushed, it powers adjacent redstone components for @1 seconds.=
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
name = mesecons_button
|
||||
depends = mesecons
|
||||
depends = mesecons, mesecons_mvps
|
||||
optional_depends = doc
|
||||
|
|
|
@ -218,7 +218,7 @@ minetest.register_node("mesecons_pistons:piston_normal_off", {
|
|||
},
|
||||
},
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
_mcl_hardness = 1.5,
|
||||
on_rotate = function(pos, node, user, mode)
|
||||
if mode == screwdriver.ROTATE_AXIS then
|
||||
minetest.set_node(pos, {name="mesecons_pistons:piston_up_normal_off"})
|
||||
|
@ -255,7 +255,7 @@ minetest.register_node("mesecons_pistons:piston_normal_on", {
|
|||
},
|
||||
},
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
_mcl_hardness = 1.5,
|
||||
on_rotate = false,
|
||||
})
|
||||
|
||||
|
@ -326,7 +326,7 @@ minetest.register_node("mesecons_pistons:piston_sticky_off", {
|
|||
},
|
||||
},
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
_mcl_hardness = 1.5,
|
||||
on_rotate = function(pos, node, user, mode)
|
||||
if mode == screwdriver.ROTATE_AXIS then
|
||||
minetest.set_node(pos, {name="mesecons_pistons:piston_up_sticky_off"})
|
||||
|
@ -363,7 +363,7 @@ minetest.register_node("mesecons_pistons:piston_sticky_on", {
|
|||
},
|
||||
},
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
_mcl_hardness = 1.5,
|
||||
on_rotate = false,
|
||||
})
|
||||
|
||||
|
@ -449,7 +449,7 @@ minetest.register_node("mesecons_pistons:piston_up_normal_off", {
|
|||
footstep = mcl_sounds.node_sound_wood_defaults().footstep
|
||||
}),
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
_mcl_hardness = 1.5,
|
||||
on_rotate = function(pos, node, user, mode)
|
||||
if mode == screwdriver.ROTATE_AXIS then
|
||||
minetest.set_node(pos, {name="mesecons_pistons:piston_down_normal_off"})
|
||||
|
@ -487,7 +487,7 @@ minetest.register_node("mesecons_pistons:piston_up_normal_on", {
|
|||
},
|
||||
},
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
_mcl_hardness = 1.5,
|
||||
on_rotate = false,
|
||||
})
|
||||
|
||||
|
@ -556,7 +556,7 @@ minetest.register_node("mesecons_pistons:piston_up_sticky_off", {
|
|||
},
|
||||
},
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
_mcl_hardness = 1.5,
|
||||
on_rotate = function(pos, node, user, mode)
|
||||
if mode == screwdriver.ROTATE_AXIS then
|
||||
minetest.set_node(pos, {name="mesecons_pistons:piston_down_sticky_off"})
|
||||
|
@ -594,7 +594,7 @@ minetest.register_node("mesecons_pistons:piston_up_sticky_on", {
|
|||
},
|
||||
},
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
_mcl_hardness = 1.5,
|
||||
on_rotate = false,
|
||||
})
|
||||
|
||||
|
@ -680,7 +680,7 @@ minetest.register_node("mesecons_pistons:piston_down_normal_off", {
|
|||
},
|
||||
},
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
_mcl_hardness = 1.5,
|
||||
on_rotate = function(pos, node, user, mode)
|
||||
if mode == screwdriver.ROTATE_AXIS then
|
||||
minetest.set_node(pos, {name="mesecons_pistons:piston_normal_off"})
|
||||
|
@ -718,7 +718,7 @@ minetest.register_node("mesecons_pistons:piston_down_normal_on", {
|
|||
},
|
||||
},
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
_mcl_hardness = 1.5,
|
||||
on_rotate = false,
|
||||
})
|
||||
|
||||
|
@ -782,7 +782,7 @@ minetest.register_node("mesecons_pistons:piston_down_sticky_off", {
|
|||
},
|
||||
},
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
_mcl_hardness = 1.5,
|
||||
on_rotate = function(pos, node, user, mode)
|
||||
if mode == screwdriver.ROTATE_AXIS then
|
||||
minetest.set_node(pos, {name="mesecons_pistons:piston_sticky_off"})
|
||||
|
@ -820,7 +820,7 @@ minetest.register_node("mesecons_pistons:piston_down_sticky_on", {
|
|||
},
|
||||
},
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
_mcl_hardness = 1.5,
|
||||
on_rotate = false,
|
||||
})
|
||||
|
||||
|
|
|
@ -6,11 +6,18 @@ Birch Pressure Plate=Birkendruckplatte
|
|||
Dark Oak Pressure Plate=Schwarzeichendruckplatte
|
||||
Spruce Pressure Plate=Fichtendruckplatte
|
||||
Jungle Pressure Plate=Dschungeldruckplatte
|
||||
Mangrove Pressure Plate=
|
||||
Crimson Pressure Plate=Karmesinholzdruckplatte
|
||||
Warped Pressure Plate=Wirrholzdruckplatte
|
||||
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.=Eine Holzdruckplatte ist eine Redstonekomponente, die ihre benachbarten Blöcke mit Redstoneenergie versorgt, solange sich ein beliebiges bewegliches Objekt (wie Gegenstände, Spieler und Mobs) auf ihm befindet.
|
||||
Stone Pressure Plate=Steindruckplatte
|
||||
Polished Blackstone Pressure Plate=Polierte Schwarzsteindruckplatte
|
||||
A stone pressure plate is a redstone component which supplies its surrounding blocks with redstone power while a player or mob stands on top of it. It is not triggered by anything else.=Eine Steindruckplatte ist eine Redstonekomponente, die ihre benachbarten Blöcke mit Redstoneenergie versorgt, solange sich ein Spieler oder Mob auf ihm befindet. Sie wird von nichts anderem ausgelöst.
|
||||
Stone Pressure Plate=Steindruckplatte
|
||||
Provides redstone power when pushed=Gibt Redstoneenergie aus, wenn gedrückt
|
||||
Pushable by players, mobs and objects=Drückbar von Spielern, Mobs und Objekten
|
||||
Pushable by players, mobs and objects=
|
||||
Pushable by players and mobs=Drückbar von Spielern und Mobs
|
||||
Pushable by players=Drückbar von Spielern
|
||||
Pushable by mobs=Drückbar von Mobs
|
||||
Pushable by players=
|
||||
Pushable by mobs=
|
||||
|
|
|
@ -28,6 +28,7 @@ local function get_anvil_formspec(set_name)
|
|||
|
||||
"field[4.125,0.75;7.25,1;name;;" .. F(set_name) .. "]",
|
||||
"field_close_on_enter[name;false]",
|
||||
"field_enter_after_edit[name;true]",
|
||||
"set_focus[name;true]",
|
||||
|
||||
mcl_formspec.get_itemslot_bg_v4(1.625, 2.6, 1, 1),
|
||||
|
|
|
@ -119,7 +119,7 @@ mcl_armor.register_set({
|
|||
end,
|
||||
},
|
||||
|
||||
--this is used to generate automaticaly armor crafts based on each element type folowing the regular minecraft pattern
|
||||
--this is used to generate automaticaly armor crafts based on each element type following the regular minecraft pattern
|
||||
--if set to nil no craft will be added
|
||||
craft_material = "mcl_mobitems:leather",
|
||||
|
||||
|
|
|
@ -58,10 +58,25 @@ mcl_armor = {
|
|||
},
|
||||
player_view_range_factors = {},
|
||||
trims = {
|
||||
core_textures = {},
|
||||
blacklisted = {["mcl_armor:elytra"]=true, ["mcl_armor:elytra_enchanted"]=true},
|
||||
core_textures = {},
|
||||
blacklisted = {["mcl_armor:elytra"]=true, ["mcl_armor:elytra_enchanted"]=true},
|
||||
overlays = {"sentry","dune","coast","wild","tide","ward","vex","rib","snout","eye","spire","silence","wayfinder"},
|
||||
colors = {["amethyst"]="#8246a5",["gold"]="#ce9627",["emerald"]="#1b9958",["copper"]="#c36447",["diamond"]="#5faed8",["iron"]="#938e88",["lapis"]="#1c306b",["netherite"]="#302a26",["quartz"]="#c9bcb9",["redstone"]="#af2c23"},
|
||||
translations = {
|
||||
sentry = S("sentry"),
|
||||
dune = S("dune"),
|
||||
coast = S("coast"),
|
||||
wild = S("wild"),
|
||||
tide = S("tide"),
|
||||
ward = S("ward"),
|
||||
vex = S("vex"),
|
||||
rib = S("rib"),
|
||||
snout = S("snout"),
|
||||
eye = S("eye"),
|
||||
spire = S("spire"),
|
||||
silence = S("silence"),
|
||||
wayfinder = S("wayfinder"),
|
||||
},
|
||||
colors = {["amethyst"]="#8246a5",["gold"]="#ce9627",["emerald"]="#1b9958",["copper"]="#c36447",["diamond"]="#5faed8",["iron"]="#938e88",["lapis"]="#1c306b",["netherite"]="#302a26",["quartz"]="#c9bcb9",["redstone"]="#af2c23"},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
# textdomain: mcl_armor
|
||||
Blast Protection=Explosionsschutz
|
||||
Projectile Protection=Projektilschutz
|
||||
Thorns=Dornen
|
||||
This is a piece of equippable armor which reduces the amount of damage you receive.=Dies ist ein Teil einer tragbaren Rüstung, die die Menge an Schaden, den Sie erleiden, reduziert.
|
||||
To equip it, put it on the corresponding armor slot in your inventory menu.=Um es zu tragen, legen Sie es in den passenden Rüstungsplatz in Ihrem Inventarmenü.
|
||||
sentry=
|
||||
dune=
|
||||
coast=Küste
|
||||
wild=
|
||||
ward=Bezirk
|
||||
vex=
|
||||
rib=
|
||||
snout=Schnauze
|
||||
eye=Auge
|
||||
spire=
|
||||
silence=
|
||||
wayfinder=Pfadfinder
|
||||
Leather Cap=Lederkappe
|
||||
Iron Helmet=Eisenhelm
|
||||
Golden Helmet=Goldhelm
|
||||
|
@ -21,6 +36,4 @@ Iron Boots=Eisenstiefel
|
|||
Golden Boots=Goldstiefel
|
||||
Diamond Boots=Diamantstiefel
|
||||
Chain Boots=Kettenstiefel
|
||||
|
||||
|
||||
Smithing Template '@1'=Schmiedevorlage '@1'
|
||||
Smithing Template '@1'=Schmiedevorlage '@1'
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
# textdomain: mcl_armor
|
||||
This is a piece of equippable armor which reduces the amount of damage you receive.=
|
||||
To equip it, put it on the corresponding armor slot in your inventory menu.=
|
||||
sentry=
|
||||
dune=
|
||||
coast=
|
||||
wild=
|
||||
ward=
|
||||
vex=
|
||||
rib=
|
||||
snout=
|
||||
eye=
|
||||
spire=
|
||||
silence=
|
||||
wayfinder=
|
||||
Leather Cap=
|
||||
Iron Helmet=
|
||||
Golden Helmet=
|
||||
|
|
|
@ -2,63 +2,63 @@ local mod_registername = minetest.get_current_modname() .. ":"
|
|||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
|
||||
for _, template_name in pairs(mcl_armor.trims.overlays) do
|
||||
minetest.register_craftitem(mod_registername .. template_name, {
|
||||
description = S("Smithing Template '@1'", template_name),
|
||||
inventory_image = template_name .. "_armor_trim_smithing_template.png",
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = mod_registername .. template_name .. " 2",
|
||||
recipe = {
|
||||
{"mcl_core:diamond",mod_registername .. template_name,"mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:cobble","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
}
|
||||
})
|
||||
minetest.register_craftitem(mod_registername .. template_name, {
|
||||
description = S("Smithing Template '@1'", mcl_armor.trims.translations[template_name]),
|
||||
inventory_image = template_name .. "_armor_trim_smithing_template.png",
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = mod_registername .. template_name .. " 2",
|
||||
recipe = {
|
||||
{"mcl_core:diamond",mod_registername .. template_name,"mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:cobble","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
--temp craft recipies, missing structures
|
||||
minetest.register_craft({
|
||||
output = mod_registername .. "eye",
|
||||
recipe = {
|
||||
{"mcl_core:diamond","mcl_end:ender_eye","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_end:ender_eye","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
}
|
||||
output = mod_registername .. "eye",
|
||||
recipe = {
|
||||
{"mcl_core:diamond","mcl_end:ender_eye","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_end:ender_eye","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = mod_registername .. "ward",
|
||||
recipe = {
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:apple_gold_enchanted","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
}
|
||||
output = mod_registername .. "ward",
|
||||
recipe = {
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:apple_gold_enchanted","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = mod_registername .. "snout",
|
||||
recipe = {
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:goldblock","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
}
|
||||
output = mod_registername .. "snout",
|
||||
recipe = {
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:goldblock","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = mod_registername .. "silence",
|
||||
recipe = {
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
{"mcl_core:diamond", mod_registername.."ward","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
}
|
||||
output = mod_registername .. "silence",
|
||||
recipe = {
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
{"mcl_core:diamond", mod_registername.."ward","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = mod_registername .. "wayfinder",
|
||||
recipe = {
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
{"mcl_core:diamond", "mcl_maps:empty_map","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
}
|
||||
})
|
||||
output = mod_registername .. "wayfinder",
|
||||
recipe = {
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
{"mcl_core:diamond", "mcl_maps:empty_map","mcl_core:diamond"},
|
||||
{"mcl_core:diamond","mcl_core:diamond","mcl_core:diamond"},
|
||||
}
|
||||
})
|
||||
|
|
|
@ -62,7 +62,7 @@ local bamboo_def = {
|
|||
inventory_image = "mcl_bamboo_bamboo_shoot.png",
|
||||
wield_image = "mcl_bamboo_bamboo_shoot.png",
|
||||
_mcl_blast_resistance = 1,
|
||||
_mcl_hardness = 1.5,
|
||||
_mcl_hardness = 1,
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
|
@ -277,7 +277,7 @@ local bamboo_block_def = {
|
|||
sounds = node_sound,
|
||||
paramtype2 = "facedir",
|
||||
drops = "mcl_bamboo:bamboo_block",
|
||||
_mcl_blast_resistance = 3,
|
||||
_mcl_blast_resistance = 2,
|
||||
_mcl_hardness = 2,
|
||||
_mcl_stripped_variant = "mcl_bamboo:bamboo_block_stripped", -- this allows us to use the built in Axe's strip block.
|
||||
on_place = mcl_util.rotate_axis,
|
||||
|
|
|
@ -208,7 +208,7 @@ if minetest.get_modpath("mcl_fences") then
|
|||
wood_groups,
|
||||
minetest.registered_nodes["mcl_core:wood"]._mcl_hardness,
|
||||
minetest.registered_nodes["mcl_core:wood"]._mcl_blast_resistance,
|
||||
node_sound) -- note: about missing params.. will use defaults.
|
||||
node_sound)
|
||||
|
||||
mcl_bamboo.mcl_log(dump(fence_id))
|
||||
mcl_bamboo.mcl_log(dump(gate_id))
|
||||
|
|
|
@ -74,7 +74,7 @@ function mcl_bamboo.break_orphaned(pos)
|
|||
local node_name = node_below.name
|
||||
|
||||
-- short circuit checks.
|
||||
if mcl_bamboo.is_dirt(node_name) or mcl_bamboo.is_bamboo(node_name) or mcl_bamboo.is_bamboo(minetest.get_node(pos).name) == false then
|
||||
if node_name == "ignore" or mcl_bamboo.is_dirt(node_name) or mcl_bamboo.is_bamboo(node_name) or mcl_bamboo.is_bamboo(minetest.get_node(pos).name) == false then
|
||||
return
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
# textdomain: mcl_bamboo
|
||||
|
||||
### bamboo_base.lua ###
|
||||
|
||||
Bamboo=Bambus
|
||||
Bamboo Mosaic Plank=Bambusmosaikplanken
|
||||
Bamboo Plank=Bambusplanken
|
||||
Stripped Bamboo Block=
|
||||
Bamboo Block=Bambusblock
|
||||
|
||||
### bamboo_items.lua ###
|
||||
|
||||
A bamboo button is a redstone component made out of bamboo which can be pushed to provide redstone power. When pushed, it powers adjacent redstone components for 1 second.=
|
||||
|
||||
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.=
|
||||
|
||||
Bamboo=Bambus
|
||||
Bamboo Button=Bambusknopf
|
||||
Bamboo Door=Bambustür
|
||||
Bamboo Fence=Bambuszaun
|
||||
Bamboo Fence Gate=Bambuszauntor
|
||||
Bamboo Mosaic Slab=
|
||||
Bamboo Mosaic Stair=Bambusmosaikstufe
|
||||
Bamboo Plank Slab=Bambusplatte
|
||||
Bamboo Plank Stair=Bambusplankenstufe
|
||||
Bamboo Pressure Plate=Bambusdruckplatte
|
||||
Bamboo Sign=Bambusschild
|
||||
Bamboo Slab=Bambusplatte
|
||||
Bamboo Stair=Bambusstufe
|
||||
Bamboo Trapdoor=Bambusfalltür
|
||||
Double Bamboo Mosaic Slab=
|
||||
Double Bamboo Plank Slab=
|
||||
Double Bamboo Slab=
|
||||
Double Stripped Bamboo Slab=
|
||||
Scaffolding=Bambusdruckplatte
|
||||
Scaffolding (horizontal)=
|
||||
Scaffolding block used to climb up or out across areas.=
|
||||
Stripped Bamboo Slab=
|
||||
Stripped Bamboo Stair=
|
||||
|
||||
To open or close the trapdoor, rightclick it or send a redstone signal to it.=
|
||||
|
||||
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.=
|
||||
|
||||
Wooden doors are 2-block high barriers which can be opened or closed by hand and by a redstone signal.=
|
||||
To open or close a wooden door, rightclick it or supply its lower half with a redstone signal.=
|
|
@ -1,5 +1,5 @@
|
|||
# textdomain: mcl_barrels
|
||||
Barrel=
|
||||
Barrel=Fass
|
||||
Barrels are containers which provide 27 inventory slots.=
|
||||
To access its inventory, rightclick it. When broken, the items will drop out.=
|
||||
27 inventory slots=
|
||||
27 inventory slots=
|
||||
|
|
|
@ -265,7 +265,7 @@ minetest.register_node("mcl_beacons:beacon", {
|
|||
remove_beacon_beam(pos)
|
||||
end,
|
||||
on_receive_fields = function(pos, formname, fields, sender)
|
||||
if fields.swiftness or fields.regeneration or fields.leaping or fields.strenght
|
||||
if fields.swiftness or fields.regeneration or fields.leaping or fields.strength
|
||||
or fields.haste or fields.resistance or fields.absorption or fields.slow_falling then
|
||||
local sender_name = sender:get_player_name()
|
||||
local power_level = beacon_blockcheck(pos)
|
||||
|
@ -329,7 +329,7 @@ minetest.register_node("mcl_beacons:beacon", {
|
|||
end
|
||||
minetest.get_meta(pos):set_string("effect","resistance")
|
||||
successful = true
|
||||
elseif fields.strenght and power_level >= 3 then
|
||||
elseif fields.strength and power_level >= 3 then
|
||||
if power_level == 4 then
|
||||
minetest.get_meta(pos):set_int("effect_level",2)
|
||||
else
|
||||
|
|
|
@ -210,7 +210,7 @@ function mcl_beds.register_bed(name, def)
|
|||
stack_max = 1,
|
||||
groups = {handy=1, bed = 1, dig_by_piston=1, bouncy=66, fall_damage_add_percent=-50, deco_block = 1, flammable=-1},
|
||||
_mcl_hardness = 0.2,
|
||||
_mcl_blast_resistance = 1,
|
||||
_mcl_blast_resistance = 0.2,
|
||||
sounds = def.sounds or default_sounds,
|
||||
selection_box = common_box,
|
||||
collision_box = common_box,
|
||||
|
@ -286,10 +286,9 @@ function mcl_beds.register_bed(name, def)
|
|||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
-- FIXME: Should be bouncy=66, but this would be a higher bounciness than slime blocks!
|
||||
groups = {handy = 1, flammable = -1, bed = 2, dig_by_piston=1, bouncy=33, fall_damage_add_percent=-50, not_in_creative_inventory = 1},
|
||||
groups = {handy = 1, flammable = -1, bed = 2, dig_by_piston=1, bouncy=66, fall_damage_add_percent=-50, not_in_creative_inventory = 1},
|
||||
_mcl_hardness = 0.2,
|
||||
_mcl_blast_resistance = 1,
|
||||
_mcl_blast_resistance = 0.2,
|
||||
sounds = def.sounds or default_sounds,
|
||||
drop = "",
|
||||
selection_box = common_box,
|
||||
|
|
|
@ -15,7 +15,7 @@ Black Bed=Schwarzes Bett
|
|||
Yellow Bed=Gelbes Bett
|
||||
Green Bed=Grünes Bett
|
||||
Magenta Bed=Magenta Bett
|
||||
Orange Bed=Orange Bett
|
||||
Orange Bed=Oranges Bett
|
||||
Purple Bed=Violettes Bett
|
||||
Brown Bed=Braunes Bett
|
||||
Pink Bed=Rosa Bett
|
||||
|
@ -47,4 +47,4 @@ You are missing the 'shout' privilege! It's required in order to talk in chat...
|
|||
You exceeded the maximum number of messages per 10 seconds!=Sie haben die maximale Anzahl an Chatnachrichten pro 10 Sekunden überschritten!
|
||||
Hey! Would you guys mind sleeping?=Hey, würdet Ihr bitte zu Bett gehen?
|
||||
Sorry, but you have to wait @1 seconds until you may use this button again!=Sie müssen leider noch @1 Sekunden warten, bevor sie diesen Knopf erneut benutzen können!
|
||||
@1/@2 players currently in bed.=@1/@2 Spieler aktuell im Bett.
|
||||
@1/@2 players currently in bed.=@1/@2 Spieler aktuell im Bett.
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# textdomain: mcl_beehives
|
||||
Beehive=Bienenstock
|
||||
Artificial bee nest.=
|
||||
Bee Nest=
|
||||
A naturally generating block that houses bees and a tasty treat...if you can get it.=
|
|
@ -0,0 +1,2 @@
|
|||
# textdomain: mcl_bells
|
||||
Bell=Dorfglocke
|
|
@ -33,8 +33,8 @@ minetest.register_node("mcl_blackstone:blackstone_gilded", {
|
|||
{items = {"mcl_blackstone:blackstone_gilded"}, rarity = 1},
|
||||
}
|
||||
},
|
||||
_mcl_blast_resistance = 2,
|
||||
_mcl_hardness = 2,
|
||||
_mcl_blast_resistance = 6,
|
||||
_mcl_hardness = 1.5,
|
||||
_mcl_silk_touch_drop = true,
|
||||
_mcl_fortune_drop = {
|
||||
discrete_uniform_distribution = true,
|
||||
|
@ -196,7 +196,7 @@ end
|
|||
mcl_stairs.register_stair_and_slab("blackstone", "mcl_blackstone:blackstone",
|
||||
{cracky=3, pickaxey=1, material_stone=1},
|
||||
{"mcl_blackstone_top.png", "mcl_blackstone_top.png", "mcl_blackstone_side.png"},
|
||||
S("Blackstone Stairs"),
|
||||
S("Blackstone Stair"),
|
||||
S("Blackstone Slab"),
|
||||
mcl_sounds.node_sound_stone_defaults(), 6, 2,
|
||||
S("Double Blackstone Slab"), nil)
|
||||
|
@ -204,7 +204,7 @@ mcl_stairs.register_stair_and_slab("blackstone", "mcl_blackstone:blackstone",
|
|||
mcl_stairs.register_stair_and_slab("blackstone_polished", "mcl_blackstone:blackstone_polished",
|
||||
{cracky=3, pickaxey=1, material_stone=1},
|
||||
{"mcl_blackstone_polished.png"},
|
||||
S("Polished Blackstone Stairs"),
|
||||
S("Polished Blackstone Stair"),
|
||||
S("Polished Blackstone Slab"),
|
||||
mcl_sounds.node_sound_stone_defaults(), 6, 2,
|
||||
S("Double Polished Blackstone Slab"), nil)
|
||||
|
@ -212,7 +212,7 @@ mcl_stairs.register_stair_and_slab("blackstone_polished", "mcl_blackstone:blacks
|
|||
mcl_stairs.register_stair_and_slab("blackstone_chiseled_polished", "mcl_blackstone:blackstone_chiseled_polished",
|
||||
{cracky=3, pickaxey=1, material_stone=1},
|
||||
{"mcl_blackstone_chiseled_polished.png"},
|
||||
S("Chiseled Polished Blackstone Stairs"),
|
||||
S("Chiseled Polished Blackstone Stair"),
|
||||
S("Chiseled Polished Blackstone Slab"),
|
||||
mcl_sounds.node_sound_stone_defaults(), 6, 2,
|
||||
S("Double Chiseled Polished Blackstone Slab"), nil)
|
||||
|
@ -220,24 +220,13 @@ mcl_stairs.register_stair_and_slab("blackstone_chiseled_polished", "mcl_blacksto
|
|||
mcl_stairs.register_stair_and_slab("blackstone_brick_polished", "mcl_blackstone:blackstone_brick_polished",
|
||||
{cracky=3, pickaxey=1, material_stone=1},
|
||||
{"mcl_blackstone_polished_bricks.png"},
|
||||
S("Polished Blackstone Brick Stair Stairs"),
|
||||
S("Polished Blackstone Brick Stair Slab"),
|
||||
S("Polished Blackstone Brick Stair"),
|
||||
S("Polished Blackstone Brick Slab"),
|
||||
mcl_sounds.node_sound_stone_defaults(), 6, 2,
|
||||
S("Double Polished Blackstone Brick Stair Slab"), nil)
|
||||
S("Double Polished Blackstone Brick Slab"), nil)
|
||||
|
||||
--Wall
|
||||
mcl_walls.register_wall(
|
||||
"mcl_blackstone:wall",
|
||||
S("Blackstone Wall"),
|
||||
"mcl_blackstone:blackstone",
|
||||
{
|
||||
"mcl_blackstone_top.png",
|
||||
"mcl_blackstone_top.png",
|
||||
"mcl_blackstone_side.png"
|
||||
},
|
||||
"",
|
||||
{ cracky=3, pickaxey=1, material_stone=1 }
|
||||
)
|
||||
mcl_walls.register_wall("mcl_blackstone:wall", S("Blackstone Wall"), "mcl_blackstone:blackstone")
|
||||
|
||||
--lavacooling
|
||||
|
||||
|
|
|
@ -5,22 +5,28 @@ Chiseled Polished Blackstone=Gemeißelter polierter Schwarzstein
|
|||
Polished Blackstone Bricks=Polierter Schwarzsteinziegel
|
||||
Basalt=Basalt
|
||||
Polished Basalt=Polierter Basalt
|
||||
Blackstone Slab=Schwarzstein Stufe
|
||||
Polished Blackstone Slab=Polierte Schwarzstein Stufe
|
||||
Chiseled Polished Blackstone Slab=Gemeißelte Polierte Schwarzstein Stufe
|
||||
Polished Blackstone Brick Slab=Polierte Schwarzsteinziegel Stufe
|
||||
Blackstone Stairs=Schwarzstein Treppe
|
||||
Polished Blackstone Stairs=Polierte Schwarzstein Treppe
|
||||
Chiseled Polished Blackstone Stairs=Gemeißelte Polierte Schwarzstein Treppe
|
||||
Polished Blackstone Brick Stairs=Polierte Schwarzsteinziegel Treppe
|
||||
Quartz Bricks=Quartz Ziegel
|
||||
Blackstone Slab=Schwarzsteinstufe
|
||||
Polished Blackstone Slab=Polierte Schwarzsteinstufe
|
||||
Chiseled Polished Blackstone Slab=Gemeißelte polierte Schwarzsteinstufe
|
||||
Polished Blackstone Brick Slab=Polierte Schwarzsteinziegelstufe
|
||||
Blackstone Stair=Schwarzsteintreppe
|
||||
Polished Blackstone Stair=Polierte Schwarzsteintreppe
|
||||
Chiseled Polished Blackstone Stair=Gemeißelte polierte Schwarzsteintreppe
|
||||
Polished Blackstone Brick Stair=Polierte Schwarzsteinziegeltreppe
|
||||
Quartz Bricks=Quarzziegel
|
||||
Soul Torch=Seelenfakel
|
||||
Torches are light sources which can be placed at the side or on the top of most blocks.=
|
||||
Soul Lantern=Seelenlaterne
|
||||
Soul Soil=Seelenerde
|
||||
Eternal Soul Fire=Seelenfeuer
|
||||
Gilded Blackstone=Vergoldeter Schwarzstein
|
||||
Nether Gold Ore=Nethergolderz
|
||||
Smooth Basalt=Glatter Basalt
|
||||
Blackstone Wall=Schwarzsteinmauer
|
||||
Double Blackstone Slab=
|
||||
Polished Double Blackstone Slab=
|
||||
Double Chiseled Polished Blackstone Slab=
|
||||
Double Polished Blackstone Brick Slab=
|
||||
|
||||
@1 has been cooked crisp.=@1 wurde knusprig gebraten.
|
||||
@1 felt the burn.=@1 ist völlig verbrannt.
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# textdomain: mcl_blast_furnace
|
||||
Inventory=
|
||||
Blast Furnace=Schmelzofen
|
||||
Smelts ores faster than furnace=
|
||||
Use the recipe book to see what ores you can smelt, what you can use as fuel and how long it will burn.=
|
||||
Use the blast furnace to open the furnace menu.=
|
||||
Place a furnace fuel in the lower slot and the source material in the upper slot.=
|
||||
The blast furnace will slowly use its fuel to smelt the item.=
|
||||
The result will be placed into the output slot at the right side.=
|
||||
Blast Furnaces smelt several items, mainly ores and armor, using a furnace fuel, but twice as fast as a normal furnace.=
|
||||
Active Blast Furnace=
|
|
@ -13,3 +13,6 @@ Ammunition=Munition
|
|||
Damage from bow: 1-10=Schaden vom Bogen: 1-10
|
||||
Damage from dispenser: 3=Schaden vom Werfer: 3
|
||||
Launches arrows=Verschießt Pfeile
|
||||
Crossbow=Armbrust
|
||||
Crossbows are ranged weapons to shoot arrows at your foes.=
|
||||
To use the crossbow, you first need to have at least one arrow anywhere in your inventory (unless in Creative Mode). Hold down the right mouse button to charge, release to load an arrow into the chamber, then to shoot press left mouse.=
|
||||
|
|
|
@ -340,6 +340,7 @@ local function on_put(pos, listname, index, stack, player)
|
|||
local inv = meta:get_inventory()
|
||||
local str = ""
|
||||
local stack
|
||||
local oldparam2 = minetest.get_node(pos).param2
|
||||
for i=1, inv:get_size("stand") do
|
||||
stack = inv:get_stack("stand", i)
|
||||
if not stack:is_empty() then
|
||||
|
@ -347,7 +348,7 @@ local function on_put(pos, listname, index, stack, player)
|
|||
else str = str.."0"
|
||||
end
|
||||
end
|
||||
minetest.swap_node(pos, {name = "mcl_brewing:stand_"..str})
|
||||
minetest.swap_node(pos, {name = "mcl_brewing:stand_"..str, param2 = oldparam2})
|
||||
minetest.get_node_timer(pos):start(1.0)
|
||||
--some code here to enforce only potions getting placed on stands
|
||||
end
|
||||
|
@ -455,8 +456,8 @@ minetest.register_node("mcl_brewing:stand_000", {
|
|||
}
|
||||
},
|
||||
sounds = mcl_sounds.node_sound_metal_defaults(),
|
||||
_mcl_blast_resistance = 1,
|
||||
_mcl_hardness = 1,
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
on_destruct = on_destruct,
|
||||
allow_metadata_inventory_take = allow_take,
|
||||
allow_metadata_inventory_put = allow_put,
|
||||
|
@ -536,8 +537,8 @@ minetest.register_node("mcl_brewing:stand_100", {
|
|||
}
|
||||
},
|
||||
sounds = mcl_sounds.node_sound_metal_defaults(),
|
||||
_mcl_blast_resistance = 1,
|
||||
_mcl_hardness = 1,
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
on_destruct = on_destruct,
|
||||
allow_metadata_inventory_take = allow_take,
|
||||
allow_metadata_inventory_put = allow_put,
|
||||
|
@ -616,8 +617,8 @@ minetest.register_node("mcl_brewing:stand_010", {
|
|||
}
|
||||
},
|
||||
sounds = mcl_sounds.node_sound_metal_defaults(),
|
||||
_mcl_blast_resistance = 1,
|
||||
_mcl_hardness = 1,
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
on_destruct = on_destruct,
|
||||
allow_metadata_inventory_take = allow_take,
|
||||
allow_metadata_inventory_put = allow_put,
|
||||
|
@ -691,8 +692,8 @@ minetest.register_node("mcl_brewing:stand_001", {
|
|||
}
|
||||
},
|
||||
sounds = mcl_sounds.node_sound_metal_defaults(),
|
||||
_mcl_blast_resistance = 1,
|
||||
_mcl_hardness = 1,
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
on_destruct = on_destruct,
|
||||
allow_metadata_inventory_take = allow_take,
|
||||
allow_metadata_inventory_put = allow_put,
|
||||
|
@ -776,8 +777,8 @@ minetest.register_node("mcl_brewing:stand_110", {
|
|||
}
|
||||
},
|
||||
sounds = mcl_sounds.node_sound_metal_defaults(),
|
||||
_mcl_blast_resistance = 1,
|
||||
_mcl_hardness = 1,
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
on_destruct = on_destruct,
|
||||
allow_metadata_inventory_take = allow_take,
|
||||
allow_metadata_inventory_put = allow_put,
|
||||
|
@ -857,8 +858,8 @@ minetest.register_node("mcl_brewing:stand_101", {
|
|||
}
|
||||
},
|
||||
sounds = mcl_sounds.node_sound_metal_defaults(),
|
||||
_mcl_blast_resistance = 1,
|
||||
_mcl_hardness = 1,
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
on_destruct = on_destruct,
|
||||
allow_metadata_inventory_take = allow_take,
|
||||
allow_metadata_inventory_put = allow_put,
|
||||
|
@ -938,8 +939,8 @@ minetest.register_node("mcl_brewing:stand_011", {
|
|||
}
|
||||
},
|
||||
sounds = mcl_sounds.node_sound_metal_defaults(),
|
||||
_mcl_blast_resistance = 1,
|
||||
_mcl_hardness = 1,
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
on_destruct = on_destruct,
|
||||
allow_metadata_inventory_take = allow_take,
|
||||
allow_metadata_inventory_put = allow_put,
|
||||
|
@ -1026,8 +1027,8 @@ minetest.register_node("mcl_brewing:stand_111", {
|
|||
}
|
||||
},
|
||||
sounds = mcl_sounds.node_sound_metal_defaults(),
|
||||
_mcl_blast_resistance = 1,
|
||||
_mcl_hardness = 1,
|
||||
_mcl_blast_resistance = 0.5,
|
||||
_mcl_hardness = 0.5,
|
||||
on_destruct = on_destruct,
|
||||
allow_metadata_inventory_take = allow_take,
|
||||
allow_metadata_inventory_put = allow_put,
|
||||
|
|
|
@ -1,25 +1,28 @@
|
|||
# mcl_buckets
|
||||
Add an API to register buckets to mcl
|
||||
Adds an API to register buckets to VL
|
||||
|
||||
## mcl_buckets.register_liquid(def)
|
||||
|
||||
Register a new liquid
|
||||
Accept folowing params:
|
||||
* source_place: a string or function.
|
||||
* string: name of the node to place
|
||||
* function(pos): will returns name of the node to place with pos being the placement position
|
||||
* source_take: table of liquid source node names to take
|
||||
* bucketname: itemstring of the new bucket item
|
||||
* inventory_image: texture of the new bucket item (ignored if itemname == nil)
|
||||
* name: user-visible bucket description
|
||||
* longdesc: long explanatory description (for help)
|
||||
* usagehelp: short usage explanation (for help)
|
||||
* tt_help: very short tooltip help
|
||||
* extra_check(pos, placer): (optional) function(pos)
|
||||
* groups: optional list of item groups
|
||||
Register a new liquid.
|
||||
|
||||
Accepts the following parameters:
|
||||
|
||||
* `source_place`: a string or a function
|
||||
* `string`: name of the node to place
|
||||
* `function(pos)`: will return name of the node to place with pos being the placement position
|
||||
* `source_take`: table of liquid source node names to take
|
||||
* `bucketname`: itemstring of the new bucket item
|
||||
* `inventory_image`: texture of the new bucket item (ignored if itemname == nil)
|
||||
* `name`: user-visible bucket description
|
||||
* `longdesc`: long explanatory description (for help)
|
||||
* `usagehelp`: short usage explanation (for help)
|
||||
* `tt_help`: very short tooltip help
|
||||
* `extra_check(pos, placer)`: (optional) additional check before liquid placement (return 2 booleans: (1) whether to place the liquid source and (2) whether to empty the bucket)
|
||||
* `groups`: optional list of item groups
|
||||
|
||||
|
||||
**Usage exemple:**
|
||||
**Usage example:**
|
||||
|
||||
```lua
|
||||
mcl_buckets.register_liquid({
|
||||
bucketname = "dummy:bucket_dummy",
|
||||
|
@ -39,7 +42,7 @@ mcl_buckets.register_liquid({
|
|||
tt_help = S("Places a dummy liquid source"),
|
||||
extra_check = function(pos, placer)
|
||||
--pos = pos where the liquid should be placed
|
||||
--placer people who tried to place the bucket (can be nil)
|
||||
--placer who tried to place the bucket (can be nil)
|
||||
|
||||
--no liquid node will be placed
|
||||
--the bucket will not be emptied
|
||||
|
@ -51,4 +54,4 @@ mcl_buckets.register_liquid({
|
|||
end,
|
||||
groups = { dummy_group = 123 },
|
||||
})
|
||||
```
|
||||
```
|
||||
|
|
|
@ -209,7 +209,7 @@ local function on_place_bucket_empty(itemstack, user, pointed_thing)
|
|||
|
||||
-- Call on_rightclick if the pointed node defines it
|
||||
local new_stack = mcl_util.call_on_rightclick(itemstack, user, pointed_thing)
|
||||
if new_stack then
|
||||
if new_stack and new_stack ~= itemstack then
|
||||
return new_stack
|
||||
end
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@ local function drop_items(pos, node, oldmeta)
|
|||
if food_entity:get_luaentity().name == "mcl_campfires:food_entity" then
|
||||
food_entity:remove()
|
||||
for i = 1, 4 do
|
||||
meta:set_string("food_x_"..tostring(i), nil)
|
||||
meta:set_string("food_y_"..tostring(i), nil)
|
||||
meta:set_string("food_z_"..tostring(i), nil)
|
||||
meta:set_string("food_x_"..tostring(i), "")
|
||||
meta:set_string("food_y_"..tostring(i), "")
|
||||
meta:set_string("food_z_"..tostring(i), "")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -135,9 +135,9 @@ function mcl_campfires.cook_item(pos, elapsed)
|
|||
if cooked then
|
||||
if food_entity then
|
||||
food_entity:remove() -- Remove visual food entity
|
||||
meta:set_string("food_x_"..tostring(i), nil)
|
||||
meta:set_string("food_y_"..tostring(i), nil)
|
||||
meta:set_string("food_z_"..tostring(i), nil)
|
||||
meta:set_string("food_x_"..tostring(i), "")
|
||||
meta:set_string("food_y_"..tostring(i), "")
|
||||
meta:set_string("food_z_"..tostring(i), "")
|
||||
minetest.add_item(pos, cooked.item) -- Drop Cooked Item
|
||||
-- Throw some Experience Points because why not?
|
||||
-- Food is cooked, xp is deserved for using this unique cooking method. Take that Minecraft ;)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue