Compare commits
1 Commits
master
...
water_foot
Author | SHA1 | Date |
---|---|---|
iliekprogrammar | 6111f3465a |
|
@ -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
|
||||
*.blend3
|
||||
/.idea/
|
||||
*.xcf
|
||||
.Rproj.user
|
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`
|
||||
* Buckets: `ITEMS/mcl_buckets`
|
||||
* Dispenser support: `ITEMS/REDSTONE/mcl_dispensers`
|
||||
* Campfires: `ITEMS/mcl_campfires`
|
||||
|
||||
### Mobs
|
||||
* Mobs: `ENTITIES/mcl_mobs`
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
So you want to contribute to MineClone2?
|
||||
Wow, thank you! :-)
|
||||
|
||||
MineClone2 is maintained by AncientMariner and Nicu. If you have any
|
||||
problems or questions, contact us on Discord/Matrix (See Links section below).
|
||||
MineClone2 is maintained by Nicu and Cora. If you have any
|
||||
problems or questions, contact us (See Links section below).
|
||||
|
||||
You can help with MineClone2's development in many different ways,
|
||||
whether you're a programmer or not.
|
||||
|
@ -76,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
|
||||
are a server admin, you can find error messages in the log file of the
|
||||
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
|
||||
the bug, e.g. before the crash happened or what causes the faulty
|
||||
behavior.
|
||||
|
@ -240,7 +240,7 @@ work causes problems, we ask you fix the issues as soon as possible.
|
|||
|
||||
### Changing Gameplay
|
||||
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.
|
||||
You can use these sources:
|
||||
|
||||
|
@ -375,7 +375,7 @@ merged.
|
|||
- Resolving conflicts and problems within the community
|
||||
|
||||
#### Current maintainers
|
||||
* AncientMariner - responsible for gameplay review, publishing releases,
|
||||
* Cora - responsible for gameplay review, publishing releases,
|
||||
technical guidelines
|
||||
* Nicu - responsible for community related issues
|
||||
|
||||
|
|
26
CREDITS.md
|
@ -35,9 +35,7 @@
|
|||
* SumianVoice
|
||||
* MrRar
|
||||
* talamh
|
||||
* Faerraven / Michieal
|
||||
* FossFanatic
|
||||
* SmokeyDope
|
||||
* Faerraven
|
||||
|
||||
## Contributors
|
||||
* Laurent Rocher
|
||||
|
@ -82,12 +80,15 @@
|
|||
* aldum
|
||||
* Dieter44
|
||||
* Pepebotella
|
||||
* MrRar
|
||||
* Lazerbeak12345
|
||||
* mrminer
|
||||
* Thunder1035
|
||||
* opfromthestart
|
||||
* snowyu
|
||||
* FaceDeer
|
||||
* Faerraven / Michieal
|
||||
* FossFanatic
|
||||
* Herbert West
|
||||
* GuyLiner
|
||||
* 3raven
|
||||
|
@ -95,12 +96,6 @@
|
|||
* TheOnlyJoeEnderman
|
||||
* Ranko Saotome
|
||||
* Gregor Parzefall
|
||||
* Wbjitscool
|
||||
* b3nderman
|
||||
* CyberMango
|
||||
* gldrk
|
||||
* atomdmac
|
||||
* emptyshore
|
||||
|
||||
## MineClone5
|
||||
* kay27
|
||||
|
@ -152,13 +147,11 @@
|
|||
* jordan4ibanez
|
||||
* paramat
|
||||
* cora
|
||||
* Faerraven / Michieal
|
||||
|
||||
## 3D Models
|
||||
* 22i
|
||||
* tobyplowy
|
||||
* epCode
|
||||
* Faerraven / Michieal
|
||||
|
||||
## Textures
|
||||
* XSSheep
|
||||
|
@ -173,8 +166,6 @@
|
|||
* RandomLegoBrick
|
||||
* cora
|
||||
* Faerraven / Michieal
|
||||
* Nicu
|
||||
* Exhale
|
||||
|
||||
## Translations
|
||||
* Wuzzy
|
||||
|
@ -189,13 +180,9 @@
|
|||
* snowyu
|
||||
* 3raven
|
||||
* SakuraRiu
|
||||
* anarquimico
|
||||
* syl
|
||||
|
||||
## Funders
|
||||
* 40W
|
||||
* bauknecht
|
||||
* Cora
|
||||
|
||||
## Special thanks
|
||||
* celeron55 for creating Minetest
|
||||
|
@ -203,7 +190,4 @@
|
|||
* 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
|
||||
* 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) and Traitor (horizonchris96), which is licensed under https://creativecommons.org/licenses/by-sa/3.0/
|
||||
* 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)
|
||||
* 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)
|
||||
* 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)
|
||||
* 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!
|
70
MODELS.md
|
@ -1,70 +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!
|
|
@ -2,6 +2,8 @@
|
|||
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
|
||||
Developed by many people. Not developed or endorsed by Mojang AB.
|
||||
|
||||
Version: 0.82 (in development)
|
||||
|
||||
### Gameplay
|
||||
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
|
||||
|
@ -78,7 +80,7 @@ The MineClone2 repository is hosted at Mesehub. To contribute or report issues,
|
|||
|
||||
* Mesehub: <https://git.minetest.land/MineClone2/MineClone2>
|
||||
* 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/>
|
||||
|
@ -156,7 +158,7 @@ The following features are incomplete:
|
|||
|
||||
* Some monsters and animals
|
||||
* Redstone-related things
|
||||
* Some special minecarts (hopper and chest minecarts work)
|
||||
* Special minecarts
|
||||
* A couple of non-trivial blocks and items
|
||||
|
||||
Bonus features (not found in Minecraft):
|
||||
|
|
|
@ -1,45 +1,48 @@
|
|||
# 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
|
||||
|
||||
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
|
||||
|
||||
* Jeu de type bac-à-sable, sans objetifs
|
||||
* Survie : combattez des monstres hostiles et la faim
|
||||
* Creusez pour du minerai et d'autres trésors
|
||||
* Magie : gagnez de l'expérience et enchantez les outils
|
||||
* Utilisez les blocs ramassés pour construire de magnifiques bâtiments, votre imagination est la seule limite
|
||||
* Ramassez des fleurs (et d'autres sources de teinture) et colorez votre monde
|
||||
* Survie : combattre des monstres hostiles et la faim
|
||||
* Creuser pour du minerai et d'autres trésors
|
||||
* Magie : gagner de l'expérience et enchanter les outils
|
||||
* Utiliser les blocs ramassés pour construire de magnifiques bâtiments, votre imagination est la limite
|
||||
* Ramasser des fleurs (et d'autres sources de teinture) et colorez votre monde
|
||||
* Trouvez des graines et commencez à cultiver
|
||||
* 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
|
||||
|
||||
## Comment jouer (démarrer rapidement)
|
||||
### Commencer
|
||||
* **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
|
||||
* Placer les 4 planches de bois dans la grille 2x2 et **fabriquez un établi**
|
||||
* **Faites un clic droit sur l'établi** (icone livre) pour apprendre toutes les recettes possibles
|
||||
* Placer les 4 planches de bois dans la grille 2x2 et **fabriquez une table d'artisanat**
|
||||
* **Cliquez droit la table d'artisanat** (icone livre) pour apprendre toutes les recettes possibles
|
||||
* **Fabriquez une pioche de bois** pour miner la pierre
|
||||
* Différents outils minent différentes sortes de blocs. Essayez-les !
|
||||
* Continuez à jouer comme vous voulez. Amusez-vous !
|
||||
* Différents outils minent différentes sortes de blocs. Essayez les !
|
||||
* Continuez à jouer comme vous voulez. Amusez vous !
|
||||
|
||||
### Agriculture
|
||||
* Trouvez des graines
|
||||
* 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
|
||||
* Récoltez les plantes une fois matûres
|
||||
* Les terres agricoles proche de l'eau deviennent humides et accélèrent la croissance
|
||||
|
||||
### Four
|
||||
* Fabriquez un four
|
||||
* Fabriquer un Four
|
||||
* 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 bas doit contenir un objet combustible (par ex : charbon)
|
||||
* L'emplacement du haut doit contienir un objet fondable (par ex : minerai de fer)
|
||||
* 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
|
||||
|
||||
### 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.
|
||||
|
||||
## 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>
|
||||
* Discord : <https://discord.gg/xE4z8EEpDC>
|
||||
* 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/>
|
||||
* Forums Minetest : <https://forum.minetest.net/viewtopic.php?f=50&t=16407>
|
||||
* ContentDB : <https://content.minetest.net/packages/wuzzy/mineclone2/>
|
||||
* OpenCollective : <https://opencollective.com/mineclone2>
|
||||
* Mesehub: <https://git.minetest.land/MineClone2/MineClone2>
|
||||
* Discord: <https://discord.gg/xE4z8EEpDC>
|
||||
* 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/>
|
||||
* OpenCollective: <https://opencollective.com/mineclone2>
|
||||
|
||||
## 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.
|
||||
* 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.
|
||||
* 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.
|
||||
* 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 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 à basse performances, les optimisations sont difficiles à explorer.
|
||||
|
||||
## Statut de complétion
|
||||
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.
|
||||
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
|
||||
* Armure
|
||||
* Système de fabrication : grille 2x2, établi (grille 3x3), four, incluant un guide de fabrication
|
||||
* Coffres, grands coffres, coffre ender, boites de Shulker
|
||||
* Système de fabrication : grille 2x2, table d'artisanat (grille 3x3), four, incluant un guide de fabrication
|
||||
* Coffres, grands coffres, coffre ender, boite de shulker
|
||||
* Fours, entonnoirs
|
||||
* Faim
|
||||
* La plupart des monstres et animaux
|
||||
* Tous les minerais de Minecraft
|
||||
* Tout les minerais de Minecraft
|
||||
* La plupart des blocs de l'overworld
|
||||
* Eau et lave
|
||||
* 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
|
||||
* Circuits Redstone (partiel)
|
||||
* Effets de Statut (partiel)
|
||||
|
@ -104,10 +107,10 @@ Les principales fonctionnalités suivantes sont disponibles :
|
|||
* Brassage, potions, flèches trempées (partiel)
|
||||
* Bâteaux
|
||||
* Feu
|
||||
* Blocs de construction : escaliers, dalles, portes, trappes, barrières, portillons, murets
|
||||
* Blocs de construction : escaliers, dalles, portes, trappes, barrière, portillon, muret
|
||||
* Horloge
|
||||
* Boussole
|
||||
* Éponge
|
||||
* Eponge
|
||||
* Bloc de slime
|
||||
* Petites plantes et pousses
|
||||
* 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
|
||||
* Cadres d'objets
|
||||
* Juke-boxes
|
||||
* Lits
|
||||
* Menu d'inventaire
|
||||
* Inventaire créatif
|
||||
* Agriculture
|
||||
* Livres pour écrire
|
||||
* Commandes
|
||||
* Villages
|
||||
* L'End
|
||||
* et plus !
|
||||
|
||||
Les fonctionnalités suivantes sont incomplètes :
|
||||
Les fonctionalités suivantes sont incomplètes :
|
||||
|
||||
* Certains monstres et animaux
|
||||
* Certains composants de Redstone
|
||||
* certains monstres et animaux
|
||||
* certains composants de Redstone
|
||||
* 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
|
||||
* 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
|
||||
* 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 :
|
||||
* Outil de recherche, montre l'aide de ce qu'il touche
|
||||
* Plus de dalles et d'escaliers
|
||||
|
@ -150,24 +149,22 @@ Fonctionnalités bonus (absentes de Minecraft) :
|
|||
* Avant-poste du Nether (Forteresse)
|
||||
|
||||
Différences techniques avec 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)
|
||||
* 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
|
||||
* Des musiques différentes pour le juke-boxe
|
||||
* Des textures différentes (Pixel Perfection)
|
||||
* Des sons différents (sources diverses)
|
||||
* Un moteur de jeu différent (Minetest)
|
||||
* Des bonus cachés différents
|
||||
|
||||
...et enfin MineClone2 est un logiciel libre !
|
||||
|
||||
## Autres fichiers readme
|
||||
|
||||
* `LICENSE.txt` : Le texte de la licence GPLv3
|
||||
* `CONTRIBUTING.md` : Information pour ceux qui veulent contribuer
|
||||
* `API.md` : Pour les modders Minetest qui veulent modder ce jeu
|
||||
* `LEGAL.md` : Information légale
|
||||
* `CREDITS.md` : Liste de toutes les personnes qui ont contribué
|
||||
* `LICENSE.txt`: Le texte de la license GPLv3
|
||||
* `CONTRIBUTING.md`: Information pour ceux qui veulent contribuer
|
||||
* `API.md`: Pour les modders Minetest qui veulent modder ce jeu
|
||||
* `LEGAL.md`: Information légale
|
||||
* `CREDITS.md`: Liste des contributeurs
|
70
RELEASE.md
|
@ -1,75 +1,19 @@
|
|||
### Standard Release
|
||||
|
||||
#File to document release steps with a view to evolving into a script
|
||||
|
||||
#Update CREDITS.md
|
||||
#Update version in game.conf
|
||||
#Update version in README.md (soon to be game.conf from of 0.82.0)
|
||||
|
||||
lua tools/generate_ingame_credits.lua
|
||||
|
||||
git add CREDITS.md
|
||||
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
|
||||
|
||||
#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
|
||||
|
||||
* Add a comment to the forum post with the release number and what is involved, and maintainer will update main post.
|
||||
* Add a comment in Discord announcement
|
||||
git push origin 0.81.1
|
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,4 +1,4 @@
|
|||
title = MineClone 2
|
||||
description = A survival sandbox game. Survive, gather, hunt, build, explore, and do much more.
|
||||
disallowed_mapgens = v6
|
||||
version=0.84.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 |
|
@ -204,7 +204,7 @@ end
|
|||
|
||||
-- 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.
|
||||
function mcl_autogroup.can_harvest(nodename, toolname, player)
|
||||
function mcl_autogroup.can_harvest(nodename, toolname)
|
||||
local ndef = minetest.registered_nodes[nodename]
|
||||
|
||||
if not ndef then
|
||||
|
@ -215,10 +215,6 @@ function mcl_autogroup.can_harvest(nodename, toolname, player)
|
|||
return true
|
||||
end
|
||||
|
||||
if minetest.get_item_group(nodename, "dig_immediate_piston") >= 1 then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Check if it can be dug by tool
|
||||
local tdef = minetest.registered_tools[toolname]
|
||||
if tdef and tdef._mcl_diggroups then
|
||||
|
@ -232,9 +228,7 @@ function mcl_autogroup.can_harvest(nodename, toolname, player)
|
|||
end
|
||||
|
||||
-- Check if it can be dug by hand
|
||||
if not player or not player:is_player() then return false end
|
||||
local name = player:get_inventory():get_stack("hand", 1):get_name()
|
||||
local tdef = minetest.registered_items[name]
|
||||
local tdef = minetest.registered_tools[""]
|
||||
if tdef then
|
||||
for g, gdef in pairs(tdef._mcl_diggroups) do
|
||||
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,
|
||||
-- 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 {
|
||||
full_punch_interval = hand_toolcaps.full_punch_interval,
|
||||
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
|
||||
-- loading order.
|
||||
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 {})
|
||||
add_groupcaps(toolname, groupcaps, tdef._mcl_diggroups, efficiency)
|
||||
return groupcaps
|
||||
|
@ -304,10 +298,6 @@ end
|
|||
-- loading order.
|
||||
function mcl_autogroup.get_wear(toolname, diggroup)
|
||||
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
|
||||
return math.ceil(65535 / uses)
|
||||
end
|
||||
|
@ -360,7 +350,7 @@ local function overwrite()
|
|||
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
|
||||
-- depending on the _mcl_diggroups in the tool definition
|
||||
if tdef._mcl_diggroups then
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
# mcl_autogroup
|
||||
This mod emulate digging times from mc.
|
||||
|
||||
## mcl_autogroup.can_harvest(nodename, toolname, player)
|
||||
Return true if <nodename> can be dig with <toolname> by <player>.
|
||||
## mcl_autogroup.can_harvest(nodename, toolname)
|
||||
Return true if <nodename> can be dig with <toolname>.
|
||||
* nodename: string, valid nodename
|
||||
* toolname: (optional) string, valid toolname
|
||||
* player: (optinal) ObjectRef, valid player
|
||||
|
||||
## mcl_autogroup.get_groupcaps(toolname, efficiency)
|
||||
This function is used to calculate diggroups for tools.
|
||||
|
|
|
@ -155,6 +155,7 @@ end, true)
|
|||
minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
|
||||
if not damage_enabled then return 0 end
|
||||
if player:get_hp() > 0 then
|
||||
mt_reason.approved = true
|
||||
if hp_change < 0 then
|
||||
mcl_damage.run_damage_callbacks(player, -hp_change, mcl_damage.from_mt(mt_reason))
|
||||
end
|
||||
|
@ -162,7 +163,9 @@ minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
|
|||
end, false)
|
||||
|
||||
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())))
|
||||
end)
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ under the LGPLv2.1 license.
|
|||
mcl_explosions = {}
|
||||
|
||||
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 math = math
|
||||
|
@ -192,7 +191,7 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
|
|||
local grief_protected = info.grief_protected
|
||||
|
||||
-- Trace rays for environment destruction
|
||||
if info.griefing and explosions_griefing then
|
||||
if info.griefing then
|
||||
for i = 1, #raydirs do
|
||||
local rpos_x = pos.x
|
||||
local rpos_y = pos.y
|
||||
|
@ -352,23 +351,6 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
|
|||
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
|
||||
|
||||
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.=
|
|
@ -3,26 +3,26 @@ mcl_vars = {}
|
|||
|
||||
mcl_vars.redstone_tick = 0.1
|
||||
|
||||
-- GUI / inventory menu settings
|
||||
--- GUI / inventory menu settings
|
||||
mcl_vars.gui_slots = "listcolors[#9990;#FFF7;#FFF0;#000;#FFF]"
|
||||
|
||||
-- nonbg is added as formspec prepend in mcl_formspec_prepend
|
||||
mcl_vars.gui_nonbg = table.concat({
|
||||
mcl_vars.gui_slots,
|
||||
"style_type[image_button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]",
|
||||
"style_type[button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]",
|
||||
"style_type[field;textcolor=#323232]",
|
||||
"style_type[label;textcolor=#323232]",
|
||||
"style_type[textarea;textcolor=#323232]",
|
||||
"style_type[checkbox;textcolor=#323232]",
|
||||
})
|
||||
mcl_vars.gui_nonbg = mcl_vars.gui_slots ..
|
||||
"style_type[image_button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]"..
|
||||
"style_type[button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]"..
|
||||
"style_type[field;textcolor=#323232]"..
|
||||
"style_type[label;textcolor=#323232]"..
|
||||
"style_type[textarea;textcolor=#323232]"..
|
||||
"style_type[checkbox;textcolor=#323232]"
|
||||
|
||||
-- Background stuff must be manually added by mods (no formspec prepend)
|
||||
mcl_vars.gui_bg_color = "bgcolor[#00000000]"
|
||||
mcl_vars.gui_bg_img = "background9[1,1;1,1;mcl_base_textures_background9.png;true;7]"
|
||||
|
||||
-- Legacy
|
||||
mcl_vars.inventory_header = ""
|
||||
|
||||
-- Tool wield size
|
||||
mcl_vars.tool_wield_scale = vector.new(1.8, 1.8, 1)
|
||||
mcl_vars.tool_wield_scale = { x = 1.8, y = 1.8, z = 1 }
|
||||
|
||||
-- Mapgen variables
|
||||
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.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
|
||||
mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, minetest.MAX_MAP_GENERATION_LIMIT or 31000)
|
||||
|
||||
local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2)
|
||||
|
||||
mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
||||
mcl_vars.chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE
|
||||
|
||||
local central_chunk_min_pos = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
||||
local central_chunk_max_pos = central_chunk_min_pos + mcl_vars.chunk_size_in_nodes - 1
|
||||
local ccfmin = central_chunk_min_pos - mcl_vars.MAP_BLOCKSIZE -- Fullminp/fullmaxp of central chunk, in nodes
|
||||
local ccfmax = central_chunk_max_pos + mcl_vars.MAP_BLOCKSIZE
|
||||
local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) /
|
||||
mcl_vars.MAP_BLOCKSIZE)
|
||||
local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) / mcl_vars.MAP_BLOCKSIZE)
|
||||
local mapgen_limit_min = -mapgen_limit_b * mcl_vars.MAP_BLOCKSIZE
|
||||
local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_vars.MAP_BLOCKSIZE - 1
|
||||
local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / mcl_vars.chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk
|
||||
local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / mcl_vars.chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits.
|
||||
|
||||
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * mcl_vars.chunk_size_in_nodes
|
||||
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * mcl_vars.chunk_size_in_nodes
|
||||
|
||||
---@param x integer
|
||||
---@return integer
|
||||
local function coordinate_to_block(x)
|
||||
return math.floor(x / mcl_vars.MAP_BLOCKSIZE)
|
||||
end
|
||||
|
||||
---@param x integer
|
||||
---@return integer
|
||||
local function coordinate_to_chunk(x)
|
||||
return math.floor((coordinate_to_block(x) - central_chunk_offset) / mcl_vars.chunksize)
|
||||
end
|
||||
|
||||
---@param pos Vector
|
||||
---@return Vector
|
||||
function mcl_vars.pos_to_block(pos)
|
||||
return vector.new(
|
||||
coordinate_to_block(pos.x),
|
||||
coordinate_to_block(pos.y),
|
||||
coordinate_to_block(pos.z)
|
||||
)
|
||||
return {
|
||||
x = coordinate_to_block(pos.x),
|
||||
y = coordinate_to_block(pos.y),
|
||||
z = coordinate_to_block(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
---@param pos Vector
|
||||
---@return Vector
|
||||
function mcl_vars.pos_to_chunk(pos)
|
||||
return vector.new(
|
||||
coordinate_to_chunk(pos.x),
|
||||
coordinate_to_chunk(pos.y),
|
||||
coordinate_to_chunk(pos.z)
|
||||
)
|
||||
return {
|
||||
x = coordinate_to_chunk(pos.x),
|
||||
y = coordinate_to_chunk(pos.y),
|
||||
z = coordinate_to_chunk(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / mcl_vars.chunk_size_in_nodes)
|
||||
local k_positive_z = k_positive * 2
|
||||
local k_positive_y = k_positive_z * k_positive_z
|
||||
|
||||
---@param pos Vector
|
||||
---@return integer
|
||||
function mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
local c = mcl_vars.pos_to_chunk(pos)
|
||||
return (c.y + k_positive) * k_positive_y +
|
||||
return
|
||||
(c.y + k_positive) * k_positive_y +
|
||||
(c.z + k_positive) * k_positive_z +
|
||||
c.x + k_positive
|
||||
c.x + k_positive
|
||||
end
|
||||
|
||||
if not superflat and not singlenode then
|
||||
|
@ -131,8 +117,11 @@ elseif singlenode then
|
|||
mcl_vars.mg_bedrock_is_rough = false
|
||||
else
|
||||
-- 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_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
||||
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())
|
||||
|
||||
local chunks = {} -- intervals of chunks generated
|
||||
|
||||
---@param pos Vector
|
||||
function mcl_vars.add_chunk(pos)
|
||||
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
local prev
|
||||
for i, d in pairs(chunks) do
|
||||
if n <= d[2] then -- we've found it
|
||||
if (n == d[2]) or (n >= d[1]) then return end -- already here
|
||||
if n == d[1] - 1 then -- right before:
|
||||
if prev and (prev[2] == n - 1) then
|
||||
if n == d[1]-1 then -- right before:
|
||||
if prev and (prev[2] == n-1) then
|
||||
prev[2] = d[2]
|
||||
table.remove(chunks, i)
|
||||
return
|
||||
|
@ -209,20 +196,17 @@ function mcl_vars.add_chunk(pos)
|
|||
d[1] = n
|
||||
return
|
||||
end
|
||||
if prev and (prev[2] == n - 1) then --join to previous
|
||||
if prev and (prev[2] == n-1) then --join to previous
|
||||
prev[2] = n
|
||||
return
|
||||
end
|
||||
table.insert(chunks, i, { n, n }) -- insert new interval before i
|
||||
table.insert(chunks, i, {n, n}) -- insert new interval before i
|
||||
return
|
||||
end
|
||||
prev = d
|
||||
end
|
||||
chunks[#chunks + 1] = { n, n }
|
||||
chunks[#chunks+1] = {n, n}
|
||||
end
|
||||
|
||||
---@param pos Vector
|
||||
---@return boolean
|
||||
function mcl_vars.is_generated(pos)
|
||||
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
for i, d in pairs(chunks) do
|
||||
|
@ -233,46 +217,47 @@ function mcl_vars.is_generated(pos)
|
|||
return false
|
||||
end
|
||||
|
||||
---"Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does.
|
||||
---@param pos Vector Position, if it's wrong, `{name="error"}` node will return.
|
||||
---@param force? boolean Optional (default: `false`), Do the maximum to still read the node within us_timeout.
|
||||
---@param us_timeout? number Optional (default: `244 = 0.000244 s = 1/80/80/80`), set it at least to `3000000` to let mapgen to finish its job
|
||||
---@return node # Node definition, eg. `{name="air"}`. Unfortunately still can return `{name="ignore"}`.
|
||||
---@nodiscard
|
||||
function mcl_vars.get_node(pos, force, us_timeout)
|
||||
-- "Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does.
|
||||
-- p: Position, if it's wrong, {name="error"} node will return.
|
||||
-- force: optional (default: false) - Do the maximum to still read the node within us_timeout.
|
||||
-- us_timeout: optional (default: 244 = 0.000244 s = 1/80/80/80), set it at least to 3000000 to let mapgen to finish its job.
|
||||
--
|
||||
-- returns node definition, eg. {name="air"}. Unfortunately still can return {name="ignore"}.
|
||||
function mcl_vars.get_node(p, force, us_timeout)
|
||||
-- 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
|
||||
local node = minetest.get_node(pos)
|
||||
local node = minetest.get_node(p)
|
||||
if node.name ~= "ignore" then
|
||||
return node
|
||||
end
|
||||
|
||||
-- copy vector to get sure it won't changed by other threads
|
||||
local pos_copy = vector.copy(pos)
|
||||
-- copy table to get sure it won't changed by other threads
|
||||
local pos = {x=p.x,y=p.y,z=p.z}
|
||||
|
||||
-- try LVM
|
||||
minetest.get_voxel_manip():read_from_map(pos_copy, pos_copy)
|
||||
node = minetest.get_node(pos_copy)
|
||||
minetest.get_voxel_manip():read_from_map(pos, pos)
|
||||
node = minetest.get_node(pos)
|
||||
if node.name ~= "ignore" or not force then
|
||||
return node
|
||||
end
|
||||
|
||||
-- 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.forceload_block(pos_copy)
|
||||
minetest.forceload_block(pos)
|
||||
else
|
||||
minetest.emerge_area(pos_copy, pos_copy)
|
||||
minetest.emerge_area(pos, pos)
|
||||
end
|
||||
|
||||
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
|
||||
node = minetest.get_node(pos_copy)
|
||||
while (not node or node.name == "ignore") and (minetest.get_us_time() - t < us_timeout) do
|
||||
node = minetest.get_node(pos)
|
||||
end
|
||||
|
||||
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 |
|
@ -39,8 +39,8 @@ Metal sounds:
|
|||
default_place_node_metal.*.ogg - Ogrebane - CC0
|
||||
- http://opengameart.org/content/wood-and-metal-sound-effects-volume-2
|
||||
|
||||
AGFX (CC BY 3.0):
|
||||
https://www.freesound.org/people/AGFX/packs/1253/
|
||||
original by anonymous (CC0 1.0), mastering by iliekprogrammar (CC0 1.0):
|
||||
https://freesound.org/people/deleted_user_2104797/sounds/166313/
|
||||
default_water_footstep.*.ogg
|
||||
|
||||
blukotek (CC0 1.0):
|
||||
|
|
|
@ -166,7 +166,7 @@ end
|
|||
function mcl_sounds.node_sound_water_defaults(table)
|
||||
table = table or {}
|
||||
table.footstep = table.footstep or
|
||||
{name = "default_water_footstep", gain = 0.2}
|
||||
{name = "default_water_footstep", gain = 0.05}
|
||||
table.place = table.place or
|
||||
{name = "mcl_sounds_place_node_water", gain = 1.0}
|
||||
table.dug = table.dug or
|
||||
|
|
|
@ -2,8 +2,8 @@ mcl_util = {}
|
|||
|
||||
-- Updates all values in t using values from to*.
|
||||
function table.update(t, ...)
|
||||
for _, to in ipairs {...} do
|
||||
for k, v in pairs(to) do
|
||||
for _, to in ipairs{...} do
|
||||
for k,v in pairs(to) do
|
||||
t[k] = v
|
||||
end
|
||||
end
|
||||
|
@ -12,8 +12,8 @@ end
|
|||
|
||||
-- Updates nil values in t using values from to*.
|
||||
function table.update_nil(t, ...)
|
||||
for _, to in ipairs {...} do
|
||||
for k, v in pairs(to) do
|
||||
for _, to in ipairs{...} do
|
||||
for k,v in pairs(to) do
|
||||
if t[k] == nil then
|
||||
t[k] = v
|
||||
end
|
||||
|
@ -22,9 +22,9 @@ function table.update_nil(t, ...)
|
|||
return t
|
||||
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]"
|
||||
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
|
||||
if module then
|
||||
selected_module = module
|
||||
|
@ -34,63 +34,6 @@ function mcl_util.mcl_log(message, module, bypass_default_logger)
|
|||
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)
|
||||
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]
|
||||
if undef and undef.on_rightclick then
|
||||
undef.on_rightclick(pointed_thing.under, unode, placer,
|
||||
itemstack, pointed_thing)
|
||||
itemstack, pointed_thing)
|
||||
return
|
||||
end
|
||||
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)
|
||||
if side == "right" 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
|
||||
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
|
||||
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
|
||||
return {x = pos.x, y = pos.y, z = pos.z - 1}
|
||||
return {x=pos.x, y=pos.y, z=pos.z-1}
|
||||
end
|
||||
else
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
|
@ -242,7 +185,7 @@ end
|
|||
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 stack
|
||||
for i = 1, size do
|
||||
for i=1, size do
|
||||
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
|
||||
return i
|
||||
|
@ -345,10 +288,10 @@ function mcl_util.move_item_container(source_pos, destination_pos, source_list,
|
|||
-- Main inventory for most container types
|
||||
if sctype == 2 or sctype == 3 or sctype == 5 or sctype == 6 or sctype == 7 then
|
||||
source_list = "main"
|
||||
-- Furnace: output
|
||||
-- Furnace: output
|
||||
elseif sctype == 4 then
|
||||
source_list = "dst"
|
||||
-- Unknown source container type. Bail out
|
||||
-- Unknown source container type. Bail out
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
@ -401,7 +344,7 @@ function mcl_util.move_item_container(source_pos, destination_pos, source_list,
|
|||
-- Main inventory for most container types
|
||||
if dctype == 2 or dctype == 3 or dctype == 5 or dctype == 6 or dctype == 7 then
|
||||
destination_list = "main"
|
||||
-- Furnace source slot
|
||||
-- Furnace source slot
|
||||
elseif dctype == 4 then
|
||||
destination_list = "src"
|
||||
end
|
||||
|
@ -466,7 +409,7 @@ end
|
|||
-- Returns true if item (itemstring or ItemStack) can be used as a furnace fuel.
|
||||
-- Returns false otherwise
|
||||
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
|
||||
|
||||
-- Returns a on_place function for plants
|
||||
|
@ -513,7 +456,7 @@ function mcl_util.generate_on_place_plant_function(condition)
|
|||
|
||||
if success 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
|
||||
itemstack = new_itemstack
|
||||
|
@ -614,11 +557,6 @@ function mcl_util.deal_damage(target, damage, mcl_reason)
|
|||
end
|
||||
end
|
||||
|
||||
local is_immortal = target:get_armor_groups().immortal or 0
|
||||
if is_immortal>0 then
|
||||
return
|
||||
end
|
||||
|
||||
local hp = target:get_hp()
|
||||
|
||||
if hp > 0 then
|
||||
|
@ -705,80 +643,78 @@ end
|
|||
|
||||
local function roundN(n, d)
|
||||
if type(n) ~= "number" then return n end
|
||||
local m = 10 ^ d
|
||||
return math.floor(n * m + 0.5) / m
|
||||
local m = 10^d
|
||||
return math.floor(n * m + 0.5) / m
|
||||
end
|
||||
|
||||
local function close_enough(a, b)
|
||||
local rt = true
|
||||
local function close_enough(a,b)
|
||||
local rt=true
|
||||
if type(a) == "table" and type(b) == "table" then
|
||||
for k, v in pairs(a) do
|
||||
if roundN(v, 2) ~= roundN(b[k], 2) then
|
||||
rt = false
|
||||
for k,v in pairs(a) do
|
||||
if roundN(v,2) ~= roundN(b[k],2) then
|
||||
rt=false
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
rt = roundN(a, 2) == roundN(b, 2)
|
||||
rt = roundN(a,2) == roundN(b,2)
|
||||
end
|
||||
return rt
|
||||
end
|
||||
|
||||
local function props_changed(props, oldprops)
|
||||
local changed = false
|
||||
local p = {}
|
||||
for k, v in pairs(props) do
|
||||
if not close_enough(v, oldprops[k]) then
|
||||
p[k] = v
|
||||
changed = true
|
||||
local function props_changed(props,oldprops)
|
||||
local changed=false
|
||||
local p={}
|
||||
for k,v in pairs(props) do
|
||||
if not close_enough(v,oldprops[k]) then
|
||||
p[k]=v
|
||||
changed=true
|
||||
end
|
||||
end
|
||||
return changed, p
|
||||
return changed,p
|
||||
end
|
||||
|
||||
--tests for roundN
|
||||
local test_round1 = 15
|
||||
local test_round2 = 15.00199999999
|
||||
local test_round3 = 15.00111111
|
||||
local test_round4 = 15.00999999
|
||||
local test_round1=15
|
||||
local test_round2=15.00199999999
|
||||
local test_round3=15.00111111
|
||||
local test_round4=15.00999999
|
||||
|
||||
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_round3, 2))
|
||||
assert(roundN(test_round1, 2) ~= roundN(test_round4, 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_round3,2))
|
||||
assert(roundN(test_round1,2)~=roundN(test_round4,2))
|
||||
|
||||
-- tests for close_enough
|
||||
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_diff = {-0.35, 0, -1.35, 0.35, 0.8, 0.35}
|
||||
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_diff = {-0.35,0,-1.35,0.35,0.8,0.35}
|
||||
|
||||
local test_eh = 1.65 --eye height
|
||||
local test_eh_close = 1.65123123
|
||||
local test_eh_diff = 1.35
|
||||
|
||||
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 = { r = 225, b = 225, a = 225, g = 225 } --nametag
|
||||
local test_nt_diff = { r = 225, b = 225, a = 0, g = 225 }
|
||||
|
||||
assert(close_enough(test_cb, test_cb_close))
|
||||
assert(not close_enough(test_cb, test_cb_diff))
|
||||
assert(close_enough(test_eh, test_eh_close))
|
||||
assert(not close_enough(test_eh, test_eh_diff))
|
||||
assert(not close_enough(test_nt, test_nt_diff)) --no floats involved here
|
||||
assert(close_enough(test_cb,test_cb_close))
|
||||
assert(not close_enough(test_cb,test_cb_diff))
|
||||
assert(close_enough(test_eh,test_eh_close))
|
||||
assert(not close_enough(test_eh,test_eh_diff))
|
||||
assert(not close_enough(test_nt,test_nt_diff)) --no floats involved here
|
||||
|
||||
--tests for properties_changed
|
||||
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}}
|
||||
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_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 }}
|
||||
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_p2, _ = props_changed(test_properties_set1, test_properties_set2)
|
||||
local test_p1,_=props_changed(test_properties_set1,test_properties_set1)
|
||||
local test_p2,_=props_changed(test_properties_set1,test_properties_set2)
|
||||
|
||||
assert(not test_p1)
|
||||
assert(test_p2)
|
||||
|
||||
function mcl_util.set_properties(obj, props)
|
||||
local changed, p = props_changed(props, obj:get_properties())
|
||||
function mcl_util.set_properties(obj,props)
|
||||
local changed,p=props_changed(props,obj:get_properties())
|
||||
if changed then
|
||||
obj:set_properties(p)
|
||||
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)
|
||||
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)
|
||||
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 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 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 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("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" }
|
||||
|
||||
for b=1, #boat_ids do
|
||||
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
|
||||
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
|
||||
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
|
||||
Acacia Boat=Bateau en acacia
|
||||
Birch Boat=Bateau en bouleau
|
||||
Acacia Boat=Bateau en Acacia
|
||||
Birch Boat=Bateau en Bouleau
|
||||
Boat=Bateau
|
||||
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
|
||||
Jungle Boat=Bateau en acajou
|
||||
Oak Boat=Bateau en chêne
|
||||
Dark Oak Boat=Bateau en Chêne Noir
|
||||
Jungle Boat=Bateau en Acajou
|
||||
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.
|
||||
Spruce Boat=Bateau en sapin
|
||||
Spruce Boat=Bateau en Sapin
|
||||
Water vehicle=Véhicule aquatique
|
||||
Sneak to dismount=Se baisser pour descendre
|
||||
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
|
||||
Obsidian Boat=Bateau en Obsidienne
|
|
@ -10,14 +10,4 @@ Rightclick on a water source to place the boat. Rightclick the boat to enter it.
|
|||
Spruce Boat=
|
||||
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=
|
||||
Obsidian 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
|
||||
|
||||
function mcl_burning.is_burning(obj)
|
||||
local storage = mcl_burning.get_storage(obj)
|
||||
if storage then
|
||||
return mcl_burning.get_storage(obj).burn_time
|
||||
else
|
||||
return false
|
||||
end
|
||||
return mcl_burning.get_storage(obj).burn_time
|
||||
end
|
||||
|
||||
function mcl_burning.is_affected_by_rain(obj)
|
||||
|
@ -158,11 +153,6 @@ function mcl_burning.extinguish(obj)
|
|||
end
|
||||
|
||||
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
|
||||
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 was smashed by a falling block.=
|
|
@ -7,19 +7,31 @@ local pool = {}
|
|||
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)
|
||||
pool[player:get_player_name()] = 0
|
||||
local name
|
||||
name = player:get_player_name()
|
||||
pool[name] = 0
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
pool[player:get_player_name()] = nil
|
||||
local name
|
||||
name = player:get_player_name()
|
||||
pool[name] = nil
|
||||
end)
|
||||
|
||||
|
||||
local has_awards = minetest.get_modpath("awards")
|
||||
|
||||
mcl_item_entity = {}
|
||||
local mcl_item_entity = {}
|
||||
|
||||
--basic settings
|
||||
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
|
||||
-- drop_single_item is disabled by default because it is annoying to throw away items from the intentory screen
|
||||
|
||||
item_drop_settings.magnet_time = 0.75 -- how many seconds an item follows the player before giving up
|
||||
item_drop_settings.magnet_time = 0.75 -- how many seconds an item follows the player before giving up
|
||||
|
||||
local function get_gravity()
|
||||
return tonumber(minetest.settings:get("movement_gravity")) or 9.81
|
||||
end
|
||||
|
||||
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
|
||||
---@param itemname string
|
||||
---@param award string
|
||||
--TODO: remove limitation of 1 award per itemname
|
||||
function mcl_item_entity.register_pickup_achievement(itemname, award)
|
||||
if not has_awards then
|
||||
minetest.log("warning",
|
||||
"[mcl_item_entity] Trying to register pickup achievement [" .. award .. "] for [" ..
|
||||
itemname .. "] while awards missing")
|
||||
elseif mcl_item_entity.registered_pickup_achievement[itemname] then
|
||||
minetest.log("error",
|
||||
"[mcl_item_entity] Trying to register already existing pickup achievement [" .. award .. "] for [" .. itemname .. "]")
|
||||
minetest.log("warning", "[mcl_item_entity] Trying to register pickup achievement ["..award.."] for ["..itemname.."] while awards missing")
|
||||
elseif registered_pickup_achievement[itemname] then
|
||||
minetest.log("error", "[mcl_item_entity] Trying to register already existing pickup achievement ["..award.."] for ["..itemname.."]")
|
||||
else
|
||||
mcl_item_entity.registered_pickup_achievement[itemname] = award
|
||||
registered_pickup_achievement[itemname] = award
|
||||
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_armor:elytra", "mcl:skysTheLimit")
|
||||
|
||||
---@param object ObjectRef
|
||||
---@param player ObjectRef
|
||||
local function check_pickup_achievements(object, player)
|
||||
if has_awards then
|
||||
local itemname = ItemStack(object:get_luaentity().itemstring):get_name()
|
||||
local playername = player:get_player_name()
|
||||
for name, award in pairs(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
|
||||
awards.unlock(playername, award)
|
||||
end
|
||||
|
@ -83,23 +86,16 @@ local function check_pickup_achievements(object, player)
|
|||
end
|
||||
end
|
||||
|
||||
---@param object ObjectRef
|
||||
---@param luaentity Luaentity
|
||||
---@param ignore_check? boolean
|
||||
local function enable_physics(object, luaentity, ignore_check)
|
||||
if luaentity.physical_state == false or ignore_check == true then
|
||||
luaentity.physical_state = true
|
||||
object:set_properties({
|
||||
physical = true
|
||||
})
|
||||
object:set_acceleration(vector.new(0, -get_gravity(), 0))
|
||||
object:set_acceleration({x=0,y=-get_gravity(),z=0})
|
||||
end
|
||||
end
|
||||
|
||||
---@param object ObjectRef
|
||||
---@param luaentity Luaentity
|
||||
---@param ignore_check? boolean
|
||||
---@param reset_movement? boolean
|
||||
local function disable_physics(object, luaentity, ignore_check, reset_movement)
|
||||
if luaentity.physical_state == true or ignore_check == true then
|
||||
luaentity.physical_state = false
|
||||
|
@ -107,16 +103,17 @@ local function disable_physics(object, luaentity, ignore_check, reset_movement)
|
|||
physical = false
|
||||
})
|
||||
if reset_movement ~= false then
|
||||
object:set_velocity(vector.zero())
|
||||
object:set_acceleration(vector.zero())
|
||||
object:set_velocity({x=0,y=0,z=0})
|
||||
object:set_acceleration({x=0,y=0,z=0})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function(_)
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
tick = not tick
|
||||
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
for _,player in pairs(minetest.get_connected_players()) do
|
||||
if player:get_hp() > 0 or not minetest.settings:get_bool("enable_damage") then
|
||||
|
||||
local name = player:get_player_name()
|
||||
|
@ -128,7 +125,7 @@ minetest.register_globalstep(function(_)
|
|||
pos = pos,
|
||||
gain = 0.3,
|
||||
max_hear_distance = 16,
|
||||
pitch = math.random(70, 110) / 100
|
||||
pitch = math.random(70,110)/100
|
||||
})
|
||||
if pool[name] > 6 then
|
||||
pool[name] = 6
|
||||
|
@ -138,18 +135,15 @@ minetest.register_globalstep(function(_)
|
|||
end
|
||||
|
||||
|
||||
|
||||
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
|
||||
for _, object in pairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do
|
||||
if not object:is_player() and vector.distance(checkpos, object:get_pos()) < item_drop_settings.radius_magnet and
|
||||
object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer
|
||||
and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
|
||||
for _,object in pairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do
|
||||
if not object:is_player() and vector.distance(checkpos, object:get_pos()) < item_drop_settings.radius_magnet and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
|
||||
|
||||
if object:get_luaentity()._magnet_timer >= 0 and
|
||||
object:get_luaentity()._magnet_timer < item_drop_settings.magnet_time and inv and
|
||||
inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
|
||||
if object:get_luaentity()._magnet_timer >= 0 and object:get_luaentity()._magnet_timer < item_drop_settings.magnet_time and inv and inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
|
||||
|
||||
-- Collection
|
||||
if not object:get_luaentity()._removed then
|
||||
|
@ -164,8 +158,8 @@ minetest.register_globalstep(function(_)
|
|||
object:get_luaentity().target = checkpos
|
||||
object:get_luaentity()._removed = true
|
||||
|
||||
object:set_velocity(vector.zero())
|
||||
object:set_acceleration(vector.zero())
|
||||
object:set_velocity({x=0,y=0,z=0})
|
||||
object:set_acceleration({x=0,y=0,z=0})
|
||||
|
||||
object:move_to(checkpos)
|
||||
|
||||
|
@ -185,6 +179,7 @@ minetest.register_globalstep(function(_)
|
|||
local entity = object:get_luaentity()
|
||||
entity.collector = player:get_player_name()
|
||||
entity.collected = true
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -199,11 +194,6 @@ end)
|
|||
|
||||
local tmp_id = 0
|
||||
|
||||
---@param drop string|drop_definition
|
||||
---@param toolname string
|
||||
---@param param2 integer
|
||||
---@param paramtype2 paramtype2
|
||||
---@return string[]
|
||||
local function get_drops(drop, toolname, param2, paramtype2)
|
||||
tmp_id = tmp_id + 1
|
||||
local tmp_node_name = "mcl_item_entity:" .. tmp_id
|
||||
|
@ -212,7 +202,7 @@ local function get_drops(drop, toolname, param2, paramtype2)
|
|||
drop = drop,
|
||||
paramtype2 = paramtype2
|
||||
}
|
||||
local drops = minetest.get_node_drops({ name = tmp_node_name, param2 = param2 }, toolname)
|
||||
local drops = minetest.get_node_drops({name = tmp_node_name, param2 = param2}, toolname)
|
||||
minetest.registered_nodes[tmp_node_name] = nil
|
||||
return drops
|
||||
end
|
||||
|
@ -247,17 +237,10 @@ function minetest.handle_node_drops(pos, drops, digger)
|
|||
-- 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
|
||||
-- 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 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
|
||||
|
||||
if (digger and digger:is_player() and minetest.is_creative_enabled(digger:get_player_name())) or doTileDrops == false then
|
||||
return
|
||||
elseif not doTileDrops then return end
|
||||
end
|
||||
|
||||
-- Check if node will yield its useful drop by the digger's tool
|
||||
local dug_node = minetest.get_node(pos)
|
||||
|
@ -265,9 +248,9 @@ function minetest.handle_node_drops(pos, drops, digger)
|
|||
local tool
|
||||
if digger then
|
||||
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
|
||||
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
|
||||
]]
|
||||
|
||||
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 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 chance = fortune_drop.chance or fortune_drop.get_chance and fortune_drop.get_chance(fortune_level)
|
||||
if not chance or math.random() < chance then
|
||||
drops = discrete_uniform_distribution(fortune_drop.multiply and drops or fortune_drop.items, min_count, max_count,
|
||||
fortune_drop.cap)
|
||||
drops = discrete_uniform_distribution(fortune_drop.multiply and drops or fortune_drop.items, min_count, max_count, fortune_drop.cap)
|
||||
elseif fortune_drop.override then
|
||||
drops = {}
|
||||
end
|
||||
|
@ -324,13 +306,13 @@ function minetest.handle_node_drops(pos, drops, digger)
|
|||
end
|
||||
|
||||
if digger and mcl_experience.throw_xp and not silk_touch_drop then
|
||||
local experience_amount = minetest.get_item_group(dug_node.name, "xp")
|
||||
local experience_amount = minetest.get_item_group(dug_node.name,"xp")
|
||||
if experience_amount > 0 then
|
||||
mcl_experience.throw_xp(pos, experience_amount)
|
||||
end
|
||||
end
|
||||
|
||||
for _, item in ipairs(drops) do
|
||||
for _,item in ipairs(drops) do
|
||||
local count
|
||||
if type(item) == "string" then
|
||||
count = ItemStack(item):get_count()
|
||||
|
@ -339,7 +321,7 @@ function minetest.handle_node_drops(pos, drops, digger)
|
|||
end
|
||||
local drop_item = ItemStack(item)
|
||||
drop_item:set_count(1)
|
||||
for i = 1, count do
|
||||
for i=1,count do
|
||||
local dpos = table.copy(pos)
|
||||
-- Apply offset for plantlike_rooted nodes because of their special shape
|
||||
if nodedef and nodedef.drawtype == "plantlike_rooted" and nodedef.walkable then
|
||||
|
@ -366,7 +348,7 @@ end
|
|||
function minetest.item_drop(itemstack, dropper, pos)
|
||||
if dropper and dropper:is_player() then
|
||||
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()
|
||||
if dropper:get_player_control().sneak then
|
||||
cs = 1
|
||||
|
@ -374,9 +356,9 @@ function minetest.item_drop(itemstack, dropper, pos)
|
|||
local item = itemstack:take_item(cs)
|
||||
local obj = minetest.add_item(p, item)
|
||||
if obj then
|
||||
v.x = v.x * 4
|
||||
v.y = v.y * 4 + 2
|
||||
v.z = v.z * 4
|
||||
v.x = v.x*4
|
||||
v.y = v.y*4 + 2
|
||||
v.z = v.z*4
|
||||
obj:set_velocity(v)
|
||||
-- Force collection delay
|
||||
obj:get_luaentity()._insta_collect = false
|
||||
|
@ -394,185 +376,123 @@ end
|
|||
|
||||
local function cxcz(o, cw, one, zero)
|
||||
if cw < 0 then
|
||||
table.insert(o, { [one] = 1, y = 0, [zero] = 0 })
|
||||
table.insert(o, { [one] = -1, y = 0, [zero] = 0 })
|
||||
table.insert(o, { [one]=1, y=0, [zero]=0 })
|
||||
table.insert(o, { [one]=-1, y=0, [zero]=0 })
|
||||
else
|
||||
table.insert(o, { [one] = -1, y = 0, [zero] = 0 })
|
||||
table.insert(o, { [one] = 1, y = 0, [zero] = 0 })
|
||||
table.insert(o, { [one]=-1, y=0, [zero]=0 })
|
||||
table.insert(o, { [one]=1, y=0, [zero]=0 })
|
||||
end
|
||||
return o
|
||||
end
|
||||
|
||||
local function nodes_destroy_items (self, moveresult, def, 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")
|
||||
local function hopper_take_item (self, pos)
|
||||
--mcl_log("self.itemstring: ".. self.itemstring)
|
||||
--mcl_log("self.itemstring: ".. minetest.pos_to_string(pos))
|
||||
|
||||
if (def and (lg ~= 0 or fg ~= 0 or dg == 1)) then
|
||||
local item_string = self.itemstring
|
||||
local item_name = ItemStack(item_string):get_name()
|
||||
local objs = minetest.get_objects_inside_radius(pos, 2)
|
||||
|
||||
--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(item_name, "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 true
|
||||
end
|
||||
end
|
||||
if objs and self.itemstring then
|
||||
--mcl_log("there is an itemstring. Number of objs: ".. #objs)
|
||||
|
||||
-- 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
|
||||
-- TODO We need to play a sound when it gets destroyed
|
||||
self._removed = true
|
||||
self.object:remove()
|
||||
return true
|
||||
for k,v in pairs(objs) do
|
||||
local ent = v:get_luaentity()
|
||||
|
||||
-- Don't forget actual hoppers
|
||||
if ent and ent.name == "mcl_minecarts:hopper_minecart" then
|
||||
local taken_items = false
|
||||
|
||||
mcl_log("ent.name: ".. tostring(ent.name))
|
||||
mcl_log("ent pos: ".. tostring(ent.object:get_pos()))
|
||||
|
||||
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
|
||||
|
||||
local function push_out_item_stuck_in_solid(self, dtime, p, def, is_in_water)
|
||||
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
|
||||
return false
|
||||
end
|
||||
|
||||
minetest.register_entity(":__builtin:item", {
|
||||
|
@ -580,13 +500,13 @@ minetest.register_entity(":__builtin:item", {
|
|||
hp_max = 1,
|
||||
physical = true,
|
||||
collide_with_objects = false,
|
||||
collisionbox = { -0.3, -0.3, -0.3, 0.3, 0.3, 0.3 },
|
||||
collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
|
||||
pointable = false,
|
||||
visual = "wielditem",
|
||||
visual_size = { x = 0.4, y = 0.4 },
|
||||
textures = { "" },
|
||||
spritediv = { x = 1, y = 1 },
|
||||
initial_sprite_basepos = { x = 0, y = 0 },
|
||||
visual_size = {x = 0.4, y = 0.4},
|
||||
textures = {""},
|
||||
spritediv = {x = 1, y = 1},
|
||||
initial_sprite_basepos = {x = 0, y = 0},
|
||||
is_visible = false,
|
||||
infotext = "",
|
||||
},
|
||||
|
@ -621,18 +541,14 @@ minetest.register_entity(":__builtin:item", {
|
|||
if speed ~= nil then self.random_velocity = speed end
|
||||
|
||||
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
|
||||
local v = self.random_velocity
|
||||
local x = math.random(5, max_vel) / 10 * v
|
||||
if math.random(0, 10) < 5 then x = -x end
|
||||
local z = math.random(5, max_vel) / 10 * v
|
||||
if math.random(0, 10) < 5 then z = -z end
|
||||
local y = math.random(1, 2)
|
||||
self.object:set_velocity(vector.new(x, y, z))
|
||||
local x = math.random(5, 10) / 10 * v
|
||||
if math.random(0,10) < 5 then x = -x end
|
||||
local z = math.random(5, 10) / 10 * v
|
||||
if math.random(0,10) < 5 then z = -z end
|
||||
local y = math.random(2,4)
|
||||
self.object:set_velocity({x=x, y=y, z=z})
|
||||
end
|
||||
self.random_velocity = 0
|
||||
end,
|
||||
|
@ -660,7 +576,7 @@ minetest.register_entity(":__builtin:item", {
|
|||
local max_count = stack:get_stack_max()
|
||||
if count > max_count then
|
||||
count = max_count
|
||||
self.itemstring = stack:get_name() .. " " .. max_count
|
||||
self.itemstring = stack:get_name().." "..max_count
|
||||
end
|
||||
local itemtable = stack:to_table()
|
||||
local itemname = nil
|
||||
|
@ -681,9 +597,9 @@ minetest.register_entity(":__builtin:item", {
|
|||
local prop = {
|
||||
is_visible = true,
|
||||
visual = "wielditem",
|
||||
textures = { itemname },
|
||||
visual_size = { x = s, y = s },
|
||||
collisionbox = { -c, -c, -c, c, c, c },
|
||||
textures = {itemname},
|
||||
visual_size = {x = s, y = s},
|
||||
collisionbox = {-c, -c, -c, c, c, c},
|
||||
automatic_rotate = math.pi * 0.5,
|
||||
infotext = description,
|
||||
glow = glow,
|
||||
|
@ -779,9 +695,9 @@ minetest.register_entity(":__builtin:item", {
|
|||
self._forcestart = nil
|
||||
self._forcetimer = 0
|
||||
|
||||
self.object:set_armor_groups({ immortal = 1 })
|
||||
-- self.object:set_velocity(vector.new(0, 2, 0))
|
||||
self.object:set_acceleration(vector.new(0, -get_gravity(), 0))
|
||||
self.object:set_armor_groups({immortal = 1})
|
||||
-- self.object:set_velocity({x = 0, y = 2, z = 0})
|
||||
self.object:set_acceleration({x = 0, y = -get_gravity(), z = 0})
|
||||
self:set_item(self.itemstring)
|
||||
end,
|
||||
|
||||
|
@ -794,9 +710,9 @@ minetest.register_entity(":__builtin:item", {
|
|||
local stack = ItemStack(entity.itemstring)
|
||||
local name = stack:get_name()
|
||||
if own_stack:get_name() ~= name or
|
||||
own_stack:get_meta() ~= stack:get_meta() or
|
||||
own_stack:get_wear() ~= stack:get_wear() or
|
||||
own_stack:get_free_space() == 0 then
|
||||
own_stack:get_meta() ~= stack:get_meta() or
|
||||
own_stack:get_wear() ~= stack:get_wear() or
|
||||
own_stack:get_free_space() == 0 then
|
||||
-- Can not merge different or full stack
|
||||
return false
|
||||
end
|
||||
|
@ -808,19 +724,11 @@ minetest.register_entity(":__builtin:item", {
|
|||
if total_count > max_count then
|
||||
return false
|
||||
end
|
||||
|
||||
-- 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 x_diff = (self_pos.x - pos.x) / 2
|
||||
local z_diff = (self_pos.z - pos.z) / 2
|
||||
|
||||
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)
|
||||
-- local pos = object:get_pos()
|
||||
-- pos.y = pos.y + ((total_count - count) / max_count) * 0.15
|
||||
-- self.object:move_to(pos)
|
||||
|
||||
self.age = 0 -- Handle as new entity
|
||||
own_stack:set_count(total_count)
|
||||
|
@ -837,11 +745,10 @@ minetest.register_entity(":__builtin:item", {
|
|||
self.object:set_properties({
|
||||
physical = false
|
||||
})
|
||||
self.object:set_velocity(vector.zero())
|
||||
self.object:set_acceleration(vector.zero())
|
||||
self.object:set_velocity({x=0,y=0,z=0})
|
||||
self.object:set_acceleration({x=0,y=0,z=0})
|
||||
return
|
||||
end
|
||||
|
||||
self.age = self.age + dtime
|
||||
if self._collector_timer then
|
||||
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,
|
||||
-- otherwise there might have some data corruption.
|
||||
if self.itemstring == "" then
|
||||
minetest.log("warning",
|
||||
"Item entity with empty itemstring found and being deleted at: " .. minetest.pos_to_string(self.object:get_pos()))
|
||||
minetest.log("warning", "Item entity with empty itemstring found at "..minetest.pos_to_string(self.object:get_pos()).. "! Deleting it now.")
|
||||
self._removed = true
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
||||
local p = self.object:get_pos()
|
||||
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
|
||||
-- Don't infinetly fall into unloaded map
|
||||
|
@ -871,32 +783,29 @@ minetest.register_entity(":__builtin:item", {
|
|||
return
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
if self.is_clock then
|
||||
self.object:set_properties({
|
||||
textures = { "mcl_clock:clock_" .. (mcl_worlds.clock_works(p) and mcl_clock.old_time or mcl_clock.random_frame) }
|
||||
textures = {"mcl_clock:clock_" .. (mcl_worlds.clock_works(p) and mcl_clock.old_time or mcl_clock.random_frame)}
|
||||
})
|
||||
end
|
||||
|
||||
local nn = node.name
|
||||
local is_in_water = (minetest.get_item_group(nn, "liquid") ~= 0)
|
||||
local nn_above = minetest.get_node(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
|
||||
local sleep_threshold = 0.3
|
||||
local is_floating = false
|
||||
local is_stationary = math.abs(self.object:get_velocity().x) < sleep_threshold
|
||||
and math.abs(self.object:get_velocity().y) < sleep_threshold
|
||||
and math.abs(self.object:get_velocity().z) < sleep_threshold
|
||||
and math.abs(self.object:get_velocity().y) < sleep_threshold
|
||||
and math.abs(self.object:get_velocity().z) < sleep_threshold
|
||||
if is_in_water and is_stationary then
|
||||
is_floating = (is_in_water
|
||||
and (minetest.get_item_group(nn_above, "liquid") == 0))
|
||||
end
|
||||
|
||||
if is_floating and self.physical_state == true then
|
||||
self.object:set_velocity(vector.zero())
|
||||
self.object:set_acceleration(vector.zero())
|
||||
self.object:set_velocity({x = 0, y = 0, z = 0})
|
||||
self.object:set_acceleration({x = 0, y = 0, z = 0})
|
||||
disable_physics(self.object, self)
|
||||
end
|
||||
-- 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
|
||||
|
||||
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
|
||||
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 v = self.object:get_velocity()
|
||||
local is_on_floor = def and (def.walkable
|
||||
and not def.groups.slippery and v.y == 0)
|
||||
|
||||
if not minetest.registered_nodes[nn] or is_floating or is_on_floor then
|
||||
|
||||
if not minetest.registered_nodes[nn]
|
||||
or is_floating or is_on_floor then
|
||||
local own_stack = ItemStack(self.object:get_luaentity().itemstring)
|
||||
-- Merge with close entities of the same item
|
||||
for _, object in pairs(minetest.get_objects_inside_radius(p, 0.8)) do
|
||||
local obj = object:get_luaentity()
|
||||
if obj and obj.name == "__builtin:item" and obj.physical_state == false then
|
||||
if obj and obj.name == "__builtin:item"
|
||||
and obj.physical_state == false then
|
||||
if self:try_merge_with(own_stack, object, obj) then
|
||||
return
|
||||
end
|
||||
|
|
|
@ -11,14 +11,6 @@ mcl_minecarts.check_float_time = 15
|
|||
dofile(mcl_minecarts.modpath.."/functions.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)
|
||||
if not self._driver then
|
||||
return
|
||||
|
@ -59,134 +51,6 @@ end
|
|||
|
||||
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._removed or not ent.itemstring or ent.itemstring == "" then
|
||||
--minetest.log("Ignore this item")
|
||||
break
|
||||
end
|
||||
|
||||
-- Don't forget actual hoppers
|
||||
|
||||
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
|
||||
mcl_log("No inv")
|
||||
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
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- Table for item-to-entity mapping. Keys: itemstring, Values: Corresponding entity ID
|
||||
local entity_mapping = {}
|
||||
|
||||
|
@ -202,7 +66,6 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
|||
on_rightclick = on_rightclick,
|
||||
|
||||
_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
|
||||
_velocity = {x=0, y=0, z=0}, -- only used on punch
|
||||
_start_pos = nil, -- Used to calculate distance for “On A Rail” achievement
|
||||
|
@ -223,7 +86,6 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
|||
local data = minetest.deserialize(staticdata)
|
||||
if type(data) == "table" then
|
||||
self._railtype = data._railtype
|
||||
self._passenger = data._passenger
|
||||
end
|
||||
self.object:set_armor_groups({immortal=1})
|
||||
|
||||
|
@ -315,11 +177,7 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
|||
|
||||
cart.on_activate_by_rail = on_activate_by_rail
|
||||
|
||||
local passenger_attach_position = vector.new(0, -1.75, 0)
|
||||
|
||||
function cart:on_step(dtime)
|
||||
hopper_take_item(self, dtime)
|
||||
|
||||
local ctrl, player = nil, nil
|
||||
if self._driver then
|
||||
player = minetest.get_player_by_name(self._driver)
|
||||
|
@ -354,29 +212,6 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
|||
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
|
||||
if self._last_float_check >= mcl_minecarts.check_float_time then
|
||||
pos = self.object:get_pos()
|
||||
|
@ -401,8 +236,19 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
|||
return
|
||||
end
|
||||
|
||||
-- Do not drop minecart. It goes off the rails too frequently, and anyone using them for farms won't
|
||||
-- notice and lose their iron and not bother. Not cool until fixed.
|
||||
-- Drop items and remove cart entity
|
||||
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
|
||||
self._last_float_check = 0
|
||||
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.
|