Compare commits
1 Commits
master
...
move_physi
Author | SHA1 | Date |
---|---|---|
iliekprogrammar | 5042b3ea51 |
|
@ -1,36 +0,0 @@
|
||||||
---
|
|
||||||
|
|
||||||
name: "Bug report"
|
|
||||||
about: "File a bug report"
|
|
||||||
labels:
|
|
||||||
|
|
||||||
- unconfirmed
|
|
||||||
- bug
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Thanks for taking the time to fill out this bug report!
|
|
||||||
|
|
||||||
Please follow our contributing guidelines first:
|
|
||||||
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CONTRIBUTING.md#rules-about-both-bugs-and-feature-requests
|
|
||||||
|
|
||||||
By submitting this issue, you agree to follow our Code of Conduct:
|
|
||||||
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CODE_OF_CONDUCT.md
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!--
|
|
||||||
What version of MineClone2 are you using? We do not provide support for outdated versions of MineClone2.
|
|
||||||
Current latest version is listed here, at the top:
|
|
||||||
https://git.minetest.land/MineClone2/MineClone2/tags
|
|
||||||
-->
|
|
||||||
MineClone2 version:
|
|
||||||
|
|
||||||
### What happened?
|
|
||||||
Report about the bug! Please send large log snippets as an attachement file.
|
|
||||||
|
|
||||||
### What should happen:
|
|
||||||
Tell us what should happen!
|
|
||||||
|
|
||||||
### Steps to reproduce
|
|
||||||
Tell us how we can reproduce the bug!
|
|
|
@ -1,26 +0,0 @@
|
||||||
---
|
|
||||||
|
|
||||||
name: "Feature request"
|
|
||||||
about: "File a feature request not in Minecraft"
|
|
||||||
labels:
|
|
||||||
|
|
||||||
- "non-Minecraft feature"
|
|
||||||
- "needs discussion"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Got a new non-Minecraft feature request? Explain to us why we should consider your idea.
|
|
||||||
|
|
||||||
Please follow our contributing guidelines first:
|
|
||||||
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CONTRIBUTING.md#rules-about-both-bugs-and-feature-requests
|
|
||||||
|
|
||||||
By submitting this issue, you agree to follow our Code of Conduct:
|
|
||||||
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CODE_OF_CONDUCT.md
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Feature
|
|
||||||
Tell us about your requested feature not in Minecraft!
|
|
||||||
|
|
||||||
### Why
|
|
||||||
Tell us why should we implement it!
|
|
|
@ -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 MineClone2
|
|
||||||
Tell us about the feature currently in MineClone2! What is different?
|
|
|
@ -1,20 +0,0 @@
|
||||||
---
|
|
||||||
|
|
||||||
name: "Pull request"
|
|
||||||
about: "Submit a pull request"
|
|
||||||
labels:
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please follow our contributing guidelines first:
|
|
||||||
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CONTRIBUTING.md#how-you-can-help-as-a-programmer
|
|
||||||
|
|
||||||
By submitting this pull request, you agree to follow our Code of Conduct:
|
|
||||||
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CODE_OF_CONDUCT.md
|
|
||||||
-->
|
|
||||||
|
|
||||||
Tell us about your pull request! Reference related issues, if necessary
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
Tell us how to test your changes!
|
|
|
@ -4,5 +4,3 @@
|
||||||
*.blend2
|
*.blend2
|
||||||
*.blend3
|
*.blend3
|
||||||
/.idea/
|
/.idea/
|
||||||
*.xcf
|
|
||||||
.Rproj.user
|
|
22
.luacheckrc
|
@ -1,12 +1,10 @@
|
||||||
---@diagnostic disable
|
|
||||||
|
|
||||||
unused_args = false
|
unused_args = false
|
||||||
allow_defined_top = true
|
allow_defined_top = true
|
||||||
max_line_length = false
|
max_line_length = false
|
||||||
redefined = false
|
redefined = false
|
||||||
|
|
||||||
globals = {
|
globals = {
|
||||||
"minetest", "core",
|
"minetest", "core",
|
||||||
}
|
}
|
||||||
|
|
||||||
read_globals = {
|
read_globals = {
|
||||||
|
@ -42,16 +40,16 @@ read_globals = {
|
||||||
"factorial"
|
"factorial"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
------
|
------
|
||||||
--MODS
|
--MODS
|
||||||
------
|
------
|
||||||
|
|
||||||
--GENERAL
|
--GENERAL
|
||||||
"default",
|
"default",
|
||||||
|
|
||||||
--ENTITIES
|
--ENTITIES
|
||||||
"cmi",
|
"cmi",
|
||||||
|
|
||||||
--HUD
|
--HUD
|
||||||
"sfinv", "sfinv_buttons", "unified_inventory", "cmsg", "inventory_plus",
|
"sfinv", "sfinv_buttons", "unified_inventory", "cmsg", "inventory_plus",
|
||||||
}
|
}
|
22
.luarc.json
|
@ -1,22 +0,0 @@
|
||||||
{
|
|
||||||
"runtime.version": "LuaJIT",
|
|
||||||
"diagnostics": { "disable": ["lowercase-global"] },
|
|
||||||
"diagnostics.globals": [
|
|
||||||
"minetest",
|
|
||||||
"dump",
|
|
||||||
"dump2",
|
|
||||||
"Raycast",
|
|
||||||
"Settings",
|
|
||||||
"PseudoRandom",
|
|
||||||
"PerlinNoise",
|
|
||||||
"VoxelManip",
|
|
||||||
"SecureRandom",
|
|
||||||
"VoxelArea",
|
|
||||||
"PerlinNoiseMap",
|
|
||||||
"PcgRandom",
|
|
||||||
"ItemStack",
|
|
||||||
"AreaStore",
|
|
||||||
"vector"
|
|
||||||
],
|
|
||||||
"workspace.ignoreDir": [".luacheckrc"]
|
|
||||||
}
|
|
1
API.md
|
@ -41,7 +41,6 @@ A lot of things are possible by using one of the APIs in the mods. Note that not
|
||||||
* Beds: `ITEMS/mcl_beds`
|
* Beds: `ITEMS/mcl_beds`
|
||||||
* Buckets: `ITEMS/mcl_buckets`
|
* Buckets: `ITEMS/mcl_buckets`
|
||||||
* Dispenser support: `ITEMS/REDSTONE/mcl_dispensers`
|
* Dispenser support: `ITEMS/REDSTONE/mcl_dispensers`
|
||||||
* Campfires: `ITEMS/mcl_campfires`
|
|
||||||
|
|
||||||
### Mobs
|
### Mobs
|
||||||
* Mobs: `ENTITIES/mcl_mobs`
|
* Mobs: `ENTITIES/mcl_mobs`
|
||||||
|
|
|
@ -2,16 +2,17 @@
|
||||||
So you want to contribute to MineClone2?
|
So you want to contribute to MineClone2?
|
||||||
Wow, thank you! :-)
|
Wow, thank you! :-)
|
||||||
|
|
||||||
MineClone2 is maintained by AncientMariner and Nicu. If you have any
|
MineClone2 is maintained by Nicu and Cora. If you have any
|
||||||
problems or questions, contact us on Discord/Matrix (See Links section below).
|
problems or questions, contact us (See Links section below).
|
||||||
|
|
||||||
You can help with MineClone2's development in many different ways,
|
You can help with MineClone2's development in many different ways,
|
||||||
whether you're a programmer or not.
|
whether you're a programmer or not.
|
||||||
|
|
||||||
## MineClone2's development target is to...
|
## MineClone2's development target is to...
|
||||||
- Create a stable, peformant, moddable, free/libre game based on Minecraft
|
- Crucially, create a stable, moddable, free/libre clone of Minecraft
|
||||||
using the Minetest engine, usable in both singleplayer and multiplayer.
|
based on the Minetest engine with polished features, usable in both
|
||||||
- Currently, a lot of features are already implemented.
|
singleplayer and multiplayer. Currently, a lot of Minecraft features
|
||||||
|
are already implemented.
|
||||||
Polishing existing features is always welcome.
|
Polishing existing features is always welcome.
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
@ -75,7 +76,7 @@ in singleplayer, post a screenshot of the message that Minetest showed
|
||||||
when the crash happened (or copy the message into your issue). If you
|
when the crash happened (or copy the message into your issue). If you
|
||||||
are a server admin, you can find error messages in the log file of the
|
are a server admin, you can find error messages in the log file of the
|
||||||
server.
|
server.
|
||||||
* Tell us which MineClone2 and Minetest versions you are using (from Minetest 5.7 type /ver, for previous versions, check the game.conf or README.md file).
|
* Tell us which MineClone2 and Minetest versions you are using.
|
||||||
* Tell us how to reproduce the problem: What you were doing to trigger
|
* Tell us how to reproduce the problem: What you were doing to trigger
|
||||||
the bug, e.g. before the crash happened or what causes the faulty
|
the bug, e.g. before the crash happened or what causes the faulty
|
||||||
behavior.
|
behavior.
|
||||||
|
@ -119,11 +120,11 @@ It's also a good idea to join the Discord server
|
||||||
(or alternatively IRC or Matrix).
|
(or alternatively IRC or Matrix).
|
||||||
|
|
||||||
#### Textures
|
#### Textures
|
||||||
For textures we prefer original art, but in the absence of that will accept
|
For textures we use the Pixel Perfection texture pack. For older Minecraft
|
||||||
Pixel Perfection texture pack contributions. Be warned many of the newer
|
features that is mostly enough but a lot of the newer textures in it are
|
||||||
textures in it are copies or slight modifications of the original MC textures
|
copies or slight modifications of the original MC textures so great caution
|
||||||
so great caution needs to be taken when using any textures coming from
|
needs to be taken when using any textures coming from Minecraft texture
|
||||||
Minecraft texture packs.
|
packs.
|
||||||
If you want to make such contributions, join our Discord server. Demands
|
If you want to make such contributions, join our Discord server. Demands
|
||||||
for textures will be communicated there.
|
for textures will be communicated there.
|
||||||
|
|
||||||
|
@ -134,10 +135,7 @@ resource pack or minetest_game. Unfortunately, MineClone2 does not play
|
||||||
a sound in every situation you would get one in Minecraft. Any help with
|
a sound in every situation you would get one in Minecraft. Any help with
|
||||||
sounds is greatly appreciated, however if you add new sounds you should
|
sounds is greatly appreciated, however if you add new sounds you should
|
||||||
probably work together with a programmer, to write the code to actually
|
probably work together with a programmer, to write the code to actually
|
||||||
play these sounds in game. All sounds should be released under an open
|
play these sounds in game.
|
||||||
source license with clear information on the source, licencing and any
|
|
||||||
changes made by the contributor. Use the README files in the mod to
|
|
||||||
communicate this information.
|
|
||||||
|
|
||||||
#### 3D Models
|
#### 3D Models
|
||||||
Most of the 3D Models in MineClone2 come from
|
Most of the 3D Models in MineClone2 come from
|
||||||
|
@ -147,9 +145,9 @@ Blender on demand. Many of the models have to be patched, some new
|
||||||
animations have to be added etc.
|
animations have to be added etc.
|
||||||
|
|
||||||
#### Crediting
|
#### Crediting
|
||||||
Asset contributions will be credited in their mods and their own respective
|
Asset contributions will be credited in their own respective sections in
|
||||||
sections in CREDITS.md. If you have commited the results yourself, you will
|
CREDITS.md. If you have commited the results yourself, you will also be
|
||||||
also be credited in the Contributors section.
|
credited in the Contributors section.
|
||||||
|
|
||||||
### Contributing Translations
|
### Contributing Translations
|
||||||
|
|
||||||
|
@ -184,12 +182,7 @@ information about the game's performance and let us know places to
|
||||||
investigate optimization issues. This way we can make the game faster.
|
investigate optimization issues. This way we can make the game faster.
|
||||||
|
|
||||||
#### Using Minetest's profiler
|
#### Using Minetest's profiler
|
||||||
We frequently will use profiling to optimise our code. We recommend use of
|
Minetest has a built in profiler. Simply set `profiler.load = true` in
|
||||||
the JIT profiler (RIP Jude) to fully understand performance impact:
|
|
||||||
|
|
||||||
https://content.minetest.net/packages/jwmhjwmh/jitprofiler/
|
|
||||||
|
|
||||||
Minetest also has a built in profiler. Simply set `profiler.load = true` in
|
|
||||||
your configuration file and restart the server. After running the server
|
your configuration file and restart the server. After running the server
|
||||||
for some time, just run `/profiler save` in chat - then you will find a
|
for some time, just run `/profiler save` in chat - then you will find a
|
||||||
file in the world directory containing the results. Open a new issue and
|
file in the world directory containing the results. Open a new issue and
|
||||||
|
@ -220,14 +213,10 @@ they have made their donation Incognito).
|
||||||
* Fork the repository (in case you have not already)
|
* Fork the repository (in case you have not already)
|
||||||
* Do your change in a new branch
|
* Do your change in a new branch
|
||||||
* Create a pull request to get your changes merged into master
|
* Create a pull request to get your changes merged into master
|
||||||
* It is important that conflicts are resolved prior to merging the pull
|
* Keep your pull request up to date by regularly merging upstream. It is
|
||||||
|
imperative that conflicts are resolved prior to merging the pull
|
||||||
request.
|
request.
|
||||||
* We update our branches via rebasing. Please avoid merging master into
|
* After the pull request got merged, you can delete the branch
|
||||||
your branch unless it's the only way you can resolve a conflict. We can
|
|
||||||
rebase branches from the GUI if the user has not merged master into the
|
|
||||||
branch.
|
|
||||||
* After the pull request got merged, you can delete the branch if the
|
|
||||||
merger hasn't done this already.
|
|
||||||
|
|
||||||
### Discuss first
|
### Discuss first
|
||||||
If you feel like a problem needs to fixed or you want to make a new
|
If you feel like a problem needs to fixed or you want to make a new
|
||||||
|
@ -251,7 +240,7 @@ work causes problems, we ask you fix the issues as soon as possible.
|
||||||
|
|
||||||
### Changing Gameplay
|
### Changing Gameplay
|
||||||
Pull Requests that change gameplay have to be properly researched and
|
Pull Requests that change gameplay have to be properly researched and
|
||||||
need to state their sources. These PRs also need the maintainer's approval
|
need to state their sources. These PRs also need Fleckenstein's approval
|
||||||
before they are merged.
|
before they are merged.
|
||||||
You can use these sources:
|
You can use these sources:
|
||||||
|
|
||||||
|
@ -273,7 +262,9 @@ excessive git bureaucracy commits in master)
|
||||||
* Submodules should only be used if a) upstream is highly reliable and
|
* Submodules should only be used if a) upstream is highly reliable and
|
||||||
b) it is 100% certain that no mcl2 specific changes to the code will be
|
b) it is 100% certain that no mcl2 specific changes to the code will be
|
||||||
needed (this has never been the case before, hence mcl2 is submodule free so far)
|
needed (this has never been the case before, hence mcl2 is submodule free so far)
|
||||||
* Commit messages should be descriptive
|
* Commit messages should be descriptive and never contain mcl2 specific
|
||||||
|
issueids - there are other projects who might use commits from mcl2 and
|
||||||
|
it will confuse their issue trackers.
|
||||||
* Try to group your submissions best as you can:
|
* Try to group your submissions best as you can:
|
||||||
* Try to keep your PRs small: In some cases things reasonably be can't
|
* Try to keep your PRs small: In some cases things reasonably be can't
|
||||||
split up but in general multiple small PRs are better than a big one.
|
split up but in general multiple small PRs are better than a big one.
|
||||||
|
@ -357,24 +348,18 @@ end
|
||||||
|
|
||||||
### Developer status
|
### Developer status
|
||||||
Active and trusted contributors are often granted write access to the
|
Active and trusted contributors are often granted write access to the
|
||||||
MineClone2 repository as a contributor. Those that have demonstrated the right
|
MineClone2 repository.
|
||||||
technical skills and behaviours may be granted developer access. These are the
|
|
||||||
most trusted contributors who will contribute to ensure coding standards and
|
|
||||||
processes are followed.
|
|
||||||
|
|
||||||
#### Developer responsibilities
|
#### Developer responsibilities
|
||||||
- If you have developer/contributor privileges you can just open a new branch
|
- If you have developer privileges you can just open a new branch in the
|
||||||
in the mcl2 repository (which is preferred). From that you create a pull request.
|
mcl2 repository (which is preferred). From that you create a pull request.
|
||||||
This way other people can review your changes and make sure they work
|
This way other people can review your changes and make sure they work
|
||||||
before they get merged.
|
before they get merged.
|
||||||
- If you do not (yet) have developer privs you do your work on a branch
|
- If you do not (yet) have developer privs you do your work on a branch
|
||||||
on your private repository e.g. using the "fork" function on mesehub.
|
on your private repository e.g. using the "fork" function on mesehub.
|
||||||
- Any developer is welcome to review, test and approve PRs. A maintainer may prefer
|
- Any developer is welcome to review, test and merge PRs. A PR needs
|
||||||
to merge the PR especially if it is in a similar area to what has been worked on
|
at least one approval (by someone else than the author) but the maintainers
|
||||||
and could result in merge conflicts for a larger older branch, or needs
|
are usually relatively quick to react to new submissions.
|
||||||
art/licencing reviewing. A PR needs at least one approval (by someone else other
|
|
||||||
than the author).
|
|
||||||
- The maintainers are usually relatively quick to react to new submissions.
|
|
||||||
|
|
||||||
### Maintainer status
|
### Maintainer status
|
||||||
Maintainers carry the main responsibility for the project.
|
Maintainers carry the main responsibility for the project.
|
||||||
|
@ -390,7 +375,7 @@ merged.
|
||||||
- Resolving conflicts and problems within the community
|
- Resolving conflicts and problems within the community
|
||||||
|
|
||||||
#### Current maintainers
|
#### Current maintainers
|
||||||
* AncientMariner - responsible for gameplay review, publishing releases,
|
* Cora - responsible for gameplay review, publishing releases,
|
||||||
technical guidelines
|
technical guidelines
|
||||||
* Nicu - responsible for community related issues
|
* Nicu - responsible for community related issues
|
||||||
|
|
||||||
|
|
100
CREDITS.md
|
@ -6,42 +6,38 @@
|
||||||
## Creator of MineClone2
|
## Creator of MineClone2
|
||||||
* Wuzzy
|
* Wuzzy
|
||||||
|
|
||||||
|
|
||||||
## Maintainers
|
## Maintainers
|
||||||
* AncientMariner
|
* AncientMariner
|
||||||
* Nicu
|
* Nicu
|
||||||
|
|
||||||
## Previous Maintainers
|
## Previous Maintainers
|
||||||
* Fleckenstein
|
* Fleckenstein
|
||||||
|
* jordan4ibanez
|
||||||
* cora
|
* cora
|
||||||
|
|
||||||
## Developers
|
## Developers
|
||||||
|
* bzoss
|
||||||
* AFCMS
|
* AFCMS
|
||||||
* epCode
|
* epCode
|
||||||
|
* ryvnf
|
||||||
|
* iliekprogrammar
|
||||||
|
* MysticTempest
|
||||||
|
* Rootyjr
|
||||||
|
* aligator
|
||||||
|
* Code-Sploit
|
||||||
|
* NO11
|
||||||
|
* kabou
|
||||||
|
* rudzik8
|
||||||
* chmodsayshello
|
* chmodsayshello
|
||||||
* PrairieWind
|
* PrairieWind
|
||||||
* MrRar
|
* RandomLegoBrick
|
||||||
* FossFanatic
|
|
||||||
* SmokeyDope
|
|
||||||
|
|
||||||
## Past Developers
|
|
||||||
* jordan4ibanez
|
|
||||||
* iliekprogrammar
|
|
||||||
* kabou
|
|
||||||
* kay27
|
|
||||||
* Faerraven / Michieal
|
|
||||||
* MysticTempest
|
|
||||||
* NO11
|
|
||||||
* SumianVoice
|
* SumianVoice
|
||||||
|
* MrRar
|
||||||
|
* talamh
|
||||||
|
* Faerraven
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
* RandomLegoBrick
|
|
||||||
* rudzik8
|
|
||||||
* Code-Sploit
|
|
||||||
* aligator
|
|
||||||
* Rootyjr
|
|
||||||
* ryvnf
|
|
||||||
* bzoss
|
|
||||||
* talamh
|
|
||||||
* Laurent Rocher
|
* Laurent Rocher
|
||||||
* HimbeerserverDE
|
* HimbeerserverDE
|
||||||
* TechDudie
|
* TechDudie
|
||||||
|
@ -70,10 +66,6 @@
|
||||||
* Marcin Serwin
|
* Marcin Serwin
|
||||||
* erlehmann
|
* erlehmann
|
||||||
* E
|
* E
|
||||||
* n_to
|
|
||||||
* debiankaios
|
|
||||||
* Gustavo6046 / wallabra
|
|
||||||
* CableGuy67
|
|
||||||
* Benjamin Schötz
|
* Benjamin Schötz
|
||||||
* Doloment
|
* Doloment
|
||||||
* Sydney Gems
|
* Sydney Gems
|
||||||
|
@ -88,12 +80,15 @@
|
||||||
* aldum
|
* aldum
|
||||||
* Dieter44
|
* Dieter44
|
||||||
* Pepebotella
|
* Pepebotella
|
||||||
|
* MrRar
|
||||||
* Lazerbeak12345
|
* Lazerbeak12345
|
||||||
* mrminer
|
* mrminer
|
||||||
* Thunder1035
|
* Thunder1035
|
||||||
* opfromthestart
|
* opfromthestart
|
||||||
* snowyu
|
* snowyu
|
||||||
* FaceDeer
|
* FaceDeer
|
||||||
|
* Faerraven / Michieal
|
||||||
|
* FossFanatic
|
||||||
* Herbert West
|
* Herbert West
|
||||||
* GuyLiner
|
* GuyLiner
|
||||||
* 3raven
|
* 3raven
|
||||||
|
@ -101,24 +96,25 @@
|
||||||
* TheOnlyJoeEnderman
|
* TheOnlyJoeEnderman
|
||||||
* Ranko Saotome
|
* Ranko Saotome
|
||||||
* Gregor Parzefall
|
* Gregor Parzefall
|
||||||
* Wbjitscool
|
|
||||||
* b3nderman
|
|
||||||
* CyberMango
|
|
||||||
* gldrk
|
|
||||||
* atomdmac
|
|
||||||
* emptyshore
|
|
||||||
* FlamingRCCars
|
|
||||||
* uqers
|
|
||||||
* Niterux
|
|
||||||
* appgurueu
|
|
||||||
* seventeenthShulker
|
|
||||||
|
|
||||||
## Music
|
## MineClone5
|
||||||
* Jordach for the jukebox music compilation from Big Freaking Dig
|
* kay27
|
||||||
* Dark Reaven Music (https://soundcloud.com/dark-reaven-music) for the main menu theme (Calmed Cube) and Traitor (horizonchris96), which is licensed under https://creativecommons.org/licenses/by-sa/3.0/
|
* Debiankaios
|
||||||
* Jester for helping to finely tune MineClone2 (https://www.youtube.com/@Jester-8-bit). Songs: Hailing Forest, Gift, 0dd BL0ck, Flock of One (License CC BY-SA 4.0)
|
* epCode
|
||||||
* Exhale & Tim Unwin for some wonderful MineClone2 tracks (https://www.youtube.com/channel/UClFo_JDWoG4NGrPQY0JPD_g). Songs: Valley of Ghosts, Lonely Blossom, Farmer (License CC BY-SA 4.0)
|
* NO11
|
||||||
* Diminixed for 3 fantastic tracks and remastering and leveling volumes. Songs: Afternoon Lullaby (pianowtune02), Spooled (ambientwip02), Never Grow Up (License CC BY-SA 4.0)
|
* j45
|
||||||
|
* chmodsayshello
|
||||||
|
* 3raven
|
||||||
|
* PrairieWind
|
||||||
|
* Gustavo6046 / wallabra
|
||||||
|
* CableGuy67
|
||||||
|
* MrRar
|
||||||
|
|
||||||
|
## Mineclonia
|
||||||
|
* erlehmann
|
||||||
|
* Li0n
|
||||||
|
* E
|
||||||
|
* n_to
|
||||||
|
|
||||||
## Original Mod Authors
|
## Original Mod Authors
|
||||||
* Wuzzy
|
* Wuzzy
|
||||||
|
@ -150,18 +146,12 @@
|
||||||
* 4Evergreen4
|
* 4Evergreen4
|
||||||
* jordan4ibanez
|
* jordan4ibanez
|
||||||
* paramat
|
* paramat
|
||||||
* debian044 / debian44
|
|
||||||
* chmodsayshello
|
|
||||||
* cora
|
* cora
|
||||||
* Faerraven / Michieal
|
|
||||||
* PrairieWind
|
|
||||||
|
|
||||||
## 3D Models
|
## 3D Models
|
||||||
* 22i
|
* 22i
|
||||||
* tobyplowy
|
* tobyplowy
|
||||||
* epCode
|
* epCode
|
||||||
* Faerraven / Michieal
|
|
||||||
* SumianVoice
|
|
||||||
|
|
||||||
## Textures
|
## Textures
|
||||||
* XSSheep
|
* XSSheep
|
||||||
|
@ -176,10 +166,6 @@
|
||||||
* RandomLegoBrick
|
* RandomLegoBrick
|
||||||
* cora
|
* cora
|
||||||
* Faerraven / Michieal
|
* Faerraven / Michieal
|
||||||
* Nicu
|
|
||||||
* Exhale
|
|
||||||
* Wbjitscool
|
|
||||||
* SmokeyDope
|
|
||||||
|
|
||||||
## Translations
|
## Translations
|
||||||
* Wuzzy
|
* Wuzzy
|
||||||
|
@ -194,18 +180,14 @@
|
||||||
* snowyu
|
* snowyu
|
||||||
* 3raven
|
* 3raven
|
||||||
* SakuraRiu
|
* SakuraRiu
|
||||||
* anarquimico
|
|
||||||
* syl
|
|
||||||
* Temak
|
|
||||||
* megustanlosfrijoles
|
|
||||||
* kbundg
|
|
||||||
|
|
||||||
## Funders
|
## Funders
|
||||||
* 40W
|
* 40W
|
||||||
* bauknecht
|
|
||||||
* Cora
|
|
||||||
|
|
||||||
## Special thanks
|
## Special thanks
|
||||||
* The Minetest team for making and supporting an engine, and distribution infrastructure that makes this all possible
|
* celeron55 for creating Minetest
|
||||||
|
* Jordach for the jukebox music compilation from Big Freaking Dig
|
||||||
|
* wsor for working tirelessly in the shadows for the good of all of us, particularly helping with solving contentDB and copyright issues.
|
||||||
* The workaholics who spent way too much time writing for the Minecraft Wiki. It's an invaluable resource for creating this game
|
* The workaholics who spent way too much time writing for the Minecraft Wiki. It's an invaluable resource for creating this game
|
||||||
* Notch and Jeb for being the major forces behind Minecraft
|
* Notch and Jeb for being the major forces behind Minecraft
|
||||||
|
* Dark Reaven Music (https://soundcloud.com/dark-reaven-music) for the main menu theme (Calmed Cube), which is licensed under https://creativecommons.org/licenses/by-sa/3.0/
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
Survive, farm, build, explore, play with friends, and do much more. Inspired by a well known block game, pushing beyond.
|
|
||||||
|
|
||||||
How to play:
|
|
||||||
|
|
||||||
#### Download Minetest
|
|
||||||
- Navigate to https://www.minetest.net/ to download the client.
|
|
||||||
- Once installed, open and select the "Content" tab
|
|
||||||
|
|
||||||
#### Install MineClone2 from ContentDB
|
|
||||||
- Click "Browse Online Content" and filter by Games (select "Games" from the dropdown box)
|
|
||||||
- Find "MineClone2" (should be first on the list or on the first page)
|
|
||||||
- Click the [+] button next to MineClone2 and wait for download to finish
|
|
||||||
- Click "Back to Main Menu"
|
|
||||||
|
|
||||||
#### Create new world and play
|
|
||||||
- Click "Start Game" tab
|
|
||||||
- At the bottom click the MineClone2 icon (the 2 dirt with grass blocks)
|
|
||||||
- Click "New", give your world a name
|
|
||||||
- You can leave seed blank or put in a word of your choice
|
|
||||||
- Select your new world
|
|
||||||
- Click "Play Game" and enjoy!
|
|
6
LEGAL.md
|
@ -5,7 +5,7 @@ Copying is an act of love. Please copy and share! <3
|
||||||
Here's the detailed legalese for those who need it:
|
Here's the detailed legalese for those who need it:
|
||||||
|
|
||||||
## License of source code
|
## License of source code
|
||||||
MineClone 2 (by Lizzy Fleckenstein, Wuzzy, davedevils and countless others)
|
MineClone 2 (by kay27, EliasFleckenstein, Wuzzy, davedevils and countless others)
|
||||||
is an imitation of Minecraft.
|
is an imitation of Minecraft.
|
||||||
|
|
||||||
MineClone 2 is free software: you can redistribute it and/or modify
|
MineClone 2 is free software: you can redistribute it and/or modify
|
||||||
|
@ -38,11 +38,11 @@ No non-free licenses are used anywhere.
|
||||||
The textures, unless otherwise noted, are based on the Pixel Perfection resource pack for Minecraft 1.11,
|
The textures, unless otherwise noted, are based on the Pixel Perfection resource pack for Minecraft 1.11,
|
||||||
authored by XSSheep. Most textures are verbatim copies, while some textures have been changed or redone
|
authored by XSSheep. Most textures are verbatim copies, while some textures have been changed or redone
|
||||||
from scratch.
|
from scratch.
|
||||||
The glazed terracotta textures have been created by [MysticTempest](https://github.com/MysticTempest).
|
The glazed terracotta textures have been created by (MysticTempest)[https://github.com/MysticTempest].
|
||||||
Source: <https://www.planetminecraft.com/texture_pack/131pixel-perfection/>
|
Source: <https://www.planetminecraft.com/texture_pack/131pixel-perfection/>
|
||||||
License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)
|
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/)
|
The main menu images are release under: [CC0](https://creativecommons.org/publicdomain/zero/1.0/)
|
||||||
|
|
||||||
All other files, unless mentioned otherwise, fall under:
|
All other files, unless mentioned otherwise, fall under:
|
||||||
Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
|
Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
|
||||||
|
|
75
MODELS.md
|
@ -1,75 +0,0 @@
|
||||||
# Models in Minetest/Mineclone2
|
|
||||||
|
|
||||||
Models are an important part of all entities & unique nodes in Mineclone2. They provide a 3 dimensional map of an object for which textures are then applied to. This document is for modders, it quickly highlights some important information for the software needed to open models in Mineclone2.
|
|
||||||
|
|
||||||
## Minetest Wiki
|
|
||||||
|
|
||||||
For more detailed information on actually using blender to create and modify models for Minetest/Mineclone2, please visit the Minetest wiki's page on using Blender [Here](https://wiki.minetest.net/Using_Blender)
|
|
||||||
|
|
||||||
## Recommended software
|
|
||||||
|
|
||||||
### Blender
|
|
||||||
|
|
||||||
Blender is a very popular and free modeling software supported on Windows, MacOS, and most Linux distributions. It is recommended to use Blender to create and modify 3D models within the minetest engine.
|
|
||||||
|
|
||||||
Download blender [Here](https://www.blender.org/download/)
|
|
||||||
|
|
||||||
### .b3d addon for blender
|
|
||||||
|
|
||||||
Blitz 3D (.b3d) Is one of the main animated model formats used for entities in the minetest engine. It cannot be imported to blender without a plugin called "Import-Export:Bitz 3D format (.b3d)".
|
|
||||||
|
|
||||||
The most up to date version of this Blender plugin can be downloaded [Here](https://github.com/GreenXenith/io_scene_b3d/releases/tag/f189786)
|
|
||||||
|
|
||||||
## Types of model formats
|
|
||||||
|
|
||||||
### Animated, skinned models
|
|
||||||
|
|
||||||
* Blitz 3D files (.b3d)
|
|
||||||
|
|
||||||
* Microsoft DirectX (.x) (binary & text, compression is not supported)
|
|
||||||
|
|
||||||
### Static meshes
|
|
||||||
|
|
||||||
* Wavefront OBJ (.obj)
|
|
||||||
|
|
||||||
Note: The sometimes accompanying .mtl files are not supported and can safely be deleted.
|
|
||||||
|
|
||||||
Note: Do not use .b3d and .x files for static meshes at the moment, Minetest currently spawns animated mesh scene nodes for these, which may result in reduced performance.
|
|
||||||
|
|
||||||
### Supported texture formats
|
|
||||||
|
|
||||||
* .png
|
|
||||||
|
|
||||||
* .jpg
|
|
||||||
|
|
||||||
* .bmp (depreciated, please use .png or .jpg)
|
|
||||||
|
|
||||||
* .tga (depreciated, please use .png or .jpg)
|
|
||||||
|
|
||||||
Note: Any formats not mentioned above but known to work in the past were removed in 5.5.0 and aren't supported anymore.
|
|
||||||
|
|
||||||
## Pros & Cons of .b3d vs .x
|
|
||||||
|
|
||||||
### B3D
|
|
||||||
|
|
||||||
* [+] Binary format means a small size
|
|
||||||
|
|
||||||
* [-] Difficult to postprocess after exporting
|
|
||||||
|
|
||||||
* [-] Difficult to debug problems
|
|
||||||
|
|
||||||
### X (text version)
|
|
||||||
|
|
||||||
* [+] Can be parsed easily with lua scripts
|
|
||||||
|
|
||||||
* [+] Can be easily generated by scripts
|
|
||||||
|
|
||||||
* [+] Easy to debug issues (you can just read it)
|
|
||||||
|
|
||||||
* [+] Can be optimized by quantizing some data
|
|
||||||
|
|
||||||
* [-] Blender exporter is kinda buggy and inefficient
|
|
||||||
|
|
||||||
* [-] Probably still bigger than an equivalent .b3d
|
|
||||||
|
|
||||||
Note: Avoid using the binary X format! It's actually just a tokenized version of the ASCII representation, and may actually be less efficient than a sufficiently optimized text .x file!
|
|
34
README.md
|
@ -2,6 +2,8 @@
|
||||||
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
|
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
|
||||||
Developed by many people. Not developed or endorsed by Mojang AB.
|
Developed by many people. Not developed or endorsed by Mojang AB.
|
||||||
|
|
||||||
|
Version: 0.82 (in development)
|
||||||
|
|
||||||
### Gameplay
|
### Gameplay
|
||||||
You start in a randomly-generated world made entirely of cubes. You can explore
|
You start in a randomly-generated world made entirely of cubes. You can explore
|
||||||
the world and dig and build almost every block in the world to create new
|
the world and dig and build almost every block in the world to create new
|
||||||
|
@ -78,33 +80,35 @@ The MineClone2 repository is hosted at Mesehub. To contribute or report issues,
|
||||||
|
|
||||||
* Mesehub: <https://git.minetest.land/MineClone2/MineClone2>
|
* Mesehub: <https://git.minetest.land/MineClone2/MineClone2>
|
||||||
* Discord: <https://discord.gg/xE4z8EEpDC>
|
* Discord: <https://discord.gg/xE4z8EEpDC>
|
||||||
* YouTube: <https://www.youtube.com/channel/UClI_YcsXMF3KNeJtoBfnk9A>
|
* YouTube <https://www.youtube.com/channel/UClI_YcsXMF3KNeJtoBfnk9A>
|
||||||
|
* IRC: <https://web.libera.chat/#mineclone2>
|
||||||
|
* Matrix: <https://app.element.io/#/room/#mc2:matrix.org>
|
||||||
|
* Reddit: <https://www.reddit.com/r/MineClone2/>
|
||||||
|
* Minetest forums: <https://forum.minetest.net/viewtopic.php?f=50&t=16407>
|
||||||
* ContentDB: <https://content.minetest.net/packages/wuzzy/mineclone2/>
|
* ContentDB: <https://content.minetest.net/packages/wuzzy/mineclone2/>
|
||||||
* OpenCollective: <https://opencollective.com/mineclone2>
|
* OpenCollective: <https://opencollective.com/mineclone2>
|
||||||
* Mastodon: <https://fosstodon.org/@MineClone2>
|
|
||||||
* Lemmy: <https://lemmy.world/c/mineclone2>
|
|
||||||
* Matrix space: <https://app.element.io/#/room/#mcl2:matrix.org>
|
|
||||||
* Minetest forums: <https://forum.minetest.net/viewtopic.php?f=50&t=16407>
|
|
||||||
* Reddit: <https://www.reddit.com/r/MineClone2/>
|
|
||||||
* IRC (barely used): <https://web.libera.chat/#mineclone2>
|
|
||||||
|
|
||||||
## Target
|
## Target
|
||||||
- Create a stable, moddable, free/libre game based on Minecraft
|
- Crucially, create a stable, moddable, free/libre clone of Minecraft
|
||||||
on the Minetest engine with polished features, usable in both
|
based on the Minetest engine with polished features, usable in both
|
||||||
singleplayer and multiplayer. Currently, a lot of **Minecraft Java
|
singleplayer and multiplayer. Currently, a lot of **Minecraft Java
|
||||||
Edition** features are already implemented and polishing existing
|
Edition** features are already implemented and polishing existing
|
||||||
features are prioritized over new feature requests.
|
features are prioritized over new feature requests.
|
||||||
- Implement features targetting
|
- With lessened priority yet strictly, implement features targetting
|
||||||
**Current Minecraft versions + OptiFine** (OptiFine only as far as supported
|
**Current Minecraft versions + OptiFine** (OptiFine only as far as supported
|
||||||
by the Minetest Engine).
|
by the Minetest Engine). This means features in parity with the listed
|
||||||
- Create a performant experience that will run relatively
|
Minecraft experiences are prioritized over those that don't fulfill this
|
||||||
well on really low spec computers.
|
scope.
|
||||||
|
- Optionally, create a performant experience that will run relatively
|
||||||
|
well on really low spec computers. Unfortunately, due to Minecraft's
|
||||||
|
mechanisms and Minetest engine's limitations along with a very small
|
||||||
|
playerbase on low spec computers, optimizations are hard to investigate.
|
||||||
|
|
||||||
## Completion status
|
## Completion status
|
||||||
This game is currently in **beta** stage.
|
This game is currently in **beta** stage.
|
||||||
It is playable, but not yet feature-complete.
|
It is playable, but not yet feature-complete.
|
||||||
Backwards-compability is not entirely guaranteed, updating your world might cause small bugs.
|
Backwards-compability is not entirely guaranteed, updating your world might cause small bugs.
|
||||||
If you want to use the development version of MineClone2 in production, the master branch is usually relatively stable.
|
If you want to use the development version of MineClone2 in production, the master branch is usually relatively stable. The testing branch often features some experimental PRs and should be considered less stable.
|
||||||
|
|
||||||
The following main features are available:
|
The following main features are available:
|
||||||
|
|
||||||
|
@ -154,7 +158,7 @@ The following features are incomplete:
|
||||||
|
|
||||||
* Some monsters and animals
|
* Some monsters and animals
|
||||||
* Redstone-related things
|
* Redstone-related things
|
||||||
* Some special minecarts (hopper and chest minecarts work)
|
* Special minecarts
|
||||||
* A couple of non-trivial blocks and items
|
* A couple of non-trivial blocks and items
|
||||||
|
|
||||||
Bonus features (not found in Minecraft):
|
Bonus features (not found in Minecraft):
|
||||||
|
|
|
@ -1,45 +1,48 @@
|
||||||
# MineClone2
|
# MineClone2
|
||||||
Un jeu non-officiel similaire à Minecraft pour Minetest. Forké depuis Mineclone par davedevils. Développé par de nombreuses personnes. Pas développé ni supporté par Mojang AB.
|
Un jeu non-officiel similaire à Minecraft pour Minetest. Forké depuis Mineclone par davedevils. Développé par de nombreuses personnes. Ni développé ou supporté par Mojang AB.
|
||||||
|
|
||||||
|
Version: 0.79 (en dévelopment)
|
||||||
|
|
||||||
### Gameplay
|
### Gameplay
|
||||||
|
|
||||||
Vous atterissez dans un monde fait entièrement de cubes et généré aléatoirement. Vous pouvez explorer le monde, miner et construire presque n'importe quel bloc pour créer de nouvelles structures. Vous pouvez choisir de jouer en "mode survie" dans lequel vous devez combattre des monstres et la faim et progresser lentement dans différents aspects du jeu, comme l'extraction de minerai, l'agriculture, la construction de machines et ainsi de suite. Ou alors vous pouvez jouer en "mode créatif" où vous pouvez construire à peu près n'importe quoi instantanément.
|
Vous atterissez dans un monde fait entièrement de cubes et généré aléatoirement. Vous pouvez explorer le monde, miner et construire presque n'importe quel bloc pour créer de nouvelles structures. Vous pouvez choisir de jouer en "mode survie" dans lequel vous devez combattre des monstres et la faim et progresser lentement dans différents aspects du jeu, comme l'extraction de minerai, l'agriculture, la construction de machines et ainsi de suite. Ou alors vous pouvez jouer en "mode créatif" où vous pouvez construire à peu près n'importe quoi instantanément.
|
||||||
|
|
||||||
### Résumé du Gameplay
|
### Résumé du Gameplay
|
||||||
|
|
||||||
* Jeu de type bac-à-sable, sans objetifs
|
* Jeu de type bac-à-sable, sans objetifs
|
||||||
* Survie : combattez des monstres hostiles et la faim
|
* Survie : combattre des monstres hostiles et la faim
|
||||||
* Creusez pour du minerai et d'autres trésors
|
* Creuser pour du minerai et d'autres trésors
|
||||||
* Magie : gagnez de l'expérience et enchantez les outils
|
* Magie : gagner de l'expérience et enchanter les outils
|
||||||
* Utilisez les blocs ramassés pour construire de magnifiques bâtiments, votre imagination est la seule limite
|
* Utiliser les blocs ramassés pour construire de magnifiques bâtiments, votre imagination est la limite
|
||||||
* Ramassez des fleurs (et d'autres sources de teinture) et colorez votre monde
|
* Ramasser des fleurs (et d'autres sources de teinture) et colorez votre monde
|
||||||
* Trouvez des graines et commencez à cultiver
|
* Trouvez des graines et commencez à cultiver
|
||||||
* Trouvez ou fabriquez des centaines d'objets
|
* Trouvez ou fabriquez des centaines d'objets
|
||||||
* Construisez un réseau ferroviaire complexe et amusez-vous avec les wagonnets
|
* Construisez un réseau ferroviaire complexe et amusez vous avec les wagonnets
|
||||||
* En mode créatif vous pouvez construire presque n'importe quoi gratuitement et sans limite
|
* En mode créatif vous pouvez construire presque n'importe quoi gratuitement et sans limite
|
||||||
|
|
||||||
## Comment jouer (démarrer rapidement)
|
## Comment jouer (démarrer rapidement)
|
||||||
### Commencer
|
### Commencer
|
||||||
* **Frappez un arbre** jusqu'à ce qu'il casse et donne du bois
|
* **Frappez un arbre** jusqu'à ce qu'il casse et donne du bois
|
||||||
* Placez le **bois dans la grille 2x2** (la "grille de fabrication" de votre menu d'inventaire) et fabriquez 4 planches de bois
|
* Placez le **bois dans la grille 2x2** (la "grille de fabrication" de votre menu d'inventaire) et fabriquez 4 planches de bois
|
||||||
* Placer les 4 planches de bois dans la grille 2x2 et **fabriquez un établi**
|
* Placer les 4 planches de bois dans la grille 2x2 et **fabriquez une table d'artisanat**
|
||||||
* **Faites un clic droit sur l'établi** (icone livre) pour apprendre toutes les recettes possibles
|
* **Cliquez droit la table d'artisanat** (icone livre) pour apprendre toutes les recettes possibles
|
||||||
* **Fabriquez une pioche de bois** pour miner la pierre
|
* **Fabriquez une pioche de bois** pour miner la pierre
|
||||||
* Différents outils minent différentes sortes de blocs. Essayez-les !
|
* Différents outils minent différentes sortes de blocs. Essayez les !
|
||||||
* Continuez à jouer comme vous voulez. Amusez-vous !
|
* Continuez à jouer comme vous voulez. Amusez vous !
|
||||||
|
|
||||||
### Agriculture
|
### Agriculture
|
||||||
* Trouvez des graines
|
* Trouvez des graines
|
||||||
* Fabriquez une houe
|
* Fabriquez une houe
|
||||||
* Faites un clic droit sur la terre ou des blocs similaires avec la houe pour créer des terres agricoles
|
* Cliquez droit la terre ou des blocs similaires avec la houe pour créer des terres agricoles
|
||||||
* Placer des graines sur des terres agricoles et regardez les pousser
|
* Placer des graines sur des terres agricoles et regardez les pousser
|
||||||
* Récoltez les plantes une fois matûres
|
* Récoltez les plantes une fois matûres
|
||||||
* Les terres agricoles proche de l'eau deviennent humides et accélèrent la croissance
|
* Les terres agricoles proche de l'eau deviennent humides et accélèrent la croissance
|
||||||
|
|
||||||
### Four
|
### Four
|
||||||
* Fabriquez un four
|
* Fabriquer un Four
|
||||||
* Le four permet d'obtenir plus d'objets
|
* Le four permet d'obtenir plus d'objets
|
||||||
* L'emplacement du haut doit contenir un objet fondable (par ex : minerai de fer)
|
* L'emplacement du haut doit contienir un objet fondable (par ex : minerai de fer)
|
||||||
* L'emplacement du bas doit contenir un objet combustible (par ex : charbon)
|
* L'emplacement du bas doit contienir un objet combustible (par ex : charbon)
|
||||||
* Voir le guide d'artisanat pour en apprendre plus sur les objets fondables et combustibles
|
* Voir le guide d'artisanat pour en apprendre plus sur les objets fondables et combustibles
|
||||||
|
|
||||||
### Aide supplémentaire
|
### Aide supplémentaire
|
||||||
|
@ -59,43 +62,43 @@ Il n'y a pas de support de MineClone2 dans les versions développement de Minete
|
||||||
Pour installer MineClone2 (si ce n'est pas déjà fait), déplacez ce dossier dans le dossier “games” de Minetest. Consultez l'aide de Minetest pour en apprendre plus.
|
Pour installer MineClone2 (si ce n'est pas déjà fait), déplacez ce dossier dans le dossier “games” de Minetest. Consultez l'aide de Minetest pour en apprendre plus.
|
||||||
|
|
||||||
## Liens utiles
|
## Liens utiles
|
||||||
Le dépôt de MineClone2 est hébergé sur Mesehub. Pour contribuer ou signaler des problèmes, allez là-bas.
|
Le dépôt de MineClone2 est hébergé sur Mesehub. Pour contribuer ou rapporter des problèmes, aller là-bas.
|
||||||
|
|
||||||
* Mesehub : <https://git.minetest.land/MineClone2/MineClone2>
|
* Mesehub: <https://git.minetest.land/MineClone2/MineClone2>
|
||||||
* Discord : <https://discord.gg/xE4z8EEpDC>
|
* Discord: <https://discord.gg/xE4z8EEpDC>
|
||||||
* YouTube : <https://www.youtube.com/channel/UClI_YcsXMF3KNeJtoBfnk9A>
|
* YouTube <https://www.youtube.com/channel/UClI_YcsXMF3KNeJtoBfnk9A>
|
||||||
* IRC : <https://web.libera.chat/#mineclone2>
|
* IRC: <https://web.libera.chat/#mineclone2>
|
||||||
* Matrix : <https://app.element.io/#/room/#mc2:matrix.org>
|
* Matrix: <https://app.element.io/#/room/#mc2:matrix.org>
|
||||||
* Reddit : <https://www.reddit.com/r/MineClone2/>
|
* Reddit: <https://www.reddit.com/r/MineClone2/>
|
||||||
* Forums Minetest : <https://forum.minetest.net/viewtopic.php?f=50&t=16407>
|
* Minetest forums: <https://forum.minetest.net/viewtopic.php?f=50&t=16407>
|
||||||
* ContentDB : <https://content.minetest.net/packages/wuzzy/mineclone2/>
|
* ContentDB: <https://content.minetest.net/packages/wuzzy/mineclone2/>
|
||||||
* OpenCollective : <https://opencollective.com/mineclone2>
|
* OpenCollective: <https://opencollective.com/mineclone2>
|
||||||
|
|
||||||
## Objectif
|
## Objectif
|
||||||
* Essentiellement, créer un clone de Minecraft stable, moddable, libre et gratuit basé sur le moteur de jeu Minetest avec des fonctionnalités abouties, utilisable à la fois en mode solo et multijoueur. Actuellement, beaucoup des fonctionnalités de **Minecraft Java Edition** sont déjà implémentées et leur amélioration est prioritaire sur les nouvelles demandes.
|
* Créer un clone stable, moddable, libre et gratuit basé sur le moteur de jeu Minetest avec des fonctionalités abouties, utilisable à la fois en mode solo et multijoueur. Actuellement, beaucoup des fonctionalités de **Minecraft Java Edition** sont déjà implémentées et leur amélioration est prioritaire sur les nouvelles demandes.
|
||||||
* Avec une priorité moindre, implémenter les fonctionnalités des versions **Minecraft + OptiFine** (OptiFine autant que supporté par le moteur Minetest). Cela signifie que les fonctionnalités présentes dans les versions listées sont priorisées.
|
* Avec une priorité moindre, implémenter les fonctionalités des versions **Minecraft + OptiFine** (OtiFine autant que supporté par le moteur Minetest). Cela signifie que les fonctionalités présentes dans les versions listées sont priorisées.
|
||||||
* Dans l'idéal, créer une expérience performante qui tourne bien sur des ordinateurs à basse performance. Malheureusement, en raison des mécanismes de Minecraft et des limitations du moteur Minetest ainsi que de la petite taille de la communauté de joueurs sur des ordinateurs à basses performances, les optimisations sont difficiles à explorer.
|
* Dans l'idéal, créer une expérience performante qui tourne bien sur des ordinateurs à basse performance. Malheureusement, en raison des mécanismes de Minecraft et des limitations du moteur Minetest ainsi que de la petite taille de la communauté de joueurs sur des ordinateurs à basse performances, les optimisations sont difficiles à explorer.
|
||||||
|
|
||||||
## Statut de complétion
|
## Statut de complétion
|
||||||
Ce jeu est actuellement au stade **beta**.
|
Ce jeu est actuellement au stade **beta**.
|
||||||
Il est jouable mais incomplet en fonctionnalités.
|
Il est jouable mais incomplet en fonctionalités.
|
||||||
La rétro-compatibilité n'est pas entièrement garantie, mettre votre monde à jour peut causer de petits bugs.
|
La rétro-compatibilité n'est pas entièrement garantie, mettre votre monde à jour peut causer de petits bugs.
|
||||||
Si vous voulez utiliser la version de développement de MineClone2 en production, la branche master est habituellement relativement stable. Les branches de test fusionnent souvent des pull requests expérimentales et doivent être considérées comme moins stable.
|
Si vous voulez utiliser la version de développement de MineClone2 en production, la branche master est habituellement relativement stable. Les branches de test fusionnent souvent des pull requests expérimentales et doivent être considérées comme moins stable.
|
||||||
|
|
||||||
Les principales fonctionnalités suivantes sont disponibles :
|
Les principales fonctionalités suivantes sont disponibles :
|
||||||
|
|
||||||
* Outils, armes
|
* Outils, armes
|
||||||
* Armure
|
* Armure
|
||||||
* Système de fabrication : grille 2x2, établi (grille 3x3), four, incluant un guide de fabrication
|
* Système de fabrication : grille 2x2, table d'artisanat (grille 3x3), four, incluant un guide de fabrication
|
||||||
* Coffres, grands coffres, coffre ender, boites de Shulker
|
* Coffres, grands coffres, coffre ender, boite de shulker
|
||||||
* Fours, entonnoirs
|
* Fours, entonnoirs
|
||||||
* Faim
|
* Faim
|
||||||
* La plupart des monstres et animaux
|
* La plupart des monstres et animaux
|
||||||
* Tous les minerais de Minecraft
|
* Tout les minerais de Minecraft
|
||||||
* La plupart des blocs de l'overworld
|
* La plupart des blocs de l'overworld
|
||||||
* Eau et lave
|
* Eau et lave
|
||||||
* Météo
|
* Météo
|
||||||
* 28 biomes + 5 biomes du Nether
|
* 28 biomes + 5 biomes du nether
|
||||||
* Le Nether, monde souterrain brûlant dans une autre dimension
|
* Le Nether, monde souterrain brûlant dans une autre dimension
|
||||||
* Circuits Redstone (partiel)
|
* Circuits Redstone (partiel)
|
||||||
* Effets de Statut (partiel)
|
* Effets de Statut (partiel)
|
||||||
|
@ -104,10 +107,10 @@ Les principales fonctionnalités suivantes sont disponibles :
|
||||||
* Brassage, potions, flèches trempées (partiel)
|
* Brassage, potions, flèches trempées (partiel)
|
||||||
* Bâteaux
|
* Bâteaux
|
||||||
* Feu
|
* Feu
|
||||||
* Blocs de construction : escaliers, dalles, portes, trappes, barrières, portillons, murets
|
* Blocs de construction : escaliers, dalles, portes, trappes, barrière, portillon, muret
|
||||||
* Horloge
|
* Horloge
|
||||||
* Boussole
|
* Boussole
|
||||||
* Éponge
|
* Eponge
|
||||||
* Bloc de slime
|
* Bloc de slime
|
||||||
* Petites plantes et pousses
|
* Petites plantes et pousses
|
||||||
* Teintures
|
* Teintures
|
||||||
|
@ -115,30 +118,26 @@ Les principales fonctionnalités suivantes sont disponibles :
|
||||||
* Blocs de décoration : verre, verre teinté, vitres, barres de fer, terre cuites (et couleurs), têtes et plus
|
* Blocs de décoration : verre, verre teinté, vitres, barres de fer, terre cuites (et couleurs), têtes et plus
|
||||||
* Cadres d'objets
|
* Cadres d'objets
|
||||||
* Juke-boxes
|
* Juke-boxes
|
||||||
* Lits
|
|
||||||
* Menu d'inventaire
|
|
||||||
* Inventaire créatif
|
|
||||||
* Agriculture
|
|
||||||
* Livres pour écrire
|
* Livres pour écrire
|
||||||
* Commandes
|
* Commandes
|
||||||
* Villages
|
* Villages
|
||||||
* L'End
|
* L'End
|
||||||
* et plus !
|
* et plus !
|
||||||
|
|
||||||
Les fonctionnalités suivantes sont incomplètes :
|
Les fonctionalités suivantes sont incomplètes :
|
||||||
|
|
||||||
* Certains monstres et animaux
|
* certains monstres et animaux
|
||||||
* Certains composants de Redstone
|
* certains composants de Redstone
|
||||||
* Wagonnets spéciaux
|
* Wagonnets spéciaux
|
||||||
* Quelques blocs et objets non-triviaux
|
* quelques blocs et objets non-triviaux
|
||||||
|
|
||||||
Fonctionnalités bonus (absentes de Minecraft) :
|
Fonctionalités bonus (absentes de Minecraft) :
|
||||||
|
|
||||||
* Guide d'artisanat intégré au jeu qui montre les recettes d'artisanat et de cuisson
|
* Guide d'artisanat intégré au jeu qui montre les recettes d'artisanat et de cuisson
|
||||||
* Système d'aide intégré au jeu contenant des informations à propos des techniques de base, blocs, objets et plus
|
* Système d'aide intégré au jeu contenant des informations à propos des techniques de base, blocs, objets et plus
|
||||||
* Recettes d'artisanat temporaires. Elles existent uniquement pour rendre des objets accessibles qui ne le seraient pas autrement sauf en mode créatif. Elles seront retirées au cours de l'avancement du développement et de l'ajout de nouvelles fonctionnalités.
|
* Recettes d'artisanat temporaires. Elles existent uniquement pour rendre des objets accessibles qui ne le seraient pas autrement sauf en mode créatif. Elles seront retirées au cours de l'avancement du développement et de l'ajout de nouvelles fonctionalités.
|
||||||
* Pousses dans les coffres en mapgen v6
|
* Pousses dans les coffres en mapgen v6
|
||||||
* Entièrement moddable (grâce la puissante API Lua de Minetest)
|
* Entièrement moddable (grâce la puissante API lua de Minetest)
|
||||||
* Nouveaux blocs et objets :
|
* Nouveaux blocs et objets :
|
||||||
* Outil de recherche, montre l'aide de ce qu'il touche
|
* Outil de recherche, montre l'aide de ce qu'il touche
|
||||||
* Plus de dalles et d'escaliers
|
* Plus de dalles et d'escaliers
|
||||||
|
@ -150,24 +149,22 @@ Fonctionnalités bonus (absentes de Minecraft) :
|
||||||
* Avant-poste du Nether (Forteresse)
|
* Avant-poste du Nether (Forteresse)
|
||||||
|
|
||||||
Différences techniques avec Minecraft :
|
Différences techniques avec Minecraft :
|
||||||
|
|
||||||
* Limite en hauteur de 31000 blocs (bien plus grand que Minecraft)
|
* Limite en hauteur de 31000 blocs (bien plus grand que Minecraft)
|
||||||
* Taille horizontale du monde 62000×62000 blocs (bien plus petit que Minecraft mais toujours très grand)
|
* Taille horizontale du monde 62000×62000 blocs (bien plus petit que Minecraft mais toujours très grand)
|
||||||
* Toujours assez incomplet et buggé
|
* Toujours assez incomplet et buggé
|
||||||
* Des blocs, objets, ennemis et fonctionnalités manquent
|
* Des blocs, objets, ennemis et fonctionalités manquent
|
||||||
* Quelques objets ont des noms légèrement différents pour être plus faciles à distinguer
|
* Quelques objets ont des noms légèrement différents pour être plus faciles à distinguer
|
||||||
* Des musiques différentes pour le juke-boxe
|
* Des musiques différentes pour le juke-boxe
|
||||||
* Des textures différentes (Pixel Perfection)
|
* Des textures différentes (Pixel Perfection)
|
||||||
* Des sons différents (sources diverses)
|
* Des sons différents (sources diverses)
|
||||||
* Un moteur de jeu différent (Minetest)
|
* Un moteur de jeu différent (Minetest)
|
||||||
* Des bonus cachés différents
|
* Des bonus cachés différents
|
||||||
|
|
||||||
...et enfin MineClone2 est un logiciel libre !
|
...et enfin MineClone2 est un logiciel libre !
|
||||||
|
|
||||||
## Autres fichiers readme
|
## Autres fichiers readme
|
||||||
|
|
||||||
* `LICENSE.txt` : Le texte de la licence GPLv3
|
* `LICENSE.txt`: Le texte de la license GPLv3
|
||||||
* `CONTRIBUTING.md` : Information pour ceux qui veulent contribuer
|
* `CONTRIBUTING.md`: Information pour ceux qui veulent contribuer
|
||||||
* `API.md` : Pour les modders Minetest qui veulent modder ce jeu
|
* `API.md`: Pour les modders Minetest qui veulent modder ce jeu
|
||||||
* `LEGAL.md` : Information légale
|
* `LEGAL.md`: Information légale
|
||||||
* `CREDITS.md` : Liste de toutes les personnes qui ont contribué
|
* `CREDITS.md`: Liste des contributeurs
|
|
@ -1,193 +0,0 @@
|
||||||
# MineClone2
|
|
||||||
Неофициальная игра в стиле Minecraft для Minetest. Форк MineClone от davedevils.
|
|
||||||
Разработана многими людьми. Не разработана и не одобрена Mojang AB.
|
|
||||||
|
|
||||||
### Игровой процесс
|
|
||||||
Вы начинаете в случайно сгенерированном мире созданном целиком из кубов. Вы можете
|
|
||||||
исследовать мир, выкопать и поставить почти каждый блок в мире, чтобы создавать новые
|
|
||||||
структуры. Вы можете играть в “режиме выживания” в котором вам придется бороться с
|
|
||||||
монстрами и голодом за выживание и медленно проходить через различные аспекты игры,
|
|
||||||
такие как копание, фермерство, постройка механизмов и так далее. Или вы можете играть
|
|
||||||
в “творческом режиме” в котором вы сразу можете строить что угодно.
|
|
||||||
|
|
||||||
#### Итоги геймплея
|
|
||||||
|
|
||||||
* Геймплей в стиле песочницы, без целей
|
|
||||||
* Выживайте: сражайтесь с враждебными монстрами и голодом
|
|
||||||
* Добывайте руды и прочие ценные предметы
|
|
||||||
* Магия: получайте опыт и зачаруйте ваше снаряжение
|
|
||||||
* Создавайте из собранных блоков величественные постройки ограниченные только воображением
|
|
||||||
* Собирайте цветы и другие красители, чтобы раскрасить ваш мир
|
|
||||||
* Найдите семена и заведите ферму
|
|
||||||
* Найдите или создайте один из сотен предметов
|
|
||||||
* Проложите рельсы и повеселитесь с вагонетками
|
|
||||||
* Постройте сложные механизмы со схемами из редстоуна
|
|
||||||
* В творческом режиме вы можете свободно строить всё без лимитов
|
|
||||||
|
|
||||||
## Как играть (быстрый старт)
|
|
||||||
### Начнем
|
|
||||||
|
|
||||||
* **Бейте по стволу дерева** пока оно не сломается и соберите древесину
|
|
||||||
* Поставьте **древесину в сетку 2×2** (“сетка крафта” в вашем инвентаре) и скрафтите 4 доски
|
|
||||||
* Разложите 4 доски в форме 2×2 в сетке крафта, чтобы **сделать верстак**
|
|
||||||
* **Правым кликом по верстаку**, чтобы открыть сетку крафта 3×3 для более сложных предметов
|
|
||||||
* Используйте **книгу рецептов** (иконка книги), чтобы узнать все возможные рецепты крафтов
|
|
||||||
* **Скрафтите деревянную кирку**, чтобы вы могли копать камень
|
|
||||||
* Разные инструменты добывают разные виды блоков. Опробуйте их все!
|
|
||||||
* Продолжайте играть как пожелаете. Повеселитесь!
|
|
||||||
|
|
||||||
### Фермерство
|
|
||||||
* Найдите семена
|
|
||||||
* Скрафтите мотыгу
|
|
||||||
* Правой кнопкой мотыгой по земле или похожему блоку, чтобы создать грядку
|
|
||||||
* Посадите семена на грядку и ждите пока они вырастут
|
|
||||||
* Соберите растение когда оно полностью созреет
|
|
||||||
* Рядом с водой грядка становится влажной и растения растут быстрее
|
|
||||||
|
|
||||||
### Переплавка
|
|
||||||
* Скрафтите печь
|
|
||||||
* Печь позволит вам получить больше предметов
|
|
||||||
* Верхний слот должен содержать переплавляемый предмет (например: железную руду)
|
|
||||||
* Нижний слот должен содержать топливо (например: уголь)
|
|
||||||
* Смотрите книгу рецептов, чтобы узнать о других переплавляемых предметах и топливе
|
|
||||||
|
|
||||||
### Дополнительная помощь
|
|
||||||
Больше информации о геймплее, блоках, предметах и многое другое можно найти во
|
|
||||||
внутриигровой справке. Вы можете перейти в неё через ваш инвентарь.
|
|
||||||
|
|
||||||
### Особые предметы
|
|
||||||
Следующие предметы интересны для творческого режима и для строителей приключенческих
|
|
||||||
карт. Их нельзя получить в игре или через творческий инвентарь.
|
|
||||||
|
|
||||||
* Барьер: `mcl_core:barrier`
|
|
||||||
|
|
||||||
Используйте чат-команду `/giveme`, чтобы получить их.
|
|
||||||
Смотрите справку для дальнейшей информации.
|
|
||||||
|
|
||||||
## Установка
|
|
||||||
Эта игра требует [Minetest](http://minetest.net) для запуска (версия 5.4.1 или
|
|
||||||
выше). Вам нужно сперва установить Minetest. Только стабильные версии поддерживаются
|
|
||||||
официально. Не поддерживается запуск MineClone2 на разрабатываемых версиях Minetest.
|
|
||||||
|
|
||||||
Чтобы установить MineClone2 (если вы этого еще не сделали), переместите эту папку в
|
|
||||||
“games” в папке данных Minetest. Смотрите справку Minetest, чтобы узнать больше.
|
|
||||||
|
|
||||||
## Полезные ссылки
|
|
||||||
Репозиторий MineClone2 хранится на Mesehub. Зайдите туда, чтобы оставить запрос или
|
|
||||||
поучаствовать в разработке.
|
|
||||||
|
|
||||||
* Mesehub: <https://git.minetest.land/MineClone2/MineClone2>
|
|
||||||
* 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>
|
|
||||||
* Mastodon: <https://fosstodon.org/@MineClone2>
|
|
||||||
* Lemmy: <https://lemmy.world/c/mineclone2>
|
|
||||||
* Matrix space: <https://app.element.io/#/room/#mcl2:matrix.org>
|
|
||||||
* Форум Minetest: <https://forum.minetest.net/viewtopic.php?f=50&t=16407>
|
|
||||||
* Reddit: <https://www.reddit.com/r/MineClone2/>
|
|
||||||
* IRC (едва используется): <https://web.libera.chat/#mineclone2>
|
|
||||||
|
|
||||||
## Цели
|
|
||||||
- Создать стабильную, модифицируемую, бесплатную и свободную игру основанную на
|
|
||||||
Minecraft на движке Minetest с проработанными возможностями для одиночной игры и
|
|
||||||
для мультиплеера. На данный момент множество возможностей **Minecraft Java
|
|
||||||
Edition** уже реализовано и доработка имеющегося контента в приоритете над
|
|
||||||
добавлением нового.
|
|
||||||
- Реализовать возможности на уровне **текущей версии Minecraft + OptiFine** (OptiFine
|
|
||||||
настолько, насколько это поддерживается движком Minetest).
|
|
||||||
- Добиться производительности для запуска на действительно слабых компьютерах.
|
|
||||||
|
|
||||||
## Готовность
|
|
||||||
Игра сейчас на стадии **бета**. Она играбельна, но еще не имеет всех возможностей.
|
|
||||||
Обратная совместимость целиком не гарантируется, обновление вашего мира может повлечь
|
|
||||||
за собой небольшие ошибки. Если вы хотите использовать разрабатываемую версию
|
|
||||||
Mineclone2, то ветка master обычно относительно стабильна.
|
|
||||||
|
|
||||||
Следущие возможности уже доступны:
|
|
||||||
|
|
||||||
* Инструменты, оружие, броня
|
|
||||||
* Система крафта: сетка 2×2, верстак (сетка 3×3) и книга рецептов
|
|
||||||
* Сундуки, большие сундуки, эндер-сундуки, ящики шалкера
|
|
||||||
* Печи и воронки
|
|
||||||
* Система голода
|
|
||||||
* Большинство монстров и животных
|
|
||||||
* Все руды из Minecraft
|
|
||||||
* Большинство блоков из Верхнего мира
|
|
||||||
* Вода и лава
|
|
||||||
* Погода
|
|
||||||
* 28 биомов + 5 биомов в Незере
|
|
||||||
* Незер, пылающий подземный мир в другом измерении
|
|
||||||
* Схемы из редстоуна (частично)
|
|
||||||
* Вагонетки (частично)
|
|
||||||
* Статусные эффекты (частично)
|
|
||||||
* Опыт
|
|
||||||
* Зачарование
|
|
||||||
* Зельеварение, зелья, смоченные стрелы (частично)
|
|
||||||
* Лодки
|
|
||||||
* Огонь
|
|
||||||
* Строительные блоки: ступени, плиты, двери, люки, заборы, калитки, стены
|
|
||||||
* Часы
|
|
||||||
* Компас
|
|
||||||
* Губки
|
|
||||||
* Блоки слизи
|
|
||||||
* Растения и саженцы
|
|
||||||
* Красители
|
|
||||||
* Флаги
|
|
||||||
* Декоративные блоки: стекло, окрашенное стекло, стеклянные панели, железные решетки, цветная керамика, головы и многое другое
|
|
||||||
* Рамки для предметов
|
|
||||||
* Прогрыватели
|
|
||||||
* Кровати
|
|
||||||
* Меню инвентаря
|
|
||||||
* Творческий инвентарь
|
|
||||||
* Фермерство
|
|
||||||
* Книги с пером
|
|
||||||
* Команды
|
|
||||||
* Деревни
|
|
||||||
* Измерение Края
|
|
||||||
* И многое другое!
|
|
||||||
|
|
||||||
Следующие возможности еще не завершены:
|
|
||||||
|
|
||||||
* Некоторые монстры и животные
|
|
||||||
* Предметы связанные с редстоуном
|
|
||||||
* Некоторые вагонетки (с сундуком и с воронкой уже работают)
|
|
||||||
* Пара нетривиальных блоков и предметов
|
|
||||||
|
|
||||||
Бонусные воронкой (нет в Minecraft-е):
|
|
||||||
|
|
||||||
* Встроенный гайд для крафта покажет вам рецепты крафта и переплавки
|
|
||||||
* Внутриигровая справка содержит всестороннюю информацию об основах игры, блоках, предметах и прочее
|
|
||||||
* Временные рецепты крафта. Они существуют, чтобы получить доступ к ранее недоступным предметам вне творческого режима. Они будут удалены как только разработка позволит им стать доступными
|
|
||||||
* Саженцы в сундуках мапгена v6
|
|
||||||
* Полностью модифицируема (благодаря мощному Lua API в Minetest)
|
|
||||||
* Новые блоки и предметы:
|
|
||||||
* Инструмент просмотра покажет справку о том чего коснется
|
|
||||||
* Больше ступеней и плит
|
|
||||||
* Калитки и заборы из адских кирпичей
|
|
||||||
* Замены структур - малые верии структур из Minecraft пока большие структуры не будут сделаны:
|
|
||||||
* Лесная хижина (Особняк)
|
|
||||||
* Форт Незера (Крепости)
|
|
||||||
|
|
||||||
Технические отличия от Minecraft:
|
|
||||||
|
|
||||||
* Лимит высоты - 31000 блоков (намного больше чем в Minecraft)
|
|
||||||
* Горизонтальный размер мира - 62000×62000 блоков (намного меньше чем в Minecraft, но всё еще очень большой)
|
|
||||||
* Всё еще не завершен и содержит много багов
|
|
||||||
* Недостающие блоки, предметы, мобы
|
|
||||||
* Некоторые предметы с другими названиями, чтобы лучше их различать
|
|
||||||
* Другая музыка для проигрывателей
|
|
||||||
* Другие текступы (Pixel Perfection)
|
|
||||||
* Другие звуки (разные источники)
|
|
||||||
* Другой движок (Minetest)
|
|
||||||
* Другие пасхалки
|
|
||||||
|
|
||||||
… и наконец, MineClone2 это свободное программное обеспечение!
|
|
||||||
|
|
||||||
## Другие readme файлы
|
|
||||||
|
|
||||||
* `LICENSE.txt`: текст лицензии GPLv3
|
|
||||||
* `CONTRIBUTING.md`: информация для тех кто хочет поучаствовать в разработке
|
|
||||||
* `API.md`: для моддеров Minetest кто хочет изменить эту игру
|
|
||||||
* `LEGAL.md`: юридическая информация
|
|
||||||
* `CREDITS.md`: список участников проекта
|
|
88
RELEASE.md
|
@ -1,89 +1,19 @@
|
||||||
### Standard Release
|
#File to document release steps with a view to evolving into a script
|
||||||
|
|
||||||
# File to document release steps with a view to evolving into a script
|
#Update CREDITS.md
|
||||||
|
#Update version in README.md (soon to be game.conf from of 0.82.0)
|
||||||
|
|
||||||
# Update CREDITS.md
|
|
||||||
# Update version in game.conf
|
|
||||||
|
|
||||||
```
|
|
||||||
lua tools/generate_ingame_credits.lua
|
lua tools/generate_ingame_credits.lua
|
||||||
|
|
||||||
git add CREDITS.md
|
git add CREDITS.md
|
||||||
git add mods/HUD/mcl_credits/people.lua
|
git add mods/HUD/mcl_credits/people.lua
|
||||||
git add game.conf
|
|
||||||
|
|
||||||
#git add RELEASE.md
|
git add README.md
|
||||||
|
# To uncomment when applicable
|
||||||
|
#git add game.conf
|
||||||
|
|
||||||
git commit -m "Pre-release update credits and set version 0.83.0"
|
git commit -m "Pre-release update credits and set version 0.81.1"
|
||||||
|
|
||||||
git tag 0.83.0
|
git tag 0.81.1
|
||||||
|
|
||||||
git push origin 0.83.0
|
git push origin 0.81.1
|
||||||
```
|
|
||||||
|
|
||||||
# Update version in game.conf to the next version with -SNAPSHOT suffix
|
|
||||||
|
|
||||||
`git commit -m "Post-release set version 0.84.0-SNAPSHOT"`
|
|
||||||
|
|
||||||
### Hotfix Release
|
|
||||||
|
|
||||||
##### Prepare release branch
|
|
||||||
|
|
||||||
When hotfixing, you should never release new features. Any new code increases risk of new bugs which has additional testing/release concerns.
|
|
||||||
To mitigate this, you just release the last release, and the relevant bug fix. For this, we do the following:
|
|
||||||
|
|
||||||
* Create release branch from the last release tag, push it:
|
|
||||||
|
|
||||||
```
|
|
||||||
git checkout -b release/0.82.1 0.82.0
|
|
||||||
|
|
||||||
git push origin release/0.82.1
|
|
||||||
```
|
|
||||||
|
|
||||||
##### Prepare feature branch and fix
|
|
||||||
|
|
||||||
* Create feature branch from that release branch (can review it to check only fix is there, nothing else, and use to also merge into master separately)
|
|
||||||
|
|
||||||
`git checkout -b hotfix_bug_1_branch`
|
|
||||||
|
|
||||||
* Fix crash/serious bug and commit
|
|
||||||
* Push branch and create pr to the release and also the master branch (Do not rebase, to reduce merge conflict risk. Do not delete after first merge or it needs to be repushed)
|
|
||||||
|
|
||||||
##### Update version and tag the release
|
|
||||||
|
|
||||||
* After all fixes are in release branch, pull it locally (best to avoid a merge conflict as feature branch will need to be merged into master also, which already changed version):
|
|
||||||
|
|
||||||
* Update version in game.conf to hotfix version and commit it. Example: version=0.82.1
|
|
||||||
|
|
||||||
* Tag it, push tag and branch:
|
|
||||||
|
|
||||||
```
|
|
||||||
git tag 0.82.1
|
|
||||||
|
|
||||||
git push origin 0.82.1
|
|
||||||
|
|
||||||
git push origin release/0.82.1
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: If you have to do more than 1 hotfix release, can do it on the same release branch.
|
|
||||||
|
|
||||||
### Release via ContentDB
|
|
||||||
|
|
||||||
* Go to MineClone2 page (https://content.minetest.net/packages/Wuzzy/mineclone2/)
|
|
||||||
* Click +Release
|
|
||||||
* Enter the release tag number in the title and Git reference box. For example (without quotes): "0.82.1"
|
|
||||||
* In the minimum minetest version, put the oldest supported version (as of 14/02/2023 it is 5.5), leave the Maximum minetest version blank
|
|
||||||
* Click save. Release is now live.
|
|
||||||
|
|
||||||
##### Inform people
|
|
||||||
|
|
||||||
* Upload video to YouTube
|
|
||||||
* Add a comment to the forum post with the release number and change log. Maintainer will update main post with code link.
|
|
||||||
* Add a Discord announcement post and @everyone with link to video, forum post and release notes.
|
|
||||||
* Share the news on reddit + Lemmy. Good subs to share with:
|
|
||||||
* r/linux_gaming
|
|
||||||
* r/opensourcegames
|
|
||||||
* r/opensource
|
|
||||||
* r/freesoftware
|
|
||||||
* r/linuxmasterrace
|
|
||||||
* r/MineClone2
|
|
57
TEXTURES.md
|
@ -1,57 +0,0 @@
|
||||||
# Making Textures In Mineclone2
|
|
||||||
|
|
||||||
Textures are a crucial asset for all items, nodes, and models in mineclone2. This document is for artist who would like to make and modify textures for mineclone2. While no means comprehensive, this document contains the basic important information for beginners to get started with texture curation and optimization.
|
|
||||||
|
|
||||||
## Minetest Wiki
|
|
||||||
For more detailed information on creating and modifing texture packs for Minetest/Mineclone2, please visit the Minetest wiki's page on creating a texture pack. Click [here](https://wiki.minetest.net/Creating_texture_packs) to view the wiki page on creating texture packs.
|
|
||||||
|
|
||||||
## GIMP Tutorials Pixel Art Guide
|
|
||||||
GIMP Tutorials has an excellent guide to making pixel art in GIMP. If you would like further clarification as well as screenshots for what we are about to cover, it is an excellent resource to turn to. Click [here](https://thegimptutorials.com/how-to-make-pixel-art/) to view the guide
|
|
||||||
|
|
||||||
## Recommended Software
|
|
||||||
|
|
||||||
### GIMP
|
|
||||||
|
|
||||||
GIMP (GNU Image Manipulation Program) is a very popular and free image editing software supported on Windows, MacOS, and most Linux distributions. It is recommended to use GIMP to create and modify textures within the minetest engine.
|
|
||||||
|
|
||||||
Download GIMP [here](http://gimp.org/)
|
|
||||||
|
|
||||||
# Getting Started
|
|
||||||
## Creating a new file
|
|
||||||
the first thing to do is open GIMP and create a new file to work in by opening the File menu and choosing "New".
|
|
||||||
|
|
||||||
Choose width of 16 and height of 16 for the image size. While higher resolution textures are possible, The default size is 16x16. It is recommended you use this size as well, as it is universally supported on all systems.
|
|
||||||
|
|
||||||
## Zoom In
|
|
||||||
Next, you'll want to zoom in as the canvas is very small at the default zoom level. To do this either use CTRL + mousewheel, +/-, or navigate to the View menu > zoom > zoom in
|
|
||||||
|
|
||||||
## Configure Grid
|
|
||||||
Now, we'll want to turn on the grid. Open the edit menu and enable the 'show grid' option.
|
|
||||||
|
|
||||||
The default grid size is 10 pixels, we want to change it to a 1 pixel grid. Go to the Image menu and choose 'configure grid.
|
|
||||||
|
|
||||||
In the Spacing section, change both the Horizontal and Vertical pixel settings to 1.00 then click ok and the grid will update.
|
|
||||||
|
|
||||||
## Pencil Tool & Color Picking
|
|
||||||
The most useful brush type for pixel art is the Pencil tool. Its nested under the paintbrush tool in the toolbox, or you can use the keyboard shortcut 'N'.
|
|
||||||
|
|
||||||
Once the pencil tool is selected, navigate to the sliders on the left side of the canvas and change brush size to 1 pixel.
|
|
||||||
|
|
||||||
Now choose a color! You can do this by clicking on the two colored squares under the toolbox. The Color Picker tool is also a good option if you already have a reference image for color palette.
|
|
||||||
|
|
||||||
## How to export optimally
|
|
||||||
|
|
||||||
Once you have finished up a texture and are ready to export it, navigate to the file menu > export as... and make sure the file name extention is .png
|
|
||||||
|
|
||||||
After clicking 'Export', a menu will appear with a bunch of options checked. Make sure to uncheck all of these options!!! This will drastically reduce the file size from multiple kilobytes to a couple of hundred bytes. Finally click 'Export' one more time.
|
|
||||||
|
|
||||||
### Further optimization with OptiPNG
|
|
||||||
For those running a GNU/linux distribution, you most likely have the 'optipng' command available to you. If it does not come with your system by default, the software homepage can be found [here](https://optipng.sourceforge.net/) where you can download and install from source.
|
|
||||||
|
|
||||||
First, Open up the terminal in the directory where your exported texture is located (or navigate to the directory with the 'cd your/directory/path/to/textures'), then run this command
|
|
||||||
```
|
|
||||||
optipng -o7 -zm1-9 -nc -clobber -strip all *.png
|
|
||||||
```
|
|
||||||
This will further optimize all the textures in the directory.
|
|
||||||
|
|
||||||
NOTE: If you would like to further edit a texture that has been optipng'd in GIMP, you must manually set the color palette back to RBG after opening. Navigate to Image menu > Mode > select RGB
|
|
|
@ -1 +1 @@
|
||||||
A survival sandbox game. Survive, gather, hunt, mine, build, explore, and do much more.
|
A survival sandbox game. Survive, gather, hunt, mine, build, explore, and do much more. Faithful clone of Minecraft 1.12. This is a work in progress! Expect bugs!
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
title = MineClone 2
|
title = MineClone 2
|
||||||
description = A survival sandbox game. Survive, gather, hunt, build, explore, and do much more.
|
description = A survival sandbox game. Survive, gather, hunt, build, explore, and do much more.
|
||||||
disallowed_mapgens = v6
|
disallowed_mapgens = v6
|
||||||
version=0.85.0-SNAPSHOT
|
version=MCL2-0.82-indev
|
BIN
menu/footer.png
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
|
@ -19,9 +19,9 @@ movement_speed_jump = 6.6
|
||||||
movement_speed_climb = 2.35
|
movement_speed_climb = 2.35
|
||||||
# TODO: Add descend speed (3.0) when available
|
# TODO: Add descend speed (3.0) when available
|
||||||
|
|
||||||
movement_liquid_fluidity = 1.13
|
movement_liquid_fluidity = 0.88
|
||||||
movement_liquid_fluidity_smooth = 0.5
|
movement_liquid_fluidity_smooth = 0.5
|
||||||
movement_liquid_sink = 23
|
movement_liquid_sink = 16
|
||||||
|
|
||||||
movement_gravity = 10.4
|
movement_gravity = 10.4
|
||||||
|
|
||||||
|
|
|
@ -204,7 +204,7 @@ end
|
||||||
|
|
||||||
-- Checks if the given node would drop its useful drop if dug by a given tool.
|
-- Checks if the given node would drop its useful drop if dug by a given tool.
|
||||||
-- Returns true if it will yield its useful drop, false otherwise.
|
-- Returns true if it will yield its useful drop, false otherwise.
|
||||||
function mcl_autogroup.can_harvest(nodename, toolname, player)
|
function mcl_autogroup.can_harvest(nodename, toolname)
|
||||||
local ndef = minetest.registered_nodes[nodename]
|
local ndef = minetest.registered_nodes[nodename]
|
||||||
|
|
||||||
if not ndef then
|
if not ndef then
|
||||||
|
@ -215,10 +215,6 @@ function mcl_autogroup.can_harvest(nodename, toolname, player)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if minetest.get_item_group(nodename, "dig_immediate_piston") >= 1 then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check if it can be dug by tool
|
-- Check if it can be dug by tool
|
||||||
local tdef = minetest.registered_tools[toolname]
|
local tdef = minetest.registered_tools[toolname]
|
||||||
if tdef and tdef._mcl_diggroups then
|
if tdef and tdef._mcl_diggroups then
|
||||||
|
@ -232,9 +228,7 @@ function mcl_autogroup.can_harvest(nodename, toolname, player)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if it can be dug by hand
|
-- Check if it can be dug by hand
|
||||||
if not player or not player:is_player() then return false end
|
local tdef = minetest.registered_tools[""]
|
||||||
local name = player:get_inventory():get_stack("hand", 1):get_name()
|
|
||||||
local tdef = minetest.registered_items[name]
|
|
||||||
if tdef then
|
if tdef then
|
||||||
for g, gdef in pairs(tdef._mcl_diggroups) do
|
for g, gdef in pairs(tdef._mcl_diggroups) do
|
||||||
if ndef.groups[g] then
|
if ndef.groups[g] then
|
||||||
|
@ -266,7 +260,7 @@ local function get_tool_capabilities(tdef)
|
||||||
|
|
||||||
-- If the damage group and punch interval from hand is not included,
|
-- If the damage group and punch interval from hand is not included,
|
||||||
-- then the user will not be able to attack with the tool.
|
-- then the user will not be able to attack with the tool.
|
||||||
local hand_toolcaps = mcl_meshhand.survival_hand_tool_caps
|
local hand_toolcaps = minetest.registered_tools[""].tool_capabilities
|
||||||
return {
|
return {
|
||||||
full_punch_interval = hand_toolcaps.full_punch_interval,
|
full_punch_interval = hand_toolcaps.full_punch_interval,
|
||||||
damage_groups = hand_toolcaps.damage_groups
|
damage_groups = hand_toolcaps.damage_groups
|
||||||
|
@ -286,7 +280,7 @@ end
|
||||||
-- would have to add _mcl_autogroup as a dependency which would break the mod
|
-- would have to add _mcl_autogroup as a dependency which would break the mod
|
||||||
-- loading order.
|
-- loading order.
|
||||||
function mcl_autogroup.get_groupcaps(toolname, efficiency)
|
function mcl_autogroup.get_groupcaps(toolname, efficiency)
|
||||||
local tdef = minetest.registered_items[toolname]
|
local tdef = minetest.registered_tools[toolname]
|
||||||
local groupcaps = table.copy(get_tool_capabilities(tdef).groupcaps or {})
|
local groupcaps = table.copy(get_tool_capabilities(tdef).groupcaps or {})
|
||||||
add_groupcaps(toolname, groupcaps, tdef._mcl_diggroups, efficiency)
|
add_groupcaps(toolname, groupcaps, tdef._mcl_diggroups, efficiency)
|
||||||
return groupcaps
|
return groupcaps
|
||||||
|
@ -304,10 +298,6 @@ end
|
||||||
-- loading order.
|
-- loading order.
|
||||||
function mcl_autogroup.get_wear(toolname, diggroup)
|
function mcl_autogroup.get_wear(toolname, diggroup)
|
||||||
local tdef = minetest.registered_tools[toolname]
|
local tdef = minetest.registered_tools[toolname]
|
||||||
if not tdef then
|
|
||||||
minetest.log("warning", "Adding wear for tool: " .. tostring(toolname) .. " failed with diggroup: " .. tostring(diggroup))
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
local uses = tdef._mcl_diggroups[diggroup].uses
|
local uses = tdef._mcl_diggroups[diggroup].uses
|
||||||
return math.ceil(65535 / uses)
|
return math.ceil(65535 / uses)
|
||||||
end
|
end
|
||||||
|
@ -360,7 +350,7 @@ local function overwrite()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for tname, tdef in pairs(minetest.registered_items) do
|
for tname, tdef in pairs(minetest.registered_tools) do
|
||||||
-- Assign groupcaps for digging the registered digging groups
|
-- Assign groupcaps for digging the registered digging groups
|
||||||
-- depending on the _mcl_diggroups in the tool definition
|
-- depending on the _mcl_diggroups in the tool definition
|
||||||
if tdef._mcl_diggroups then
|
if tdef._mcl_diggroups then
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
# mcl_autogroup
|
# mcl_autogroup
|
||||||
This mod emulate digging times from mc.
|
This mod emulate digging times from mc.
|
||||||
|
|
||||||
## mcl_autogroup.can_harvest(nodename, toolname, player)
|
## mcl_autogroup.can_harvest(nodename, toolname)
|
||||||
Return true if <nodename> can be dig with <toolname> by <player>.
|
Return true if <nodename> can be dig with <toolname>.
|
||||||
* nodename: string, valid nodename
|
* nodename: string, valid nodename
|
||||||
* toolname: (optional) string, valid toolname
|
* toolname: (optional) string, valid toolname
|
||||||
* player: (optinal) ObjectRef, valid player
|
|
||||||
|
|
||||||
## mcl_autogroup.get_groupcaps(toolname, efficiency)
|
## mcl_autogroup.get_groupcaps(toolname, efficiency)
|
||||||
This function is used to calculate diggroups for tools.
|
This function is used to calculate diggroups for tools.
|
||||||
|
|
|
@ -96,8 +96,8 @@ function mcl_damage.finish_reason(mcl_reason)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_damage.from_mt(mt_reason)
|
function mcl_damage.from_mt(mt_reason)
|
||||||
if mt_reason._mcl_cached_reason then
|
if mt_reason._mcl_chached_reason then
|
||||||
return mt_reason._mcl_cached_reason
|
return mt_reason._mcl_chached_reason
|
||||||
end
|
end
|
||||||
|
|
||||||
local mcl_reason
|
local mcl_reason
|
||||||
|
@ -155,6 +155,7 @@ end, true)
|
||||||
minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
|
minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
|
||||||
if not damage_enabled then return 0 end
|
if not damage_enabled then return 0 end
|
||||||
if player:get_hp() > 0 then
|
if player:get_hp() > 0 then
|
||||||
|
mt_reason.approved = true
|
||||||
if hp_change < 0 then
|
if hp_change < 0 then
|
||||||
mcl_damage.run_damage_callbacks(player, -hp_change, mcl_damage.from_mt(mt_reason))
|
mcl_damage.run_damage_callbacks(player, -hp_change, mcl_damage.from_mt(mt_reason))
|
||||||
end
|
end
|
||||||
|
@ -162,7 +163,9 @@ minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
|
||||||
end, false)
|
end, false)
|
||||||
|
|
||||||
minetest.register_on_dieplayer(function(player, mt_reason)
|
minetest.register_on_dieplayer(function(player, mt_reason)
|
||||||
mcl_damage.run_death_callbacks(player, mcl_damage.from_mt(mt_reason))
|
if mt_reason.approved then
|
||||||
|
mcl_damage.run_death_callbacks(player, mcl_damage.from_mt(mt_reason))
|
||||||
|
end
|
||||||
minetest.log("action","Player "..player:get_player_name().." died at "..minetest.pos_to_string(vector.round(player:get_pos())))
|
minetest.log("action","Player "..player:get_player_name().." died at "..minetest.pos_to_string(vector.round(player:get_pos())))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ under the LGPLv2.1 license.
|
||||||
mcl_explosions = {}
|
mcl_explosions = {}
|
||||||
|
|
||||||
local mod_fire = minetest.get_modpath("mcl_fire")
|
local mod_fire = minetest.get_modpath("mcl_fire")
|
||||||
local explosions_griefing = minetest.settings:get_bool("mcl_explosions_griefing", true)
|
|
||||||
--local CONTENT_FIRE = minetest.get_content_id("mcl_fire:fire")
|
--local CONTENT_FIRE = minetest.get_content_id("mcl_fire:fire")
|
||||||
|
|
||||||
local math = math
|
local math = math
|
||||||
|
@ -192,7 +191,7 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
|
||||||
local grief_protected = info.grief_protected
|
local grief_protected = info.grief_protected
|
||||||
|
|
||||||
-- Trace rays for environment destruction
|
-- Trace rays for environment destruction
|
||||||
if info.griefing and explosions_griefing then
|
if info.griefing then
|
||||||
for i = 1, #raydirs do
|
for i = 1, #raydirs do
|
||||||
local rpos_x = pos.x
|
local rpos_x = pos.x
|
||||||
local rpos_y = pos.y
|
local rpos_y = pos.y
|
||||||
|
@ -352,23 +351,6 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Punch End Crystals to make them explode
|
|
||||||
if ent and ent.name == "mcl_end:crystal" then
|
|
||||||
if direct then
|
|
||||||
local puncher = direct:get_luaentity()
|
|
||||||
if puncher and puncher.name == "mcl_end:crystal" then
|
|
||||||
ent.object:punch(direct, 1.0, { -- End Crystal nearby, trigger it.
|
|
||||||
full_punch_interval = 1.0,
|
|
||||||
damage_groups = {fleshy = 1},
|
|
||||||
}, nil, nil)
|
|
||||||
else
|
|
||||||
ent.object:remove() -- Direct Exists, but it is not an end crystal, remove crystal.
|
|
||||||
end
|
|
||||||
else
|
|
||||||
ent.object:remove() -- Node exploded the end crystal, remove it.
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local airs, fires = {}, {}
|
local airs, fires = {}, {}
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
# textdomain:mcl_explosions
|
|
||||||
@1 was caught in an explosion.=@1 est mort dans une explosion
|
|
|
@ -1,2 +0,0 @@
|
||||||
# textdomain:mcl_explosions
|
|
||||||
@1 was caught in an explosion.=@1 попал(а) под взрыв.
|
|
|
@ -1,2 +0,0 @@
|
||||||
# textdomain:mcl_explosions
|
|
||||||
@1 was caught in an explosion.=
|
|
|
@ -3,26 +3,26 @@ mcl_vars = {}
|
||||||
|
|
||||||
mcl_vars.redstone_tick = 0.1
|
mcl_vars.redstone_tick = 0.1
|
||||||
|
|
||||||
-- GUI / inventory menu settings
|
--- GUI / inventory menu settings
|
||||||
mcl_vars.gui_slots = "listcolors[#9990;#FFF7;#FFF0;#000;#FFF]"
|
mcl_vars.gui_slots = "listcolors[#9990;#FFF7;#FFF0;#000;#FFF]"
|
||||||
|
|
||||||
-- nonbg is added as formspec prepend in mcl_formspec_prepend
|
-- nonbg is added as formspec prepend in mcl_formspec_prepend
|
||||||
mcl_vars.gui_nonbg = table.concat({
|
mcl_vars.gui_nonbg = mcl_vars.gui_slots ..
|
||||||
mcl_vars.gui_slots,
|
"style_type[image_button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]"..
|
||||||
"style_type[image_button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]",
|
"style_type[button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]"..
|
||||||
"style_type[button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]",
|
"style_type[field;textcolor=#323232]"..
|
||||||
"style_type[field;textcolor=#323232]",
|
"style_type[label;textcolor=#323232]"..
|
||||||
"style_type[label;textcolor=#323232]",
|
"style_type[textarea;textcolor=#323232]"..
|
||||||
"style_type[textarea;textcolor=#323232]",
|
"style_type[checkbox;textcolor=#323232]"
|
||||||
"style_type[checkbox;textcolor=#323232]",
|
|
||||||
})
|
|
||||||
|
|
||||||
-- Background stuff must be manually added by mods (no formspec prepend)
|
-- Background stuff must be manually added by mods (no formspec prepend)
|
||||||
mcl_vars.gui_bg_color = "bgcolor[#00000000]"
|
mcl_vars.gui_bg_color = "bgcolor[#00000000]"
|
||||||
mcl_vars.gui_bg_img = "background9[1,1;1,1;mcl_base_textures_background9.png;true;7]"
|
mcl_vars.gui_bg_img = "background9[1,1;1,1;mcl_base_textures_background9.png;true;7]"
|
||||||
|
|
||||||
|
-- Legacy
|
||||||
|
mcl_vars.inventory_header = ""
|
||||||
|
|
||||||
-- Tool wield size
|
-- Tool wield size
|
||||||
mcl_vars.tool_wield_scale = vector.new(1.8, 1.8, 1)
|
mcl_vars.tool_wield_scale = { x = 1.8, y = 1.8, z = 1 }
|
||||||
|
|
||||||
-- Mapgen variables
|
-- Mapgen variables
|
||||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||||
|
@ -35,69 +35,55 @@ mcl_vars.chunksize = math.max(1, tonumber(minetest.get_mapgen_setting("chunksize
|
||||||
mcl_vars.MAP_BLOCKSIZE = math.max(1, minetest.MAP_BLOCKSIZE or 16)
|
mcl_vars.MAP_BLOCKSIZE = math.max(1, minetest.MAP_BLOCKSIZE or 16)
|
||||||
mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
|
mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
|
||||||
mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, minetest.MAX_MAP_GENERATION_LIMIT or 31000)
|
mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, minetest.MAX_MAP_GENERATION_LIMIT or 31000)
|
||||||
|
|
||||||
local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2)
|
local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2)
|
||||||
|
|
||||||
mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
||||||
mcl_vars.chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE
|
mcl_vars.chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE
|
||||||
|
|
||||||
local central_chunk_min_pos = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
local central_chunk_min_pos = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
||||||
local central_chunk_max_pos = central_chunk_min_pos + mcl_vars.chunk_size_in_nodes - 1
|
local central_chunk_max_pos = central_chunk_min_pos + mcl_vars.chunk_size_in_nodes - 1
|
||||||
local ccfmin = central_chunk_min_pos - mcl_vars.MAP_BLOCKSIZE -- Fullminp/fullmaxp of central chunk, in nodes
|
local ccfmin = central_chunk_min_pos - mcl_vars.MAP_BLOCKSIZE -- Fullminp/fullmaxp of central chunk, in nodes
|
||||||
local ccfmax = central_chunk_max_pos + mcl_vars.MAP_BLOCKSIZE
|
local ccfmax = central_chunk_max_pos + mcl_vars.MAP_BLOCKSIZE
|
||||||
local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) /
|
local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) / mcl_vars.MAP_BLOCKSIZE)
|
||||||
mcl_vars.MAP_BLOCKSIZE)
|
|
||||||
local mapgen_limit_min = -mapgen_limit_b * mcl_vars.MAP_BLOCKSIZE
|
local mapgen_limit_min = -mapgen_limit_b * mcl_vars.MAP_BLOCKSIZE
|
||||||
local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_vars.MAP_BLOCKSIZE - 1
|
local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_vars.MAP_BLOCKSIZE - 1
|
||||||
local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / mcl_vars.chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk
|
local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / mcl_vars.chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk
|
||||||
local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / mcl_vars.chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits.
|
local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / mcl_vars.chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits.
|
||||||
|
|
||||||
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * mcl_vars.chunk_size_in_nodes
|
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * mcl_vars.chunk_size_in_nodes
|
||||||
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * mcl_vars.chunk_size_in_nodes
|
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * mcl_vars.chunk_size_in_nodes
|
||||||
|
|
||||||
---@param x integer
|
|
||||||
---@return integer
|
|
||||||
local function coordinate_to_block(x)
|
local function coordinate_to_block(x)
|
||||||
return math.floor(x / mcl_vars.MAP_BLOCKSIZE)
|
return math.floor(x / mcl_vars.MAP_BLOCKSIZE)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param x integer
|
|
||||||
---@return integer
|
|
||||||
local function coordinate_to_chunk(x)
|
local function coordinate_to_chunk(x)
|
||||||
return math.floor((coordinate_to_block(x) - central_chunk_offset) / mcl_vars.chunksize)
|
return math.floor((coordinate_to_block(x) - central_chunk_offset) / mcl_vars.chunksize)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param pos Vector
|
|
||||||
---@return Vector
|
|
||||||
function mcl_vars.pos_to_block(pos)
|
function mcl_vars.pos_to_block(pos)
|
||||||
return vector.new(
|
return {
|
||||||
coordinate_to_block(pos.x),
|
x = coordinate_to_block(pos.x),
|
||||||
coordinate_to_block(pos.y),
|
y = coordinate_to_block(pos.y),
|
||||||
coordinate_to_block(pos.z)
|
z = coordinate_to_block(pos.z)
|
||||||
)
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param pos Vector
|
|
||||||
---@return Vector
|
|
||||||
function mcl_vars.pos_to_chunk(pos)
|
function mcl_vars.pos_to_chunk(pos)
|
||||||
return vector.new(
|
return {
|
||||||
coordinate_to_chunk(pos.x),
|
x = coordinate_to_chunk(pos.x),
|
||||||
coordinate_to_chunk(pos.y),
|
y = coordinate_to_chunk(pos.y),
|
||||||
coordinate_to_chunk(pos.z)
|
z = coordinate_to_chunk(pos.z)
|
||||||
)
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / mcl_vars.chunk_size_in_nodes)
|
local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / mcl_vars.chunk_size_in_nodes)
|
||||||
local k_positive_z = k_positive * 2
|
local k_positive_z = k_positive * 2
|
||||||
local k_positive_y = k_positive_z * k_positive_z
|
local k_positive_y = k_positive_z * k_positive_z
|
||||||
|
|
||||||
---@param pos Vector
|
|
||||||
---@return integer
|
|
||||||
function mcl_vars.get_chunk_number(pos) -- unsigned int
|
function mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||||
local c = mcl_vars.pos_to_chunk(pos)
|
local c = mcl_vars.pos_to_chunk(pos)
|
||||||
return (c.y + k_positive) * k_positive_y +
|
return
|
||||||
|
(c.y + k_positive) * k_positive_y +
|
||||||
(c.z + k_positive) * k_positive_z +
|
(c.z + k_positive) * k_positive_z +
|
||||||
c.x + k_positive
|
c.x + k_positive
|
||||||
end
|
end
|
||||||
|
|
||||||
if not superflat and not singlenode then
|
if not superflat and not singlenode then
|
||||||
|
@ -131,8 +117,11 @@ elseif singlenode then
|
||||||
mcl_vars.mg_bedrock_is_rough = false
|
mcl_vars.mg_bedrock_is_rough = false
|
||||||
else
|
else
|
||||||
-- Classic superflat
|
-- Classic superflat
|
||||||
local ground = tonumber(minetest.get_mapgen_setting("mgflat_ground_level")) or 8
|
local ground = minetest.get_mapgen_setting("mgflat_ground_level")
|
||||||
|
ground = tonumber(ground)
|
||||||
|
if not ground then
|
||||||
|
ground = 8
|
||||||
|
end
|
||||||
mcl_vars.mg_overworld_min = ground - 3
|
mcl_vars.mg_overworld_min = ground - 3
|
||||||
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
||||||
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
|
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
|
||||||
|
@ -192,16 +181,14 @@ minetest.craftitemdef_default.stack_max = 64
|
||||||
math.randomseed(os.time())
|
math.randomseed(os.time())
|
||||||
|
|
||||||
local chunks = {} -- intervals of chunks generated
|
local chunks = {} -- intervals of chunks generated
|
||||||
|
|
||||||
---@param pos Vector
|
|
||||||
function mcl_vars.add_chunk(pos)
|
function mcl_vars.add_chunk(pos)
|
||||||
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||||
local prev
|
local prev
|
||||||
for i, d in pairs(chunks) do
|
for i, d in pairs(chunks) do
|
||||||
if n <= d[2] then -- we've found it
|
if n <= d[2] then -- we've found it
|
||||||
if (n == d[2]) or (n >= d[1]) then return end -- already here
|
if (n == d[2]) or (n >= d[1]) then return end -- already here
|
||||||
if n == d[1] - 1 then -- right before:
|
if n == d[1]-1 then -- right before:
|
||||||
if prev and (prev[2] == n - 1) then
|
if prev and (prev[2] == n-1) then
|
||||||
prev[2] = d[2]
|
prev[2] = d[2]
|
||||||
table.remove(chunks, i)
|
table.remove(chunks, i)
|
||||||
return
|
return
|
||||||
|
@ -209,20 +196,17 @@ function mcl_vars.add_chunk(pos)
|
||||||
d[1] = n
|
d[1] = n
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if prev and (prev[2] == n - 1) then --join to previous
|
if prev and (prev[2] == n-1) then --join to previous
|
||||||
prev[2] = n
|
prev[2] = n
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
table.insert(chunks, i, { n, n }) -- insert new interval before i
|
table.insert(chunks, i, {n, n}) -- insert new interval before i
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
prev = d
|
prev = d
|
||||||
end
|
end
|
||||||
chunks[#chunks + 1] = { n, n }
|
chunks[#chunks+1] = {n, n}
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param pos Vector
|
|
||||||
---@return boolean
|
|
||||||
function mcl_vars.is_generated(pos)
|
function mcl_vars.is_generated(pos)
|
||||||
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||||
for i, d in pairs(chunks) do
|
for i, d in pairs(chunks) do
|
||||||
|
@ -233,46 +217,47 @@ function mcl_vars.is_generated(pos)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
---"Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does.
|
-- "Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does.
|
||||||
---@param pos Vector Position, if it's wrong, `{name="error"}` node will return.
|
-- p: Position, if it's wrong, {name="error"} node will return.
|
||||||
---@param force? boolean Optional (default: `false`), Do the maximum to still read the node within us_timeout.
|
-- force: optional (default: false) - Do the maximum to still read the node within us_timeout.
|
||||||
---@param us_timeout? number Optional (default: `244 = 0.000244 s = 1/80/80/80`), set it at least to `3000000` to let mapgen to finish its job
|
-- us_timeout: optional (default: 244 = 0.000244 s = 1/80/80/80), set it at least to 3000000 to let mapgen to finish its job.
|
||||||
---@return node # Node definition, eg. `{name="air"}`. Unfortunately still can return `{name="ignore"}`.
|
--
|
||||||
---@nodiscard
|
-- returns node definition, eg. {name="air"}. Unfortunately still can return {name="ignore"}.
|
||||||
function mcl_vars.get_node(pos, force, us_timeout)
|
function mcl_vars.get_node(p, force, us_timeout)
|
||||||
-- check initial circumstances
|
-- check initial circumstances
|
||||||
if not pos or not pos.x or not pos.y or not pos.z then return { name = "error" } end
|
if not p or not p.x or not p.y or not p.z then return {name="error"} end
|
||||||
|
|
||||||
-- try common way
|
-- try common way
|
||||||
local node = minetest.get_node(pos)
|
local node = minetest.get_node(p)
|
||||||
if node.name ~= "ignore" then
|
if node.name ~= "ignore" then
|
||||||
return node
|
return node
|
||||||
end
|
end
|
||||||
|
|
||||||
-- copy vector to get sure it won't changed by other threads
|
-- copy table to get sure it won't changed by other threads
|
||||||
local pos_copy = vector.copy(pos)
|
local pos = {x=p.x,y=p.y,z=p.z}
|
||||||
|
|
||||||
-- try LVM
|
-- try LVM
|
||||||
minetest.get_voxel_manip():read_from_map(pos_copy, pos_copy)
|
minetest.get_voxel_manip():read_from_map(pos, pos)
|
||||||
node = minetest.get_node(pos_copy)
|
node = minetest.get_node(pos)
|
||||||
if node.name ~= "ignore" or not force then
|
if node.name ~= "ignore" or not force then
|
||||||
return node
|
return node
|
||||||
end
|
end
|
||||||
|
|
||||||
-- all ways failed - need to emerge (or forceload if generated)
|
-- all ways failed - need to emerge (or forceload if generated)
|
||||||
if mcl_vars.is_generated(pos_copy) then
|
local us_timeout = us_timeout or 244
|
||||||
|
if mcl_vars.is_generated(pos) then
|
||||||
minetest.chat_send_all("IMPOSSIBLE! Please report this to MCL2 issue tracker!")
|
minetest.chat_send_all("IMPOSSIBLE! Please report this to MCL2 issue tracker!")
|
||||||
minetest.forceload_block(pos_copy)
|
minetest.forceload_block(pos)
|
||||||
else
|
else
|
||||||
minetest.emerge_area(pos_copy, pos_copy)
|
minetest.emerge_area(pos, pos)
|
||||||
end
|
end
|
||||||
|
|
||||||
local t = minetest.get_us_time()
|
local t = minetest.get_us_time()
|
||||||
|
|
||||||
node = minetest.get_node(pos_copy)
|
node = minetest.get_node(pos)
|
||||||
|
|
||||||
while (not node or node.name == "ignore") and (minetest.get_us_time() - t < (us_timeout or 244)) do
|
while (not node or node.name == "ignore") and (minetest.get_us_time() - t < us_timeout) do
|
||||||
node = minetest.get_node(pos_copy)
|
node = minetest.get_node(pos)
|
||||||
end
|
end
|
||||||
|
|
||||||
return node
|
return node
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
# Oxidization API for MineClone 2
|
|
||||||
This mods adds the oxidization api, so that modders can easily use the same features that copper uses.
|
|
||||||
|
|
||||||
## API
|
|
||||||
To take advantage of the actual oxidization, put `oxidizable = 1` into the list of groups for the oxidizable node.
|
|
||||||
You would also need to put `_mcl_oxidized_variant = itemstring of node this node will oxidize into` into the node definition.
|
|
||||||
For example, a copper block oxidizes into exposed copper, so the defintion would be `_mcl_oxidized_variant = "mcl_copper:block_exposed"`.
|
|
||||||
|
|
||||||
To utilize the ability to wax the block for protection from oxidization, put `mcl_waxed_variant = item string of waxed variant of node` into the node definition table.
|
|
||||||
For example, Copper Blocks have the definition arguement of `_mcl_waxed_variant = "mcl_copper:waxed_block"`.
|
|
||||||
|
|
||||||
For waxed nodes, scraping is easy. Start by putting `waxed = 1` into the list of groups of the waxed node.
|
|
||||||
Next put `_mcl_stripped_variant = item string of the unwaxed variant of the node` into the defintion table.
|
|
||||||
Wxaed Copper Blocks can be scrapped into normal Copper Blocks because of the definition `_mcl_stripped_variant = "mcl_copper:block"`.
|
|
|
@ -1,12 +0,0 @@
|
||||||
minetest.register_abm({
|
|
||||||
label = "Oxidatize Nodes",
|
|
||||||
nodenames = { "group:oxidizable" },
|
|
||||||
interval = 500,
|
|
||||||
chance = 3,
|
|
||||||
action = function(pos, node)
|
|
||||||
local def = minetest.registered_nodes[node.name]
|
|
||||||
if def and def._mcl_oxidized_variant then
|
|
||||||
minetest.set_node(pos, { name = def._mcl_oxidized_variant, param2 = node.param2 })
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
})
|
|
|
@ -1,4 +0,0 @@
|
||||||
name = mcl_oxidation
|
|
||||||
title = Oxidation API for MineClone 2
|
|
||||||
author = PrairieWind, N011, Michael
|
|
||||||
description = API to allow oxidizing different nodes.
|
|
After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 126 B After Width: | Height: | Size: 126 B |
Before Width: | Height: | Size: 127 B After Width: | Height: | Size: 127 B |
Before Width: | Height: | Size: 91 B After Width: | Height: | Size: 91 B |
Before Width: | Height: | Size: 137 B After Width: | Height: | Size: 137 B |
Before Width: | Height: | Size: 145 B After Width: | Height: | Size: 145 B |
Before Width: | Height: | Size: 125 B After Width: | Height: | Size: 125 B |
After Width: | Height: | Size: 183 B |
After Width: | Height: | Size: 262 B |
After Width: | Height: | Size: 126 B |
Before Width: | Height: | Size: 126 B After Width: | Height: | Size: 126 B |
After Width: | Height: | Size: 216 B |
Before Width: | Height: | Size: 144 B After Width: | Height: | Size: 144 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 101 B After Width: | Height: | Size: 101 B |
After Width: | Height: | Size: 148 B |
After Width: | Height: | Size: 154 B |
After Width: | Height: | Size: 155 B |
After Width: | Height: | Size: 165 B |
|
@ -2,8 +2,8 @@ mcl_util = {}
|
||||||
|
|
||||||
-- Updates all values in t using values from to*.
|
-- Updates all values in t using values from to*.
|
||||||
function table.update(t, ...)
|
function table.update(t, ...)
|
||||||
for _, to in ipairs {...} do
|
for _, to in ipairs{...} do
|
||||||
for k, v in pairs(to) do
|
for k,v in pairs(to) do
|
||||||
t[k] = v
|
t[k] = v
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -12,8 +12,8 @@ end
|
||||||
|
|
||||||
-- Updates nil values in t using values from to*.
|
-- Updates nil values in t using values from to*.
|
||||||
function table.update_nil(t, ...)
|
function table.update_nil(t, ...)
|
||||||
for _, to in ipairs {...} do
|
for _, to in ipairs{...} do
|
||||||
for k, v in pairs(to) do
|
for k,v in pairs(to) do
|
||||||
if t[k] == nil then
|
if t[k] == nil then
|
||||||
t[k] = v
|
t[k] = v
|
||||||
end
|
end
|
||||||
|
@ -22,9 +22,9 @@ function table.update_nil(t, ...)
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_default", false)
|
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_default",false)
|
||||||
local LOG_MODULE = "[MCL2]"
|
local LOG_MODULE = "[MCL2]"
|
||||||
function mcl_util.mcl_log(message, module, bypass_default_logger)
|
function mcl_util.mcl_log (message, module, bypass_default_logger)
|
||||||
local selected_module = LOG_MODULE
|
local selected_module = LOG_MODULE
|
||||||
if module then
|
if module then
|
||||||
selected_module = module
|
selected_module = module
|
||||||
|
@ -34,63 +34,6 @@ function mcl_util.mcl_log(message, module, bypass_default_logger)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local player_timers = {}
|
|
||||||
|
|
||||||
-- This is a dtime timer than can be used in on_step functions so it works every x seconds
|
|
||||||
-- self - Object you want to store timer data on. E.g. mob or a minecart, or player_name
|
|
||||||
-- dtime - The time since last run of on_step, should be passed in to function
|
|
||||||
-- timer_name - This is the name of the timer and also the key to store the data. No spaces + lowercase.
|
|
||||||
-- threshold - The time before it returns successful. 0.2 if you want to run it 5 times a second.
|
|
||||||
function mcl_util.check_dtime_timer(self, dtime, timer_name, threshold)
|
|
||||||
if not self or not threshold or not dtime then return end
|
|
||||||
if not timer_name or timer_name == "" then return end
|
|
||||||
|
|
||||||
if type(self) == "string" then
|
|
||||||
local player_name = self
|
|
||||||
if not player_timers[player_name] then
|
|
||||||
player_timers[player_name] = {}
|
|
||||||
end
|
|
||||||
self = player_timers[player_name]
|
|
||||||
end
|
|
||||||
|
|
||||||
if not self._timers then
|
|
||||||
self._timers = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
if not self._timers[timer_name] then
|
|
||||||
self._timers[timer_name] = 0
|
|
||||||
else
|
|
||||||
self._timers[timer_name] = self._timers[timer_name] + dtime
|
|
||||||
--minetest.log("dtime: " .. tostring(self._timers[timer_name]))
|
|
||||||
end
|
|
||||||
|
|
||||||
if self._timers[timer_name] > threshold then
|
|
||||||
--minetest.log("Over threshold")
|
|
||||||
self._timers[timer_name] = 0
|
|
||||||
return true
|
|
||||||
--else
|
|
||||||
--minetest.log("Not over threshold")
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Minetest 5.3.0 or less can only measure the light level. This came in at 5.4
|
|
||||||
-- This function has been known to fail in multiple places so the error handling is added increase safety and improve
|
|
||||||
-- debugging. See:
|
|
||||||
-- https://git.minetest.land/MineClone2/MineClone2/issues/1392
|
|
||||||
function mcl_util.get_natural_light (pos, time)
|
|
||||||
local status, retVal = pcall(minetest.get_natural_light, pos, time)
|
|
||||||
if status then
|
|
||||||
return retVal
|
|
||||||
else
|
|
||||||
minetest.log("warning", "Failed to get natural light at pos: " .. dump(pos) .. ", time: " .. dump(time))
|
|
||||||
if (pos) then
|
|
||||||
local node = minetest.get_node(pos)
|
|
||||||
minetest.log("warning", "Node at pos: " .. dump(node.name))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function mcl_util.file_exists(name)
|
function mcl_util.file_exists(name)
|
||||||
if type(name) ~= "string" then return end
|
if type(name) ~= "string" then return end
|
||||||
|
@ -126,7 +69,7 @@ function mcl_util.rotate_axis_and_place(itemstack, placer, pointed_thing, infini
|
||||||
local undef = minetest.registered_nodes[unode.name]
|
local undef = minetest.registered_nodes[unode.name]
|
||||||
if undef and undef.on_rightclick then
|
if undef and undef.on_rightclick then
|
||||||
undef.on_rightclick(pointed_thing.under, unode, placer,
|
undef.on_rightclick(pointed_thing.under, unode, placer,
|
||||||
itemstack, pointed_thing)
|
itemstack, pointed_thing)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local fdir = minetest.dir_to_facedir(placer:get_look_dir())
|
local fdir = minetest.dir_to_facedir(placer:get_look_dir())
|
||||||
|
@ -208,23 +151,23 @@ end
|
||||||
function mcl_util.get_double_container_neighbor_pos(pos, param2, side)
|
function mcl_util.get_double_container_neighbor_pos(pos, param2, side)
|
||||||
if side == "right" then
|
if side == "right" then
|
||||||
if param2 == 0 then
|
if param2 == 0 then
|
||||||
return {x = pos.x - 1, y = pos.y, z = pos.z}
|
return {x=pos.x-1, y=pos.y, z=pos.z}
|
||||||
elseif param2 == 1 then
|
elseif param2 == 1 then
|
||||||
return {x = pos.x, y = pos.y, z = pos.z + 1}
|
return {x=pos.x, y=pos.y, z=pos.z+1}
|
||||||
elseif param2 == 2 then
|
elseif param2 == 2 then
|
||||||
return {x = pos.x + 1, y = pos.y, z = pos.z}
|
return {x=pos.x+1, y=pos.y, z=pos.z}
|
||||||
elseif param2 == 3 then
|
elseif param2 == 3 then
|
||||||
return {x = pos.x, y = pos.y, z = pos.z - 1}
|
return {x=pos.x, y=pos.y, z=pos.z-1}
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if param2 == 0 then
|
if param2 == 0 then
|
||||||
return {x = pos.x + 1, y = pos.y, z = pos.z}
|
return {x=pos.x+1, y=pos.y, z=pos.z}
|
||||||
elseif param2 == 1 then
|
elseif param2 == 1 then
|
||||||
return {x = pos.x, y = pos.y, z = pos.z - 1}
|
return {x=pos.x, y=pos.y, z=pos.z-1}
|
||||||
elseif param2 == 2 then
|
elseif param2 == 2 then
|
||||||
return {x = pos.x - 1, y = pos.y, z = pos.z}
|
return {x=pos.x-1, y=pos.y, z=pos.z}
|
||||||
elseif param2 == 3 then
|
elseif param2 == 3 then
|
||||||
return {x = pos.x, y = pos.y, z = pos.z + 1}
|
return {x=pos.x, y=pos.y, z=pos.z+1}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -242,7 +185,7 @@ end
|
||||||
function mcl_util.get_eligible_transfer_item_slot(src_inventory, src_list, dst_inventory, dst_list, condition)
|
function mcl_util.get_eligible_transfer_item_slot(src_inventory, src_list, dst_inventory, dst_list, condition)
|
||||||
local size = src_inventory:get_size(src_list)
|
local size = src_inventory:get_size(src_list)
|
||||||
local stack
|
local stack
|
||||||
for i = 1, size do
|
for i=1, size do
|
||||||
stack = src_inventory:get_stack(src_list, i)
|
stack = src_inventory:get_stack(src_list, i)
|
||||||
if not stack:is_empty() and (condition == nil or condition(stack, src_inventory, src_list, dst_inventory, dst_list)) then
|
if not stack:is_empty() and (condition == nil or condition(stack, src_inventory, src_list, dst_inventory, dst_list)) then
|
||||||
return i
|
return i
|
||||||
|
@ -345,10 +288,10 @@ function mcl_util.move_item_container(source_pos, destination_pos, source_list,
|
||||||
-- Main inventory for most container types
|
-- Main inventory for most container types
|
||||||
if sctype == 2 or sctype == 3 or sctype == 5 or sctype == 6 or sctype == 7 then
|
if sctype == 2 or sctype == 3 or sctype == 5 or sctype == 6 or sctype == 7 then
|
||||||
source_list = "main"
|
source_list = "main"
|
||||||
-- Furnace: output
|
-- Furnace: output
|
||||||
elseif sctype == 4 then
|
elseif sctype == 4 then
|
||||||
source_list = "dst"
|
source_list = "dst"
|
||||||
-- Unknown source container type. Bail out
|
-- Unknown source container type. Bail out
|
||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
@ -401,7 +344,7 @@ function mcl_util.move_item_container(source_pos, destination_pos, source_list,
|
||||||
-- Main inventory for most container types
|
-- Main inventory for most container types
|
||||||
if dctype == 2 or dctype == 3 or dctype == 5 or dctype == 6 or dctype == 7 then
|
if dctype == 2 or dctype == 3 or dctype == 5 or dctype == 6 or dctype == 7 then
|
||||||
destination_list = "main"
|
destination_list = "main"
|
||||||
-- Furnace source slot
|
-- Furnace source slot
|
||||||
elseif dctype == 4 then
|
elseif dctype == 4 then
|
||||||
destination_list = "src"
|
destination_list = "src"
|
||||||
end
|
end
|
||||||
|
@ -466,7 +409,7 @@ end
|
||||||
-- Returns true if item (itemstring or ItemStack) can be used as a furnace fuel.
|
-- Returns true if item (itemstring or ItemStack) can be used as a furnace fuel.
|
||||||
-- Returns false otherwise
|
-- Returns false otherwise
|
||||||
function mcl_util.is_fuel(item)
|
function mcl_util.is_fuel(item)
|
||||||
return minetest.get_craft_result({method = "fuel", width = 1, items = {item}}).time ~= 0
|
return minetest.get_craft_result({method="fuel", width=1, items={item}}).time ~= 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Returns a on_place function for plants
|
-- Returns a on_place function for plants
|
||||||
|
@ -513,7 +456,7 @@ function mcl_util.generate_on_place_plant_function(condition)
|
||||||
|
|
||||||
if success then
|
if success then
|
||||||
if idef.sounds and idef.sounds.place then
|
if idef.sounds and idef.sounds.place then
|
||||||
minetest.sound_play(idef.sounds.place, {pos = pointed_thing.above, gain = 1}, true)
|
minetest.sound_play(idef.sounds.place, {pos=pointed_thing.above, gain=1}, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
itemstack = new_itemstack
|
itemstack = new_itemstack
|
||||||
|
@ -614,11 +557,6 @@ function mcl_util.deal_damage(target, damage, mcl_reason)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local is_immortal = target:get_armor_groups().immortal or 0
|
|
||||||
if is_immortal>0 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local hp = target:get_hp()
|
local hp = target:get_hp()
|
||||||
|
|
||||||
if hp > 0 then
|
if hp > 0 then
|
||||||
|
@ -705,80 +643,78 @@ end
|
||||||
|
|
||||||
local function roundN(n, d)
|
local function roundN(n, d)
|
||||||
if type(n) ~= "number" then return n end
|
if type(n) ~= "number" then return n end
|
||||||
local m = 10 ^ d
|
local m = 10^d
|
||||||
return math.floor(n * m + 0.5) / m
|
return math.floor(n * m + 0.5) / m
|
||||||
end
|
end
|
||||||
|
|
||||||
local function close_enough(a, b)
|
local function close_enough(a,b)
|
||||||
local rt = true
|
local rt=true
|
||||||
if type(a) == "table" and type(b) == "table" then
|
if type(a) == "table" and type(b) == "table" then
|
||||||
for k, v in pairs(a) do
|
for k,v in pairs(a) do
|
||||||
if roundN(v, 2) ~= roundN(b[k], 2) then
|
if roundN(v,2) ~= roundN(b[k],2) then
|
||||||
rt = false
|
rt=false
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
rt = roundN(a, 2) == roundN(b, 2)
|
rt = roundN(a,2) == roundN(b,2)
|
||||||
end
|
end
|
||||||
return rt
|
return rt
|
||||||
end
|
end
|
||||||
|
|
||||||
local function props_changed(props, oldprops)
|
local function props_changed(props,oldprops)
|
||||||
local changed = false
|
local changed=false
|
||||||
local p = {}
|
local p={}
|
||||||
for k, v in pairs(props) do
|
for k,v in pairs(props) do
|
||||||
if not close_enough(v, oldprops[k]) then
|
if not close_enough(v,oldprops[k]) then
|
||||||
p[k] = v
|
p[k]=v
|
||||||
changed = true
|
changed=true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return changed, p
|
return changed,p
|
||||||
end
|
end
|
||||||
|
|
||||||
--tests for roundN
|
--tests for roundN
|
||||||
local test_round1 = 15
|
local test_round1=15
|
||||||
local test_round2 = 15.00199999999
|
local test_round2=15.00199999999
|
||||||
local test_round3 = 15.00111111
|
local test_round3=15.00111111
|
||||||
local test_round4 = 15.00999999
|
local test_round4=15.00999999
|
||||||
|
|
||||||
assert(roundN(test_round1, 2) == roundN(test_round1, 2))
|
assert(roundN(test_round1,2)==roundN(test_round1,2))
|
||||||
assert(roundN(test_round1, 2) == roundN(test_round2, 2))
|
assert(roundN(test_round1,2)==roundN(test_round2,2))
|
||||||
assert(roundN(test_round1, 2) == roundN(test_round3, 2))
|
assert(roundN(test_round1,2)==roundN(test_round3,2))
|
||||||
assert(roundN(test_round1, 2) ~= roundN(test_round4, 2))
|
assert(roundN(test_round1,2)~=roundN(test_round4,2))
|
||||||
|
|
||||||
-- tests for close_enough
|
-- tests for close_enough
|
||||||
local test_cb = {-0.35, 0, -0.35, 0.35, 0.8, 0.35} --collisionboxes
|
local test_cb = {-0.35,0,-0.35,0.35,0.8,0.35} --collisionboxes
|
||||||
local test_cb_close = {-0.351213, 0, -0.35, 0.35, 0.8, 0.351212}
|
local test_cb_close = {-0.351213,0,-0.35,0.35,0.8,0.351212}
|
||||||
local test_cb_diff = {-0.35, 0, -1.35, 0.35, 0.8, 0.35}
|
local test_cb_diff = {-0.35,0,-1.35,0.35,0.8,0.35}
|
||||||
|
|
||||||
local test_eh = 1.65 --eye height
|
local test_eh = 1.65 --eye height
|
||||||
local test_eh_close = 1.65123123
|
local test_eh_close = 1.65123123
|
||||||
local test_eh_diff = 1.35
|
local test_eh_diff = 1.35
|
||||||
|
|
||||||
local test_nt = {r = 225, b = 225, a = 225, g = 225} --nametag
|
local test_nt = { r = 225, b = 225, a = 225, g = 225 } --nametag
|
||||||
local test_nt_diff = {r = 225, b = 225, a = 0, g = 225}
|
local test_nt_diff = { r = 225, b = 225, a = 0, g = 225 }
|
||||||
|
|
||||||
assert(close_enough(test_cb, test_cb_close))
|
assert(close_enough(test_cb,test_cb_close))
|
||||||
assert(not close_enough(test_cb, test_cb_diff))
|
assert(not close_enough(test_cb,test_cb_diff))
|
||||||
assert(close_enough(test_eh, test_eh_close))
|
assert(close_enough(test_eh,test_eh_close))
|
||||||
assert(not close_enough(test_eh, test_eh_diff))
|
assert(not close_enough(test_eh,test_eh_diff))
|
||||||
assert(not close_enough(test_nt, test_nt_diff)) --no floats involved here
|
assert(not close_enough(test_nt,test_nt_diff)) --no floats involved here
|
||||||
|
|
||||||
--tests for properties_changed
|
--tests for properties_changed
|
||||||
local test_properties_set1 = {collisionbox = {-0.35, 0, -0.35, 0.35, 0.8, 0.35}, eye_height = 0.65,
|
local test_properties_set1={collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 0.65, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}
|
||||||
nametag_color = {r = 225, b = 225, a = 225, g = 225}}
|
local test_properties_set2={collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 1.35, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}
|
||||||
local test_properties_set2 = {collisionbox = {-0.35, 0, -0.35, 0.35, 0.8, 0.35}, eye_height = 1.35,
|
|
||||||
nametag_color = {r = 225, b = 225, a = 225, g = 225}}
|
|
||||||
|
|
||||||
local test_p1, _ = props_changed(test_properties_set1, test_properties_set1)
|
local test_p1,_=props_changed(test_properties_set1,test_properties_set1)
|
||||||
local test_p2, _ = props_changed(test_properties_set1, test_properties_set2)
|
local test_p2,_=props_changed(test_properties_set1,test_properties_set2)
|
||||||
|
|
||||||
assert(not test_p1)
|
assert(not test_p1)
|
||||||
assert(test_p2)
|
assert(test_p2)
|
||||||
|
|
||||||
function mcl_util.set_properties(obj, props)
|
function mcl_util.set_properties(obj,props)
|
||||||
local changed, p = props_changed(props, obj:get_properties())
|
local changed,p=props_changed(props,obj:get_properties())
|
||||||
if changed then
|
if changed then
|
||||||
obj:set_properties(p)
|
obj:set_properties(p)
|
||||||
end
|
end
|
||||||
|
@ -792,312 +728,3 @@ function mcl_util.set_bone_position(obj, bone, pos, rot)
|
||||||
obj:set_bone_position(bone, pos or current_pos, rot or current_rot)
|
obj:set_bone_position(bone, pos or current_pos, rot or current_rot)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---Return a function to use in `on_place`.
|
|
||||||
---
|
|
||||||
---Allow to bypass the `buildable_to` node field in a `on_place` callback.
|
|
||||||
---
|
|
||||||
---You have to make sure that the nodes you return true for have `buildable_to = true`.
|
|
||||||
---@param func fun(node_name: string): boolean Return `true` if node must not replace the buildable_to node which have `node_name`
|
|
||||||
---@return fun(itemstack: ItemStack, placer: ObjectRef, pointed_thing: pointed_thing, param2: integer): ItemStack?
|
|
||||||
function mcl_util.bypass_buildable_to(func)
|
|
||||||
--------------------------
|
|
||||||
-- MINETEST CODE: UTILS --
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
local function copy_pointed_thing(pointed_thing)
|
|
||||||
return {
|
|
||||||
type = pointed_thing.type,
|
|
||||||
above = pointed_thing.above and vector.copy(pointed_thing.above),
|
|
||||||
under = pointed_thing.under and vector.copy(pointed_thing.under),
|
|
||||||
ref = pointed_thing.ref,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local function user_name(user)
|
|
||||||
return user and user:get_player_name() or ""
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Returns a logging function. For empty names, does not log.
|
|
||||||
local function make_log(name)
|
|
||||||
return name ~= "" and minetest.log or function() end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function check_attached_node(p, n, group_rating)
|
|
||||||
local def = core.registered_nodes[n.name]
|
|
||||||
local d = vector.zero()
|
|
||||||
if group_rating == 3 then
|
|
||||||
-- always attach to floor
|
|
||||||
d.y = -1
|
|
||||||
elseif group_rating == 4 then
|
|
||||||
-- always attach to ceiling
|
|
||||||
d.y = 1
|
|
||||||
elseif group_rating == 2 then
|
|
||||||
-- attach to facedir or 4dir direction
|
|
||||||
if (def.paramtype2 == "facedir" or
|
|
||||||
def.paramtype2 == "colorfacedir") then
|
|
||||||
-- Attach to whatever facedir is "mounted to".
|
|
||||||
-- For facedir, this is where tile no. 5 point at.
|
|
||||||
|
|
||||||
-- The fallback vector here is in case 'facedir to dir' is nil due
|
|
||||||
-- to voxelmanip placing a wallmounted node without resetting a
|
|
||||||
-- pre-existing param2 value that is out-of-range for facedir.
|
|
||||||
-- The fallback vector corresponds to param2 = 0.
|
|
||||||
d = core.facedir_to_dir(n.param2) or vector.new(0, 0, 1)
|
|
||||||
elseif (def.paramtype2 == "4dir" or
|
|
||||||
def.paramtype2 == "color4dir") then
|
|
||||||
-- Similar to facedir handling
|
|
||||||
d = core.fourdir_to_dir(n.param2) or vector.new(0, 0, 1)
|
|
||||||
end
|
|
||||||
elseif def.paramtype2 == "wallmounted" or
|
|
||||||
def.paramtype2 == "colorwallmounted" then
|
|
||||||
-- Attach to whatever this node is "mounted to".
|
|
||||||
-- This where tile no. 2 points at.
|
|
||||||
|
|
||||||
-- The fallback vector here is used for the same reason as
|
|
||||||
-- for facedir nodes.
|
|
||||||
d = core.wallmounted_to_dir(n.param2) or vector.new(0, 1, 0)
|
|
||||||
else
|
|
||||||
d.y = -1
|
|
||||||
end
|
|
||||||
local p2 = vector.add(p, d)
|
|
||||||
local nn = core.get_node(p2).name
|
|
||||||
local def2 = core.registered_nodes[nn]
|
|
||||||
if def2 and not def2.walkable then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
return function(itemstack, placer, pointed_thing, param2)
|
|
||||||
-------------------
|
|
||||||
-- MINETEST CODE --
|
|
||||||
-------------------
|
|
||||||
local def = itemstack:get_definition()
|
|
||||||
if def.type ~= "node" or pointed_thing.type ~= "node" then
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
|
|
||||||
local under = pointed_thing.under
|
|
||||||
local oldnode_under = minetest.get_node_or_nil(under)
|
|
||||||
local above = pointed_thing.above
|
|
||||||
local oldnode_above = minetest.get_node_or_nil(above)
|
|
||||||
local playername = user_name(placer)
|
|
||||||
local log = make_log(playername)
|
|
||||||
|
|
||||||
if not oldnode_under or not oldnode_above then
|
|
||||||
log("info", playername .. " tried to place"
|
|
||||||
.. " node in unloaded position " .. minetest.pos_to_string(above))
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
|
|
||||||
local olddef_under = minetest.registered_nodes[oldnode_under.name]
|
|
||||||
olddef_under = olddef_under or minetest.nodedef_default
|
|
||||||
local olddef_above = minetest.registered_nodes[oldnode_above.name]
|
|
||||||
olddef_above = olddef_above or minetest.nodedef_default
|
|
||||||
|
|
||||||
if not olddef_above.buildable_to and not olddef_under.buildable_to then
|
|
||||||
log("info", playername .. " tried to place"
|
|
||||||
.. " node in invalid position " .. minetest.pos_to_string(above)
|
|
||||||
.. ", replacing " .. oldnode_above.name)
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
|
|
||||||
---------------------
|
|
||||||
-- CUSTOMIZED CODE --
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
-- Place above pointed node
|
|
||||||
local place_to = vector.copy(above)
|
|
||||||
|
|
||||||
-- If node under is buildable_to, check for callback result and place into it instead
|
|
||||||
if olddef_under.buildable_to and not func(oldnode_under.name) then
|
|
||||||
log("info", "node under is buildable to")
|
|
||||||
place_to = vector.copy(under)
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------
|
|
||||||
-- MINETEST CODE --
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
if minetest.is_protected(place_to, playername) then
|
|
||||||
log("action", playername
|
|
||||||
.. " tried to place " .. def.name
|
|
||||||
.. " at protected position "
|
|
||||||
.. minetest.pos_to_string(place_to))
|
|
||||||
minetest.record_protection_violation(place_to, playername)
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
|
|
||||||
local oldnode = minetest.get_node(place_to)
|
|
||||||
local newnode = {name = def.name, param1 = 0, param2 = param2 or 0}
|
|
||||||
|
|
||||||
-- Calculate direction for wall mounted stuff like torches and signs
|
|
||||||
if def.place_param2 ~= nil then
|
|
||||||
newnode.param2 = def.place_param2
|
|
||||||
elseif (def.paramtype2 == "wallmounted" or
|
|
||||||
def.paramtype2 == "colorwallmounted") and not param2 then
|
|
||||||
local dir = vector.subtract(under, above)
|
|
||||||
newnode.param2 = minetest.dir_to_wallmounted(dir)
|
|
||||||
-- Calculate the direction for furnaces and chests and stuff
|
|
||||||
elseif (def.paramtype2 == "facedir" or
|
|
||||||
def.paramtype2 == "colorfacedir" or
|
|
||||||
def.paramtype2 == "4dir" or
|
|
||||||
def.paramtype2 == "color4dir") and not param2 then
|
|
||||||
local placer_pos = placer and placer:get_pos()
|
|
||||||
if placer_pos then
|
|
||||||
local dir = vector.subtract(above, placer_pos)
|
|
||||||
newnode.param2 = minetest.dir_to_facedir(dir)
|
|
||||||
log("info", "facedir: " .. newnode.param2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local metatable = itemstack:get_meta():to_table().fields
|
|
||||||
|
|
||||||
-- Transfer color information
|
|
||||||
if metatable.palette_index and not def.place_param2 then
|
|
||||||
local color_divisor = nil
|
|
||||||
if def.paramtype2 == "color" then
|
|
||||||
color_divisor = 1
|
|
||||||
elseif def.paramtype2 == "colorwallmounted" then
|
|
||||||
color_divisor = 8
|
|
||||||
elseif def.paramtype2 == "colorfacedir" then
|
|
||||||
color_divisor = 32
|
|
||||||
elseif def.paramtype2 == "color4dir" then
|
|
||||||
color_divisor = 4
|
|
||||||
elseif def.paramtype2 == "colordegrotate" then
|
|
||||||
color_divisor = 32
|
|
||||||
end
|
|
||||||
if color_divisor then
|
|
||||||
local color = math.floor(metatable.palette_index / color_divisor)
|
|
||||||
local other = newnode.param2 % color_divisor
|
|
||||||
newnode.param2 = color * color_divisor + other
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check if the node is attached and if it can be placed there
|
|
||||||
local an = minetest.get_item_group(def.name, "attached_node")
|
|
||||||
if an ~= 0 and
|
|
||||||
not check_attached_node(place_to, newnode, an) then
|
|
||||||
log("action", "attached node " .. def.name ..
|
|
||||||
" cannot be placed at " .. minetest.pos_to_string(place_to))
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
|
|
||||||
log("action", playername .. " places node "
|
|
||||||
.. def.name .. " at " .. minetest.pos_to_string(place_to))
|
|
||||||
|
|
||||||
-- Add node and update
|
|
||||||
minetest.add_node(place_to, newnode)
|
|
||||||
|
|
||||||
-- Play sound if it was done by a player
|
|
||||||
if playername ~= "" and def.sounds and def.sounds.place then
|
|
||||||
minetest.sound_play(def.sounds.place, {
|
|
||||||
pos = place_to,
|
|
||||||
exclude_player = playername,
|
|
||||||
}, true)
|
|
||||||
end
|
|
||||||
|
|
||||||
local take_item = true
|
|
||||||
|
|
||||||
-- Run callback
|
|
||||||
if def.after_place_node then
|
|
||||||
-- Deepcopy place_to and pointed_thing because callback can modify it
|
|
||||||
local place_to_copy = vector.copy(place_to)
|
|
||||||
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
|
|
||||||
if def.after_place_node(place_to_copy, placer, itemstack,
|
|
||||||
pointed_thing_copy) then
|
|
||||||
take_item = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Run script hook
|
|
||||||
for _, callback in ipairs(minetest.registered_on_placenodes) do
|
|
||||||
-- Deepcopy pos, node and pointed_thing because callback can modify them
|
|
||||||
local place_to_copy = vector.copy(place_to)
|
|
||||||
local newnode_copy = {name = newnode.name, param1 = newnode.param1, param2 = newnode.param2}
|
|
||||||
local oldnode_copy = {name = oldnode.name, param1 = oldnode.param1, param2 = oldnode.param2}
|
|
||||||
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
|
|
||||||
if callback(place_to_copy, newnode_copy, placer, oldnode_copy, itemstack, pointed_thing_copy) then
|
|
||||||
take_item = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if take_item then
|
|
||||||
itemstack:take_item()
|
|
||||||
end
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[Check for a protection violation in a given area.
|
|
||||||
--
|
|
||||||
-- Applies is_protected() to a 3D lattice of points in the defined volume. The points are spaced
|
|
||||||
-- evenly throughout the volume and have a spacing similar to, but no larger than, "interval".
|
|
||||||
--
|
|
||||||
-- @param pos1 A position table of the area volume's first edge.
|
|
||||||
-- @param pos2 A position table of the area volume's second edge.
|
|
||||||
-- @param player The player performing the action.
|
|
||||||
-- @param interval Optional. Max spacing between checked points at the volume.
|
|
||||||
-- Default: Same as minetest.is_area_protected.
|
|
||||||
--
|
|
||||||
-- @return true on protection violation detection. false otherwise.
|
|
||||||
--
|
|
||||||
-- @notes *All corners and edges of the defined volume are checked.
|
|
||||||
]]
|
|
||||||
function mcl_util.check_area_protection(pos1, pos2, player, interval)
|
|
||||||
local name = player and player:get_player_name() or ""
|
|
||||||
|
|
||||||
local protected_pos = minetest.is_area_protected(pos1, pos2, name, interval)
|
|
||||||
if protected_pos then
|
|
||||||
minetest.record_protection_violation(protected_pos, name)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[Check for a protection violation on a single position.
|
|
||||||
--
|
|
||||||
-- @param position A position table to check for protection violation.
|
|
||||||
-- @param player The player performing the action.
|
|
||||||
--
|
|
||||||
-- @return true on protection violation detection. false otherwise.
|
|
||||||
]]
|
|
||||||
function mcl_util.check_position_protection(position, player)
|
|
||||||
local name = player and player:get_player_name() or ""
|
|
||||||
|
|
||||||
if minetest.is_protected(position, name) then
|
|
||||||
minetest.record_protection_violation(position, name)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local palette_indexes = {grass_palette_index = 0, foliage_palette_index = 0, water_palette_index = 0}
|
|
||||||
function mcl_util.get_palette_indexes_from_pos(pos)
|
|
||||||
local biome_data = minetest.get_biome_data(pos)
|
|
||||||
local biome = biome_data.biome
|
|
||||||
local biome_name = minetest.get_biome_name(biome)
|
|
||||||
local reg_biome = minetest.registered_biomes[biome_name]
|
|
||||||
if reg_biome and reg_biome._mcl_grass_palette_index and reg_biome._mcl_foliage_palette_index and reg_biome._mcl_water_palette_index then
|
|
||||||
local gpi = reg_biome._mcl_grass_palette_index
|
|
||||||
local fpi = reg_biome._mcl_foliage_palette_index
|
|
||||||
local wpi = reg_biome._mcl_water_palette_index
|
|
||||||
local palette_indexes = {grass_palette_index = gpi, foliage_palette_index = fpi, water_palette_index = wpi}
|
|
||||||
return palette_indexes
|
|
||||||
else
|
|
||||||
return palette_indexes
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function mcl_util.get_colorwallmounted_rotation(pos)
|
|
||||||
local colorwallmounted_node = minetest.get_node(pos)
|
|
||||||
for i = 0, 32, 1 do
|
|
||||||
local colorwallmounted_rotation = colorwallmounted_node.param2 - (i * 8)
|
|
||||||
if colorwallmounted_rotation < 6 then
|
|
||||||
return colorwallmounted_rotation
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
|
@ -437,9 +437,9 @@ cboat.selectionbox = {-0.7, -0.15, -0.7, 0.7, 0.75, 0.7}
|
||||||
minetest.register_entity("mcl_boats:chest_boat", cboat)
|
minetest.register_entity("mcl_boats:chest_boat", cboat)
|
||||||
mcl_entity_invs.register_inv("mcl_boats:chest_boat","Boat",27)
|
mcl_entity_invs.register_inv("mcl_boats:chest_boat","Boat",27)
|
||||||
|
|
||||||
local boat_ids = { "boat", "boat_spruce", "boat_birch", "boat_jungle", "boat_acacia", "boat_dark_oak", "boat_obsidian", "boat_mangrove", "boat_cherry", "chest_boat", "chest_boat_spruce", "chest_boat_birch", "chest_boat_jungle", "chest_boat_acacia", "chest_boat_dark_oak", "chest_boat_mangrove", "chest_boat_cherry" }
|
local boat_ids = { "boat", "boat_spruce", "boat_birch", "boat_jungle", "boat_acacia", "boat_dark_oak", "boat_obsidian", "boat_mangrove", "chest_boat", "chest_boat_spruce", "chest_boat_birch", "chest_boat_jungle", "chest_boat_acacia", "chest_boat_dark_oak", "chest_boat_mangrove" }
|
||||||
local names = { S("Oak Boat"), S("Spruce Boat"), S("Birch Boat"), S("Jungle Boat"), S("Acacia Boat"), S("Dark Oak Boat"), S("Obsidian Boat"), S("Mangrove Boat"), S("Cherry Boat"), S("Oak Chest Boat"), S("Spruce Chest Boat"), S("Birch Chest Boat"), S("Jungle Chest Boat"), S("Acacia Chest Boat"), S("Dark Oak Chest Boat"), S("Mangrove Chest Boat"), S("Cherry Chest Boat") }
|
local names = { S("Oak Boat"), S("Spruce Boat"), S("Birch Boat"), S("Jungle Boat"), S("Acacia Boat"), S("Dark Oak Boat"), S("Obsidian Boat"), S("Mangrove Boat"), S("Oak Chest Boat"), S("Spruce Chest Boat"), S("Birch Chest Boat"), S("Jungle Chest Boat"), S("Acacia Chest Boat"), S("Dark Oak Chest Boat"), S("Mangrove Chest Boat") }
|
||||||
local craftstuffs = { "mcl_core:wood", "mcl_core:sprucewood", "mcl_core:birchwood", "mcl_core:junglewood", "mcl_core:acaciawood", "mcl_core:darkwood", "mcl_core:obsidian", "mcl_mangrove:mangrove_wood", "mcl_cherry_blossom:cherrywood" }
|
local craftstuffs = { "mcl_core:wood", "mcl_core:sprucewood", "mcl_core:birchwood", "mcl_core:junglewood", "mcl_core:acaciawood", "mcl_core:darkwood", "mcl_core:obsidian", "mcl_mangrove:mangrove_wood" }
|
||||||
|
|
||||||
for b=1, #boat_ids do
|
for b=1, #boat_ids do
|
||||||
local itemstring = "mcl_boats:"..boat_ids[b]
|
local itemstring = "mcl_boats:"..boat_ids[b]
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
# textdomain: mcl_boats
|
|
||||||
Acacia Boat=Akaciebåd
|
|
||||||
Birch Boat=Birkebåd
|
|
||||||
Boat=Båd
|
|
||||||
Boats are used to travel on the surface of water.=Både blier brugt til at rejse på vandoverflader.
|
|
||||||
Dark Oak Boat=Mørk egetræsbåd
|
|
||||||
Jungle Boat=Junglebåd
|
|
||||||
Oak Boat=Egetræsbåd
|
|
||||||
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Use [Sneak] to leave the boat, punch the boat to make it drop as an item.=Højre-klik på en vand for at placere båden. Højre-klik på båden for at gå ombord. Brug [Left] og [Right] til at styre. [Forwards] for at øge hastigheden, og [Backwards] for at sænke farten eller sejle bagud. Brug [Sneak] for at forlade båden, slå båden for at lave den om til en genstand.
|
|
||||||
Spruce Boat=Granbåd
|
|
||||||
Water vehicle=Vandfartøj
|
|
||||||
Sneak to dismount=Snig for at stige ud
|
|
||||||
Obsidian Boat=Obsidianbåd
|
|
|
@ -8,6 +8,3 @@ Jungle Boat=Barca de la selva
|
||||||
Oak Boat=Barca de roble
|
Oak Boat=Barca de roble
|
||||||
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Rightclick the boat again to leave it, punch the boat to make it drop as an item.=Haga clic derecho en una fuente de agua para colocar el barco. Haga clic derecho en el barco para entrar. Utilice [Izquierda] y [Derecha] para dirigir, [Adelante] para acelerar y [Atrás] para reducir la velocidad o retroceder. Haga clic derecho en el barco nuevamente para dejarlo, golpee el barco para que se caiga como un artículo.
|
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Rightclick the boat again to leave it, punch the boat to make it drop as an item.=Haga clic derecho en una fuente de agua para colocar el barco. Haga clic derecho en el barco para entrar. Utilice [Izquierda] y [Derecha] para dirigir, [Adelante] para acelerar y [Atrás] para reducir la velocidad o retroceder. Haga clic derecho en el barco nuevamente para dejarlo, golpee el barco para que se caiga como un artículo.
|
||||||
Spruce Boat=Barca de abeto
|
Spruce Boat=Barca de abeto
|
||||||
Water vehicle=Vehículo acuático
|
|
||||||
Sneak to dismount=Agáchate para bajar
|
|
||||||
Obsidian Boat=Barca de obsidiana
|
|
||||||
|
|
|
@ -1,21 +1,13 @@
|
||||||
# textdomain: mcl_boats
|
# textdomain: mcl_boats
|
||||||
Acacia Boat=Bateau en acacia
|
Acacia Boat=Bateau en Acacia
|
||||||
Birch Boat=Bateau en bouleau
|
Birch Boat=Bateau en Bouleau
|
||||||
Boat=Bateau
|
Boat=Bateau
|
||||||
Boats are used to travel on the surface of water.=Les bateaux sont utilisés pour voyager à la surface de l'eau.
|
Boats are used to travel on the surface of water.=Les bateaux sont utilisés pour voyager à la surface de l'eau.
|
||||||
Dark Oak Boat=Bateau en chêne noir
|
Dark Oak Boat=Bateau en Chêne Noir
|
||||||
Jungle Boat=Bateau en acajou
|
Jungle Boat=Bateau en Acajou
|
||||||
Oak Boat=Bateau en chêne
|
Oak Boat=Bateau en Chêne
|
||||||
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Use [Sneak] to leave the boat, punch the boat to make it drop as an item.=Faites un clic droit sur une source d'eau pour placer le bateau. Faites un clic droit sur le bateau pour y entrer. Utilisez [Gauche] et [Droite] pour diriger, [Avant] pour accélérer et [Arrière] pour ralentir ou reculer. Utilisez [Sneak] pour le quitter, frappez le bateau pour le faire tomber en tant qu'objet.
|
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Use [Sneak] to leave the boat, punch the boat to make it drop as an item.=Faites un clic droit sur une source d'eau pour placer le bateau. Faites un clic droit sur le bateau pour y entrer. Utilisez [Gauche] et [Droite] pour diriger, [Avant] pour accélérer et [Arrière] pour ralentir ou reculer. Utilisez [Sneak] pour le quitter, frappez le bateau pour le faire tomber en tant qu'objet.
|
||||||
Spruce Boat=Bateau en sapin
|
Spruce Boat=Bateau en Sapin
|
||||||
Water vehicle=Véhicule aquatique
|
Water vehicle=Véhicule aquatique
|
||||||
Sneak to dismount=Se baisser pour descendre
|
Sneak to dismount=Se baisser pour descendre
|
||||||
Obsidian Boat=Bateau en obsidienne
|
Obsidian Boat=Bateau en Obsidienne
|
||||||
Mangrove Boat=Bateau en palétuvier
|
|
||||||
Oak Chest Boat=Bateau en chêne avec coffre
|
|
||||||
Spruce Chest Boat=Bateau en sapin avec coffre
|
|
||||||
Birch Chest Boat=Bateau en bouleau avec coffre
|
|
||||||
Jungle Chest Boat=Bateau en acajou avec coffre
|
|
||||||
Acacia Chest Boat=Bateau en acacia avec coffre
|
|
||||||
Dark Oak Chest Boat=Bateau en chêne noir avec coffre
|
|
||||||
Mangrove Chest Boat=Bateau en palétuvier avec coffre
|
|
|
@ -1,23 +1,11 @@
|
||||||
# textdomain: mcl_boats
|
# textdomain: mcl_boats
|
||||||
Acacia Boat=Акациевая лодка
|
Acacia Boat=Лодка из акации
|
||||||
Birch Boat=Берёзовая лодка
|
Birch Boat=Берёзовая лодка
|
||||||
Boat=Лодка
|
Boat=Лодка
|
||||||
Boats are used to travel on the surface of water.=На лодке можно плыть по водной поверхности.
|
Boats are used to travel on the surface of water.=С помощью лодки можно путешествовать по водной поверхности.
|
||||||
Dark Oak Boat=Лодка из тёмного дуба
|
Dark Oak Boat=Лодка из тёмного дуба
|
||||||
Jungle Boat=Лодка из тропического дерева
|
Jungle Boat=Лодка из дерева джунглей
|
||||||
Oak Boat=Дубовая лодка
|
Oak Boat=Дубовая лодка
|
||||||
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Use [Sneak] to leave the boat, punch the boat to make it drop as an item.=Правый клик на воде, чтобы установить лодку. Правый клик по лодке, чтобы сесть в нее. [Влево] и [Вправо] - рулить, [Вперед] - разгоняться, [Назад] - тормозить или плыть назад. Нажмите [Красться] для высадки, бейте по лодке, чтобы забрать её.
|
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Rightclick the boat again to leave it, punch the boat to make it drop as an item.=Правый клик по воде спустит лодку на воду. Правый клик по лодке разместит вас в ней. [Влево] и [Вправо] - рулить, [Вперед] - разгоняться, [Назад] - тормозить или плыть назад. Правый клик по лодке, когда вы в ней, позволит выйти из неё. Удар по лодке превратит её обратно в предмет.
|
||||||
Spruce Boat=Еловая лодка
|
Spruce Boat=Еловая лодка
|
||||||
Water vehicle=Водный транспорт
|
Water vehicle=Водный транспорт
|
||||||
Sneak to dismount=Нажмите [Красться] для высадки
|
|
||||||
Obsidian Boat=Обсидиановая лодка
|
|
||||||
Mangrove Boat=Мангровая лодка
|
|
||||||
Cherry Boat=Вишнёвая лодка
|
|
||||||
Oak Chest Boat=Дубовая лодка с сундуком
|
|
||||||
Spruce Chest Boat=Еловая лодка с сундуком
|
|
||||||
Birch Chest Boat=Берёзовая лодка с сундуком
|
|
||||||
Jungle Chest Boat=Лодка из тропического дерева с сундуком
|
|
||||||
Acacia Chest Boat=Акациевая лодка с сундуком
|
|
||||||
Dark Oak Chest Boat=Лодка из тёмного дуба с сундуком
|
|
||||||
Mangrove Chest Boat=Мангровая лодка с сундуком
|
|
||||||
Cherry Chest Boat=Вишнёвая лодка с сундуком
|
|
|
@ -11,13 +11,3 @@ Spruce Boat=
|
||||||
Water vehicle=
|
Water vehicle=
|
||||||
Sneak to dismount=
|
Sneak to dismount=
|
||||||
Obsidian Boat=
|
Obsidian Boat=
|
||||||
Mangrove Boat=
|
|
||||||
Cherry Boat=
|
|
||||||
Oak Chest Boat=
|
|
||||||
Spruce Chest Boat=
|
|
||||||
Birch Chest Boat=
|
|
||||||
Jungle Chest Boat=
|
|
||||||
Acacia Chest Boat=
|
|
||||||
Dark Oak Chest Boat=
|
|
||||||
Mangrove Chest Boat=
|
|
||||||
Cherry Chest Boat=
|
|
After Width: | Height: | Size: 265 B |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 264 B |
After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 261 B After Width: | Height: | Size: 261 B |
After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 271 B After Width: | Height: | Size: 271 B |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 267 B |
After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 264 B After Width: | Height: | Size: 264 B |
Before Width: | Height: | Size: 267 B After Width: | Height: | Size: 267 B |
After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 969 B After Width: | Height: | Size: 969 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 535 B After Width: | Height: | Size: 535 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
@ -5,12 +5,7 @@ function mcl_burning.get_storage(obj)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_burning.is_burning(obj)
|
function mcl_burning.is_burning(obj)
|
||||||
local storage = mcl_burning.get_storage(obj)
|
return mcl_burning.get_storage(obj).burn_time
|
||||||
if storage then
|
|
||||||
return mcl_burning.get_storage(obj).burn_time
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_burning.is_affected_by_rain(obj)
|
function mcl_burning.is_affected_by_rain(obj)
|
||||||
|
@ -158,11 +153,6 @@ function mcl_burning.extinguish(obj)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_burning.tick(obj, dtime, storage)
|
function mcl_burning.tick(obj, dtime, storage)
|
||||||
if not storage then
|
|
||||||
minetest.log("warning", "No storage for burning tick. Should not happen: " .. dump(obj))
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if storage.burn_time then
|
if storage.burn_time then
|
||||||
storage.burn_time = storage.burn_time - dtime
|
storage.burn_time = storage.burn_time - dtime
|
||||||
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
# textdomain: mcl_falling_nodes
|
|
||||||
@1 was smashed by a falling anvil.=@1 blev smadret af en nedfaldende ambolt.
|
|
||||||
@1 was smashed by a falling block.=@1 blev smadret af en nedfaldende blok.
|
|
|
@ -1,3 +0,0 @@
|
||||||
# textdomain: mcl_falling_nodes
|
|
||||||
@1 was smashed by a falling anvil.=@1 fue aplastado por un yunque.
|
|
||||||
@1 was smashed by a falling block.=@1 fue aplastado por un bloque.
|
|
|
@ -1,3 +0,0 @@
|
||||||
# textdomain: mcl_falling_nodes
|
|
||||||
@1 was smashed by a falling anvil.=@1 a été écrasé par une enclume
|
|
||||||
@1 was smashed by a falling block.=@1 a été écrasé par un bloc
|
|
|
@ -1,3 +0,0 @@
|
||||||
# textdomain: mcl_falling_nodes
|
|
||||||
@1 was smashed by a falling anvil.=@1 был(а) раздавлен(а) падающей наковальней.
|
|
||||||
@1 was smashed by a falling block.=@1 был(а) раздавлен(а) падающим блоком.
|
|
|
@ -1,3 +0,0 @@
|
||||||
# textdomain: mcl_falling_nodes
|
|
||||||
@1 was smashed by a falling anvil.=
|
|
||||||
@1 was smashed by a falling block.=
|
|
|
@ -7,19 +7,31 @@ local pool = {}
|
||||||
local tick = false
|
local tick = false
|
||||||
|
|
||||||
|
|
||||||
|
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_item_entities",false)
|
||||||
|
local function mcl_log (message)
|
||||||
|
if LOGGING_ON then
|
||||||
|
mcl_util.mcl_log (message, "[Item Entities]", true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
minetest.register_on_joinplayer(function(player)
|
minetest.register_on_joinplayer(function(player)
|
||||||
pool[player:get_player_name()] = 0
|
local name
|
||||||
|
name = player:get_player_name()
|
||||||
|
pool[name] = 0
|
||||||
end)
|
end)
|
||||||
|
|
||||||
minetest.register_on_leaveplayer(function(player)
|
minetest.register_on_leaveplayer(function(player)
|
||||||
pool[player:get_player_name()] = nil
|
local name
|
||||||
|
name = player:get_player_name()
|
||||||
|
pool[name] = nil
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
local has_awards = minetest.get_modpath("awards")
|
local has_awards = minetest.get_modpath("awards")
|
||||||
|
|
||||||
mcl_item_entity = {}
|
local mcl_item_entity = {}
|
||||||
|
|
||||||
--basic settings
|
--basic settings
|
||||||
local item_drop_settings = {} --settings table
|
local item_drop_settings = {} --settings table
|
||||||
|
@ -34,29 +46,22 @@ item_drop_settings.random_item_velocity = true --this sets random item velocity
|
||||||
item_drop_settings.drop_single_item = false --if true, the drop control drops 1 item instead of the entire stack, and sneak+drop drops the stack
|
item_drop_settings.drop_single_item = false --if true, the drop control drops 1 item instead of the entire stack, and sneak+drop drops the stack
|
||||||
-- drop_single_item is disabled by default because it is annoying to throw away items from the intentory screen
|
-- drop_single_item is disabled by default because it is annoying to throw away items from the intentory screen
|
||||||
|
|
||||||
item_drop_settings.magnet_time = 0.75 -- how many seconds an item follows the player before giving up
|
item_drop_settings.magnet_time = 0.75 -- how many seconds an item follows the player before giving up
|
||||||
|
|
||||||
local function get_gravity()
|
local function get_gravity()
|
||||||
return tonumber(minetest.settings:get("movement_gravity")) or 9.81
|
return tonumber(minetest.settings:get("movement_gravity")) or 9.81
|
||||||
end
|
end
|
||||||
|
|
||||||
mcl_item_entity.registered_pickup_achievement = {}
|
local registered_pickup_achievement = {}
|
||||||
|
|
||||||
---Register an achievement that will be unlocked on pickup.
|
--TODO: remove limitation of 1 award per itemname
|
||||||
---
|
|
||||||
---TODO: remove limitation of 1 award per itemname
|
|
||||||
---@param itemname string
|
|
||||||
---@param award string
|
|
||||||
function mcl_item_entity.register_pickup_achievement(itemname, award)
|
function mcl_item_entity.register_pickup_achievement(itemname, award)
|
||||||
if not has_awards then
|
if not has_awards then
|
||||||
minetest.log("warning",
|
minetest.log("warning", "[mcl_item_entity] Trying to register pickup achievement ["..award.."] for ["..itemname.."] while awards missing")
|
||||||
"[mcl_item_entity] Trying to register pickup achievement [" .. award .. "] for [" ..
|
elseif registered_pickup_achievement[itemname] then
|
||||||
itemname .. "] while awards missing")
|
minetest.log("error", "[mcl_item_entity] Trying to register already existing pickup achievement ["..award.."] for ["..itemname.."]")
|
||||||
elseif mcl_item_entity.registered_pickup_achievement[itemname] then
|
|
||||||
minetest.log("error",
|
|
||||||
"[mcl_item_entity] Trying to register already existing pickup achievement [" .. award .. "] for [" .. itemname .. "]")
|
|
||||||
else
|
else
|
||||||
mcl_item_entity.registered_pickup_achievement[itemname] = award
|
registered_pickup_achievement[itemname] = award
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -69,13 +74,11 @@ mcl_item_entity.register_pickup_achievement("mcl_nether:ancient_debris", "mcl:hi
|
||||||
mcl_item_entity.register_pickup_achievement("mcl_end:dragon_egg", "mcl:PickUpDragonEgg")
|
mcl_item_entity.register_pickup_achievement("mcl_end:dragon_egg", "mcl:PickUpDragonEgg")
|
||||||
mcl_item_entity.register_pickup_achievement("mcl_armor:elytra", "mcl:skysTheLimit")
|
mcl_item_entity.register_pickup_achievement("mcl_armor:elytra", "mcl:skysTheLimit")
|
||||||
|
|
||||||
---@param object ObjectRef
|
|
||||||
---@param player ObjectRef
|
|
||||||
local function check_pickup_achievements(object, player)
|
local function check_pickup_achievements(object, player)
|
||||||
if has_awards then
|
if has_awards then
|
||||||
local itemname = ItemStack(object:get_luaentity().itemstring):get_name()
|
local itemname = ItemStack(object:get_luaentity().itemstring):get_name()
|
||||||
local playername = player:get_player_name()
|
local playername = player:get_player_name()
|
||||||
for name, award in pairs(mcl_item_entity.registered_pickup_achievement) do
|
for name,award in pairs(registered_pickup_achievement) do
|
||||||
if itemname == name or minetest.get_item_group(itemname, name) ~= 0 then
|
if itemname == name or minetest.get_item_group(itemname, name) ~= 0 then
|
||||||
awards.unlock(playername, award)
|
awards.unlock(playername, award)
|
||||||
end
|
end
|
||||||
|
@ -83,23 +86,16 @@ local function check_pickup_achievements(object, player)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param object ObjectRef
|
|
||||||
---@param luaentity Luaentity
|
|
||||||
---@param ignore_check? boolean
|
|
||||||
local function enable_physics(object, luaentity, ignore_check)
|
local function enable_physics(object, luaentity, ignore_check)
|
||||||
if luaentity.physical_state == false or ignore_check == true then
|
if luaentity.physical_state == false or ignore_check == true then
|
||||||
luaentity.physical_state = true
|
luaentity.physical_state = true
|
||||||
object:set_properties({
|
object:set_properties({
|
||||||
physical = true
|
physical = true
|
||||||
})
|
})
|
||||||
object:set_acceleration(vector.new(0, -get_gravity(), 0))
|
object:set_acceleration({x=0,y=-get_gravity(),z=0})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param object ObjectRef
|
|
||||||
---@param luaentity Luaentity
|
|
||||||
---@param ignore_check? boolean
|
|
||||||
---@param reset_movement? boolean
|
|
||||||
local function disable_physics(object, luaentity, ignore_check, reset_movement)
|
local function disable_physics(object, luaentity, ignore_check, reset_movement)
|
||||||
if luaentity.physical_state == true or ignore_check == true then
|
if luaentity.physical_state == true or ignore_check == true then
|
||||||
luaentity.physical_state = false
|
luaentity.physical_state = false
|
||||||
|
@ -107,16 +103,17 @@ local function disable_physics(object, luaentity, ignore_check, reset_movement)
|
||||||
physical = false
|
physical = false
|
||||||
})
|
})
|
||||||
if reset_movement ~= false then
|
if reset_movement ~= false then
|
||||||
object:set_velocity(vector.zero())
|
object:set_velocity({x=0,y=0,z=0})
|
||||||
object:set_acceleration(vector.zero())
|
object:set_acceleration({x=0,y=0,z=0})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_globalstep(function(_)
|
|
||||||
|
minetest.register_globalstep(function(dtime)
|
||||||
tick = not tick
|
tick = not tick
|
||||||
|
|
||||||
for _, player in pairs(minetest.get_connected_players()) do
|
for _,player in pairs(minetest.get_connected_players()) do
|
||||||
if player:get_hp() > 0 or not minetest.settings:get_bool("enable_damage") then
|
if player:get_hp() > 0 or not minetest.settings:get_bool("enable_damage") then
|
||||||
|
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
|
@ -128,7 +125,7 @@ minetest.register_globalstep(function(_)
|
||||||
pos = pos,
|
pos = pos,
|
||||||
gain = 0.3,
|
gain = 0.3,
|
||||||
max_hear_distance = 16,
|
max_hear_distance = 16,
|
||||||
pitch = math.random(70, 110) / 100
|
pitch = math.random(70,110)/100
|
||||||
})
|
})
|
||||||
if pool[name] > 6 then
|
if pool[name] > 6 then
|
||||||
pool[name] = 6
|
pool[name] = 6
|
||||||
|
@ -138,18 +135,15 @@ minetest.register_globalstep(function(_)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local inv = player:get_inventory()
|
local inv = player:get_inventory()
|
||||||
local checkpos = vector.offset(pos, 0, item_drop_settings.player_collect_height, 0)
|
local checkpos = {x=pos.x,y=pos.y + item_drop_settings.player_collect_height,z=pos.z}
|
||||||
|
|
||||||
--magnet and collection
|
--magnet and collection
|
||||||
for _, object in pairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do
|
for _,object in pairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do
|
||||||
if not object:is_player() and vector.distance(checkpos, object:get_pos()) < item_drop_settings.radius_magnet and
|
if not object:is_player() and vector.distance(checkpos, object:get_pos()) < item_drop_settings.radius_magnet and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
|
||||||
object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer
|
|
||||||
and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
|
|
||||||
|
|
||||||
if object:get_luaentity()._magnet_timer >= 0 and
|
if object:get_luaentity()._magnet_timer >= 0 and object:get_luaentity()._magnet_timer < item_drop_settings.magnet_time and inv and inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
|
||||||
object:get_luaentity()._magnet_timer < item_drop_settings.magnet_time and inv and
|
|
||||||
inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
|
|
||||||
|
|
||||||
-- Collection
|
-- Collection
|
||||||
if not object:get_luaentity()._removed then
|
if not object:get_luaentity()._removed then
|
||||||
|
@ -164,8 +158,8 @@ minetest.register_globalstep(function(_)
|
||||||
object:get_luaentity().target = checkpos
|
object:get_luaentity().target = checkpos
|
||||||
object:get_luaentity()._removed = true
|
object:get_luaentity()._removed = true
|
||||||
|
|
||||||
object:set_velocity(vector.zero())
|
object:set_velocity({x=0,y=0,z=0})
|
||||||
object:set_acceleration(vector.zero())
|
object:set_acceleration({x=0,y=0,z=0})
|
||||||
|
|
||||||
object:move_to(checkpos)
|
object:move_to(checkpos)
|
||||||
|
|
||||||
|
@ -185,6 +179,7 @@ minetest.register_globalstep(function(_)
|
||||||
local entity = object:get_luaentity()
|
local entity = object:get_luaentity()
|
||||||
entity.collector = player:get_player_name()
|
entity.collector = player:get_player_name()
|
||||||
entity.collected = true
|
entity.collected = true
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -199,11 +194,6 @@ end)
|
||||||
|
|
||||||
local tmp_id = 0
|
local tmp_id = 0
|
||||||
|
|
||||||
---@param drop string|drop_definition
|
|
||||||
---@param toolname string
|
|
||||||
---@param param2 integer
|
|
||||||
---@param paramtype2 paramtype2
|
|
||||||
---@return string[]
|
|
||||||
local function get_drops(drop, toolname, param2, paramtype2)
|
local function get_drops(drop, toolname, param2, paramtype2)
|
||||||
tmp_id = tmp_id + 1
|
tmp_id = tmp_id + 1
|
||||||
local tmp_node_name = "mcl_item_entity:" .. tmp_id
|
local tmp_node_name = "mcl_item_entity:" .. tmp_id
|
||||||
|
@ -212,7 +202,7 @@ local function get_drops(drop, toolname, param2, paramtype2)
|
||||||
drop = drop,
|
drop = drop,
|
||||||
paramtype2 = paramtype2
|
paramtype2 = paramtype2
|
||||||
}
|
}
|
||||||
local drops = minetest.get_node_drops({ name = tmp_node_name, param2 = param2 }, toolname)
|
local drops = minetest.get_node_drops({name = tmp_node_name, param2 = param2}, toolname)
|
||||||
minetest.registered_nodes[tmp_node_name] = nil
|
minetest.registered_nodes[tmp_node_name] = nil
|
||||||
return drops
|
return drops
|
||||||
end
|
end
|
||||||
|
@ -247,17 +237,10 @@ function minetest.handle_node_drops(pos, drops, digger)
|
||||||
-- NOTE: This function override allows digger to be nil.
|
-- NOTE: This function override allows digger to be nil.
|
||||||
-- This means there is no digger. This is a special case which allows this function to be called
|
-- This means there is no digger. This is a special case which allows this function to be called
|
||||||
-- by hand. Creative Mode is intentionally ignored in this case.
|
-- by hand. Creative Mode is intentionally ignored in this case.
|
||||||
if digger and digger:is_player() and minetest.is_creative_enabled(digger:get_player_name()) then
|
|
||||||
local inv = digger:get_inventory()
|
if (digger and digger:is_player() and minetest.is_creative_enabled(digger:get_player_name())) or doTileDrops == false then
|
||||||
if inv then
|
|
||||||
for _, item in ipairs(drops) do
|
|
||||||
if not inv:contains_item("main", item, true) then
|
|
||||||
inv:add_item("main", item)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return
|
return
|
||||||
elseif not doTileDrops then return end
|
end
|
||||||
|
|
||||||
-- Check if node will yield its useful drop by the digger's tool
|
-- Check if node will yield its useful drop by the digger's tool
|
||||||
local dug_node = minetest.get_node(pos)
|
local dug_node = minetest.get_node(pos)
|
||||||
|
@ -265,9 +248,9 @@ function minetest.handle_node_drops(pos, drops, digger)
|
||||||
local tool
|
local tool
|
||||||
if digger then
|
if digger then
|
||||||
tool = digger:get_wielded_item()
|
tool = digger:get_wielded_item()
|
||||||
tooldef = minetest.registered_items[tool:get_name()]
|
tooldef = minetest.registered_tools[tool:get_name()]
|
||||||
|
|
||||||
if not mcl_autogroup.can_harvest(dug_node.name, tool:get_name(), digger) then
|
if not mcl_autogroup.can_harvest(dug_node.name, tool:get_name()) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -282,7 +265,7 @@ function minetest.handle_node_drops(pos, drops, digger)
|
||||||
* table: Drop every itemstring in this table when dug by shears _mcl_silk_touch_drop
|
* table: Drop every itemstring in this table when dug by shears _mcl_silk_touch_drop
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local enchantments = tool and mcl_enchanting.get_enchantments(tool)
|
local enchantments = tool and mcl_enchanting.get_enchantments(tool, "silk_touch")
|
||||||
|
|
||||||
local silk_touch_drop = false
|
local silk_touch_drop = false
|
||||||
local nodedef = minetest.registered_nodes[dug_node.name]
|
local nodedef = minetest.registered_nodes[dug_node.name]
|
||||||
|
@ -311,8 +294,7 @@ function minetest.handle_node_drops(pos, drops, digger)
|
||||||
local max_count = fortune_drop.max_count + fortune_level * (fortune_drop.factor or 1)
|
local max_count = fortune_drop.max_count + fortune_level * (fortune_drop.factor or 1)
|
||||||
local chance = fortune_drop.chance or fortune_drop.get_chance and fortune_drop.get_chance(fortune_level)
|
local chance = fortune_drop.chance or fortune_drop.get_chance and fortune_drop.get_chance(fortune_level)
|
||||||
if not chance or math.random() < chance then
|
if not chance or math.random() < chance then
|
||||||
drops = discrete_uniform_distribution(fortune_drop.multiply and drops or fortune_drop.items, min_count, max_count,
|
drops = discrete_uniform_distribution(fortune_drop.multiply and drops or fortune_drop.items, min_count, max_count, fortune_drop.cap)
|
||||||
fortune_drop.cap)
|
|
||||||
elseif fortune_drop.override then
|
elseif fortune_drop.override then
|
||||||
drops = {}
|
drops = {}
|
||||||
end
|
end
|
||||||
|
@ -324,13 +306,13 @@ function minetest.handle_node_drops(pos, drops, digger)
|
||||||
end
|
end
|
||||||
|
|
||||||
if digger and mcl_experience.throw_xp and not silk_touch_drop then
|
if digger and mcl_experience.throw_xp and not silk_touch_drop then
|
||||||
local experience_amount = minetest.get_item_group(dug_node.name, "xp")
|
local experience_amount = minetest.get_item_group(dug_node.name,"xp")
|
||||||
if experience_amount > 0 then
|
if experience_amount > 0 then
|
||||||
mcl_experience.throw_xp(pos, experience_amount)
|
mcl_experience.throw_xp(pos, experience_amount)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, item in ipairs(drops) do
|
for _,item in ipairs(drops) do
|
||||||
local count
|
local count
|
||||||
if type(item) == "string" then
|
if type(item) == "string" then
|
||||||
count = ItemStack(item):get_count()
|
count = ItemStack(item):get_count()
|
||||||
|
@ -339,7 +321,7 @@ function minetest.handle_node_drops(pos, drops, digger)
|
||||||
end
|
end
|
||||||
local drop_item = ItemStack(item)
|
local drop_item = ItemStack(item)
|
||||||
drop_item:set_count(1)
|
drop_item:set_count(1)
|
||||||
for i = 1, count do
|
for i=1,count do
|
||||||
local dpos = table.copy(pos)
|
local dpos = table.copy(pos)
|
||||||
-- Apply offset for plantlike_rooted nodes because of their special shape
|
-- Apply offset for plantlike_rooted nodes because of their special shape
|
||||||
if nodedef and nodedef.drawtype == "plantlike_rooted" and nodedef.walkable then
|
if nodedef and nodedef.drawtype == "plantlike_rooted" and nodedef.walkable then
|
||||||
|
@ -366,7 +348,7 @@ end
|
||||||
function minetest.item_drop(itemstack, dropper, pos)
|
function minetest.item_drop(itemstack, dropper, pos)
|
||||||
if dropper and dropper:is_player() then
|
if dropper and dropper:is_player() then
|
||||||
local v = dropper:get_look_dir()
|
local v = dropper:get_look_dir()
|
||||||
local p = vector.offset(pos, 0, 1.2, 0)
|
local p = {x=pos.x, y=pos.y+1.2, z=pos.z}
|
||||||
local cs = itemstack:get_count()
|
local cs = itemstack:get_count()
|
||||||
if dropper:get_player_control().sneak then
|
if dropper:get_player_control().sneak then
|
||||||
cs = 1
|
cs = 1
|
||||||
|
@ -374,9 +356,9 @@ function minetest.item_drop(itemstack, dropper, pos)
|
||||||
local item = itemstack:take_item(cs)
|
local item = itemstack:take_item(cs)
|
||||||
local obj = minetest.add_item(p, item)
|
local obj = minetest.add_item(p, item)
|
||||||
if obj then
|
if obj then
|
||||||
v.x = v.x * 4
|
v.x = v.x*4
|
||||||
v.y = v.y * 4 + 2
|
v.y = v.y*4 + 2
|
||||||
v.z = v.z * 4
|
v.z = v.z*4
|
||||||
obj:set_velocity(v)
|
obj:set_velocity(v)
|
||||||
-- Force collection delay
|
-- Force collection delay
|
||||||
obj:get_luaentity()._insta_collect = false
|
obj:get_luaentity()._insta_collect = false
|
||||||
|
@ -394,185 +376,123 @@ end
|
||||||
|
|
||||||
local function cxcz(o, cw, one, zero)
|
local function cxcz(o, cw, one, zero)
|
||||||
if cw < 0 then
|
if cw < 0 then
|
||||||
table.insert(o, { [one] = 1, y = 0, [zero] = 0 })
|
table.insert(o, { [one]=1, y=0, [zero]=0 })
|
||||||
table.insert(o, { [one] = -1, y = 0, [zero] = 0 })
|
table.insert(o, { [one]=-1, y=0, [zero]=0 })
|
||||||
else
|
else
|
||||||
table.insert(o, { [one] = -1, y = 0, [zero] = 0 })
|
table.insert(o, { [one]=-1, y=0, [zero]=0 })
|
||||||
table.insert(o, { [one] = 1, y = 0, [zero] = 0 })
|
table.insert(o, { [one]=1, y=0, [zero]=0 })
|
||||||
end
|
end
|
||||||
return o
|
return o
|
||||||
end
|
end
|
||||||
|
|
||||||
local function nodes_destroy_items (self, moveresult, def, nn)
|
local function hopper_take_item (self, pos)
|
||||||
local lg = minetest.get_item_group(nn, "lava")
|
--mcl_log("self.itemstring: ".. self.itemstring)
|
||||||
local fg = minetest.get_item_group(nn, "fire")
|
--mcl_log("self.itemstring: ".. minetest.pos_to_string(pos))
|
||||||
local dg = minetest.get_item_group(nn, "destroys_items")
|
|
||||||
|
|
||||||
if (def and (lg ~= 0 or fg ~= 0 or dg == 1)) then
|
local objs = minetest.get_objects_inside_radius(pos, 2)
|
||||||
local item_string = self.itemstring
|
|
||||||
local item_name = ItemStack(item_string):get_name()
|
|
||||||
|
|
||||||
--Wait 2 seconds to allow mob drops to be cooked, & picked up instead of instantly destroyed.
|
if objs and self.itemstring then
|
||||||
if self.age > 2 and minetest.get_item_group(item_name, "fire_immune") == 0 then
|
--mcl_log("there is an itemstring. Number of objs: ".. #objs)
|
||||||
if dg ~= 2 then
|
|
||||||
minetest.sound_play("builtin_item_lava", { pos = self.object:get_pos(), gain = 0.5 })
|
|
||||||
end
|
|
||||||
self._removed = true
|
|
||||||
self.object:remove()
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Destroy item when it collides with a cactus
|
for k,v in pairs(objs) do
|
||||||
if moveresult and moveresult.collides then
|
local ent = v:get_luaentity()
|
||||||
for _, collision in pairs(moveresult.collisions) do
|
|
||||||
local pos = collision.node_pos
|
-- Don't forget actual hoppers
|
||||||
if collision.type == "node" and minetest.get_node(pos).name == "mcl_core:cactus" then
|
if ent and ent.name == "mcl_minecarts:hopper_minecart" then
|
||||||
-- TODO We need to play a sound when it gets destroyed
|
local taken_items = false
|
||||||
self._removed = true
|
|
||||||
self.object:remove()
|
mcl_log("ent.name: ".. tostring(ent.name))
|
||||||
return true
|
mcl_log("ent pos: ".. tostring(ent.object:get_pos()))
|
||||||
|
|
||||||
|
local inv = mcl_entity_invs.load_inv(ent,5)
|
||||||
|
|
||||||
|
if not inv then
|
||||||
|
mcl_log("No inv")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local current_itemstack = ItemStack(self.itemstring)
|
||||||
|
|
||||||
|
mcl_log("inv. size: " .. ent._inv_size)
|
||||||
|
if inv:room_for_item("main", current_itemstack) then
|
||||||
|
mcl_log("Room")
|
||||||
|
inv:add_item("main", current_itemstack)
|
||||||
|
self.object:get_luaentity().itemstring = ""
|
||||||
|
self.object:remove()
|
||||||
|
taken_items = true
|
||||||
|
else
|
||||||
|
mcl_log("no Room")
|
||||||
|
end
|
||||||
|
|
||||||
|
if not taken_items then
|
||||||
|
local items_remaining = current_itemstack:get_count()
|
||||||
|
|
||||||
|
-- This will take part of a floating item stack if no slot can hold the full amount
|
||||||
|
for i = 1, ent._inv_size,1 do
|
||||||
|
local stack = inv:get_stack("main", i)
|
||||||
|
|
||||||
|
mcl_log("i: " .. tostring(i))
|
||||||
|
mcl_log("Items remaining: " .. items_remaining)
|
||||||
|
mcl_log("Name: " .. tostring(stack:get_name()))
|
||||||
|
|
||||||
|
if current_itemstack:get_name() == stack:get_name() then
|
||||||
|
mcl_log("We have a match. Name: " .. tostring(stack:get_name()))
|
||||||
|
|
||||||
|
local room_for = stack:get_stack_max() - stack:get_count()
|
||||||
|
mcl_log("Room for: " .. tostring(room_for))
|
||||||
|
|
||||||
|
if room_for == 0 then
|
||||||
|
-- Do nothing
|
||||||
|
mcl_log("No room")
|
||||||
|
elseif room_for < items_remaining then
|
||||||
|
mcl_log("We have more items remaining than space")
|
||||||
|
|
||||||
|
items_remaining = items_remaining - room_for
|
||||||
|
stack:set_count(stack:get_stack_max())
|
||||||
|
inv:set_stack("main", i, stack)
|
||||||
|
taken_items = true
|
||||||
|
else
|
||||||
|
local new_stack_size = stack:get_count() + items_remaining
|
||||||
|
stack:set_count(new_stack_size)
|
||||||
|
mcl_log("We have more than enough space. Now holds: " .. new_stack_size)
|
||||||
|
|
||||||
|
inv:set_stack("main", i, stack)
|
||||||
|
items_remaining = 0
|
||||||
|
|
||||||
|
self.object:get_luaentity().itemstring = ""
|
||||||
|
self.object:remove()
|
||||||
|
|
||||||
|
taken_items = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
mcl_log("Count: " .. tostring(stack:get_count()))
|
||||||
|
mcl_log("stack max: " .. tostring(stack:get_stack_max()))
|
||||||
|
--mcl_log("Is it empty: " .. stack:to_string())
|
||||||
|
end
|
||||||
|
|
||||||
|
if i == ent._inv_size and taken_items then
|
||||||
|
mcl_log("We are on last item and still have items left. Set final stack size: " .. items_remaining)
|
||||||
|
current_itemstack:set_count(items_remaining)
|
||||||
|
--mcl_log("Itemstack2: " .. current_itemstack:to_string())
|
||||||
|
self.itemstring = current_itemstack:to_string()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--Add in, and delete
|
||||||
|
if taken_items then
|
||||||
|
mcl_log("Saving")
|
||||||
|
mcl_entity_invs.save_inv(ent)
|
||||||
|
return taken_items
|
||||||
|
else
|
||||||
|
mcl_log("No need to save")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
local function push_out_item_stuck_in_solid(self, dtime, p, def, is_in_water)
|
return false
|
||||||
if not is_in_water and def and def.walkable and def.groups and def.groups.opaque == 1 then
|
|
||||||
local shootdir
|
|
||||||
local cx = (p.x % 1) - 0.5
|
|
||||||
local cz = (p.z % 1) - 0.5
|
|
||||||
local order = {}
|
|
||||||
|
|
||||||
-- First prepare the order in which the 4 sides are to be checked.
|
|
||||||
-- 1st: closest
|
|
||||||
-- 2nd: other direction
|
|
||||||
-- 3rd and 4th: other axis
|
|
||||||
if math.abs(cx) < math.abs(cz) then
|
|
||||||
order = cxcz(order, cx, "x", "z")
|
|
||||||
order = cxcz(order, cz, "z", "x")
|
|
||||||
else
|
|
||||||
order = cxcz(order, cz, "z", "x")
|
|
||||||
order = cxcz(order, cx, "x", "z")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check which one of the 4 sides is free
|
|
||||||
for o = 1, #order do
|
|
||||||
local nn = minetest.get_node(vector.add(p, order[o])).name
|
|
||||||
local def = minetest.registered_nodes[nn]
|
|
||||||
if def and def.walkable == false and nn ~= "ignore" then
|
|
||||||
shootdir = order[o]
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- If none of the 4 sides is free, shoot upwards
|
|
||||||
if shootdir == nil then
|
|
||||||
shootdir = vector.new(0, 1, 0)
|
|
||||||
local nn = minetest.get_node(vector.add(p, shootdir)).name
|
|
||||||
if nn == "ignore" then
|
|
||||||
-- Do not push into ignore
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Set new item moving speed accordingly
|
|
||||||
local newv = vector.multiply(shootdir, 3)
|
|
||||||
self.object:set_acceleration(vector.zero())
|
|
||||||
self.object:set_velocity(newv)
|
|
||||||
disable_physics(self.object, self, false, false)
|
|
||||||
|
|
||||||
|
|
||||||
if shootdir.y == 0 then
|
|
||||||
self._force = newv
|
|
||||||
p.x = math.floor(p.x)
|
|
||||||
p.y = math.floor(p.y)
|
|
||||||
p.z = math.floor(p.z)
|
|
||||||
self._forcestart = p
|
|
||||||
self._forcetimer = 1
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- This code is run after the entity got a push from above “push away” code.
|
|
||||||
-- It is responsible for making sure the entity is entirely outside the solid node
|
|
||||||
-- (with its full collision box), not just its center.
|
|
||||||
if self._forcetimer > 0 then
|
|
||||||
local cbox = self.object:get_properties().collisionbox
|
|
||||||
local ok = false
|
|
||||||
if self._force.x > 0 and (p.x > (self._forcestart.x + 0.5 + (cbox[4] - cbox[1]) / 2)) then ok = true
|
|
||||||
elseif self._force.x < 0 and (p.x < (self._forcestart.x + 0.5 - (cbox[4] - cbox[1]) / 2)) then ok = true
|
|
||||||
elseif self._force.z > 0 and (p.z > (self._forcestart.z + 0.5 + (cbox[6] - cbox[3]) / 2)) then ok = true
|
|
||||||
elseif self._force.z < 0 and (p.z < (self._forcestart.z + 0.5 - (cbox[6] - cbox[3]) / 2)) then ok = true end
|
|
||||||
-- Item was successfully forced out. No more pushing
|
|
||||||
if ok then
|
|
||||||
self._forcetimer = -1
|
|
||||||
self._force = nil
|
|
||||||
enable_physics(self.object, self)
|
|
||||||
else
|
|
||||||
self._forcetimer = self._forcetimer - dtime
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
elseif self._force then
|
|
||||||
self._force = nil
|
|
||||||
enable_physics(self.object, self)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function move_items_in_water (self, p, def, node, is_floating, is_in_water)
|
|
||||||
-- Move item around on flowing liquids; add 'source' check to allow items to continue flowing a bit in the source block of flowing water.
|
|
||||||
if def and not is_floating and (def.liquidtype == "flowing" or def.liquidtype == "source") then
|
|
||||||
self._flowing = true
|
|
||||||
|
|
||||||
--[[ Get flowing direction (function call from flowlib), if there's a liquid.
|
|
||||||
NOTE: According to Qwertymine, flowlib.quickflow is only reliable for liquids with a flowing distance of 7.
|
|
||||||
Luckily, this is exactly what we need if we only care about water, which has this flowing distance. ]]
|
|
||||||
local vec = flowlib.quick_flow(p, node)
|
|
||||||
-- Just to make sure we don't manipulate the speed for no reason
|
|
||||||
if vec.x ~= 0 or vec.y ~= 0 or vec.z ~= 0 then
|
|
||||||
-- Minecraft Wiki: Flowing speed is "about 1.39 meters per second"
|
|
||||||
local f = 1.2
|
|
||||||
-- Set new item moving speed into the direciton of the liquid
|
|
||||||
local newv = vector.multiply(vec, f)
|
|
||||||
-- Swap to acceleration instead of a static speed to better mimic MC mechanics.
|
|
||||||
self.object:set_acceleration(vector.new(newv.x, -0.22, newv.z))
|
|
||||||
|
|
||||||
self.physical_state = true
|
|
||||||
self._flowing = true
|
|
||||||
self.object:set_properties({
|
|
||||||
physical = true
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
if is_in_water and def.liquidtype == "source" then
|
|
||||||
local cur_vec = self.object:get_velocity()
|
|
||||||
-- apply some acceleration in the opposite direction so it doesn't slide forever
|
|
||||||
local vec = {
|
|
||||||
x = 0 - cur_vec.x * 0.9,
|
|
||||||
y = 3 - cur_vec.y * 0.9,
|
|
||||||
z = 0 - cur_vec.z * 0.9
|
|
||||||
}
|
|
||||||
self.object:set_acceleration(vec)
|
|
||||||
-- slow down the item in water
|
|
||||||
local vel = self.object:get_velocity()
|
|
||||||
if vel.y < 0 then
|
|
||||||
vel.y = vel.y * 0.9
|
|
||||||
end
|
|
||||||
self.object:set_velocity(vel)
|
|
||||||
if self.physical_state ~= false or self._flowing ~= true then
|
|
||||||
self.physical_state = true
|
|
||||||
self._flowing = true
|
|
||||||
self.object:set_properties({
|
|
||||||
physical = true
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif self._flowing == true and not is_in_water and not is_floating then
|
|
||||||
-- Disable flowing physics if not on/in flowing liquid
|
|
||||||
self._flowing = false
|
|
||||||
enable_physics(self.object, self, true)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_entity(":__builtin:item", {
|
minetest.register_entity(":__builtin:item", {
|
||||||
|
@ -580,13 +500,13 @@ minetest.register_entity(":__builtin:item", {
|
||||||
hp_max = 1,
|
hp_max = 1,
|
||||||
physical = true,
|
physical = true,
|
||||||
collide_with_objects = false,
|
collide_with_objects = false,
|
||||||
collisionbox = { -0.3, -0.3, -0.3, 0.3, 0.3, 0.3 },
|
collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
|
||||||
pointable = false,
|
pointable = false,
|
||||||
visual = "wielditem",
|
visual = "wielditem",
|
||||||
visual_size = { x = 0.4, y = 0.4 },
|
visual_size = {x = 0.4, y = 0.4},
|
||||||
textures = { "" },
|
textures = {""},
|
||||||
spritediv = { x = 1, y = 1 },
|
spritediv = {x = 1, y = 1},
|
||||||
initial_sprite_basepos = { x = 0, y = 0 },
|
initial_sprite_basepos = {x = 0, y = 0},
|
||||||
is_visible = false,
|
is_visible = false,
|
||||||
infotext = "",
|
infotext = "",
|
||||||
},
|
},
|
||||||
|
@ -621,18 +541,14 @@ minetest.register_entity(":__builtin:item", {
|
||||||
if speed ~= nil then self.random_velocity = speed end
|
if speed ~= nil then self.random_velocity = speed end
|
||||||
|
|
||||||
local vel = self.object:get_velocity()
|
local vel = self.object:get_velocity()
|
||||||
|
|
||||||
-- There is perhaps a cleverer way of making this physical so it bounces off the wall like swords.
|
|
||||||
local max_vel = 6.5 -- Faster than this and it throws it into the wall / floor and turns black because of clipping.
|
|
||||||
|
|
||||||
if vel and vel.x == 0 and vel.z == 0 and self.random_velocity > 0 then
|
if vel and vel.x == 0 and vel.z == 0 and self.random_velocity > 0 then
|
||||||
local v = self.random_velocity
|
local v = self.random_velocity
|
||||||
local x = math.random(5, max_vel) / 10 * v
|
local x = math.random(5, 10) / 10 * v
|
||||||
if math.random(0, 10) < 5 then x = -x end
|
if math.random(0,10) < 5 then x = -x end
|
||||||
local z = math.random(5, max_vel) / 10 * v
|
local z = math.random(5, 10) / 10 * v
|
||||||
if math.random(0, 10) < 5 then z = -z end
|
if math.random(0,10) < 5 then z = -z end
|
||||||
local y = math.random(1, 2)
|
local y = math.random(2,4)
|
||||||
self.object:set_velocity(vector.new(x, y, z))
|
self.object:set_velocity({x=x, y=y, z=z})
|
||||||
end
|
end
|
||||||
self.random_velocity = 0
|
self.random_velocity = 0
|
||||||
end,
|
end,
|
||||||
|
@ -660,7 +576,7 @@ minetest.register_entity(":__builtin:item", {
|
||||||
local max_count = stack:get_stack_max()
|
local max_count = stack:get_stack_max()
|
||||||
if count > max_count then
|
if count > max_count then
|
||||||
count = max_count
|
count = max_count
|
||||||
self.itemstring = stack:get_name() .. " " .. max_count
|
self.itemstring = stack:get_name().." "..max_count
|
||||||
end
|
end
|
||||||
local itemtable = stack:to_table()
|
local itemtable = stack:to_table()
|
||||||
local itemname = nil
|
local itemname = nil
|
||||||
|
@ -681,9 +597,9 @@ minetest.register_entity(":__builtin:item", {
|
||||||
local prop = {
|
local prop = {
|
||||||
is_visible = true,
|
is_visible = true,
|
||||||
visual = "wielditem",
|
visual = "wielditem",
|
||||||
textures = { itemname },
|
textures = {itemname},
|
||||||
visual_size = { x = s, y = s },
|
visual_size = {x = s, y = s},
|
||||||
collisionbox = { -c, -c, -c, c, c, c },
|
collisionbox = {-c, -c, -c, c, c, c},
|
||||||
automatic_rotate = math.pi * 0.5,
|
automatic_rotate = math.pi * 0.5,
|
||||||
infotext = description,
|
infotext = description,
|
||||||
glow = glow,
|
glow = glow,
|
||||||
|
@ -779,9 +695,9 @@ minetest.register_entity(":__builtin:item", {
|
||||||
self._forcestart = nil
|
self._forcestart = nil
|
||||||
self._forcetimer = 0
|
self._forcetimer = 0
|
||||||
|
|
||||||
self.object:set_armor_groups({ immortal = 1 })
|
self.object:set_armor_groups({immortal = 1})
|
||||||
-- self.object:set_velocity(vector.new(0, 2, 0))
|
-- self.object:set_velocity({x = 0, y = 2, z = 0})
|
||||||
self.object:set_acceleration(vector.new(0, -get_gravity(), 0))
|
self.object:set_acceleration({x = 0, y = -get_gravity(), z = 0})
|
||||||
self:set_item(self.itemstring)
|
self:set_item(self.itemstring)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
@ -794,9 +710,9 @@ minetest.register_entity(":__builtin:item", {
|
||||||
local stack = ItemStack(entity.itemstring)
|
local stack = ItemStack(entity.itemstring)
|
||||||
local name = stack:get_name()
|
local name = stack:get_name()
|
||||||
if own_stack:get_name() ~= name or
|
if own_stack:get_name() ~= name or
|
||||||
own_stack:get_meta() ~= stack:get_meta() or
|
own_stack:get_meta() ~= stack:get_meta() or
|
||||||
own_stack:get_wear() ~= stack:get_wear() or
|
own_stack:get_wear() ~= stack:get_wear() or
|
||||||
own_stack:get_free_space() == 0 then
|
own_stack:get_free_space() == 0 then
|
||||||
-- Can not merge different or full stack
|
-- Can not merge different or full stack
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
@ -808,19 +724,11 @@ minetest.register_entity(":__builtin:item", {
|
||||||
if total_count > max_count then
|
if total_count > max_count then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Merge the remote stack into this one
|
-- Merge the remote stack into this one
|
||||||
local self_pos = self.object:get_pos()
|
|
||||||
local pos = object:get_pos()
|
|
||||||
|
|
||||||
--local y = pos.y + ((total_count - count) / max_count) * 0.15
|
-- local pos = object:get_pos()
|
||||||
local x_diff = (self_pos.x - pos.x) / 2
|
-- pos.y = pos.y + ((total_count - count) / max_count) * 0.15
|
||||||
local z_diff = (self_pos.z - pos.z) / 2
|
-- self.object:move_to(pos)
|
||||||
|
|
||||||
local new_pos = vector.offset(pos, x_diff, 0, z_diff)
|
|
||||||
new_pos.y = math.max(self_pos.y, pos.y) + 0.1
|
|
||||||
|
|
||||||
self.object:move_to(new_pos)
|
|
||||||
|
|
||||||
self.age = 0 -- Handle as new entity
|
self.age = 0 -- Handle as new entity
|
||||||
own_stack:set_count(total_count)
|
own_stack:set_count(total_count)
|
||||||
|
@ -837,11 +745,10 @@ minetest.register_entity(":__builtin:item", {
|
||||||
self.object:set_properties({
|
self.object:set_properties({
|
||||||
physical = false
|
physical = false
|
||||||
})
|
})
|
||||||
self.object:set_velocity(vector.zero())
|
self.object:set_velocity({x=0,y=0,z=0})
|
||||||
self.object:set_acceleration(vector.zero())
|
self.object:set_acceleration({x=0,y=0,z=0})
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
self.age = self.age + dtime
|
self.age = self.age + dtime
|
||||||
if self._collector_timer then
|
if self._collector_timer then
|
||||||
self._collector_timer = self._collector_timer + dtime
|
self._collector_timer = self._collector_timer + dtime
|
||||||
|
@ -854,16 +761,21 @@ minetest.register_entity(":__builtin:item", {
|
||||||
-- Delete corrupted item entities. The itemstring MUST be non-empty on its first step,
|
-- Delete corrupted item entities. The itemstring MUST be non-empty on its first step,
|
||||||
-- otherwise there might have some data corruption.
|
-- otherwise there might have some data corruption.
|
||||||
if self.itemstring == "" then
|
if self.itemstring == "" then
|
||||||
minetest.log("warning",
|
minetest.log("warning", "Item entity with empty itemstring found at "..minetest.pos_to_string(self.object:get_pos()).. "! Deleting it now.")
|
||||||
"Item entity with empty itemstring found and being deleted at: " .. minetest.pos_to_string(self.object:get_pos()))
|
|
||||||
self._removed = true
|
self._removed = true
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local p = self.object:get_pos()
|
local p = self.object:get_pos()
|
||||||
local node = minetest.get_node(p)
|
|
||||||
local in_unloaded = node.name == "ignore"
|
-- If hopper has taken item, it has gone, and no operations should be conducted on this item
|
||||||
|
if hopper_take_item(self, p) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local node = minetest.get_node_or_nil(p)
|
||||||
|
local in_unloaded = (node == nil)
|
||||||
|
|
||||||
if in_unloaded then
|
if in_unloaded then
|
||||||
-- Don't infinetly fall into unloaded map
|
-- Don't infinetly fall into unloaded map
|
||||||
|
@ -871,32 +783,29 @@ minetest.register_entity(":__builtin:item", {
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if self.is_clock then
|
if self.is_clock then
|
||||||
self.object:set_properties({
|
self.object:set_properties({
|
||||||
textures = { "mcl_clock:clock_" .. (mcl_worlds.clock_works(p) and mcl_clock.old_time or mcl_clock.random_frame) }
|
textures = {"mcl_clock:clock_" .. (mcl_worlds.clock_works(p) and mcl_clock.old_time or mcl_clock.random_frame)}
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
local nn = node.name
|
local nn = node.name
|
||||||
local is_in_water = (minetest.get_item_group(nn, "liquid") ~= 0)
|
local is_in_water = (minetest.get_item_group(nn, "liquid") ~= 0)
|
||||||
local nn_above = minetest.get_node(vector.offset(p, 0, 0.1, 0)).name
|
local nn_above = minetest.get_node({x=p.x, y=p.y+0.1, z=p.z}).name
|
||||||
-- make sure it's more or less stationary and is at water level
|
-- make sure it's more or less stationary and is at water level
|
||||||
local sleep_threshold = 0.3
|
local sleep_threshold = 0.3
|
||||||
local is_floating = false
|
local is_floating = false
|
||||||
local is_stationary = math.abs(self.object:get_velocity().x) < sleep_threshold
|
local is_stationary = math.abs(self.object:get_velocity().x) < sleep_threshold
|
||||||
and math.abs(self.object:get_velocity().y) < sleep_threshold
|
and math.abs(self.object:get_velocity().y) < sleep_threshold
|
||||||
and math.abs(self.object:get_velocity().z) < sleep_threshold
|
and math.abs(self.object:get_velocity().z) < sleep_threshold
|
||||||
if is_in_water and is_stationary then
|
if is_in_water and is_stationary then
|
||||||
is_floating = (is_in_water
|
is_floating = (is_in_water
|
||||||
and (minetest.get_item_group(nn_above, "liquid") == 0))
|
and (minetest.get_item_group(nn_above, "liquid") == 0))
|
||||||
end
|
end
|
||||||
|
|
||||||
if is_floating and self.physical_state == true then
|
if is_floating and self.physical_state == true then
|
||||||
self.object:set_velocity(vector.zero())
|
self.object:set_velocity({x = 0, y = 0, z = 0})
|
||||||
self.object:set_acceleration(vector.zero())
|
self.object:set_acceleration({x = 0, y = 0, z = 0})
|
||||||
disable_physics(self.object, self)
|
disable_physics(self.object, self)
|
||||||
end
|
end
|
||||||
-- If no collector was found for a long enough time, declare the magnet as disabled
|
-- If no collector was found for a long enough time, declare the magnet as disabled
|
||||||
|
@ -909,27 +818,182 @@ minetest.register_entity(":__builtin:item", {
|
||||||
-- Destroy item in lava, fire or special nodes
|
-- Destroy item in lava, fire or special nodes
|
||||||
|
|
||||||
local def = minetest.registered_nodes[nn]
|
local def = minetest.registered_nodes[nn]
|
||||||
|
local lg = minetest.get_item_group(nn, "lava")
|
||||||
|
local fg = minetest.get_item_group(nn, "fire")
|
||||||
|
local dg = minetest.get_item_group(nn, "destroys_items")
|
||||||
|
if (def and (lg ~= 0 or fg ~= 0 or dg == 1)) then
|
||||||
|
--Wait 2 seconds to allow mob drops to be cooked, & picked up instead of instantly destroyed.
|
||||||
|
if self.age > 2 and minetest.get_item_group(self.itemstring, "fire_immune") == 0 then
|
||||||
|
if dg ~= 2 then
|
||||||
|
minetest.sound_play("builtin_item_lava", {pos = self.object:get_pos(), gain = 0.5})
|
||||||
|
end
|
||||||
|
self._removed = true
|
||||||
|
self.object:remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if nodes_destroy_items(self, moveresult, def, nn) then return end
|
-- Destroy item when it collides with a cactus
|
||||||
|
if moveresult and moveresult.collides then
|
||||||
|
for _, collision in pairs(moveresult.collisions) do
|
||||||
|
local pos = collision.node_pos
|
||||||
|
if collision.type == "node" and minetest.get_node(pos).name == "mcl_core:cactus" then
|
||||||
|
self._removed = true
|
||||||
|
self.object:remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if push_out_item_stuck_in_solid(self, dtime, p, def, is_in_water) then return end
|
-- Push item out when stuck inside solid opaque node
|
||||||
|
if not is_in_water and def and def.walkable and def.groups and def.groups.opaque == 1 then
|
||||||
|
local shootdir
|
||||||
|
local cx = (p.x % 1) - 0.5
|
||||||
|
local cz = (p.z % 1) - 0.5
|
||||||
|
local order = {}
|
||||||
|
|
||||||
if move_items_in_water (self, p, def, node, is_floating, is_in_water) then return end
|
-- First prepare the order in which the 4 sides are to be checked.
|
||||||
|
-- 1st: closest
|
||||||
|
-- 2nd: other direction
|
||||||
|
-- 3rd and 4th: other axis
|
||||||
|
if math.abs(cx) < math.abs(cz) then
|
||||||
|
order = cxcz(order, cx, "x", "z")
|
||||||
|
order = cxcz(order, cz, "z", "x")
|
||||||
|
else
|
||||||
|
order = cxcz(order, cz, "z", "x")
|
||||||
|
order = cxcz(order, cx, "x", "z")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check which one of the 4 sides is free
|
||||||
|
for o=1, #order do
|
||||||
|
local nn = minetest.get_node(vector.add(p, order[o])).name
|
||||||
|
local def = minetest.registered_nodes[nn]
|
||||||
|
if def and def.walkable == false and nn ~= "ignore" then
|
||||||
|
shootdir = order[o]
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- If none of the 4 sides is free, shoot upwards
|
||||||
|
if shootdir == nil then
|
||||||
|
shootdir = { x=0, y=1, z=0 }
|
||||||
|
local nn = minetest.get_node(vector.add(p, shootdir)).name
|
||||||
|
if nn == "ignore" then
|
||||||
|
-- Do not push into ignore
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set new item moving speed accordingly
|
||||||
|
local newv = vector.multiply(shootdir, 3)
|
||||||
|
self.object:set_acceleration({x = 0, y = 0, z = 0})
|
||||||
|
self.object:set_velocity(newv)
|
||||||
|
disable_physics(self.object, self, false, false)
|
||||||
|
|
||||||
|
|
||||||
|
if shootdir.y == 0 then
|
||||||
|
self._force = newv
|
||||||
|
p.x = math.floor(p.x)
|
||||||
|
p.y = math.floor(p.y)
|
||||||
|
p.z = math.floor(p.z)
|
||||||
|
self._forcestart = p
|
||||||
|
self._forcetimer = 1
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- This code is run after the entity got a push from above “push away” code.
|
||||||
|
-- It is responsible for making sure the entity is entirely outside the solid node
|
||||||
|
-- (with its full collision box), not just its center.
|
||||||
|
if self._forcetimer > 0 then
|
||||||
|
local cbox = self.object:get_properties().collisionbox
|
||||||
|
local ok = false
|
||||||
|
if self._force.x > 0 and (p.x > (self._forcestart.x + 0.5 + (cbox[4] - cbox[1])/2)) then ok = true
|
||||||
|
elseif self._force.x < 0 and (p.x < (self._forcestart.x + 0.5 - (cbox[4] - cbox[1])/2)) then ok = true
|
||||||
|
elseif self._force.z > 0 and (p.z > (self._forcestart.z + 0.5 + (cbox[6] - cbox[3])/2)) then ok = true
|
||||||
|
elseif self._force.z < 0 and (p.z < (self._forcestart.z + 0.5 - (cbox[6] - cbox[3])/2)) then ok = true end
|
||||||
|
-- Item was successfully forced out. No more pushing
|
||||||
|
if ok then
|
||||||
|
self._forcetimer = -1
|
||||||
|
self._force = nil
|
||||||
|
enable_physics(self.object, self)
|
||||||
|
else
|
||||||
|
self._forcetimer = self._forcetimer - dtime
|
||||||
|
end
|
||||||
|
return
|
||||||
|
elseif self._force then
|
||||||
|
self._force = nil
|
||||||
|
enable_physics(self.object, self)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Move item around on flowing liquids; add 'source' check to allow items to continue flowing a bit in the source block of flowing water.
|
||||||
|
if def and not is_floating and (def.liquidtype == "flowing" or def.liquidtype == "source") then
|
||||||
|
self._flowing = true
|
||||||
|
|
||||||
|
--[[ Get flowing direction (function call from flowlib), if there's a liquid.
|
||||||
|
NOTE: According to Qwertymine, flowlib.quickflow is only reliable for liquids with a flowing distance of 7.
|
||||||
|
Luckily, this is exactly what we need if we only care about water, which has this flowing distance. ]]
|
||||||
|
local vec = flowlib.quick_flow(p, node)
|
||||||
|
-- Just to make sure we don't manipulate the speed for no reason
|
||||||
|
if vec.x ~= 0 or vec.y ~= 0 or vec.z ~= 0 then
|
||||||
|
-- Minecraft Wiki: Flowing speed is "about 1.39 meters per second"
|
||||||
|
local f = 1.2
|
||||||
|
-- Set new item moving speed into the direciton of the liquid
|
||||||
|
local newv = vector.multiply(vec, f)
|
||||||
|
-- Swap to acceleration instead of a static speed to better mimic MC mechanics.
|
||||||
|
self.object:set_acceleration({x = newv.x, y = -0.22, z = newv.z})
|
||||||
|
|
||||||
|
self.physical_state = true
|
||||||
|
self._flowing = true
|
||||||
|
self.object:set_properties({
|
||||||
|
physical = true
|
||||||
|
})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if is_in_water and def.liquidtype == "source" then
|
||||||
|
local cur_vec = self.object:get_velocity()
|
||||||
|
-- apply some acceleration in the opposite direction so it doesn't slide forever
|
||||||
|
local vec = {
|
||||||
|
x = 0 -cur_vec.x*0.9,
|
||||||
|
y = 3 -cur_vec.y*0.9,
|
||||||
|
z = 0 -cur_vec.z*0.9}
|
||||||
|
self.object:set_acceleration(vec)
|
||||||
|
-- slow down the item in water
|
||||||
|
local vel = self.object:get_velocity()
|
||||||
|
if vel.y < 0 then
|
||||||
|
vel.y = vel.y * 0.9
|
||||||
|
end
|
||||||
|
self.object:set_velocity(vel)
|
||||||
|
if self.physical_state ~= false or self._flowing ~= true then
|
||||||
|
self.physical_state = true
|
||||||
|
self._flowing = true
|
||||||
|
self.object:set_properties({
|
||||||
|
physical = true
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif self._flowing == true and not is_in_water and not is_floating then
|
||||||
|
-- Disable flowing physics if not on/in flowing liquid
|
||||||
|
self._flowing = false
|
||||||
|
enable_physics(self.object, self, true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- If node is not registered or node is walkably solid and resting on nodebox
|
-- If node is not registered or node is walkably solid and resting on nodebox
|
||||||
local nn = minetest.get_node(vector.offset(p, 0, -0.5, 0)).name
|
local nn = minetest.get_node({x=p.x, y=p.y-0.5, z=p.z}).name
|
||||||
local def = minetest.registered_nodes[nn]
|
local def = minetest.registered_nodes[nn]
|
||||||
local v = self.object:get_velocity()
|
local v = self.object:get_velocity()
|
||||||
local is_on_floor = def and (def.walkable
|
local is_on_floor = def and (def.walkable
|
||||||
and not def.groups.slippery and v.y == 0)
|
and not def.groups.slippery and v.y == 0)
|
||||||
|
|
||||||
if not minetest.registered_nodes[nn] or is_floating or is_on_floor then
|
if not minetest.registered_nodes[nn]
|
||||||
|
or is_floating or is_on_floor then
|
||||||
local own_stack = ItemStack(self.object:get_luaentity().itemstring)
|
local own_stack = ItemStack(self.object:get_luaentity().itemstring)
|
||||||
-- Merge with close entities of the same item
|
-- Merge with close entities of the same item
|
||||||
for _, object in pairs(minetest.get_objects_inside_radius(p, 0.8)) do
|
for _, object in pairs(minetest.get_objects_inside_radius(p, 0.8)) do
|
||||||
local obj = object:get_luaentity()
|
local obj = object:get_luaentity()
|
||||||
if obj and obj.name == "__builtin:item" and obj.physical_state == false then
|
if obj and obj.name == "__builtin:item"
|
||||||
|
and obj.physical_state == false then
|
||||||
if self:try_merge_with(own_stack, object, obj) then
|
if self:try_merge_with(own_stack, object, obj) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,14 +11,6 @@ mcl_minecarts.check_float_time = 15
|
||||||
dofile(mcl_minecarts.modpath.."/functions.lua")
|
dofile(mcl_minecarts.modpath.."/functions.lua")
|
||||||
dofile(mcl_minecarts.modpath.."/rails.lua")
|
dofile(mcl_minecarts.modpath.."/rails.lua")
|
||||||
|
|
||||||
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_minecarts", false)
|
|
||||||
local function mcl_log(message)
|
|
||||||
if LOGGING_ON then
|
|
||||||
mcl_util.mcl_log(message, "[Minecarts]", true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function detach_driver(self)
|
local function detach_driver(self)
|
||||||
if not self._driver then
|
if not self._driver then
|
||||||
return
|
return
|
||||||
|
@ -59,126 +51,6 @@ end
|
||||||
|
|
||||||
local activate_normal_minecart = detach_driver
|
local activate_normal_minecart = detach_driver
|
||||||
|
|
||||||
local function hopper_take_item(self, dtime)
|
|
||||||
local pos = self.object:get_pos()
|
|
||||||
if not pos then return end
|
|
||||||
|
|
||||||
if not self or self.name ~= "mcl_minecarts:hopper_minecart" then return end
|
|
||||||
|
|
||||||
if mcl_util.check_dtime_timer(self, dtime, "hoppermc_take", 0.15) then
|
|
||||||
--minetest.log("The check timer was triggered: " .. dump(pos) .. ", name:" .. self.name)
|
|
||||||
else
|
|
||||||
--minetest.log("The check timer was not triggered")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
--mcl_log("self.itemstring: ".. self.itemstring)
|
|
||||||
|
|
||||||
local above_pos = vector.offset(pos, 0, 0.9, 0)
|
|
||||||
--mcl_log("self.itemstring: ".. minetest.pos_to_string(above_pos))
|
|
||||||
local objs = minetest.get_objects_inside_radius(above_pos, 1.25)
|
|
||||||
|
|
||||||
if objs then
|
|
||||||
|
|
||||||
mcl_log("there is an itemstring. Number of objs: ".. #objs)
|
|
||||||
|
|
||||||
for k, v in pairs(objs) do
|
|
||||||
local ent = v:get_luaentity()
|
|
||||||
|
|
||||||
if ent and not ent._removed and ent.itemstring and ent.itemstring ~= "" then
|
|
||||||
local taken_items = false
|
|
||||||
|
|
||||||
mcl_log("ent.name: " .. tostring(ent.name))
|
|
||||||
mcl_log("ent pos: " .. tostring(ent.object:get_pos()))
|
|
||||||
|
|
||||||
local inv = mcl_entity_invs.load_inv(self, 5)
|
|
||||||
if not inv then return false end
|
|
||||||
|
|
||||||
local current_itemstack = ItemStack(ent.itemstring)
|
|
||||||
|
|
||||||
mcl_log("inv. size: " .. self._inv_size)
|
|
||||||
if inv:room_for_item("main", current_itemstack) then
|
|
||||||
mcl_log("Room")
|
|
||||||
inv:add_item("main", current_itemstack)
|
|
||||||
ent.object:get_luaentity().itemstring = ""
|
|
||||||
ent.object:remove()
|
|
||||||
taken_items = true
|
|
||||||
else
|
|
||||||
mcl_log("no Room")
|
|
||||||
end
|
|
||||||
|
|
||||||
if not taken_items then
|
|
||||||
local items_remaining = current_itemstack:get_count()
|
|
||||||
|
|
||||||
-- This will take part of a floating item stack if no slot can hold the full amount
|
|
||||||
for i = 1, self._inv_size, 1 do
|
|
||||||
local stack = inv:get_stack("main", i)
|
|
||||||
|
|
||||||
mcl_log("i: " .. tostring(i))
|
|
||||||
mcl_log("Items remaining: " .. items_remaining)
|
|
||||||
mcl_log("Name: " .. tostring(stack:get_name()))
|
|
||||||
|
|
||||||
if current_itemstack:get_name() == stack:get_name() then
|
|
||||||
mcl_log("We have a match. Name: " .. tostring(stack:get_name()))
|
|
||||||
|
|
||||||
local room_for = stack:get_stack_max() - stack:get_count()
|
|
||||||
mcl_log("Room for: " .. tostring(room_for))
|
|
||||||
|
|
||||||
if room_for == 0 then
|
|
||||||
-- Do nothing
|
|
||||||
mcl_log("No room")
|
|
||||||
elseif room_for < items_remaining then
|
|
||||||
mcl_log("We have more items remaining than space")
|
|
||||||
|
|
||||||
items_remaining = items_remaining - room_for
|
|
||||||
stack:set_count(stack:get_stack_max())
|
|
||||||
inv:set_stack("main", i, stack)
|
|
||||||
taken_items = true
|
|
||||||
else
|
|
||||||
local new_stack_size = stack:get_count() + items_remaining
|
|
||||||
stack:set_count(new_stack_size)
|
|
||||||
mcl_log("We have more than enough space. Now holds: " .. new_stack_size)
|
|
||||||
|
|
||||||
inv:set_stack("main", i, stack)
|
|
||||||
items_remaining = 0
|
|
||||||
|
|
||||||
ent.object:get_luaentity().itemstring = ""
|
|
||||||
ent.object:remove()
|
|
||||||
|
|
||||||
taken_items = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
mcl_log("Count: " .. tostring(stack:get_count()))
|
|
||||||
mcl_log("stack max: " .. tostring(stack:get_stack_max()))
|
|
||||||
--mcl_log("Is it empty: " .. stack:to_string())
|
|
||||||
end
|
|
||||||
|
|
||||||
if i == self._inv_size and taken_items then
|
|
||||||
mcl_log("We are on last item and still have items left. Set final stack size: " .. items_remaining)
|
|
||||||
current_itemstack:set_count(items_remaining)
|
|
||||||
--mcl_log("Itemstack2: " .. current_itemstack:to_string())
|
|
||||||
ent.itemstring = current_itemstack:to_string()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--Add in, and delete
|
|
||||||
if taken_items then
|
|
||||||
mcl_log("Saving")
|
|
||||||
mcl_entity_invs.save_inv(ent)
|
|
||||||
return taken_items
|
|
||||||
else
|
|
||||||
mcl_log("No need to save")
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Table for item-to-entity mapping. Keys: itemstring, Values: Corresponding entity ID
|
-- Table for item-to-entity mapping. Keys: itemstring, Values: Corresponding entity ID
|
||||||
local entity_mapping = {}
|
local entity_mapping = {}
|
||||||
|
|
||||||
|
@ -194,7 +66,6 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
||||||
on_rightclick = on_rightclick,
|
on_rightclick = on_rightclick,
|
||||||
|
|
||||||
_driver = nil, -- player who sits in and controls the minecart (only for minecart!)
|
_driver = nil, -- player who sits in and controls the minecart (only for minecart!)
|
||||||
_passenger = nil, -- for mobs
|
|
||||||
_punched = false, -- used to re-send _velocity and position
|
_punched = false, -- used to re-send _velocity and position
|
||||||
_velocity = {x=0, y=0, z=0}, -- only used on punch
|
_velocity = {x=0, y=0, z=0}, -- only used on punch
|
||||||
_start_pos = nil, -- Used to calculate distance for “On A Rail” achievement
|
_start_pos = nil, -- Used to calculate distance for “On A Rail” achievement
|
||||||
|
@ -215,7 +86,6 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
||||||
local data = minetest.deserialize(staticdata)
|
local data = minetest.deserialize(staticdata)
|
||||||
if type(data) == "table" then
|
if type(data) == "table" then
|
||||||
self._railtype = data._railtype
|
self._railtype = data._railtype
|
||||||
self._passenger = data._passenger
|
|
||||||
end
|
end
|
||||||
self.object:set_armor_groups({immortal=1})
|
self.object:set_armor_groups({immortal=1})
|
||||||
|
|
||||||
|
@ -307,11 +177,7 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
||||||
|
|
||||||
cart.on_activate_by_rail = on_activate_by_rail
|
cart.on_activate_by_rail = on_activate_by_rail
|
||||||
|
|
||||||
local passenger_attach_position = vector.new(0, -1.75, 0)
|
|
||||||
|
|
||||||
function cart:on_step(dtime)
|
function cart:on_step(dtime)
|
||||||
hopper_take_item(self, dtime)
|
|
||||||
|
|
||||||
local ctrl, player = nil, nil
|
local ctrl, player = nil, nil
|
||||||
if self._driver then
|
if self._driver then
|
||||||
player = minetest.get_player_by_name(self._driver)
|
player = minetest.get_player_by_name(self._driver)
|
||||||
|
@ -346,29 +212,6 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Grab mob
|
|
||||||
if math.random(1,20) > 15 and not self._passenger then
|
|
||||||
if self.name == "mcl_minecarts:minecart" then
|
|
||||||
local mobsnear = minetest.get_objects_inside_radius(self.object:get_pos(), 1.3)
|
|
||||||
for n=1, #mobsnear do
|
|
||||||
local mob = mobsnear[n]
|
|
||||||
if mob then
|
|
||||||
local entity = mob:get_luaentity()
|
|
||||||
if entity and entity.is_mob then
|
|
||||||
self._passenger = entity
|
|
||||||
mob:set_attach(self.object, "", passenger_attach_position, vector.zero())
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif self._passenger then
|
|
||||||
local passenger_pos = self._passenger.object:get_pos()
|
|
||||||
if not passenger_pos then
|
|
||||||
self._passenger = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Drop minecart if it isn't on a rail anymore
|
-- Drop minecart if it isn't on a rail anymore
|
||||||
if self._last_float_check >= mcl_minecarts.check_float_time then
|
if self._last_float_check >= mcl_minecarts.check_float_time then
|
||||||
pos = self.object:get_pos()
|
pos = self.object:get_pos()
|
||||||
|
@ -393,8 +236,19 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Do not drop minecart. It goes off the rails too frequently, and anyone using them for farms won't
|
-- Drop items and remove cart entity
|
||||||
-- notice and lose their iron and not bother. Not cool until fixed.
|
local pname = ""
|
||||||
|
if player then
|
||||||
|
pname = player:get_player_name()
|
||||||
|
end
|
||||||
|
if not minetest.is_creative_enabled(pname) then
|
||||||
|
for d=1, #drop do
|
||||||
|
minetest.add_item(self.object:get_pos(), drop[d])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.object:remove()
|
||||||
|
return
|
||||||
end
|
end
|
||||||
self._last_float_check = 0
|
self._last_float_check = 0
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
# textdomain: mcl_minecarts
|
|
||||||
Minecart=Minevogn
|
|
||||||
Minecarts can be used for a quick transportion on rails.=Minevogne kan bruges til hurtig transport på spor.
|
|
||||||
Minecarts only ride on rails and always follow the tracks. At a T-junction with no straight way ahead, they turn left. The speed is affected by the rail type.=Minevogne kan kun køre på spor, og følger dem altid. Ved et T-kryds uden en vej ligeud drejer de altid til venstre. Farten påvirkes af sportypen.
|
|
||||||
You can place the minecart on rails. Right-click it to enter it. Punch it to get it moving.=Du kan placere minevogne på spor. Højre-klik for at stige ombord.
|
|
||||||
To obtain the minecart, punch it while holding down the sneak key.=For at at få minevognen i din oppakning.
|
|
||||||
A minecart with TNT is an explosive vehicle that travels on rail.=En minevogn med TNT as et eksplosivt fartøj som kører på spor.
|
|
||||||
Place it on rails. Punch it to move it. The TNT is ignited with a flint and steel or when the minecart is on an powered activator rail.=Placér den på spor. Slå den for at flytte den. TNTet bliver antændt med flint og stål eller når minevognen er på et aktiveringsspor.
|
|
||||||
To obtain the minecart and TNT, punch them while holding down the sneak key. You can't do this if the TNT was ignited.=For at få minevognen med TNT i din oppakning skal du slå den mens du holder snigeknappen nede. Du kan ikke gøre dette hvis TNTen er antændt.
|
|
||||||
A minecart with furnace is a vehicle that travels on rails. It can propel itself with fuel.=En minevogn med ovn er et fartøj som kører på spor. Den kan køre af sig selv med brændstof.
|
|
||||||
Place it on rails. If you give it some coal, the furnace will start burning for a long time and the minecart will be able to move itself. Punch it to get it moving.=Placér den på spor. Hvis du putter kul i den vil ovnen brænde i lang tid, og minevognen vil køre af sig selv. Slå den for at sætte den i bevægelse.
|
|
||||||
To obtain the minecart and furnace, punch them while holding down the sneak key.=For at få minevognen med ovn i din oppakning skal du slå den mens du holder snigeknappen nede.
|
|
||||||
Minecart with Chest=Minevogn med kiste
|
|
||||||
Minecart with Furnace=Minevogn med ovn
|
|
||||||
Minecart with Command Block=Minevogn med kommandoblok
|
|
||||||
Minecart with Hopper=Minevogn med tragt
|
|
||||||
Minecart with TNT=Minevogn med TNT
|
|
||||||
Place them on the ground to build your railway, the rails will automatically connect to each other and will turn into curves, T-junctions, crossings and slopes as needed.=Placér dem på jorden for at bygge din jerbane. Sporene kobler sig automatisk sammen med hinanden og laver sving, T-kryds, kryds og skråninger efter behov.
|
|
||||||
Rail=Spor
|
|
||||||
Rails can be used to build transport tracks for minecarts. Normal rails slightly slow down minecarts due to friction.=Spor kan bruges til at bygge jernbaner til minevogne. Normale spor sænker minevognene en smule på grund af friktionsmodstand.
|
|
||||||
Powered Rail=Strømspor
|
|
||||||
Rails can be used to build transport tracks for minecarts. Powered rails are able to accelerate and brake minecarts.=Spor kan bruges til at bygge jernbaner til minevogne. Strømspor kan accelerere eller bremse minevogne.
|
|
||||||
Without redstone power, the rail will brake minecarts. To make this rail accelerate minecarts, power it with redstone power.=Uden redstonekraft vil sporet bremse minevognen. For at accelerere minevognen skal den bruge redstoneskraft.
|
|
||||||
Activator Rail=Aktiveringsspor
|
|
||||||
Rails can be used to build transport tracks for minecarts. Activator rails are used to activate special minecarts.=Spor kan bruges til at bygge jernbaner til minevogne. Aktiveringsspor bruges til at aktivere specielle minevogne.
|
|
||||||
To make this rail activate minecarts, power it with redstone power and send a minecart over this piece of rail.=For at få dette spor til at aktiere minevogne skal du give det redstonekraft og sende en minevogn over dette sporstykke.
|
|
||||||
Detector Rail=Detektorspor
|
|
||||||
Rails can be used to build transport tracks for minecarts. A detector rail is able to detect a minecart above it and powers redstone mechanisms.=Spor kan bruges til at bygge jernbaner til minevogne. Et detektorspor kan opdage en minevogn som kører over det og give kraft til redstonemekanismer.
|
|
||||||
To detect a minecart and provide redstone power, connect it to redstone trails or redstone mechanisms and send any minecart over the rail.=For at opdage en minevogn og give redstonekraft skal den forbindes til redstonestøv eller redstonemekanismer og send en hvilkensomhelst minevogn hen over sporet.
|
|
||||||
Track for minecarts=Spor til minevogne.
|
|
||||||
Speed up when powered, slow down when not powered=Accelerérer når der er strøm, sænk hastigheden når der ikke er strøm.
|
|
||||||
Activates minecarts when powered=Aktieverer minevogne når der er strøm.
|
|
||||||
Emits redstone power when a minecart is detected=Udsender redstonekraft når en minevogn bliver opdaget.
|
|
||||||
Vehicle for fast travel on rails=Fartøj til hurtig kørsel på spor.
|
|
||||||
Can be ignited by tools or powered activator rail=Kan antændes med værktøj eller et aktivatorspor med strøm.
|
|
||||||
Sneak to dismount=Snig for at stige af.
|
|
|
@ -10,15 +10,15 @@ To obtain the minecart and TNT, punch them while holding down the sneak key. You
|
||||||
A minecart with furnace is a vehicle that travels on rails. It can propel itself with fuel.=Une wagonnet avec un four est un véhicule qui se déplace sur rails. Il peut se propulser avec du carburant.
|
A minecart with furnace is a vehicle that travels on rails. It can propel itself with fuel.=Une wagonnet avec un four est un véhicule qui se déplace sur rails. Il peut se propulser avec du carburant.
|
||||||
Place it on rails. If you give it some coal, the furnace will start burning for a long time and the minecart will be able to move itself. Punch it to get it moving.=Placez-le sur des rails. Si vous lui donnez du charbon, le four commencera à brûler pendant longtemps et le wagonnet pourra se déplacer. Frappez-le pour le faire bouger.
|
Place it on rails. If you give it some coal, the furnace will start burning for a long time and the minecart will be able to move itself. Punch it to get it moving.=Placez-le sur des rails. Si vous lui donnez du charbon, le four commencera à brûler pendant longtemps et le wagonnet pourra se déplacer. Frappez-le pour le faire bouger.
|
||||||
To obtain the minecart and furnace, punch them while holding down the sneak key.=Pour obtenir le wagonnet et le four, frappez-les tout en maintenant la touche furtive enfoncée.
|
To obtain the minecart and furnace, punch them while holding down the sneak key.=Pour obtenir le wagonnet et le four, frappez-les tout en maintenant la touche furtive enfoncée.
|
||||||
Minecart with Chest=Wagonnet avec coffre
|
Minecart with Chest=Wagonnet avec Coffre
|
||||||
Minecart with Furnace=Wagonnet avec four
|
Minecart with Furnace=Wagonnet avec Four
|
||||||
Minecart with Command Block=Wagonnet avec bloc de commande
|
Minecart with Command Block=Wagonnet avec Bloc de Commande
|
||||||
Minecart with Hopper=Wagonnet avec entonnoir
|
Minecart with Hopper=Wagonnet avec Entonoir
|
||||||
Minecart with TNT=Wagonnet avec TNT
|
Minecart with TNT=Wagonnet avec TNT
|
||||||
Place them on the ground to build your railway, the rails will automatically connect to each other and will turn into curves, T-junctions, crossings and slopes as needed.=Placez-les sur le sol pour construire votre chemin de fer, les rails se connecteront automatiquement les uns aux autres et se transformeront en courbes, en jonctions en T, en traversées et en pentes au besoin.
|
Place them on the ground to build your railway, the rails will automatically connect to each other and will turn into curves, T-junctions, crossings and slopes as needed.=Placez-les sur le sol pour construire votre chemin de fer, les rails se connecteront automatiquement les uns aux autres et se transformeront en courbes, en jonctions en T, en traversées et en pentes au besoin.
|
||||||
Rail=Rail
|
Rail=Rail
|
||||||
Rails can be used to build transport tracks for minecarts. Normal rails slightly slow down minecarts due to friction.=Les rails peuvent être utilisés pour construire des voies de transport pour les wagonnets. Les rails ralentissent légèrement les wagonnets en raison de la friction.
|
Rails can be used to build transport tracks for minecarts. Normal rails slightly slow down minecarts due to friction.=Les rails peuvent être utilisés pour construire des voies de transport pour les wagonnets. Les rails ralentissent légèrement les wagonnets en raison de la friction.
|
||||||
Powered Rail=Rail alimenté
|
Powered Rail=Rail allimenté
|
||||||
Rails can be used to build transport tracks for minecarts. Powered rails are able to accelerate and brake minecarts.=Les rails peuvent être utilisés pour construire des voies de transport pour les wagonnets. Les rails motorisés sont capables d'accélérer et de freiner les wagonnets.
|
Rails can be used to build transport tracks for minecarts. Powered rails are able to accelerate and brake minecarts.=Les rails peuvent être utilisés pour construire des voies de transport pour les wagonnets. Les rails motorisés sont capables d'accélérer et de freiner les wagonnets.
|
||||||
Without redstone power, the rail will brake minecarts. To make this rail accelerate minecarts, power it with redstone power.=Sans énergie de redstone, le rail freinera les wagonnets. Pour que ce rail accélère les minecarts, alimentez-le avec une source d'énergie redstone.
|
Without redstone power, the rail will brake minecarts. To make this rail accelerate minecarts, power it with redstone power.=Sans énergie de redstone, le rail freinera les wagonnets. Pour que ce rail accélère les minecarts, alimentez-le avec une source d'énergie redstone.
|
||||||
Activator Rail=Rail d'activation
|
Activator Rail=Rail d'activation
|
||||||
|
|
|
@ -1,36 +1,36 @@
|
||||||
# textdomain: mcl_minecarts
|
# textdomain: mcl_minecarts
|
||||||
Minecart=Вагонетка
|
Minecart=Вагонетка
|
||||||
Minecarts can be used for a quick transportion on rails.=Вагонетка может быть использована для быстрого перемещения по рельсам.
|
Minecarts can be used for a quick transportion on rails.=Вагонетки нужны, чтобы быстро перемещаться по рельсам.
|
||||||
Minecarts only ride on rails and always follow the tracks. At a T-junction with no straight way ahead, they turn left. The speed is affected by the rail type.=Вагонетки едут только по проложенным рельсам. На Т-образной развилке они поворачивают налево. Скорость зависит от типа рельсов.
|
Minecarts only ride on rails and always follow the tracks. At a T-junction with no straight way ahead, they turn left. The speed is affected by the rail type.=Вагонетки едут строго по проложенному железнодорожному пути. На Т-образной развилке они поворачивают налево. Скорость зависит от типа рельсов.
|
||||||
You can place the minecart on rails. Right-click it to enter it. Punch it to get it moving.=Вы можете поставить вагонетку на рельсы. Правым кликом сядьте в неё. Ударьте по ней, чтобы она поехала.
|
You can place the minecart on rails. Right-click it to enter it. Punch it to get it moving.=Вы ставите вагонетку на рельсы. Правым кликом садитесь в неё. Стукаете, чтобы начать движение.
|
||||||
To obtain the minecart, punch it while holding down the sneak key.=Чтобы забрать вагонетку, ударьте по ней, удерживая клавишу [Красться].
|
To obtain the minecart, punch it while holding down the sneak key.=Чтобы взять вагонетку, стукните её, удерживая клавишу [Красться].
|
||||||
A minecart with TNT is an explosive vehicle that travels on rail.=Вагонетка с ТНТ это взрывающийся железнодорожный транспорт.
|
A minecart with TNT is an explosive vehicle that travels on rail.=Вагон тротила это подрывной железнодорожный транспорт.
|
||||||
Place it on rails. Punch it to move it. The TNT is ignited with a flint and steel or when the minecart is on an powered activator rail.=Поместите вагонетку на рельсы. Ударьте по ней, чтобы она поехала. ТНТ активируется, если его поджечь огнивом или когда вагонетка проедет через подключенные активирующие рельсы.
|
Place it on rails. Punch it to move it. The TNT is ignited with a flint and steel or when the minecart is on an powered activator rail.=Поместите его на рельсы. Стукните, чтобы он поехал. Тротил воспламеняется, если его поджечь огнивом, либо при попадании на подключенный рельсовый активатор.
|
||||||
To obtain the minecart and TNT, punch them while holding down the sneak key. You can't do this if the TNT was ignited.=Чтобы забрать вагонетку с ТНТ, ударьте по ней, удерживая клавишу [Красться]. Если ТНТ подожжён, сделать это нельзя.
|
To obtain the minecart and TNT, punch them while holding down the sneak key. You can't do this if the TNT was ignited.=Чтобы взять вагон тротила, стукните его, удерживая клавишу [Красться]. Если тротил воспламенён, сделать это нельзя.
|
||||||
A minecart with furnace is a vehicle that travels on rails. It can propel itself with fuel.=Вагонетка с печью это железнодорожный транспорт. Она может ехать сама за счёт топлива.
|
A minecart with furnace is a vehicle that travels on rails. It can propel itself with fuel.=Вагон с печью - это железнодорожный транспорт. Он может двигаться за счёт топлива.
|
||||||
Place it on rails. If you give it some coal, the furnace will start burning for a long time and the minecart will be able to move itself. Punch it to get it moving.=Поставьте вагонетку на рельсы. Если добавить в неё угля, то печь будет гореть продолжительное время и вагонетка сможет поехать сама. Ударьте по ней, чтобы она поехала.
|
Place it on rails. If you give it some coal, the furnace will start burning for a long time and the minecart will be able to move itself. Punch it to get it moving.=Поставьте его на рельсы. Если добавить немного угля, то печь зажжётся на продолжительное время и вагон сможет ехать. Стукните вагон для начала движения.
|
||||||
To obtain the minecart and furnace, punch them while holding down the sneak key.=Чтобы забрать вагонетку с печью, ударьте по ней, удерживая клавишу [Красться].
|
To obtain the minecart and furnace, punch them while holding down the sneak key.=Чтобы взять вагон с печью, стукните его, удерживая клавишу [Красться].
|
||||||
Minecart with Chest=Вагонетка с сундуком
|
Minecart with Chest=Вагон с сундуком
|
||||||
Minecart with Furnace=Вагонетка с печью
|
Minecart with Furnace=Вагон с печью
|
||||||
Minecart with Command Block=Вагонетка с командным блоком
|
Minecart with Command Block=Вагон с командным блоком
|
||||||
Minecart with Hopper=Вагонетка с воронкой
|
Minecart with Hopper=Вагон с бункером
|
||||||
Minecart with TNT=Вагонетка с ТНТ
|
Minecart with TNT=Вагон тротила
|
||||||
Place them on the ground to build your railway, the rails will automatically connect to each other and will turn into curves, T-junctions, crossings and slopes as needed.=Поместите рельсы на землю, чтобы сделать железную дорогу, рельсы автоматически соединятся между собой и будут образовывать повороты, T-образные развилки, перекрёстки и склоны там, где это потребуется.
|
Place them on the ground to build your railway, the rails will automatically connect to each other and will turn into curves, T-junctions, crossings and slopes as needed.=Поместите на землю, чтобы сделать железную дорогу, рельсы автоматически соединятся между собой и будут превращаться в плавный повороты, T-образные развилки, перекрёстки и уклоны там, где это потребуется.
|
||||||
Rail=Рельсы
|
Rail=Рельсы
|
||||||
Rails can be used to build transport tracks for minecarts. Normal rails slightly slow down minecarts due to friction.=Рельсы используются для строительства железной дороги. Обычные рельсы немного замедляют движение вагонеток из-за трения.
|
Rails can be used to build transport tracks for minecarts. Normal rails slightly slow down minecarts due to friction.=Рельсы используются для строительства железной дороги. Обычные рельсы немного замедляют движение вагонеток из-за трения.
|
||||||
Powered Rail=Энергорельсы
|
Powered Rail=Подключаемые рельсы
|
||||||
Rails can be used to build transport tracks for minecarts. Powered rails are able to accelerate and brake minecarts.=Энергорельсы используются для строительства железной дороги. Энергорельсы могут ускорять и тормозить вагонетки.
|
Rails can be used to build transport tracks for minecarts. Powered rails are able to accelerate and brake minecarts.=Рельсы используются для строительства железной дороги. Подключённые рельсы могут разгонять и тормозить вагонетки.
|
||||||
Without redstone power, the rail will brake minecarts. To make this rail accelerate minecarts, power it with redstone power.=Неподключенные энергорельсы замедляют вагонетки. Чтобы энергорельсы ускоряли вагонетки, проведите к ним сигнал редстоуна.
|
Without redstone power, the rail will brake minecarts. To make this rail accelerate minecarts, power it with redstone power.=Без энергии редстоуна рельсы будут тормозить вагонетки.
|
||||||
Activator Rail=Активирующие рельсы
|
Activator Rail=Рельсовый активатор
|
||||||
Rails can be used to build transport tracks for minecarts. Activator rails are used to activate special minecarts.=Активирующие рельсы используются для строительства железной дороги. Активирующие рельсы активируют некоторые особые вагонетки.
|
Rails can be used to build transport tracks for minecarts. Activator rails are used to activate special minecarts.=Рельсы используются для строительства железной дороги. Рельсовый активатор активирует особые вагонетки.
|
||||||
To make this rail activate minecarts, power it with redstone power and send a minecart over this piece of rail.=Чтобы эти рельсы активировали вагонетки, подключите активирующие рельсы к сигналу редстоуна и направьте вагонетку через них.
|
To make this rail activate minecarts, power it with redstone power and send a minecart over this piece of rail.=Чтобы этот блок рельсов активировал вагонетку, подключите его к энергии редстоуна и направьте вагонетку через него.
|
||||||
Detector Rail=Нажимные рельсы
|
Detector Rail=Рельсовый детектор
|
||||||
Rails can be used to build transport tracks for minecarts. A detector rail is able to detect a minecart above it and powers redstone mechanisms.=Нажимные рельсы используются для строительства железной дороги. Нажимные рельсы реагируют на проезжающие по ним вагонетки и выдают сигнал для механизмов из редстоуна.
|
Rails can be used to build transport tracks for minecarts. A detector rail is able to detect a minecart above it and powers redstone mechanisms.=Рельсы используются для строительства железной дороги. Рельсовый детектор может обнаруживать вагонетку у себя наверху и подключать механизмы редстоуна.
|
||||||
To detect a minecart and provide redstone power, connect it to redstone trails or redstone mechanisms and send any minecart over the rail.=Подсоедините к нажимным рельсам редстоун или редстоуновые механизмы, чтобы активировать их когда по рельсам проезжает вагонетка.
|
To detect a minecart and provide redstone power, connect it to redstone trails or redstone mechanisms and send any minecart over the rail.=Чтобы обнаруживать вагонетку и подавать энергию редстоуна, подключите его к дорожке редстоуна или механизму редстоуна, после чего направьте любую вагонетку через него.
|
||||||
Track for minecarts=Железная дорога
|
Track for minecarts=Железная дорога
|
||||||
Speed up when powered, slow down when not powered=Если подключены - ускоряют, если нет - тормозят
|
Speed up when powered, slow down when not powered=Разгоняет, если подключён, тормозит, если не подключён
|
||||||
Activates minecarts when powered=Активирует особые вагонетки, если подключены
|
Activates minecarts when powered=Активирует особые вагонетки, если подключён
|
||||||
Emits redstone power when a minecart is detected=Подает сигнал редстоуна при обнаружении вагонетки
|
Emits redstone power when a minecart is detected=Испускает энергию редстоуна при обнаружении вагонетки
|
||||||
Vehicle for fast travel on rails=Железнодорожный транспорт
|
Vehicle for fast travel on rails=Быстрый железнодорожный транспорт
|
||||||
Can be ignited by tools or powered activator rail=Можно поджечь инструментом или активирующими рельсами
|
Can be ignited by tools or powered activator rail=Можно воспламенить с помощью инструмента или подключенного рельсового активатора
|
||||||
Sneak to dismount=Нажмите [Красться] для высадки
|
Sneak to dismount=Нажмите [Красться] для высадки
|
||||||
|
|