Compare commits

..

2 Commits

558 changed files with 7082 additions and 14650 deletions

2
.gitignore vendored
View File

@ -1,2 +0,0 @@
# Text Editor TMP Files
*.swp

View File

@ -40,16 +40,4 @@ read_globals = {
"factorial" "factorial"
} }
}, },
------
--MODS
------
--GENERAL
"default",
--ENTITIES
"cmi",
--HUD
"sfinv", "sfinv_buttons", "unified_inventory", "cmsg", "inventory_plus",
} }

View File

@ -1,128 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
eliasfleckenstein@web.de.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@ -1,414 +1,83 @@
# Contributing to MineClone2 # Contributing to MineClone 2
So you want to contribute to MineClone2? So you want to MineClone 2?
Wow, thank you! :-) Wow, thank you! :-)
MineClone2 is maintained by Nicu and Fleckenstein. If you have any But first, some things to note:
problems or questions, contact us (See Links section below).
You can help with MineClone2's development in many different ways, MineClone 2's development target is to make a free software clone of Minecraft,
whether you're a programmer or not. ***version 1.12***, ***PC edition***, *** + Optifine features supported by the Minetest Engine ***.
## MineClone2's development target is to... MineClone 2 is maintained by three persons. Namely, kay27, EliasFleckenstein and jordan4ibanez. You can find us
- Crucially, create a stable, moddable, free/libre clone of Minecraft in the Minetest forums (forums.minetest.net), in IRC in the #mineclone2
based on the Minetest engine with polished features, usable in both channel on irc.freenode.net. And finally, you can send e-mails to
singleplayer and multiplayer. Currently, most of **Minecraft Java <eliasfleckenstein@web.de> or <kay27@bk.ru>.
Edition 1.12.2** features are already implemented and polishing existing
features are prioritized over new feature requests.
- With lessened priority yet strictly, implement features targetting
**Minecraft version 1.17 + OptiFine** (OptiFine only as far as supported
by the Minetest Engine). This means features in parity with the listed
Minecraft experiences are prioritized over those that don't fulfill this
scope.
- Optionally, create a performant experience that will run relatively
well on really low spec computers. Unfortunately, due to Minecraft's
mechanisms and Minetest engine's limitations along with a very small
playerbase on low spec computers, optimizations are hard to investigate.
## Links By sending us patches or asking us to include your changes in this game,
* [Mesehub](https://git.minetest.land/MineClone2/MineClone2) you agree that they fall under the terms of the LGPLv2.1, which basically
* [Discord](https://discord.gg/xE4z8EEpDC) means they will become part of a free software.
* [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)
## Using git ## The suggested workflow
MineClone2 is developed using the version control system We don't **dictate** your workflow, but in order to work with us in an efficient
[git](https://git-scm.com/). If you want to contribute code to the way, you can follow these suggestions:
project, it is **highly recommended** that you learn the git basics.
For non-programmers and people who do not plan to contribute code to
MineClone2, git is not required. However, git is a tool that will be
referenced frequently because of its usefulness. As such, it is valuable
in learning how git works and its terminology. It can also help you
keeping your game updated, and easily test pull requests.
## How you can help as a non-programmer For small and medium changes:
As someone who does not know how to write programs in Lua or does not * Fork the repository
know how to use the Minetest API, you can still help us out a lot. For
example, by opening an issue in the
[Issue tracker](https://git.minetest.land/MineClone2/MineClone2/issues),
you can report a bug or request a feature.
### Rules about both bugs and feature requests
* Stay polite towards the developers and anyone else involved in the
discussion.
* Choose a descriptive title (e.g. not just "crash", "bug" or "question"
).
* Please write in plain, understandable English. It will be easier to
communicate.
* Please start the issue title with a capital letter.
* Always check the currently opened issues before creating a new one.
Don't report bugs that have already been reported or request features
that already have been requested.
* If you know about Minetest's inner workings, please think about
whether the bug / the feature that you are reporting / requesting is
actually an issue with Minetest itself, and if it is, head to the
[Minetest issue tracker](https://github.com/minetest/minetest/issues)
instead.
* If you need any help regarding creating a Mesehub account or opening
an issue, feel free to ask on the Discord / Matrix server or the IRC
channel.
### Reporting bugs
* A bug is an unintended behavior or, in the worst case, a crash.
However, it is not a bug if you believe something is missing in the
game. In this case, please read "Requesting features"
* If you report a crash, always include the error message. If you play
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.
* 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.
### Requesting features
* Ensure the requested feature fulfills our development targets and
goals.
* Begging or excessive attention seeking does not help us in the
slightest, and may very well disrupt MineClone2 development. It's better
to put that energy into helping or researching the feature in question.
After all, we're just volunteers working on our spare time.
* Ensure the requested feature has not been implemented in MineClone2
latest or development versions.
### Testing code
If you want to help us with speeding up MineClone2 development and
making the game more stable, a great way to do that is by testing out
new features from contributors. For most new things that get into the
game, a pull request is created. A pull request is essentially a
programmer saying "Look, I modified the game, please apply my changes
to the upstream version of the game". However, every programmer makes
mistakes sometimes, some of which are hard to spot. You can help by
downloading this modified version of the game and trying it out - then
tell us if the code works as expected without any issues. Ideally, you
would report issues will pull requests similar to when you were
reporting bugs that are the mainline (See Reporting bugs section). You
can find currently open pull requests here:
<https://git.minetest.land/MineClone2/MineClone2/pulls>. Note that pull
requests that start with a `WIP:` are not done yet, and therefore might
not work, so it's not very useful to try them out yet.
### Contributing assets
Due to license problems, MineClone2 unfortunately cannot use
Minecraft's assets, therefore we are always looking for asset
contributions. To contribute assets, it can be useful to learn git
basics and read the section for Programmers of this document, however
this is not required. It's also a good idea to join the Discord server
(or alternatively IRC or Matrix).
#### Textures
For textures we use the Pixel Perfection texture pack. This is mostly
enough; however in some cases - e.g. for newer Minecraft features, it's
useful to have texture artists around. If you want to make such
contributions, join our Discord server. Demands for textures will be
communicated there.
#### Sounds
MineClone2 currently does not have a consistent way to handle sounds.
The sounds in the game come from different sources, like the SnowZone
resource pack or minetest_game. Unfortunately, MineClone2 does not play
a sound in every situation you would get one in Minecraft. Any help with
sounds is greatly appreciated, however if you add new sounds you should
probably work together with a programmer, to write the code to actually
play these sounds in game.
#### 3D Models
Most of the 3D Models in MineClone2 come from
[22i's repository](https://github.com/22i/minecraft-voxel-blender-models).
Similar to the textures, we need people that can make 3D Models with
Blender on demand. Many of the models have to be patched, some new
animations have to be added etc.
#### Crediting
Asset contributions will be credited in their own respective sections in
CREDITS.md. If you have commited the results yourself, you will also be
credited in the Contributors section.
### Contributing Translations
#### Workflow
To add/update support for your language to MineClone2, you should take
the steps documented in the section for Programmers, add/update the
translation files of the mods that you want to update. You can add
support for all mods, just some of them or only one mod; you can update
the translation file entirely or only partly; basically any effort is
valued. If your changes are small, you can also send them to developers
via E-Mail, Discord, IRC or Matrix - they will credit you appropriately.
#### Things to note
You can use the script at `tools/check_translate_files.py` to compare
the translation files for the language you are working on with the
template files, to see what is missing and what is out of date with
the template file. However, template files are often incomplete and/or
out of date, sometimes they don't match the code. You can update the
translation files if that is required, you can also modify the code in
your translation PR if it's related to translation. You can also work on
multiple languages at the same time in one PR.
#### Crediting
Translation contributions will be credited in their own in CREDITS.md.
If you have commited the results yourself, you will also be credited in
the Contributors section.
### Profiling
If you own a server, a great way to help us improve MineClone2's code
is by giving us profiler results. Profiler results give us detailed
information about the game's performance and let us know places to
investigate optimization issues. This way we can make the game faster.
#### Using Minetest's profiler
Minetest has a built in profiler. Simply set `profiler.load = true` in
your configuration file and restart the server. After running the server
for some time, just run `/profiler save` in chat - then you will find a
file in the world directory containing the results. Open a new issue and
upload the file. You can name the issue "<Server name> profiler
results".
### Let us know your opinion
It is always encouraged to actively contribute to issue discussions on
MeseHub, let us know what you think about a topic and help us make
decisions. Also, note that a lot of discussion takes place on the
Discord server, so it's definitely worth checking it out.
### Funding
You can help pay for our infrastructure (Mesehub) by donating to our
OpenCollective link (See Links section).
### Crediting
If you opened or have contributed to an issue, you receive the
`Community` role on our Discord (after asking for it).
OpenCollective Funders are credited in their own section in
`CREDITS.md` and receive a special role "Funder" on our discord (unless
they have made their donation Incognito).
## How you can help as a programmer
(Almost) all the MineClone2 development is done using pull requests.
### Recommended workflow
* Fork the repository (in case you have not already)
* Do your change in a new branch * Do your change in a new branch
* Create a pull request to get your changes merged into master * Create a pull request to get your changes merged into master
* Keep your pull request up to date by regularly merging upstream. It is
imperative that conflicts are resolved prior to merging the pull
request.
* After the pull request got merged, you can delete the branch
### Discuss first For small changes, sending us a patch is also good.
If you feel like a problem needs to fixed or you want to make a new
feature, you could start writing the code right away and notifying us
when you're done, but it never hurts to discuss things first. If there
is no issue on the topic, open one. If there is an issue, tell us that
you'd like to take care of it, to avoid duplicate work.
### Don't hesitate to ask for help For big changes: Same as above, but consider notifying us first to avoid
We appreciate any contributing effort to MineClone2. If you are a duplicate work and possible tears of rejection. ;-)
relatively new programmer, you can reach us on Discord, Matrix or IRC
for questions about git, Lua, Minetest API, MineClone2 codebase or
anything related to MineClone2. We can help you avoid writing code that
would be deemed inadequate, or help you become familiar with MineClone2
better, or assist you use development tools.
### Maintain your own code, even if already got merged For trusted people, we might give them direct commit access to this
Sometimes, your code may cause crashes or bugs - we try to avoid such repository. In this case, you obviously don't need to fork, but you still
scenarios by testing every time before merging it, but if your merged need to show your contributions align with the project goals. We still
work causes problems, we ask you fix the issues as soon as possible. reserve the right to revert everything that we don't like.
For bigger changes, we strongly recommend to use feature branches and
discuss with me first.
### Changing Gameplay If your code causes bugs and crashes, it is your responsibility to fix them as soon as possible.
Pull Requests that change gameplay have to be properly researched and
need to state their sources. These PRs also need Fleckenstein's approval
before they are merged.
You can use these sources:
* Minecraft code (Name the source file and line, however DONT post any We mostly use plain merging rather than rebasing or squash merging.
proprietary code). You can use
[MCP](https://minecraft.fandom.com/wiki/Programs_and_editors/Mod_Coder_Pack)
to decompile Minecraft or look at
[Minestorm](https://github.com/Minestom/Minestom) code.
* Testing things inside of Minecraft (Attach screenshots / video footage
of the results)
* [Official Minecraft Wiki](https://minecraft.fandom.com/wiki/Minecraft_Wiki)
(Include a link to the specific page you used)
### Stick to our guidelines Your commit names should be relatively descriptive, e.g. when saying "Fix #issueid", the commit message should also contain the title of the issue.
#### Git Guidelines Contributors will be credited in `CREDITS.md`.
* We use merge rather than rebase or squash merge
* We don't use git submodules.
* Your commit names should be relatively descriptive, e.g. when saying
"Fix #issueid", the commit message should also contain the title of the
issue.
* Try to keep your commits as atomic as possible (advise, but completely
optional)
#### Code Guidelines ## Features > 1.12
* Each mod must provide `mod.conf`.
* Mod names are snake case, and newly added mods start with `mcl_`, e.g.
`mcl_core`, `mcl_farming`, `mcl_monster_eggs`. Keep in mind Minetest
does not support capital letters in mod names.
* To export functions, store them inside a global table named like the
mod, e.g.
```lua If you want to make a feature that was added in a Minecraft version later than 1.12, you should fork MineClone5 (mineclone5 branch in the repository) and add your changes to this.
mcl_example = {}
function mcl_example.do_something() ## What we accept
-- ...
end
``` * Every MC features up to version 1.12 JE.
* Every already finished and working good features from versions above (only when making a MineClone5 PR / Contribution).
* Except features which couldn't be done easily and bugfree because of Minetest engine limitations. Eg. we CAN extend world boundaries by playing with map chunks, just teleporting player onto next layer after 31000 , but it would cost too much (time, code, bugs, performance, stability, etc).
* Some features, approved by the rest of the community, I mean maybe some voting and really missing any negative feedback.
* Public functions should not use self references but rather just access ## What we reject
the table directly, e.g.
```lua * Any features which cause critical bugs, sending them to rework/fix or trying to fix immediately.
-- bad * Some small portions of big entirely missing features which just definitely break gamplay balance give nothing useful
function mcl_example:do_something() * Controversial features, which some people support while others do not should be discussed well, with publishing forum announcements, at least during the week. In case if there are still doubts - send them into the mod.
end
-- good ## Reporting bugs
function mcl_example.do_something() Report all bugs and missing Minecraft features here:
end
```
* Use modern Minetest API, e.g. no usage of `minetest.env` <https://git.minetest.land/MineClone2/MineClone2/issues>
* Tabs should be used for indent, spaces for alignment, e.g.
```lua ## Direct discussion
We have an IRC channel! Join us on #mineclone2 in freenode.net.
-- use tabs for indent <ircs://irc.freenode.net:6697/#mineclone2>
for i = 1, 10 do ## Creating releases
if i % 3 == 0 then
print(i)
end
end
-- use tabs for indent and spaces to align things
some_table = {
{"a string", 5},
{"a very much longer string", 10},
}
```
* Use double quotes for strings, e.g. `"asdf"` rather than `'asdf'`
* Use snake_case rather than CamelCase, e.g. `my_function` rather than
`MyFunction`
* Don't declare functions as an assignment, e.g.
```lua
-- bad
local some_local_func = function()
-- ...
end
my_mod.some_func = function()
-- ...
end
-- good
local function some_local_func()
-- ...
end
function my_mod.some_func()
-- ...
end
```
### Developer status
Active and trusted contributors are often granted write access to the
MineClone2 repository.
#### Developer responsibilities
- You should not push things directly to
MineClone2 master - rather, do your work on a branch on your private
repository, then create a pull request. This way other people can review
your changes and make sure they work before they get merged.
- Merge PRs only when they have recieved the necessary feedback and have
been tested by at least two different people (including the author of
the pull request), to avoid crashes or the introduction of new bugs.
- You may also be assigned to issues or pull
requests as a developer. In this case it is your responsibility to fix
the issue / review and merge the pull request when it is ready. You can
also unassign yourself from the issue / PR if you have no time or don't
want to take care of it for some other reason. After all, everyone is a
volunteer and we can't expect you to do work that you are not interested
in. **The important thing is that you make sure to inform us if you
won't take care of something that has been assigned to you.**
- Please assign yourself to something that you want to work on to avoid
duplicate work.
- As a developer, it should be easy to reach you about your work. You
should be in at least one of the public MineClone2 discussion rooms -
preferrably Discord, but if you really don't like Discord, Matrix
or IRC are fine too.
### Maintainer status
Maintainers carry the main responsibility for the project.
#### Maintainer responsibilities
- Making sure issues are addressed and pull requests are reviewed and
merged, by assigning either themselves or Developers to issues / PRs
- Making releases
- Making sure guidelines are kept
- Making project decisions based on community feedback
- Granting/revoking developer access
- Enforcing the code of conduct (See CODE_OF_CONDUCT.md)
- Moderating official community spaces (See Links section)
- Resolving conflicts and problems within the community
#### Current maintainers
* Fleckenstein - responsible for gameplay review, publishing releases,
technical guidelines and issue/PR delegation
* Nicu - responsible for community related issues
#### Release process
* Run `tools/generate_ingame_credits.lua` to update the ingame credits
from `CREDITS.md` and commit the result (if anything changed)
* Launch MineClone2 to make sure it still runs * Launch MineClone2 to make sure it still runs
* Update the version number in README.md * Update the version number in README.md
* Use `git tag <version number>` to tag the latest commit with the * Use `git tag <version number>` to tag the latest commit with the version number
version number * Push to repo (don't forget `--tags`!)
* Push to repository (don't forget `--tags`!) * Update ContentDB (https://content.minetest.net/packages/Wuzzy/mineclone2/)
* Update ContentDB * Update first post in forum thread (https://forum.minetest.net/viewtopic.php?f=50&t=16407)
(https://content.minetest.net/packages/Wuzzy/mineclone2/)
* Update first post in forum thread
(https://forum.minetest.net/viewtopic.php?f=50&t=16407)
* Post release announcement and changelog in forums * Post release announcement and changelog in forums
### Licensing
By asking us to include your changes in this game, you agree that they
fall under the terms of the GPLv3, which basically means they will
become part of a free/libre software.
### Crediting
Contributors, Developers and Maintainers will be credited in
`CREDITS.md`. If you make your first time contribution, please add
yourself to this file. There are also Discord roles for Contributors,
Developers and Maintainers.

View File

@ -8,8 +8,8 @@
## Maintainers ## Maintainers
* Fleckenstein * Fleckenstein
* Nicu
* kay27 * kay27
* jordan4ibanez
## Developers ## Developers
* bzoss * bzoss
@ -19,11 +19,9 @@
* iliekprogrammar * iliekprogrammar
* MysticTempest * MysticTempest
* Rootyjr * Rootyjr
* Nicu
* aligator * aligator
* Code-Sploit * Code-Sploit
* NO11
* cora
* jordan4ibanez
## Contributors ## Contributors
* Laurent Rocher * Laurent Rocher
@ -42,6 +40,7 @@
* Jared Moody * Jared Moody
* Li0n * Li0n
* Midgard * Midgard
* NO11
* Saku Laesvuori * Saku Laesvuori
* Yukitty * Yukitty
* ZedekThePD * ZedekThePD
@ -49,25 +48,8 @@
* dBeans * dBeans
* nickolas360 * nickolas360
* yutyo * yutyo
* Tianyang Zhang * ztianyang
* j45 * j45
* Marcin Serwin
* erlehmann
* E
* Benjamin Schötz
* Doloment
* Sydney Gems
* talamh
* Emily2255
* Emojigit
* FinishedFragment
* sfan5
* Blue Blancmange
* Jared Moody
* SmallJoker
* Sven792
* aldum
* Dieter44
## MineClone5 ## MineClone5
* kay27 * kay27
@ -92,6 +74,7 @@
* Rochambeau * Rochambeau
* rubenwardy * rubenwardy
* stu * stu
* jordan4ibanez
* 4aiman * 4aiman
* Kahrl * Kahrl
* Krock * Krock
@ -119,8 +102,6 @@
* leorockway * leorockway
* xMrVizzy * xMrVizzy
* yutyo * yutyo
* NO11
* kay27
## Translations ## Translations
* Wuzzy * Wuzzy
@ -128,11 +109,6 @@
* wuniversales * wuniversales
* kay27 * kay27
* pitchum * pitchum
* todoporlalibertad
* Marcin Serwin
## Funders
* 40W
## Special thanks ## Special thanks
* celeron55 for creating Minetest * celeron55 for creating Minetest

View File

@ -149,7 +149,7 @@ These groups are used mostly for informational purposes
* `trapdoor=2`: Open trapdoor * `trapdoor=2`: Open trapdoor
* `glass=1`: Glass (full cubes only) * `glass=1`: Glass (full cubes only)
* `rail=1`: Rail * `rail=1`: Rail
* `music_record`: Item is Music Disc * `music_record`: Music Disc (rating is track ID)
* `tnt=1`: Block is TNT * `tnt=1`: Block is TNT
* `boat=1`: Boat * `boat=1`: Boat
* `minecart=1`: Minecart * `minecart=1`: Minecart

View File

@ -1,4 +1,6 @@
# MineClone2 # (Currently in feature freeze)
# MineClone 2
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils. An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
Developed by many people. Not developed or endorsed by Mojang AB. Developed by many people. Not developed or endorsed by Mojang AB.
@ -69,40 +71,36 @@ an explanation.
This game requires [Minetest](http://minetest.net) to run (version 5.3.0 or This game requires [Minetest](http://minetest.net) to run (version 5.3.0 or
later). So you need to install Minetest first. Only stable versions of Minetest later). So you need to install Minetest first. Only stable versions of Minetest
are officially supported. are officially supported.
There is no support for running MineClone2 in development versions of Minetest. There is no support for running MineClone 2 in development versions of Minetest.
To install MineClone2 (if you haven't already), move this directory into the To install MineClone 2 (if you haven't already), move this directory into the
“games” directory of your Minetest data directory. Consult the help of “games” directory of your Minetest data directory. Consult the help of
Minetest to learn more. Minetest to learn more.
## Useful links ## Reporting bugs
The MineClone2 repository is hosted at Mesehub. To contribute or report issues, head there. Please report all bugs and missing Minecraft features here:
* Mesehub: <https://git.minetest.land/MineClone2/MineClone2> <https://git.minetest.land/MineClone2/MineClone2/issues>
* 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>
## Target ## Chating with the community
- Crucially, create a stable, moddable, free/libre clone of Minecraft Join our discord server at:
based on the Minetest engine with polished features, usable in both
singleplayer and multiplayer. Currently, most of **Minecraft Java <https://discord.gg/84GKcxczG3>
Edition 1.12.2** features are already implemented and polishing existing
features are prioritized over new feature requests. ## Project description
- With lessened priority yet strictly, implement features targetting The main goal of **MineClone 2** is to be a clone of Minecraft and to be released as free software.
**Minecraft version 1.17 + OptiFine** (OptiFine only as far as supported
by the Minetest Engine). This means features in parity with the listed * **Target of development: Minecraft, PC Edition, version 1.12** (later known as “Java Edition”)
Minecraft experiences are prioritized over those that don't fulfill this * MineClone2 also includes Optifine features supported by the Minetest
scope. * In general, Minecraft is aimed to be cloned as good as possible
- Optionally, create a performant experience that will run relatively * Cloning the gameplay has highest priority
well on really low spec computers. Unfortunately, due to Minecraft's * MineClone 2 will use different assets, but with a similar style
mechanisms and Minetest engine's limitations along with a very small * Limitations found in Minetest will be documented in the course of development
playerbase on low spec computers, optimizations are hard to investigate. * Features of later Minecraft versions are collected in the mineclone5 branch
## Using features from newer versions of Minecraft
For > 1.12 features, checkout MineClone5. It includes features from newer Minecraft versions.
Download it here: https://git.minetest.land/MineClone2/MineClone2/src/branch/mineclone5
## Completion status ## Completion status
This game is currently in **beta** stage. This game is currently in **beta** stage.
@ -189,7 +187,7 @@ Technical differences from Minecraft:
* Different engine (Minetest) * Different engine (Minetest)
* Different easter eggs * Different easter eggs
… and finally, MineClone2 is free software (“free” as in “freedom”)! … and finally, MineClone 2 is free software (“free” as in “freedom”)!
## Other readme files ## Other readme files

Binary file not shown.

View File

@ -83,7 +83,7 @@ local function get_hardness_values_for_groups()
for _, ndef in pairs(minetest.registered_nodes) do for _, ndef in pairs(minetest.registered_nodes) do
for g, _ in pairs(mcl_autogroup.registered_diggroups) do for g, _ in pairs(mcl_autogroup.registered_diggroups) do
if ndef.groups[g] then if ndef.groups[g] ~= nil then
maps[g][ndef._mcl_hardness or 0] = true maps[g][ndef._mcl_hardness or 0] = true
end end
end end
@ -121,7 +121,7 @@ local hardness_values = get_hardness_values_for_groups()
-- hardness_value. Used for quick lookup. -- hardness_value. Used for quick lookup.
local hardness_lookup = get_hardness_lookup_for_groups(hardness_values) local hardness_lookup = get_hardness_lookup_for_groups(hardness_values)
--[[local function compute_creativetimes(group) local function compute_creativetimes(group)
local creativetimes = {} local creativetimes = {}
for index, hardness in pairs(hardness_values[group]) do for index, hardness in pairs(hardness_values[group]) do
@ -129,7 +129,7 @@ local hardness_lookup = get_hardness_lookup_for_groups(hardness_values)
end end
return creativetimes return creativetimes
end]] end
-- Get the list of digging times for using a specific tool on a specific -- Get the list of digging times for using a specific tool on a specific
-- diggroup. -- diggroup.
@ -207,10 +207,6 @@ end
function mcl_autogroup.can_harvest(nodename, toolname) function mcl_autogroup.can_harvest(nodename, toolname)
local ndef = minetest.registered_nodes[nodename] local ndef = minetest.registered_nodes[nodename]
if not ndef then
return false
end
if minetest.get_item_group(nodename, "dig_immediate") >= 2 then if minetest.get_item_group(nodename, "dig_immediate") >= 2 then
return true return true
end end
@ -243,13 +239,13 @@ function mcl_autogroup.can_harvest(nodename, toolname)
end end
-- Get one groupcap field for using a specific tool on a specific group. -- Get one groupcap field for using a specific tool on a specific group.
--[[local function get_groupcap(group, can_harvest, multiplier, efficiency, uses) local function get_groupcap(group, can_harvest, multiplier, efficiency, uses)
return { return {
times = get_digtimes(group, can_harvest, multiplier, efficiency), times = get_digtimes(group, can_harvest, multiplier, efficiency),
uses = uses, uses = uses,
maxlevel = 0, maxlevel = 0,
} }
end]] end
-- Returns the tool_capabilities from a tool definition or a default set of -- Returns the tool_capabilities from a tool definition or a default set of
-- tool_capabilities -- tool_capabilities
@ -275,7 +271,7 @@ end
-- toolname - Name of the tool being enchanted (like "mcl_tools:diamond_pickaxe") -- toolname - Name of the tool being enchanted (like "mcl_tools:diamond_pickaxe")
-- efficiency - The efficiency level the tool is enchanted with (default 0) -- efficiency - The efficiency level the tool is enchanted with (default 0)
-- --
-- NOTE: -- NOTE:
-- This function can only be called after mod initialization. Otherwise a mod -- This function can only be called after mod initialization. Otherwise a mod
-- would have to add _mcl_autogroup as a dependency which would break the mod -- would have to add _mcl_autogroup as a dependency which would break the mod
-- loading order. -- loading order.
@ -292,7 +288,7 @@ end
-- toolname - Name of the tool used -- toolname - Name of the tool used
-- diggroup - The name of the diggroup the tool is used on -- diggroup - The name of the diggroup the tool is used on
-- --
-- NOTE: -- NOTE:
-- This function can only be called after mod initialization. Otherwise a mod -- This function can only be called after mod initialization. Otherwise a mod
-- would have to add _mcl_autogroup as a dependency which would break the mod -- would have to add _mcl_autogroup as a dependency which would break the mod
-- loading order. -- loading order.
@ -302,7 +298,7 @@ function mcl_autogroup.get_wear(toolname, diggroup)
return math.ceil(65535 / uses) return math.ceil(65535 / uses)
end end
local function overwrite() local overwrite = function()
for nname, ndef in pairs(minetest.registered_nodes) do for nname, ndef in pairs(minetest.registered_nodes) do
local newgroups = table.copy(ndef.groups) local newgroups = table.copy(ndef.groups)
if (nname ~= "ignore" and ndef.diggable) then if (nname ~= "ignore" and ndef.diggable) then
@ -319,12 +315,12 @@ local function overwrite()
newgroups.opaque = 1 newgroups.opaque = 1
end end
--local creative_breakable = false local creative_breakable = false
-- Assign groups used for digging this node depending on -- Assign groups used for digging this node depending on
-- the registered digging groups -- the registered digging groups
for g, gdef in pairs(mcl_autogroup.registered_diggroups) do for g, gdef in pairs(mcl_autogroup.registered_diggroups) do
--creative_breakable = true creative_breakable = true
local index = hardness_lookup[g][ndef._mcl_hardness or 0] local index = hardness_lookup[g][ndef._mcl_hardness or 0]
if ndef.groups[g] then if ndef.groups[g] then
if gdef.levels then if gdef.levels then

View File

@ -81,11 +81,11 @@ if v6_use_snow_biomes then
end end
local v6_freq_desert = tonumber(minetest.get_mapgen_setting("mgv6_freq_desert") or 0.45) local v6_freq_desert = tonumber(minetest.get_mapgen_setting("mgv6_freq_desert") or 0.45)
--local NOISE_MAGIC_X = 1619 local NOISE_MAGIC_X = 1619
--local NOISE_MAGIC_Y = 31337 local NOISE_MAGIC_Y = 31337
--local NOISE_MAGIC_Z = 52591 local NOISE_MAGIC_Z = 52591
--local NOISE_MAGIC_SEED = 1013 local NOISE_MAGIC_SEED = 1013
local function noise2d(x, y, seed) local noise2d = function(x, y, seed)
-- TODO: implement noise2d function for biome blend -- TODO: implement noise2d function for biome blend
return 0 return 0
--[[ --[[

View File

@ -1,8 +1,6 @@
local get_connected_players = minetest.get_connected_players local get_connected_players = minetest.get_connected_players
local clock = os.clock local clock = os.clock
local pairs = pairs
controls = {} controls = {}
controls.players = {} controls.players = {}
@ -22,15 +20,15 @@ function controls.register_on_hold(func)
end end
local known_controls = { local known_controls = {
jump = true, jump=true,
right = true, right=true,
left = true, left=true,
LMB = true, LMB=true,
RMB = true, RMB=true,
sneak = true, sneak=true,
aux1 = true, aux1=true,
down = true, down=true,
up = true, up=true,
} }
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
@ -51,27 +49,27 @@ minetest.register_globalstep(function(dtime)
local player_name = player:get_player_name() local player_name = player:get_player_name()
local player_controls = player:get_player_control() local player_controls = player:get_player_control()
if controls.players[player_name] then if controls.players[player_name] then
for cname, cbool in pairs(player_controls) do for cname, cbool in pairs(player_controls) do
if known_controls[cname] == true then if known_controls[cname] == true then
--Press a key --Press a key
if cbool == true and controls.players[player_name][cname][1] == false then if cbool==true and controls.players[player_name][cname][1]==false then
for _, func in pairs(controls.registered_on_press) do for _, func in pairs(controls.registered_on_press) do
func(player, cname) func(player, cname)
end
controls.players[player_name][cname] = {true, clock()}
elseif cbool == true and controls.players[player_name][cname][1] == true then
for _, func in pairs(controls.registered_on_hold) do
func(player, cname, clock()-controls.players[player_name][cname][2])
end
--Release a key
elseif cbool == false and controls.players[player_name][cname][1] == true then
for _, func in pairs(controls.registered_on_release) do
func(player, cname, clock()-controls.players[player_name][cname][2])
end
controls.players[player_name][cname] = {false}
end
end end
controls.players[player_name][cname] = {true, clock()}
elseif cbool==true and controls.players[player_name][cname][1]==true then
for _, func in pairs(controls.registered_on_hold) do
func(player, cname, clock()-controls.players[player_name][cname][2])
end
--Release a key
elseif cbool==false and controls.players[player_name][cname][1]==true then
for _, func in pairs(controls.registered_on_release) do
func(player, cname, clock()-controls.players[player_name][cname][2])
end
controls.players[player_name][cname] = {false}
end end
end end
end
end
end end
end) end)

View File

@ -1,100 +1,95 @@
local math = math
local get_node = minetest.get_node
local get_item_group = minetest.get_item_group
local registered_nodes = minetest.registered_nodes
flowlib = {} flowlib = {}
--sum of direction vectors must match an array index --sum of direction vectors must match an array index
--(sum,root)
--(0,1), (1,1+0=1), (2,1+1=2), (3,1+2^2=5), (4,2^2+2^2=8)
local inv_roots = {
[0] = 1,
[1] = 1,
[2] = 0.70710678118655,
[4] = 0.5,
[5] = 0.44721359549996,
[8] = 0.35355339059327,
}
local function to_unit_vector(dir_vector) local function to_unit_vector(dir_vector)
local sum = dir_vector.x * dir_vector.x + dir_vector.z * dir_vector.z --(sum,root)
return {x = dir_vector.x * inv_roots[sum], y = dir_vector.y, z = dir_vector.z * inv_roots[sum]} -- (0,1), (1,1+0=1), (2,1+1=2), (3,1+2^2=5), (4,2^2+2^2=8)
local inv_roots = {[0] = 1, [1] = 1, [2] = 0.70710678118655, [4] = 0.5
, [5] = 0.44721359549996, [8] = 0.35355339059327}
local sum = dir_vector.x*dir_vector.x + dir_vector.z*dir_vector.z
return {x=dir_vector.x*inv_roots[sum],y=dir_vector.y
,z=dir_vector.z*inv_roots[sum]}
end end
local function is_touching(realpos,nodepos,radius) local is_touching = function(realpos,nodepos,radius)
local boarder = 0.5 - radius local boarder = 0.5 - radius
return math.abs(realpos - nodepos) > (boarder) return (math.abs(realpos - nodepos) > (boarder))
end end
flowlib.is_touching = is_touching flowlib.is_touching = is_touching
local function is_water(pos) local is_water = function(pos)
return get_item_group(get_node(pos).name, "water") ~= 0 return (minetest.get_item_group(minetest.get_node(
{x=pos.x,y=pos.y,z=pos.z}).name
, "water") ~= 0)
end end
flowlib.is_water = is_water flowlib.is_water = is_water
local function node_is_water(node) local node_is_water = function(node)
return get_item_group(node.name, "water") ~= 0 return (minetest.get_item_group(node.name, "water") ~= 0)
end end
flowlib.node_is_water = node_is_water flowlib.node_is_water = node_is_water
local function is_lava(pos) local is_lava = function(pos)
return get_item_group(get_node(pos).name, "lava") ~= 0 return (minetest.get_item_group(minetest.get_node(
{x=pos.x,y=pos.y,z=pos.z}).name
, "lava") ~= 0)
end end
flowlib.is_lava = is_lava flowlib.is_lava = is_lava
local function node_is_lava(node) local node_is_lava = function(node)
return get_item_group(node.name, "lava") ~= 0 return (minetest.get_item_group(node.name, "lava") ~= 0)
end end
flowlib.node_is_lava = node_is_lava flowlib.node_is_lava = node_is_lava
local function is_liquid(pos) local is_liquid = function(pos)
return get_item_group(get_node(pos).name, "liquid") ~= 0 return (minetest.get_item_group(minetest.get_node(
{x=pos.x,y=pos.y,z=pos.z}).name
, "liquid") ~= 0)
end end
flowlib.is_liquid = is_liquid flowlib.is_liquid = is_liquid
local function node_is_liquid(node) local node_is_liquid = function(node)
return minetest.get_item_group(node.name, "liquid") ~= 0 return (minetest.get_item_group(node.name, "liquid") ~= 0)
end end
flowlib.node_is_liquid = node_is_liquid flowlib.node_is_liquid = node_is_liquid
--This code is more efficient --This code is more efficient
local function quick_flow_logic(node, pos_testing, direction) local function quick_flow_logic(node,pos_testing,direction)
local name = node.name local name = node.name
if not registered_nodes[name] then if not minetest.registered_nodes[name] then
return 0 return 0
end end
if registered_nodes[name].liquidtype == "source" then if minetest.registered_nodes[name].liquidtype == "source" then
local node_testing = get_node(pos_testing) local node_testing = minetest.get_node(pos_testing)
if not registered_nodes[node_testing.name] then local param2_testing = node_testing.param2
if not minetest.registered_nodes[node_testing.name] then
return 0 return 0
end end
if registered_nodes[node_testing.name].liquidtype ~= "flowing" then if minetest.registered_nodes[node_testing.name].liquidtype
~= "flowing" then
return 0 return 0
else else
return direction return direction
end end
elseif registered_nodes[name].liquidtype == "flowing" then elseif minetest.registered_nodes[name].liquidtype == "flowing" then
local node_testing = get_node(pos_testing) local node_testing = minetest.get_node(pos_testing)
local param2_testing = node_testing.param2 local param2_testing = node_testing.param2
if not registered_nodes[node_testing.name] then if not minetest.registered_nodes[node_testing.name] then
return 0 return 0
end end
if registered_nodes[node_testing.name].liquidtype == "source" then if minetest.registered_nodes[node_testing.name].liquidtype
== "source" then
return -direction return -direction
elseif registered_nodes[node_testing.name].liquidtype == "flowing" then elseif minetest.registered_nodes[node_testing.name].liquidtype
== "flowing" then
if param2_testing < node.param2 then if param2_testing < node.param2 then
if (node.param2 - param2_testing) > 6 then if (node.param2 - param2_testing) > 6 then
return -direction return -direction
@ -113,41 +108,48 @@ local function quick_flow_logic(node, pos_testing, direction)
return 0 return 0
end end
local function quick_flow(pos, node) local quick_flow = function(pos,node)
local x = 0
local z = 0
if not node_is_liquid(node) then if not node_is_liquid(node) then
return {x = 0, y = 0, z = 0} return {x=0,y=0,z=0}
end end
local x = quick_flow_logic(node,{x = pos.x-1, y = pos.y, z = pos.z},-1) + quick_flow_logic(node,{x = pos.x+1, y = pos.y, z = pos.z}, 1)
local z = quick_flow_logic(node,{x = pos.x, y = pos.y, z = pos.z-1},-1) + quick_flow_logic(node,{x = pos.x, y = pos.y, z = pos.z+1}, 1) x = x + quick_flow_logic(node,{x=pos.x-1,y=pos.y,z=pos.z},-1)
return to_unit_vector({x = x, y = 0, z = z}) x = x + quick_flow_logic(node,{x=pos.x+1,y=pos.y,z=pos.z}, 1)
z = z + quick_flow_logic(node,{x=pos.x,y=pos.y,z=pos.z-1},-1)
z = z + quick_flow_logic(node,{x=pos.x,y=pos.y,z=pos.z+1}, 1)
return to_unit_vector({x=x,y=0,z=z})
end end
flowlib.quick_flow = quick_flow flowlib.quick_flow = quick_flow
--if not in water but touching, move centre to touching block
--x has higher precedence than z
--if pos changes with x, it affects z
local function move_centre(pos, realpos, node, radius) --if not in water but touching, move centre to touching block
if is_touching(realpos.x, pos.x, radius) then --x has higher precedence than z
if is_liquid({x = pos.x-1, y = pos.y, z = pos.z}) then --if pos changes with x, it affects z
node = get_node({x=pos.x-1, y = pos.y, z = pos.z}) local move_centre = function(pos,realpos,node,radius)
pos = {x = pos.x-1, y = pos.y, z = pos.z} if is_touching(realpos.x,pos.x,radius) then
elseif is_liquid({x = pos.x+1, y = pos.y, z = pos.z}) then if is_liquid({x=pos.x-1,y=pos.y,z=pos.z}) then
node = get_node({x = pos.x+1, y = pos.y, z = pos.z}) node = minetest.get_node({x=pos.x-1,y=pos.y,z=pos.z})
pos = {x = pos.x+1, y = pos.y, z = pos.z} pos = {x=pos.x-1,y=pos.y,z=pos.z}
elseif is_liquid({x=pos.x+1,y=pos.y,z=pos.z}) then
node = minetest.get_node({x=pos.x+1,y=pos.y,z=pos.z})
pos = {x=pos.x+1,y=pos.y,z=pos.z}
end end
end end
if is_touching(realpos.z, pos.z, radius) then if is_touching(realpos.z,pos.z,radius) then
if is_liquid({x = pos.x, y = pos.y, z = pos.z - 1}) then if is_liquid({x=pos.x,y=pos.y,z=pos.z-1}) then
node = get_node({x = pos.x, y = pos.y, z = pos.z - 1}) node = minetest.get_node({x=pos.x,y=pos.y,z=pos.z-1})
pos = {x = pos.x, y = pos.y, z = pos.z - 1} pos = {x=pos.x,y=pos.y,z=pos.z-1}
elseif is_liquid({x = pos.x, y = pos.y, z = pos.z + 1}) then elseif is_liquid({x=pos.x,y=pos.y,z=pos.z+1}) then
node = get_node({x = pos.x, y = pos.y, z = pos.z + 1}) node = minetest.get_node({x=pos.x,y=pos.y,z=pos.z+1})
pos = {x = pos.x, y = pos.y, z = pos.z + 1} pos = {x=pos.x,y=pos.y,z=pos.z+1}
end end
end end
return pos, node return pos,node
end end
flowlib.move_centre = move_centre flowlib.move_centre = move_centre

View File

@ -1,21 +1,17 @@
local vector = vector
local facedir_to_dir = minetest.facedir_to_dir
local get_item_group = minetest.get_item_group
local remove_node = minetest.remove_node
local get_node = minetest.get_node
local original_function = minetest.check_single_for_falling local original_function = minetest.check_single_for_falling
function minetest.check_single_for_falling(pos) minetest.check_single_for_falling = function(pos)
local ret_o = original_function(pos) local ret_o = original_function(pos)
local ret = false local ret = false
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
if get_item_group(node.name, "attached_node_facedir") ~= 0 then if minetest.get_item_group(node.name, "attached_node_facedir") ~= 0 then
local dir = facedir_to_dir(node.param2) local dir = minetest.facedir_to_dir(node.param2)
if dir then if dir then
if get_item_group(get_node(vector.add(pos, dir)).name, "solid") == 0 then local cpos = vector.add(pos, dir)
remove_node(pos) local cnode = minetest.get_node(cpos)
if minetest.get_item_group(cnode.name, "solid") == 0 then
minetest.remove_node(pos)
local drops = minetest.get_node_drops(node.name, "") local drops = minetest.get_node_drops(node.name, "")
for dr=1, #drops do for dr=1, #drops do
minetest.add_item(pos, drops[dr]) minetest.add_item(pos, drops[dr])
@ -24,6 +20,7 @@ function minetest.check_single_for_falling(pos)
end end
end end
end end
return ret_o or ret return ret_o or ret
end end

View File

@ -12,12 +12,10 @@ under the LGPLv2.1 license.
mcl_explosions = {} mcl_explosions = {}
local mod_fire = minetest.get_modpath("mcl_fire") local mod_fire = minetest.get_modpath("mcl_fire") ~= nil
--local CONTENT_FIRE = minetest.get_content_id("mcl_fire:fire") local CONTENT_FIRE = minetest.get_content_id("mcl_fire:fire")
local math = math local S = minetest.get_translator("mcl_explosions")
local vector = vector
local table = table
local hash_node_position = minetest.hash_node_position local hash_node_position = minetest.hash_node_position
local get_objects_inside_radius = minetest.get_objects_inside_radius local get_objects_inside_radius = minetest.get_objects_inside_radius
@ -28,7 +26,6 @@ local get_voxel_manip = minetest.get_voxel_manip
local bulk_set_node = minetest.bulk_set_node local bulk_set_node = minetest.bulk_set_node
local check_for_falling = minetest.check_for_falling local check_for_falling = minetest.check_for_falling
local add_item = minetest.add_item local add_item = minetest.add_item
local pos_to_string = minetest.pos_to_string
-- Saved sphere explosion shapes for various radiuses -- Saved sphere explosion shapes for various radiuses
local sphere_shapes = {} local sphere_shapes = {}
@ -69,44 +66,46 @@ local function compute_sphere_rays(radius)
local rays = {} local rays = {}
local sphere = {} local sphere = {}
local function add_ray(pos) for i=1, 2 do
sphere[hash_node_position(pos)] = pos
end
for y = -radius, radius do
for z = -radius, radius do
for x = -radius, 0 do
local d = x * x + y * y + z * z
if d <= radius * radius then
add_ray(vector.new(x, y, z))
add_ray(vector.new(-x, y, z))
break
end
end
end
end
for x = -radius, radius do
for z = -radius, radius do
for y = -radius, 0 do
local d = x * x + y * y + z * z
if d <= radius * radius then
add_ray(vector.new(x, y, z))
add_ray(vector.new(x, -y, z))
break
end
end
end
end
for x = -radius, radius do
for y = -radius, radius do for y = -radius, radius do
for z = -radius, 0 do for z = -radius, radius do
local d = x * x + y * y + z * z for x = -radius, 0, 1 do
if d <= radius * radius then local d = x * x + y * y + z * z
add_ray(vector.new(x, y, z)) if d <= radius * radius then
add_ray(vector.new(x, y, -z)) local pos = { x = x, y = y, z = z }
break sphere[hash_node_position(pos)] = pos
break
end
end
end
end
end
for i=1,2 do
for x = -radius, radius do
for z = -radius, radius do
for y = -radius, 0, 1 do
local d = x * x + y * y + z * z
if d <= radius * radius then
local pos = { x = x, y = y, z = z }
sphere[hash_node_position(pos)] = pos
break
end
end
end
end
end
for i=1,2 do
for x = -radius, radius do
for y = -radius, radius do
for z = -radius, 0, 1 do
local d = x * x + y * y + z * z
if d <= radius * radius then
local pos = { x = x, y = y, z = z }
sphere[hash_node_position(pos)] = pos
break
end
end end
end end
end end
@ -177,11 +176,14 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
local ystride = (emax.x - emin_x + 1) local ystride = (emax.x - emin_x + 1)
local zstride = ystride * (emax.y - emin_y + 1) local zstride = ystride * (emax.y - emin_y + 1)
local pos_x = pos.x
local pos_y = pos.y
local pos_z = pos.z
--[[local area = VoxelArea:new { local area = VoxelArea:new {
MinEdge = emin, MinEdge = emin,
MaxEdge = emax MaxEdge = emax
}]] }
local data = vm:get_data() local data = vm:get_data()
local destroy = {} local destroy = {}
@ -245,7 +247,7 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
local ent = obj:get_luaentity() local ent = obj:get_luaentity()
-- Ignore items to lower lag -- Ignore items to lower lag
if (obj:is_player() or (ent and ent.name ~= "__builtin.item")) and obj:get_hp() > 0 then if (obj:is_player() or (ent and ent.name ~= '__builtin.item')) and obj:get_hp() > 0 then
local opos = obj:get_pos() local opos = obj:get_pos()
local collisionbox = nil local collisionbox = nil
@ -258,12 +260,12 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
if collisionbox then if collisionbox then
-- Create rays from random points in the collision box -- Create rays from random points in the collision box
local x1 = collisionbox[1] local x1 = collisionbox[1] * 2
local y1 = collisionbox[2] local y1 = collisionbox[2] * 2
local z1 = collisionbox[3] local z1 = collisionbox[3] * 2
local x2 = collisionbox[4] local x2 = collisionbox[4] * 2
local y2 = collisionbox[5] local y2 = collisionbox[5] * 2
local z2 = collisionbox[6] local z2 = collisionbox[6] * 2
local x_len = math.abs(x2 - x1) local x_len = math.abs(x2 - x1)
local y_len = math.abs(y2 - y1) local y_len = math.abs(y2 - y1)
local z_len = math.abs(z2 - z1) local z_len = math.abs(z2 - z1)
@ -361,9 +363,9 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
local on_blast = node_on_blast[data[idx]] local on_blast = node_on_blast[data[idx]]
local remove = true local remove = true
if do_drop or on_blast then if do_drop or on_blast ~= nil then
local npos = get_position_from_hash(hash) local npos = get_position_from_hash(hash)
if on_blast then if on_blast ~= nil then
on_blast(npos, 1.0, do_drop) on_blast(npos, 1.0, do_drop)
remove = false remove = false
else else
@ -405,7 +407,8 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
end end
-- Log explosion -- Log explosion
minetest.log("action", "Explosion at "..pos_to_string(pos).." with strength "..strength.." and radius "..radius) minetest.log('action', 'Explosion at ' .. minetest.pos_to_string(pos) ..
' with strength ' .. strength .. ' and radius ' .. radius)
end end
-- Create an explosion with strength at pos. -- Create an explosion with strength at pos.

View File

@ -0,0 +1,2 @@
# textdomain:mcl_explosions
@1 was caught in an explosion.=@1 wurde Opfer einer Explosion.

View File

@ -0,0 +1,2 @@
# textdomain:mcl_explosions
@1 was caught in an explosion.=@1 a été pris dans une explosion.

View File

@ -1,2 +0,0 @@
# textdomain:mcl_explosions
@1 was caught in an explosion.=@1 została wysadzona.

View File

@ -0,0 +1,2 @@
# textdomain:mcl_explosions
@1 was caught in an explosion.=@1 не удалось пережить взрыва.

View File

@ -0,0 +1,2 @@
# textdomain:mcl_explosions
@1 was caught in an explosion.=

View File

@ -32,9 +32,9 @@ local singlenode = mg_name == "singlenode"
-- Calculate mapgen_edge_min/mapgen_edge_max -- Calculate mapgen_edge_min/mapgen_edge_max
mcl_vars.chunksize = math.max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5) mcl_vars.chunksize = math.max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5)
mcl_vars.MAP_BLOCKSIZE = math.max(1, minetest.MAP_BLOCKSIZE or 16) mcl_vars.MAP_BLOCKSIZE = math.max(1, core.MAP_BLOCKSIZE or 16)
mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000) mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, minetest.MAX_MAP_GENERATION_LIMIT or 31000) mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, core.MAX_MAP_GENERATION_LIMIT or 31000)
local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2) local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2)
mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
mcl_vars.chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE mcl_vars.chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE

View File

@ -40,9 +40,10 @@ function mcl_loot.get_loot(loot_definitions, pr)
total_weight = total_weight + (loot_definitions.items[i].weight or 1) total_weight = total_weight + (loot_definitions.items[i].weight or 1)
end end
--local stacks_min = loot_definitions.stacks_min or 1 local stacks_min = loot_definitions.stacks_min
--local stacks_max = loot_definitions.stacks_max or 1 local stacks_max = loot_definitions.stacks_max
if not stacks_min then stacks_min = 1 end
if not stacks_max then stacks_max = 1 end
local stacks = pr:next(loot_definitions.stacks_min, loot_definitions.stacks_max) local stacks = pr:next(loot_definitions.stacks_min, loot_definitions.stacks_max)
for s=1, stacks do for s=1, stacks do
local r = pr:next(1, total_weight) local r = pr:next(1, total_weight)

View File

@ -1,12 +1,3 @@
local vector = vector
local table = table
local hash_node_position = minetest.hash_node_position
local add_particlespawner = minetest.add_particlespawner
local delete_particlespawner = minetest.delete_particlespawner
local ipairs = ipairs
mcl_particles = {} mcl_particles = {}
-- Table of particlespawner IDs on a per-node hash basis -- Table of particlespawner IDs on a per-node hash basis
@ -41,11 +32,11 @@ function mcl_particles.add_node_particlespawner(pos, particlespawner_definition,
if allowed_level == 0 or levels[level] > allowed_level then if allowed_level == 0 or levels[level] > allowed_level then
return return
end end
local poshash = hash_node_position(pos) local poshash = minetest.hash_node_position(pos)
if not poshash then if not poshash then
return return
end end
local id = add_particlespawner(particlespawner_definition) local id = minetest.add_particlespawner(particlespawner_definition)
if id == -1 then if id == -1 then
return return
end end
@ -56,8 +47,6 @@ function mcl_particles.add_node_particlespawner(pos, particlespawner_definition,
return id return id
end end
local add_node_particlespawner = mcl_particles.add_node_particlespawner
-- Deletes all particlespawners that are assigned to a node position. -- Deletes all particlespawners that are assigned to a node position.
-- If no particlespawners exist for this position, nothing happens. -- If no particlespawners exist for this position, nothing happens.
-- pos: Node positon. MUST use integer values! -- pos: Node positon. MUST use integer values!
@ -66,11 +55,11 @@ function mcl_particles.delete_node_particlespawners(pos)
if allowed_level == 0 then if allowed_level == 0 then
return false return false
end end
local poshash = hash_node_position(pos) local poshash = minetest.hash_node_position(pos)
local ids = particle_nodes[poshash] local ids = particle_nodes[poshash]
if ids then if ids then
for i=1, #ids do for i=1, #ids do
delete_particlespawner(ids[i]) minetest.delete_particlespawner(ids[i])
end end
particle_nodes[poshash] = nil particle_nodes[poshash] = nil
return true return true
@ -83,6 +72,7 @@ end
local smoke_pdef_cached = {} local smoke_pdef_cached = {}
function mcl_particles.spawn_smoke(pos, name, smoke_pdef_base) function mcl_particles.spawn_smoke(pos, name, smoke_pdef_base)
local min = math.min
local new_minpos = vector.add(pos, smoke_pdef_base.minrelpos) local new_minpos = vector.add(pos, smoke_pdef_base.minrelpos)
local new_maxpos = vector.add(pos, smoke_pdef_base.maxrelpos) local new_maxpos = vector.add(pos, smoke_pdef_base.maxrelpos)
@ -91,7 +81,7 @@ function mcl_particles.spawn_smoke(pos, name, smoke_pdef_base)
for i, smoke_pdef in ipairs(smoke_pdef_cached[name]) do for i, smoke_pdef in ipairs(smoke_pdef_cached[name]) do
smoke_pdef.minpos = new_minpos smoke_pdef.minpos = new_minpos
smoke_pdef.maxpos = new_maxpos smoke_pdef.maxpos = new_maxpos
add_node_particlespawner(pos, smoke_pdef, "high") mcl_particles.add_node_particlespawner(pos, smoke_pdef, "high")
end end
-- cache already populated -- cache already populated
else else
@ -121,11 +111,13 @@ function mcl_particles.spawn_smoke(pos, name, smoke_pdef_base)
smoke_pdef.animation.length = exptime + 0.1 smoke_pdef.animation.length = exptime + 0.1
-- minexptime must be set such that the last frame is actully rendered, -- minexptime must be set such that the last frame is actully rendered,
-- even if its very short. Larger exptime -> larger range -- even if its very short. Larger exptime -> larger range
smoke_pdef.minexptime = math.min(exptime, (7.0/8.0 * (exptime + 0.1) + 0.1)) smoke_pdef.minexptime = min(exptime, (7.0/8.0 * (exptime + 0.1) + 0.1))
smoke_pdef.texture = "mcl_particles_smoke_anim.png^[colorize:#000000:" ..colorize smoke_pdef.texture = "mcl_particles_smoke_anim.png^[colorize:#000000:" ..colorize
add_node_particlespawner(pos, smoke_pdef, "high")
mcl_particles.add_node_particlespawner(pos, smoke_pdef, "high")
table.insert(smoke_pdef_cached[name], table.copy(smoke_pdef)) table.insert(smoke_pdef_cached[name], table.copy(smoke_pdef))
end end
end end
end end
end end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 B

View File

@ -1,27 +1,5 @@
mcl_util = {} 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
t[k] = v
end
end
return t
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
if t[k] == nil then
t[k] = v
end
end
end
return t
end
-- Based on minetest.rotate_and_place -- Based on minetest.rotate_and_place
--[[ --[[
@ -172,7 +150,7 @@ function mcl_util.get_eligible_transfer_item_slot(src_inventory, src_list, dst_i
end end
-- Returns true if itemstack is a shulker box -- Returns true if itemstack is a shulker box
local function is_not_shulker_box(itemstack) local is_not_shulker_box = function(itemstack)
local g = minetest.get_item_group(itemstack:get_name(), "shulker_box") local g = minetest.get_item_group(itemstack:get_name(), "shulker_box")
return g == 0 or g == nil return g == 0 or g == nil
end end
@ -234,7 +212,7 @@ function mcl_util.move_item_container(source_pos, destination_pos, source_list,
end end
-- Normalize double container by forcing to always use the left segment first -- Normalize double container by forcing to always use the left segment first
local function normalize_double_container(pos, node, ctype) local normalize_double_container = function(pos, node, ctype)
if ctype == 6 then if ctype == 6 then
pos = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right") pos = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
if not pos then if not pos then
@ -478,7 +456,14 @@ function mcl_util.calculate_durability(itemstack)
end end
end end
end end
uses = uses or (next(itemstack:get_tool_capabilities().groupcaps) or {}).uses if not uses then
local toolcaps = itemstack:get_tool_capabilities()
local groupcaps = toolcaps.groupcaps
for _, v in pairs(groupcaps) do
uses = v.uses
break
end
end
end end
return uses or 0 return uses or 0
@ -560,12 +545,3 @@ function mcl_util.get_object_name(object)
return luaentity.nametag and luaentity.nametag ~= "" and luaentity.nametag or luaentity.description or luaentity.name return luaentity.nametag and luaentity.nametag ~= "" and luaentity.nametag or luaentity.description or luaentity.name
end end
end end
function mcl_util.replace_mob(obj, mob)
local rot = obj:get_yaw()
local pos = obj:get_pos()
obj:remove()
obj = minetest.add_entity(pos, mob)
obj:set_yaw(rot)
return obj
end

View File

@ -12,7 +12,7 @@ Params:
* pos: position * pos: position
## mcl_worlds.y_to_layer(y) ## mcl_worlds.y_to_layer(y)
This function is used to calculate the minetest y layer and dimension of the given <y> minecraft layer. This function is used to calculate the minetest y layer and dimension of the given <y> minecraft layer.
Mainly used for ore generation. Mainly used for ore generation.
Takes an Y coordinate as input and returns: Takes an Y coordinate as input and returns:
@ -61,21 +61,20 @@ In mc, you cant use clock in the nether and the end.
* pos: position * pos: position
## mcl_worlds.register_on_dimension_change(function(player, dimension, last_dimension)) ## mcl_worlds.register_on_dimension_change(function(player, dimension))
Register a callback function func(player, dimension). Register a callback function func(player, dimension).
It will be called whenever a player changes between dimensions. It will be called whenever a player changes between dimensions.
The void counts as dimension. The void counts as dimension.
* player: player, the player who changed of dimension * player: player, the player who changed the dimension
* dimension: string, The new dimension of the player ("overworld", "nether", "end", "void"). * dimension: position, The new dimension of the player ("overworld", "nether", "end", "void").
* last_dimension: string, The dimension where the player was ("overworld", "nether", "end", "void").
## mcl_worlds.registered_on_dimension_change ## mcl_worlds.registered_on_dimension_change
Table containing all function registered with mcl_worlds.register_on_dimension_change() Table containing all function registered with mcl_worlds.register_on_dimension_change()
## mcl_worlds.dimension_change(player, dimension) ## mcl_worlds.dimension_change(player, dimension)
Notify this mod of a dimension change of <player> to <dimension> Notify this mod of a dimmension change of <player> to <dimension>
* player: player, player who changed the dimension * player: player, player who changed the dimension
* dimension: string, new dimension ("overworld", "nether", "end", "void") * dimension: string, new dimension ("overworld", "nether", "end", "void")

View File

@ -1,7 +1,5 @@
mcl_worlds = {} mcl_worlds = {}
local get_connected_players = minetest.get_connected_players
-- For a given position, returns a 2-tuple: -- For a given position, returns a 2-tuple:
-- 1st return value: true if pos is in void -- 1st return value: true if pos is in void
-- 2nd return value: true if it is in the deadly part of the void -- 2nd return value: true if it is in the deadly part of the void
@ -35,64 +33,60 @@ end
-- If the Y coordinate is not located in any dimension, it will return: -- If the Y coordinate is not located in any dimension, it will return:
-- nil, "void" -- nil, "void"
function mcl_worlds.y_to_layer(y) function mcl_worlds.y_to_layer(y)
if y >= mcl_vars.mg_overworld_min then if y >= mcl_vars.mg_overworld_min then
return y - mcl_vars.mg_overworld_min, "overworld" return y - mcl_vars.mg_overworld_min, "overworld"
elseif y >= mcl_vars.mg_nether_min and y <= mcl_vars.mg_nether_max+128 then elseif y >= mcl_vars.mg_nether_min and y <= mcl_vars.mg_nether_max+128 then
return y - mcl_vars.mg_nether_min, "nether" return y - mcl_vars.mg_nether_min, "nether"
elseif y >= mcl_vars.mg_end_min and y <= mcl_vars.mg_end_max then elseif y >= mcl_vars.mg_end_min and y <= mcl_vars.mg_end_max then
return y - mcl_vars.mg_end_min, "end" return y - mcl_vars.mg_end_min, "end"
else else
return nil, "void" return nil, "void"
end end
end end
local y_to_layer = mcl_worlds.y_to_layer
-- Takes a pos and returns the dimension it belongs to (same as above) -- Takes a pos and returns the dimension it belongs to (same as above)
function mcl_worlds.pos_to_dimension(pos) function mcl_worlds.pos_to_dimension(pos)
local _, dim = y_to_layer(pos.y) local _, dim = mcl_worlds.y_to_layer(pos.y)
return dim return dim
end end
local pos_to_dimension = mcl_worlds.pos_to_dimension
-- Takes a Minecraft layer and a “dimension” name -- Takes a Minecraft layer and a “dimension” name
-- and returns the corresponding Y coordinate for -- and returns the corresponding Y coordinate for
-- MineClone 2. -- MineClone 2.
-- mc_dimension is one of "overworld", "nether", "end" (default: "overworld"). -- mc_dimension is one of "overworld", "nether", "end" (default: "overworld").
function mcl_worlds.layer_to_y(layer, mc_dimension) function mcl_worlds.layer_to_y(layer, mc_dimension)
if mc_dimension == "overworld" or mc_dimension == nil then if mc_dimension == "overworld" or mc_dimension == nil then
return layer + mcl_vars.mg_overworld_min return layer + mcl_vars.mg_overworld_min
elseif mc_dimension == "nether" then elseif mc_dimension == "nether" then
return layer + mcl_vars.mg_nether_min return layer + mcl_vars.mg_nether_min
elseif mc_dimension == "end" then elseif mc_dimension == "end" then
return layer + mcl_vars.mg_end_min return layer + mcl_vars.mg_end_min
end end
end end
-- Takes a position and returns true if this position can have weather -- Takes a position and returns true if this position can have weather
function mcl_worlds.has_weather(pos) function mcl_worlds.has_weather(pos)
-- Weather in the Overworld and the high part of the void below -- Weather in the Overworld and the high part of the void below
return pos.y <= mcl_vars.mg_overworld_max and pos.y >= mcl_vars.mg_overworld_min - 64 return pos.y <= mcl_vars.mg_overworld_max and pos.y >= mcl_vars.mg_overworld_min - 64
end end
-- Takes a position and returns true if this position can have Nether dust -- Takes a position and returns true if this position can have Nether dust
function mcl_worlds.has_dust(pos) function mcl_worlds.has_dust(pos)
-- Weather in the Overworld and the high part of the void below -- Weather in the Overworld and the high part of the void below
return pos.y <= mcl_vars.mg_nether_max + 138 and pos.y >= mcl_vars.mg_nether_min - 10 return pos.y <= mcl_vars.mg_nether_max + 138 and pos.y >= mcl_vars.mg_nether_min - 10
end end
-- Takes a position (pos) and returns true if compasses are working here -- Takes a position (pos) and returns true if compasses are working here
function mcl_worlds.compass_works(pos) function mcl_worlds.compass_works(pos)
-- It doesn't work in Nether and the End, but it works in the Overworld and in the high part of the void below -- It doesn't work in Nether and the End, but it works in the Overworld and in the high part of the void below
local _, dim = mcl_worlds.y_to_layer(pos.y) local _, dim = mcl_worlds.y_to_layer(pos.y)
if dim == "nether" or dim == "end" then if dim == "nether" or dim == "end" then
return false return false
elseif dim == "void" then elseif dim == "void" then
return pos.y <= mcl_vars.mg_overworld_max and pos.y >= mcl_vars.mg_overworld_min - 64 return pos.y <= mcl_vars.mg_overworld_max and pos.y >= mcl_vars.mg_overworld_min - 64
else else
return true return true
end end
end end
-- Takes a position (pos) and returns true if clocks are working here -- Takes a position (pos) and returns true if clocks are working here
@ -118,15 +112,12 @@ local last_dimension = {}
-- * player: Player who changed the dimension -- * player: Player who changed the dimension
-- * dimension: New dimension ("overworld", "nether", "end", "void") -- * dimension: New dimension ("overworld", "nether", "end", "void")
function mcl_worlds.dimension_change(player, dimension) function mcl_worlds.dimension_change(player, dimension)
local playername = player:get_player_name()
for i=1, #mcl_worlds.registered_on_dimension_change do for i=1, #mcl_worlds.registered_on_dimension_change do
mcl_worlds.registered_on_dimension_change[i](player, dimension, last_dimension[playername]) mcl_worlds.registered_on_dimension_change[i](player, dimension)
last_dimension[player:get_player_name()] = dimension
end end
last_dimension[playername] = dimension
end end
local dimension_change = mcl_worlds.dimension_change
----------------------- INTERNAL STUFF ---------------------- ----------------------- INTERNAL STUFF ----------------------
-- Update the dimension callbacks every DIM_UPDATE seconds -- Update the dimension callbacks every DIM_UPDATE seconds
@ -134,19 +125,19 @@ local DIM_UPDATE = 1
local dimtimer = 0 local dimtimer = 0
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
last_dimension[player:get_player_name()] = pos_to_dimension(player:get_pos()) last_dimension[player:get_player_name()] = mcl_worlds.pos_to_dimension(player:get_pos())
end) end)
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
-- regular updates based on iterval -- regular updates based on iterval
dimtimer = dimtimer + dtime; dimtimer = dimtimer + dtime;
if dimtimer >= DIM_UPDATE then if dimtimer >= DIM_UPDATE then
local players = get_connected_players() local players = minetest.get_connected_players()
for p = 1, #players do for p=1, #players do
local dim = pos_to_dimension(players[p]:get_pos()) local dim = mcl_worlds.pos_to_dimension(players[p]:get_pos())
local name = players[p]:get_player_name() local name = players[p]:get_player_name()
if dim ~= last_dimension[name] then if dim ~= last_dimension[name] then
dimension_change(players[p], dim) mcl_worlds.dimension_change(players[p], dim)
end end
end end
dimtimer = 0 dimtimer = 0

View File

@ -38,32 +38,18 @@ function image:encode_header()
self.data = self.data self.data = self.data
.. string.char(0) -- image id .. string.char(0) -- image id
.. string.char(0) -- color map type .. string.char(0) -- color map type
.. string.char(10) -- image type (RLE RGB = 10) .. string.char(2) -- image type (uncompressed true-color image = 2)
self:encode_colormap_spec() -- color map specification self:encode_colormap_spec() -- color map specification
self:encode_image_spec() -- image specification self:encode_image_spec() -- image specification
end end
function image:encode_data() function image:encode_data()
local current_pixel = ''
local previous_pixel = ''
local count = 1
local packets = {}
local rle_packet = ''
for _, row in ipairs(self.pixels) do for _, row in ipairs(self.pixels) do
for _, pixel in ipairs(row) do for _, pixel in ipairs(row) do
current_pixel = string.char(pixel[3], pixel[2], pixel[1]) self.data = self.data
if current_pixel ~= previous_pixel or count == 128 then .. string.char(pixel[3], pixel[2], pixel[1])
packets[#packets +1] = rle_packet
count = 1
previous_pixel = current_pixel
else
count = count + 1
end
rle_packet = string.char(128 + count - 1) .. current_pixel
end end
end end
packets[#packets +1] = rle_packet
self.data = self.data .. table.concat(packets)
end end
function image:encode_footer() function image:encode_footer()

View File

@ -4,7 +4,6 @@ local get_connected_players = minetest.get_connected_players
local get_node = minetest.get_node local get_node = minetest.get_node
local vector_add = vector.add local vector_add = vector.add
local ceil = math.ceil local ceil = math.ceil
local pairs = pairs
walkover = {} walkover = {}
walkover.registered_globals = {} walkover.registered_globals = {}
@ -32,21 +31,24 @@ minetest.register_globalstep(function(dtime)
timer = timer + dtime; timer = timer + dtime;
if timer >= 0.3 then if timer >= 0.3 then
for _,player in pairs(get_connected_players()) do for _,player in pairs(get_connected_players()) do
local pp = player:get_pos() local pp = player:get_pos()
pp.y = ceil(pp.y) pp.y = ceil(pp.y)
local loc = vector_add(pp, {x=0,y=-1,z=0}) local loc = vector_add(pp, {x=0,y=-1,z=0})
if loc then if loc ~= nil then
local nodeiamon = get_node(loc)
if nodeiamon then local nodeiamon = get_node(loc)
if on_walk[nodeiamon.name] then
on_walk[nodeiamon.name](loc, nodeiamon, player) if nodeiamon ~= nil then
end if on_walk[nodeiamon.name] then
for i = 1, #registered_globals do on_walk[nodeiamon.name](loc, nodeiamon, player)
end
for i = 1, #registered_globals do
registered_globals[i](loc, nodeiamon, player) registered_globals[i](loc, nodeiamon, player)
end end
end end
end end
end end
timer = 0 timer = 0
end end
end) end)

View File

@ -0,0 +1,125 @@
--Dripping Water Mod
--by kddekadenz
-- License of code, textures & sounds: CC0
--Drop entities
--water
local water_tex = "default_water_source_animated.png^[verticalframe:16:0"
minetest.register_entity("drippingwater:drop_water", {
hp_max = 1,
physical = true,
collide_with_objects = false,
collisionbox = {-0.025,-0.05,-0.025,0.025,-0.01,0.025},
pointable = false,
visual = "cube",
visual_size = {x=0.05, y=0.1},
textures = {water_tex, water_tex, water_tex, water_tex, water_tex, water_tex},
spritediv = {x=1, y=1},
initial_sprite_basepos = {x=0, y=0},
static_save = false,
on_activate = function(self, staticdata)
self.object:set_sprite({x=0,y=0}, 1, 1, true)
end,
on_step = function(self, dtime)
local k = math.random(1,222)
local ownpos = self.object:get_pos()
if k==1 then
self.object:set_acceleration({x=0, y=-5, z=0})
end
if minetest.get_node({x=ownpos.x, y=ownpos.y +0.5, z=ownpos.z}).name == "air" then
self.object:set_acceleration({x=0, y=-5, z=0})
end
if minetest.get_node({x=ownpos.x, y=ownpos.y -0.5, z=ownpos.z}).name ~= "air" then
self.object:remove()
minetest.sound_play({name="drippingwater_drip"}, {pos = ownpos, gain = 0.5, max_hear_distance = 8}, true)
end
end,
})
--lava
local lava_tex = "default_lava_source_animated.png^[verticalframe:16:0"
minetest.register_entity("drippingwater:drop_lava", {
hp_max = 1,
physical = true,
collide_with_objects = false,
collisionbox = {-0.025,-0.05,-0.025,0.025,-0.01,0.025},
glow = math.max(7, minetest.registered_nodes["mcl_core:lava_source"].light_source - 3),
pointable = false,
visual = "cube",
visual_size = {x=0.05, y=0.1},
textures = {lava_tex, lava_tex, lava_tex, lava_tex, lava_tex, lava_tex},
spritediv = {x=1, y=1},
initial_sprite_basepos = {x=0, y=0},
static_save = false,
on_activate = function(self, staticdata)
self.object:set_sprite({x=0,y=0}, 1, 0, true)
end,
on_step = function(self, dtime)
local k = math.random(1,222)
local ownpos = self.object:get_pos()
if k==1 then
self.object:set_acceleration({x=0, y=-5, z=0})
end
if minetest.get_node({x=ownpos.x, y=ownpos.y +0.5, z=ownpos.z}).name == "air" then
self.object:set_acceleration({x=0, y=-5, z=0})
end
if minetest.get_node({x=ownpos.x, y=ownpos.y -0.5, z=ownpos.z}).name ~= "air" then
self.object:remove()
minetest.sound_play({name="drippingwater_lavadrip"}, {pos = ownpos, gain = 0.5, max_hear_distance = 8}, true)
end
end,
})
--Create drop
minetest.register_abm(
{
label = "Create water drops",
nodenames = {"group:opaque", "group:leaves"},
neighbors = {"group:water"},
interval = 2,
chance = 22,
action = function(pos)
if minetest.get_item_group(minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name, "water") ~= 0 and
minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == "air" then
local i = math.random(-45,45) / 100
minetest.add_entity({x=pos.x + i, y=pos.y - 0.501, z=pos.z + i}, "drippingwater:drop_water")
end
end,
})
--Create lava drop
minetest.register_abm(
{
label = "Create lava drops",
nodenames = {"group:opaque"},
neighbors = {"group:lava"},
interval = 2,
chance = 22,
action = function(pos)
if minetest.get_item_group(minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name, "lava") ~= 0 and
minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == "air" then
local i = math.random(-45,45) / 100
minetest.add_entity({x=pos.x + i, y=pos.y - 0.501, z=pos.z + i}, "drippingwater:drop_lava")
end
end,
})

View File

@ -1,4 +1,4 @@
name = mcl_dripping name = drippingwater
author = kddekadenz author = kddekadenz
description = Drops are generated rarely under solid nodes description = Drops are generated rarely under solid nodes
depends = mcl_core depends = mcl_core

View File

@ -1,12 +1,12 @@
Dripping Mod Dripping Water Mod
by kddekadenz by kddekadenz
modified for MineClone 2 by Wuzzy and NO11 modified for MineClone 2 by Wuzzy
Installing instructions: Installing instructions:
1. Copy the mcl_dripping mod folder into games/gamemode/mods 1. Copy the drippingwater mod folder into games/gamemode/mods
2. Start game and enjoy :) 2. Start game and enjoy :)

View File

@ -1,4 +1,4 @@
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator("mcl_boats")
local boat_visual_size = {x = 1, y = 1, z = 1} local boat_visual_size = {x = 1, y = 1, z = 1}
local paddling_speed = 22 local paddling_speed = 22
@ -84,7 +84,7 @@ local function attach_object(self, obj)
end end
end, name) end, name)
obj:set_look_horizontal(yaw) obj:set_look_horizontal(yaw)
mcl_title.set(obj, "actionbar", {text=S("Sneak to dismount"), color="white", stay=60}) mcl_tmp_message.message(obj, S("Sneak to dismount"))
else else
obj:get_luaentity()._old_visual_size = visual_size obj:get_luaentity()._old_visual_size = visual_size
end end
@ -115,7 +115,7 @@ local boat = {
collisionbox = {-0.5, -0.35, -0.5, 0.5, 0.3, 0.5}, collisionbox = {-0.5, -0.35, -0.5, 0.5, 0.3, 0.5},
visual = "mesh", visual = "mesh",
mesh = "mcl_boats_boat.b3d", mesh = "mcl_boats_boat.b3d",
textures = {"mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png"}, textures = {"mcl_boats_texture_oak_boat.png"},
visual_size = boat_visual_size, visual_size = boat_visual_size,
hp_max = boat_max_hp, hp_max = boat_max_hp,
damage_texture_modifier = "^[colorize:white:0", damage_texture_modifier = "^[colorize:white:0",
@ -148,11 +148,6 @@ function boat.on_activate(self, staticdata, dtime_s)
self._v = data.v self._v = data.v
self._last_v = self._v self._last_v = self._v
self._itemstring = data.itemstring self._itemstring = data.itemstring
while #data.textures < 5 do
table.insert(data.textures, data.textures[1])
end
self.object:set_properties({textures = data.textures}) self.object:set_properties({textures = data.textures})
end end
end end
@ -333,17 +328,16 @@ function boat.on_step(self, dtime, moveresult)
p.y = p.y - boat_y_offset p.y = p.y - boat_y_offset
local new_velo local new_velo
local new_acce local new_acce = {x = 0, y = 0, z = 0}
if not is_water(p) and not on_ice then if not is_water(p) and not on_ice then
-- Not on water or inside water: Free fall -- Not on water or inside water: Free fall
--local nodedef = minetest.registered_nodes[minetest.get_node(p).name] local nodedef = minetest.registered_nodes[minetest.get_node(p).name]
new_acce = {x = 0, y = -9.8, z = 0} new_acce = {x = 0, y = -9.8, z = 0}
new_velo = get_velocity(self._v, self.object:get_yaw(), new_velo = get_velocity(self._v, self.object:get_yaw(),
self.object:get_velocity().y) self.object:get_velocity().y)
else else
p.y = p.y + 1 p.y = p.y + 1
local is_obsidian_boat = self.object:get_luaentity()._itemstring == "mcl_boats:boat_obsidian" if is_water(p) then
if is_water(p) or is_obsidian_boat then
-- Inside water: Slowly sink -- Inside water: Slowly sink
local y = self.object:get_velocity().y local y = self.object:get_velocity().y
y = y - 0.01 y = y - 0.01
@ -383,13 +377,13 @@ end
-- Register one entity for all boat types -- Register one entity for all boat types
minetest.register_entity("mcl_boats:boat", boat) minetest.register_entity("mcl_boats:boat", boat)
local boat_ids = { "boat", "boat_spruce", "boat_birch", "boat_jungle", "boat_acacia", "boat_dark_oak", "boat_obsidian" } local boat_ids = { "boat", "boat_spruce", "boat_birch", "boat_jungle", "boat_acacia", "boat_dark_oak" }
local names = { S("Oak Boat"), S("Spruce Boat"), S("Birch Boat"), S("Jungle Boat"), S("Acacia Boat"), S("Dark Oak Boat"), S("Obsidian Boat") } local names = { S("Oak Boat"), S("Spruce Boat"), S("Birch Boat"), S("Jungle Boat"), S("Acacia Boat"), S("Dark Oak Boat") }
local craftstuffs = {} local craftstuffs = {}
if minetest.get_modpath("mcl_core") then if minetest.get_modpath("mcl_core") then
craftstuffs = { "mcl_core:wood", "mcl_core:sprucewood", "mcl_core:birchwood", "mcl_core:junglewood", "mcl_core:acaciawood", "mcl_core:darkwood", "mcl_core:obsidian" } craftstuffs = { "mcl_core:wood", "mcl_core:sprucewood", "mcl_core:birchwood", "mcl_core:junglewood", "mcl_core:acaciawood", "mcl_core:darkwood" }
end end
local images = { "oak", "spruce", "birch", "jungle", "acacia", "dark_oak", "obsidian" } local images = { "oak", "spruce", "birch", "jungle", "acacia", "dark_oak" }
for b=1, #boat_ids do for b=1, #boat_ids do
local itemstring = "mcl_boats:"..boat_ids[b] local itemstring = "mcl_boats:"..boat_ids[b]
@ -440,9 +434,8 @@ for b=1, #boat_ids do
pos = vector.add(pos, vector.multiply(dir, boat_y_offset_ground)) pos = vector.add(pos, vector.multiply(dir, boat_y_offset_ground))
end end
local boat = minetest.add_entity(pos, "mcl_boats:boat") local boat = minetest.add_entity(pos, "mcl_boats:boat")
local texture = "mcl_boats_texture_"..images[b].."_boat.png"
boat:get_luaentity()._itemstring = itemstring boat:get_luaentity()._itemstring = itemstring
boat:set_properties({textures = { texture, texture, texture, texture, texture }}) boat:set_properties({textures = { "mcl_boats_texture_"..images[b].."_boat.png" }})
boat:set_yaw(placer:get_look_horizontal()) boat:set_yaw(placer:get_look_horizontal())
if not minetest.is_creative_enabled(placer:get_player_name()) then if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item() itemstack:take_item()
@ -477,6 +470,6 @@ minetest.register_craft({
burntime = 20, burntime = 20,
}) })
if minetest.get_modpath("doc_identifier") then if minetest.get_modpath("doc_identifier") ~= nil then
doc.sub.identifier.register_object("mcl_boats:boat", "craftitems", "mcl_boats:boat") doc.sub.identifier.register_object("mcl_boats:boat", "craftitems", "mcl_boats:boat")
end end

View File

@ -6,7 +6,6 @@ Boats are used to travel on the surface of water.=Les bateaux sont utilisés pou
Dark Oak Boat=Bateau en Chêne Noir Dark Oak Boat=Bateau en Chêne Noir
Jungle Boat=Bateau en Acajou Jungle Boat=Bateau en Acajou
Oak Boat=Bateau en Chêne Oak Boat=Bateau en Chêne
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Use [Sneak] to leave the boat, punch the boat to make it drop as an item.=Faites un clic droit sur une source d'eau pour placer le bateau. Faites un clic droit sur le bateau pour y entrer. Utilisez [Gauche] et [Droite] pour diriger, [Avant] pour accélérer et [Arrière] pour ralentir ou reculer. Utilisez [Sneak] pour le quitter, frappez le bateau pour le faire tomber en tant qu'objet. Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Rightclick the boat again to leave it, 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. Cliquez de nouveau avec le bouton droit sur le bateau pour le quitter, frappez le bateau pour le faire tomber en tant qu'objet.
Spruce Boat=Bateau en Sapin Spruce Boat=Bateau en Sapin
Water vehicle=Véhicule aquatique Water vehicle=Véhicule aquatique
Sneak to dismount=

View File

@ -1,12 +0,0 @@
# textdomain: mcl_boats
Acacia Boat=Akacjowa łódź
Birch Boat=Brzozowa łódź
Boat=Łódź
Boats are used to travel on the surface of water.=Łodzie są wykorzystywane do podróżowania po powierzchni wody.
Dark Oak Boat=Ciemno-dębowa łódź
Jungle Boat=Tropikalna łódź
Oak Boat=Dębowa łó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.=Kliknij prawym przyciskiem myszy na źródło wody by postawić łódź. Kliknij prawym przyciskiem myszy by w nią wsiąść. Użyj przycisków [Lewy] oraz [Prawy] by sterować, [Naprzód] by przyspieszyć i [W tył] by zwolnić lub się cofać. Kliknij [Skradanie] by z niej wyjść, uderz ją by wziąć ją jako przedmiot.
Spruce Boat=Świerkowa łódź
Water vehicle=Pojazd wodny
Sneak to dismount=Skradaj się by opuścić łódź

View File

@ -1,7 +1,7 @@
name = mcl_boats name = mcl_boats
author = PilzAdam author = PilzAdam
description = Adds drivable boats. description = Adds drivable boats.
depends = mcl_player, flowlib, mcl_title depends = mcl_player, flowlib
optional_depends = mcl_core, doc_identifier optional_depends = mcl_core, doc_identifier

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 535 B

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator("mcl_burning")
function mcl_burning.get_storage(obj) function mcl_burning.get_storage(obj)
return obj:is_player() and mcl_burning.storage[obj] or obj:get_luaentity() return obj:is_player() and mcl_burning.storage[obj] or obj:get_luaentity()
end end
@ -67,9 +69,14 @@ function mcl_burning.set_on_fire(obj, burn_time)
end end
if not storage.burn_time or burn_time >= storage.burn_time then if not storage.burn_time or burn_time >= storage.burn_time then
if obj:is_player() then if obj:is_player() and not storage.fire_hud_id then
mcl_burning.channels[obj]:send_all(tostring(mcl_burning.animation_frames)) storage.fire_hud_id = obj:hud_add({
mcl_burning.channels[obj]:send_all("start") hud_elem_type = "image",
position = {x = 0.5, y = 0.5},
scale = {x = -100, y = -100},
text = "mcl_burning_entity_flame_animated.png^[opacity:180^[verticalframe:" .. mcl_burning.animation_frames .. ":" .. 1,
z_index = 1000,
})
end end
storage.burn_time = burn_time storage.burn_time = burn_time
storage.fire_damage_timer = 0 storage.fire_damage_timer = 0
@ -90,6 +97,7 @@ function mcl_burning.set_on_fire(obj, burn_time)
fire_entity:set_properties({visual_size = size}) fire_entity:set_properties({visual_size = size})
fire_entity:set_attach(obj, "", offset, {x = 0, y = 0, z = 0}) fire_entity:set_attach(obj, "", offset, {x = 0, y = 0, z = 0})
local fire_luaentity = fire_entity:get_luaentity() local fire_luaentity = fire_entity:get_luaentity()
fire_luaentity:update_frame(obj, storage)
for _, other in pairs(minetest.get_objects_inside_radius(fire_entity:get_pos(), 0)) do for _, other in pairs(minetest.get_objects_inside_radius(fire_entity:get_pos(), 0)) do
local other_luaentity = other:get_luaentity() local other_luaentity = other:get_luaentity()
@ -105,7 +113,9 @@ function mcl_burning.extinguish(obj)
if mcl_burning.is_burning(obj) then if mcl_burning.is_burning(obj) then
local storage = mcl_burning.get_storage(obj) local storage = mcl_burning.get_storage(obj)
if obj:is_player() then if obj:is_player() then
mcl_burning.channels[obj]:send_all("stop") if storage.fire_hud_id then
obj:hud_remove(storage.fire_hud_id)
end
mcl_burning.storage[obj] = {} mcl_burning.storage[obj] = {}
else else
storage.burn_time = nil storage.burn_time = nil

View File

@ -1,20 +1,15 @@
local modpath = minetest.get_modpath(minetest.get_current_modname()) local S = minetest.get_translator("mcl_burning")
local modpath = minetest.get_modpath("mcl_burning")
local pairs = pairs
local get_connected_players = minetest.get_connected_players
local get_item_group = minetest.get_item_group
mcl_burning = { mcl_burning = {
storage = {}, storage = {},
channels = {},
animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8 animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8
} }
dofile(modpath .. "/api.lua") dofile(modpath .. "/api.lua")
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
for _, player in pairs(get_connected_players()) do for _, player in pairs(minetest.get_connected_players()) do
local storage = mcl_burning.storage[player] local storage = mcl_burning.storage[player]
if not mcl_burning.tick(player, dtime, storage) and not mcl_burning.is_affected_by_rain(player) then if not mcl_burning.tick(player, dtime, storage) and not mcl_burning.is_affected_by_rain(player) then
local nodes = mcl_burning.get_touching_nodes(player, {"group:puts_out_fire", "group:set_on_fire"}, storage) local nodes = mcl_burning.get_touching_nodes(player, {"group:puts_out_fire", "group:set_on_fire"}, storage)
@ -22,12 +17,12 @@ minetest.register_globalstep(function(dtime)
for _, pos in pairs(nodes) do for _, pos in pairs(nodes) do
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
if get_item_group(node.name, "puts_out_fire") > 0 then if minetest.get_item_group(node.name, "puts_out_fire") > 0 then
burn_time = 0 burn_time = 0
break break
end end
local value = get_item_group(node.name, "set_on_fire") local value = minetest.get_item_group(node.name, "set_on_fire")
if value > burn_time then if value > burn_time then
burn_time = value burn_time = value
end end
@ -44,22 +39,24 @@ minetest.register_on_respawnplayer(function(player)
mcl_burning.extinguish(player) mcl_burning.extinguish(player)
end) end)
function mcl_burning.init_player(player)
local meta = player:get_meta()
-- NOTE: mcl_burning:data may be "return nil" (which deserialize into nil) for reasons unknown.
if meta:get_string("mcl_burning:data"):find("return nil", 1, true) then
minetest.log("warning", "[mcl_burning] 'mcl_burning:data' player meta field is invalid! Please report this bug")
end
mcl_burning.storage[player] = meta:contains("mcl_burning:data") and minetest.deserialize(meta:get_string("mcl_burning:data")) or {}
mcl_burning.channels[player] = minetest.mod_channel_join("mcl_burning:" .. player:get_player_name())
end
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
mcl_burning.init_player(player) local storage
local burn_data = player:get_meta():get_string("mcl_burning:data")
if burn_data == "" then
storage = {}
else
storage = minetest.deserialize(burn_data)
end
mcl_burning.storage[player] = storage
end) end)
minetest.register_on_leaveplayer(function(player) minetest.register_on_leaveplayer(function(player)
player:get_meta():set_string("mcl_burning:data", minetest.serialize(mcl_burning.storage[player])) local storage = mcl_burning.storage[player]
storage.fire_hud_id = nil
player:get_meta():set_string("mcl_burning:data", minetest.serialize(storage))
mcl_burning.storage[player] = nil mcl_burning.storage[player] = nil
end) end)
@ -68,28 +65,28 @@ minetest.register_entity("mcl_burning:fire", {
initial_properties = { initial_properties = {
physical = false, physical = false,
collisionbox = {0, 0, 0, 0, 0, 0}, collisionbox = {0, 0, 0, 0, 0, 0},
visual = "upright_sprite", visual = "cube",
textures = {
name = "mcl_burning_entity_flame_animated.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},
},
spritediv = {x = 1, y = mcl_burning.animation_frames},
pointable = false, pointable = false,
glow = -1, glow = -1,
backface_culling = false,
}, },
animation_frame = 0, animation_frame = 0,
animation_timer = 0, animation_timer = 0,
on_activate = function(self)
self.object:set_sprite({x = 0, y = 0}, mcl_burning.animation_frames, 1.0 / mcl_burning.animation_frames) on_step = function(self, dtime)
end, local parent, storage = self:sanity_check()
on_step = function(self)
if not self:sanity_check() then if parent then
self.animation_timer = self.animation_timer + dtime
if self.animation_timer >= 0.1 then
self.animation_timer = 0
self.animation_frame = self.animation_frame + 1
if self.animation_frame > mcl_burning.animation_frames - 1 then
self.animation_frame = 0
end
self:update_frame(parent, storage)
end
else
self.object:remove() self.object:remove()
end end
end, end,
@ -97,15 +94,23 @@ minetest.register_entity("mcl_burning:fire", {
local parent = self.object:get_attach() local parent = self.object:get_attach()
if not parent then if not parent then
return false return
end end
local storage = mcl_burning.get_storage(parent) local storage = mcl_burning.get_storage(parent)
if not storage or not storage.burn_time then if not storage or not storage.burn_time then
return false return
end end
return true return parent, storage
end,
update_frame = function(self, parent, storage)
local frame_overlay = "^[opacity:180^[verticalframe:" .. mcl_burning.animation_frames .. ":" .. self.animation_frame
local fire_texture = "mcl_burning_entity_flame_animated.png" .. frame_overlay
self.object:set_properties({textures = {"blank.png", "blank.png", fire_texture, fire_texture, fire_texture, fire_texture}})
if parent:is_player() then
parent:hud_change(storage.fire_hud_id, "text", "mcl_burning_hud_flame_animated.png" .. frame_overlay)
end
end, end,
}) })

View File

@ -1,66 +0,0 @@
-- Dripping Water Mod
-- by kddekadenz
local math = math
-- License of code, textures & sounds: CC0
local function register_drop(liquid, glow, sound, nodes)
minetest.register_entity("mcl_dripping:drop_" .. liquid, {
hp_max = 1,
physical = true,
collide_with_objects = false,
collisionbox = {-0.01, 0.01, -0.01, 0.01, 0.01, 0.01},
glow = glow,
pointable = false,
visual = "sprite",
visual_size = {x = 0.1, y = 0.1},
textures = {""},
spritediv = {x = 1, y = 1},
initial_sprite_basepos = {x = 0, y = 0},
static_save = false,
_dropped = false,
on_activate = function(self)
self.object:set_properties({
textures = {"[combine:2x2:" .. -math.random(1, 16) .. "," .. -math.random(1, 16) .. "=default_" .. liquid .. "_source_animated.png"}
})
end,
on_step = function(self, dtime)
local k = math.random(1, 222)
local ownpos = self.object:get_pos()
if k == 1 then
self.object:set_acceleration(vector.new(0, -5, 0))
end
if minetest.get_node(vector.offset(ownpos, 0, 0.5, 0)).name == "air" then
self.object:set_acceleration(vector.new(0, -5, 0))
end
if minetest.get_node(vector.offset(ownpos, 0, -0.1, 0)).name ~= "air" then
local ent = self.object:get_luaentity()
if not ent._dropped then
ent._dropped = true
minetest.sound_play({name = "drippingwater_" .. sound .. "drip"}, {pos = ownpos, gain = 0.5, max_hear_distance = 8}, true)
end
if k < 3 then
self.object:remove()
end
end
end,
})
minetest.register_abm({
label = "Create drops",
nodenames = nodes,
neighbors = {"group:" .. liquid},
interval = 2,
chance = 22,
action = function(pos)
if minetest.get_item_group(minetest.get_node(vector.offset(pos, 0, 1, 0)).name, liquid) ~= 0
and minetest.get_node(vector.offset(pos, 0, -1, 0)).name == "air" then
local x, z = math.random(-45, 45) / 100, math.random(-45, 45) / 100
minetest.add_entity(vector.offset(pos, x, -0.520, z), "mcl_dripping:drop_" .. liquid)
end
end,
})
end
register_drop("water", 1, "", {"group:opaque", "group:leaves"})
register_drop("lava", math.max(7, minetest.registered_nodes["mcl_core:lava_source"].light_source - 3), "lava", {"group:opaque"})

View File

@ -1,4 +1,7 @@
local function get_falling_depth(self) local S = minetest.get_translator("mcl_falling_nodes")
local has_mcl_armor = minetest.get_modpath("mcl_armor")
local get_falling_depth = function(self)
if not self._startpos then if not self._startpos then
-- Fallback -- Fallback
self._startpos = self.object:get_pos() self._startpos = self.object:get_pos()
@ -6,7 +9,7 @@ local function get_falling_depth(self)
return self._startpos.y - vector.round(self.object:get_pos()).y return self._startpos.y - vector.round(self.object:get_pos()).y
end end
local function deal_falling_damage(self, dtime) local deal_falling_damage = function(self, dtime)
if minetest.get_item_group(self.node.name, "falling_node_damage") == 0 then if minetest.get_item_group(self.node.name, "falling_node_damage") == 0 then
return return
end end
@ -19,10 +22,7 @@ local function deal_falling_damage(self, dtime)
end end
self._hit = self._hit or {} self._hit = self._hit or {}
for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 1)) do for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
local entity = obj:get_luaentity() if mcl_util.get_hp(obj) > 0 and not self._hit[obj] then
if entity and entity.name == "__builtin:item" then
obj:remove()
elseif mcl_util.get_hp(obj) > 0 and not self._hit[obj] then
self._hit[obj] = true self._hit[obj] = true
local way = self._startpos.y - pos.y local way = self._startpos.y - pos.y
local damage = (way - 1) * 2 local damage = (way - 1) * 2
@ -38,7 +38,7 @@ local function deal_falling_damage(self, dtime)
inv:set_stack("armor", 2, helmet) inv:set_stack("armor", 2, helmet)
end end
end end
local dmg_type local deathmsg, dmg_type
if minetest.get_item_group(self.node.name, "anvil") ~= 0 then if minetest.get_item_group(self.node.name, "anvil") ~= 0 then
dmg_type = "anvil" dmg_type = "anvil"
else else
@ -60,8 +60,10 @@ minetest.register_entity(":__builtin:falling_node", {
collide_with_objects = false, collide_with_objects = false,
collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
}, },
node = {}, node = {},
meta = {}, meta = {},
set_node = function(self, node, meta) set_node = function(self, node, meta)
local def = minetest.registered_nodes[node.name] local def = minetest.registered_nodes[node.name]
-- Change falling node if definition tells us to -- Change falling node if definition tells us to
@ -88,6 +90,7 @@ minetest.register_entity(":__builtin:falling_node", {
glow = glow, glow = glow,
}) })
end, end,
get_staticdata = function(self) get_staticdata = function(self)
local meta = self.meta local meta = self.meta
-- Workaround: Save inventory seperately from metadata. -- Workaround: Save inventory seperately from metadata.
@ -108,6 +111,7 @@ minetest.register_entity(":__builtin:falling_node", {
} }
return minetest.serialize(ds) return minetest.serialize(ds)
end, end,
on_activate = function(self, staticdata) on_activate = function(self, staticdata)
self.object:set_armor_groups({immortal = 1}) self.object:set_armor_groups({immortal = 1})
@ -130,6 +134,7 @@ minetest.register_entity(":__builtin:falling_node", {
end end
self._startpos = vector.round(self._startpos) self._startpos = vector.round(self._startpos)
end, end,
on_step = function(self, dtime) on_step = function(self, dtime)
-- Set gravity -- Set gravity
local acceleration = self.object:get_acceleration() local acceleration = self.object:get_acceleration()
@ -181,9 +186,10 @@ minetest.register_entity(":__builtin:falling_node", {
return return
end end
local nd = minetest.registered_nodes[n2.name] local nd = minetest.registered_nodes[n2.name]
--if n2.name == "mcl_portals:portal_end" then if n2.name == "mcl_portals:portal_end" then
-- TODO: Teleport falling node. -- TODO: Teleport falling node.
if (nd and nd.buildable_to == true) or minetest.get_item_group(self.node.name, "crush_after_fall") ~= 0 then
elseif (nd and nd.buildable_to == true) or minetest.get_item_group(self.node.name, "crush_after_fall") ~= 0 then
-- Replace destination node if it's buildable to -- Replace destination node if it's buildable to
minetest.remove_node(np) minetest.remove_node(np)
-- Run script hook -- Run script hook
@ -250,6 +256,7 @@ minetest.register_entity(":__builtin:falling_node", {
self.object:set_pos(npos) self.object:set_pos(npos)
end end
end end
deal_falling_damage(self, dtime) deal_falling_damage(self, dtime)
end end
}) })

View File

@ -0,0 +1,3 @@
# textdomain: mcl_falling_nodes
@1 was smashed by a falling anvil.=@1 wurde von einem fallenden Amboss zerschmettert.
@1 was smashed by a falling block.=@1 wurde von einem fallenden Block zerschmettert.

View File

@ -0,0 +1,3 @@
# textdomain: mcl_falling_nodes
@1 was smashed by a falling anvil.=@1 fue aplastado por la caída de un yunque.
@1 was smashed by a falling block.=@1 fue aplastado por la caída de un bloque.

View File

@ -0,0 +1,3 @@
# textdomain: mcl_falling_nodes
@1 was smashed by a falling anvil.=@1 a été écrasé par une enclume qui tombait.
@1 was smashed by a falling block.=@1 a été écrasé par un bloc qui tombait.

View File

@ -1,3 +0,0 @@
# textdomain: mcl_falling_nodes
@1 was smashed by a falling anvil.=@1 została zmiażdżona przez spadające kowadło.
@1 was smashed by a falling block.=@1 została zmiażdżona przez spadający blok.

View File

@ -0,0 +1,3 @@
# textdomain: mcl_falling_nodes
@1 was smashed by a falling anvil.=@1 придавило падающей наковальней.
@1 was smashed by a falling block.=@1 раздавило падающим блоком.

View File

@ -0,0 +1,3 @@
# textdomain: mcl_falling_nodes
@1 was smashed by a falling anvil.=
@1 was smashed by a falling block.=

View File

@ -1,5 +1,5 @@
--these are lua locals, used for higher performance --these are lua locals, used for higher performance
local minetest, math, vector, ipairs, pairs = minetest, math, vector, ipairs, pairs local minetest,math,vector,ipairs = minetest,math,vector,ipairs
--this is used for the player pool in the sound buffer --this is used for the player pool in the sound buffer
local pool = {} local pool = {}
@ -38,7 +38,7 @@ item_drop_settings.drop_single_item = false --if true, the drop control dro
item_drop_settings.magnet_time = 0.75 -- how many seconds an item follows the player before giving up item_drop_settings.magnet_time = 0.75 -- how many seconds an item follows the player before giving up
local function get_gravity() local get_gravity = function()
return tonumber(minetest.settings:get("movement_gravity")) or 9.81 return tonumber(minetest.settings:get("movement_gravity")) or 9.81
end end
@ -60,7 +60,7 @@ mcl_item_entity.register_pickup_achievement("mcl_mobitems:blaze_rod", "mcl:blaze
mcl_item_entity.register_pickup_achievement("mcl_mobitems:leather", "mcl:killCow") mcl_item_entity.register_pickup_achievement("mcl_mobitems:leather", "mcl:killCow")
mcl_item_entity.register_pickup_achievement("mcl_core:diamond", "mcl:diamonds") mcl_item_entity.register_pickup_achievement("mcl_core:diamond", "mcl:diamonds")
local function check_pickup_achievements(object, player) local check_pickup_achievements = function(object, player)
if has_awards then if has_awards then
local itemname = ItemStack(object:get_luaentity().itemstring):get_name() local itemname = ItemStack(object:get_luaentity().itemstring):get_name()
local playername = player:get_player_name() local playername = player:get_player_name()
@ -72,7 +72,7 @@ local function check_pickup_achievements(object, player)
end end
end end
local function enable_physics(object, luaentity, ignore_check) local enable_physics = function(object, luaentity, ignore_check)
if luaentity.physical_state == false or ignore_check == true then if luaentity.physical_state == false or ignore_check == true then
luaentity.physical_state = true luaentity.physical_state = true
object:set_properties({ object:set_properties({
@ -83,7 +83,7 @@ local function enable_physics(object, luaentity, ignore_check)
end end
end end
local function disable_physics(object, luaentity, ignore_check, reset_movement) local disable_physics = function(object, luaentity, ignore_check, reset_movement)
if luaentity.physical_state == true or ignore_check == true then if luaentity.physical_state == true or ignore_check == true then
luaentity.physical_state = false luaentity.physical_state = false
object:set_properties({ object:set_properties({
@ -98,11 +98,13 @@ end
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
tick = not tick tick = not tick
for _,player in pairs(minetest.get_connected_players()) do for _,player in pairs(minetest.get_connected_players()) do
if player:get_hp() > 0 or not minetest.settings:get_bool("enable_damage") then if player:get_hp() > 0 or not minetest.settings:get_bool("enable_damage") then
local name = player:get_player_name() local name = player:get_player_name()
local pos = player:get_pos() local pos = player:get_pos()
@ -233,7 +235,7 @@ function minetest.handle_node_drops(pos, drops, digger)
local dug_node = minetest.get_node(pos) local dug_node = minetest.get_node(pos)
local tooldef local tooldef
local tool local tool
if digger then if digger ~= nil then
tool = digger:get_wielded_item() tool = digger:get_wielded_item()
tooldef = minetest.registered_tools[tool:get_name()] tooldef = minetest.registered_tools[tool:get_name()]
@ -290,10 +292,10 @@ function minetest.handle_node_drops(pos, drops, digger)
end end
end end
if digger and mcl_experience.throw_xp and not silk_touch_drop then if digger and mcl_experience.throw_experience and not silk_touch_drop then
local experience_amount = minetest.get_item_group(dug_node.name,"xp") local experience_amount = minetest.get_item_group(dug_node.name,"xp")
if experience_amount > 0 then if experience_amount > 0 then
mcl_experience.throw_xp(pos, experience_amount) mcl_experience.throw_experience(pos, experience_amount)
end end
end end
@ -314,7 +316,7 @@ function minetest.handle_node_drops(pos, drops, digger)
end end
-- Spawn item and apply random speed -- Spawn item and apply random speed
local obj = minetest.add_item(dpos, drop_item) local obj = minetest.add_item(dpos, drop_item)
if obj then if obj ~= nil then
local x = math.random(1, 5) local x = math.random(1, 5)
if math.random(1,2) == 1 then if math.random(1,2) == 1 then
x = -x x = -x
@ -363,17 +365,6 @@ if not time_to_live then
time_to_live = 300 time_to_live = 300
end 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 })
else
table.insert(o, { [one]=-1, y=0, [zero]=0 })
table.insert(o, { [one]=1, y=0, [zero]=0 })
end
return o
end
minetest.register_entity(":__builtin:item", { minetest.register_entity(":__builtin:item", {
initial_properties = { initial_properties = {
hp_max = 1, hp_max = 1,
@ -394,7 +385,7 @@ minetest.register_entity(":__builtin:item", {
-- The itemstring MUST be set immediately to a non-empty string after creating the entity. -- The itemstring MUST be set immediately to a non-empty string after creating the entity.
-- The hand is NOT permitted as dropped item. ;-) -- The hand is NOT permitted as dropped item. ;-)
-- Item entities will be deleted if they still have an empty itemstring on their first on_step tick. -- Item entities will be deleted if they still have an empty itemstring on their first on_step tick.
itemstring = "", itemstring = '',
-- If true, item will fall -- If true, item will fall
physical_state = true, physical_state = true,
@ -435,9 +426,13 @@ minetest.register_entity(":__builtin:item", {
if itemtable then if itemtable then
itemname = stack:to_table().name itemname = stack:to_table().name
end end
local item_texture = nil
local item_type = ""
local glow local glow
local def = minetest.registered_items[itemname] local def = minetest.registered_items[itemname]
if def then if def then
item_texture = def.inventory_image
item_type = def.type
description = def.description description = def.description
glow = def.light_source glow = def.light_source
end end
@ -480,7 +475,7 @@ minetest.register_entity(":__builtin:item", {
end, end,
get_staticdata = function(self) get_staticdata = function(self)
local data = minetest.serialize({ return minetest.serialize({
itemstring = self.itemstring, itemstring = self.itemstring,
always_collect = self.always_collect, always_collect = self.always_collect,
age = self.age, age = self.age,
@ -488,39 +483,6 @@ minetest.register_entity(":__builtin:item", {
_flowing = self._flowing, _flowing = self._flowing,
_removed = self._removed, _removed = self._removed,
}) })
-- sfan5 guessed that the biggest serializable item
-- entity would have a size of 65530 bytes. This has
-- been experimentally verified to be still too large.
--
-- anon5 has calculated that the biggest serializable
-- item entity has a size of exactly 65487 bytes:
--
-- 1. serializeString16 can handle max. 65535 bytes.
-- 2. The following engine metadata is always saved:
-- • 1 byte (version)
-- • 2 byte (length prefix)
-- • 14 byte “__builtin:item”
-- • 4 byte (length prefix)
-- • 2 byte (health)
-- • 3 × 4 byte = 12 byte (position)
-- • 4 byte (yaw)
-- • 1 byte (version 2)
-- • 2 × 4 byte = 8 byte (pitch and roll)
-- 3. This leaves 65487 bytes for the serialization.
if #data > 65487 then -- would crash the engine
local stack = ItemStack(self.itemstring)
stack:get_meta():from_table(nil)
self.itemstring = stack:to_string()
minetest.log(
"warning",
"Overlong item entity metadata removed: “" ..
self.itemstring ..
"” had serialized length of " ..
#data
)
return self:get_staticdata()
end
return data
end, end,
on_activate = function(self, staticdata, dtime_s) on_activate = function(self, staticdata, dtime_s)
@ -608,7 +570,7 @@ minetest.register_entity(":__builtin:item", {
return true return true
end, end,
on_step = function(self, dtime, moveresult) on_step = function(self, dtime)
if self._removed then if self._removed then
self.object:set_properties({ self.object:set_properties({
physical = false physical = false
@ -618,7 +580,7 @@ minetest.register_entity(":__builtin:item", {
return return
end end
self.age = self.age + dtime self.age = self.age + dtime
if self._collector_timer then if self._collector_timer ~= nil then
self._collector_timer = self._collector_timer + dtime self._collector_timer = self._collector_timer + dtime
end end
if time_to_live > 0 and self.age > time_to_live then if time_to_live > 0 and self.age > time_to_live then
@ -675,18 +637,6 @@ minetest.register_entity(":__builtin:item", {
end end
end 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
-- Push item out when stuck inside solid opaque node -- Push item out when stuck inside solid opaque node
if def and def.walkable and def.groups and def.groups.opaque == 1 then if def and def.walkable and def.groups and def.groups.opaque == 1 then
local shootdir local shootdir
@ -698,6 +648,16 @@ minetest.register_entity(":__builtin:item", {
-- 1st: closest -- 1st: closest
-- 2nd: other direction -- 2nd: other direction
-- 3rd and 4th: other axis -- 3rd and 4th: other axis
local cxcz = function(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 })
else
table.insert(o, { [one]=-1, y=0, [zero]=0 })
table.insert(o, { [one]=1, y=0, [zero]=0 })
end
return o
end
if math.abs(cx) < math.abs(cz) then if math.abs(cx) < math.abs(cz) then
order = cxcz(order, cx, "x", "z") order = cxcz(order, cx, "x", "z")
order = cxcz(order, cz, "z", "x") order = cxcz(order, cz, "z", "x")

View File

@ -1,5 +1,3 @@
local vector = vector
function mcl_minecarts:get_sign(z) function mcl_minecarts:get_sign(z)
if z == 0 then if z == 0 then
return 0 return 0
@ -40,9 +38,11 @@ end
function mcl_minecarts:check_front_up_down(pos, dir_, check_down, railtype) function mcl_minecarts:check_front_up_down(pos, dir_, check_down, railtype)
local dir = vector.new(dir_) local dir = vector.new(dir_)
local cur = nil
-- Front -- Front
dir.y = 0 dir.y = 0
local cur = vector.add(pos, dir) cur = vector.add(pos, dir)
if mcl_minecarts:is_rail(cur, railtype) then if mcl_minecarts:is_rail(cur, railtype) then
return dir return dir
end end
@ -65,9 +65,9 @@ end
function mcl_minecarts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype) function mcl_minecarts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
local pos = vector.round(pos_) local pos = vector.round(pos_)
local cur local cur = nil
local left_check, right_check = true, true local left_check, right_check = true, true
-- Check left and right -- Check left and right
local left = {x=0, y=0, z=0} local left = {x=0, y=0, z=0}
local right = {x=0, y=0, z=0} local right = {x=0, y=0, z=0}
@ -78,7 +78,7 @@ function mcl_minecarts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
left.z = dir.x left.z = dir.x
right.z = -dir.x right.z = -dir.x
end end
if ctrl then if ctrl then
if old_switch == 1 then if old_switch == 1 then
left_check = false left_check = false
@ -100,13 +100,13 @@ function mcl_minecarts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
right_check = true right_check = true
end end
end end
-- Normal -- Normal
cur = mcl_minecarts:check_front_up_down(pos, dir, true, railtype) cur = mcl_minecarts:check_front_up_down(pos, dir, true, railtype)
if cur then if cur then
return cur return cur
end end
-- Left, if not already checked -- Left, if not already checked
if left_check then if left_check then
cur = mcl_minecarts:check_front_up_down(pos, left, false, railtype) cur = mcl_minecarts:check_front_up_down(pos, left, false, railtype)
@ -114,7 +114,7 @@ function mcl_minecarts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
return cur return cur
end end
end end
-- Right, if not already checked -- Right, if not already checked
if right_check then if right_check then
cur = mcl_minecarts:check_front_up_down(pos, right, false, railtype) cur = mcl_minecarts:check_front_up_down(pos, right, false, railtype)
@ -122,6 +122,7 @@ function mcl_minecarts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
return cur return cur
end end
end end
-- Backwards -- Backwards
if not old_switch then if not old_switch then
cur = mcl_minecarts:check_front_up_down(pos, { cur = mcl_minecarts:check_front_up_down(pos, {
@ -133,5 +134,7 @@ function mcl_minecarts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
return cur return cur
end end
end end
return {x=0, y=0, z=0} return {x=0, y=0, z=0}
end end

View File

@ -1,10 +1,9 @@
local modname = minetest.get_current_modname() local S = minetest.get_translator("mcl_minecarts")
local S = minetest.get_translator(modname)
local has_mcl_wip = minetest.get_modpath("mcl_wip") local has_mcl_wip = minetest.get_modpath("mcl_wip")
mcl_minecarts = {} mcl_minecarts = {}
mcl_minecarts.modpath = minetest.get_modpath(modname) mcl_minecarts.modpath = minetest.get_modpath("mcl_minecarts")
mcl_minecarts.speed_max = 10 mcl_minecarts.speed_max = 10
mcl_minecarts.check_float_time = 15 mcl_minecarts.check_float_time = 15
@ -198,27 +197,14 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
else else
self._last_float_check = self._last_float_check + dtime self._last_float_check = self._last_float_check + dtime
end end
local pos, rou_pos, node
local pos, rou_pos, node = self.object:get_pos()
local r = 0.6
for _, node_pos in pairs({{r, 0}, {0, r}, {-r, 0}, {0, -r}}) do
if minetest.get_node(vector.offset(pos, node_pos[1], 0, node_pos[2])).name == "mcl_core:cactus" then
detach_driver(self)
for d = 1, #drop do
minetest.add_item(pos, drop[d])
end
self.object:remove()
return
end
end
-- Drop minecart if it isn't on a rail anymore -- Drop minecart if it isn't on a rail anymore
if self._last_float_check >= mcl_minecarts.check_float_time then if self._last_float_check >= mcl_minecarts.check_float_time then
pos = self.object:get_pos() pos = self.object:get_pos()
rou_pos = vector.round(pos) rou_pos = vector.round(pos)
node = minetest.get_node(rou_pos) node = minetest.get_node(rou_pos)
local g = minetest.get_item_group(node.name, "connect_to_raillike") local g = minetest.get_item_group(node.name, "connect_to_raillike")
if g ~= self._railtype and self._railtype then if g ~= self._railtype and self._railtype ~= nil then
-- Detach driver -- Detach driver
if player then if player then
if self._old_pos then if self._old_pos then
@ -500,6 +486,7 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
if update.pos then if update.pos then
self.object:set_pos(pos) self.object:set_pos(pos)
end end
update = nil
end end
function cart:get_staticdata() function cart:get_staticdata()
@ -510,7 +497,7 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
end end
-- Place a minecart at pointed_thing -- Place a minecart at pointed_thing
function mcl_minecarts.place_minecart(itemstack, pointed_thing, placer) mcl_minecarts.place_minecart = function(itemstack, pointed_thing, placer)
if not pointed_thing.type == "node" then if not pointed_thing.type == "node" then
return return
end end
@ -537,7 +524,7 @@ function mcl_minecarts.place_minecart(itemstack, pointed_thing, placer)
local cart = minetest.add_entity(railpos, entity_id) local cart = minetest.add_entity(railpos, entity_id)
local railtype = minetest.get_item_group(node.name, "connect_to_raillike") local railtype = minetest.get_item_group(node.name, "connect_to_raillike")
local le = cart:get_luaentity() local le = cart:get_luaentity()
if le then if le ~= nil then
le._railtype = railtype le._railtype = railtype
end end
local cart_dir = mcl_minecarts:get_rail_direction(railpos, {x=1, y=0, z=0}, nil, nil, railtype) local cart_dir = mcl_minecarts:get_rail_direction(railpos, {x=1, y=0, z=0}, nil, nil, railtype)
@ -554,7 +541,7 @@ function mcl_minecarts.place_minecart(itemstack, pointed_thing, placer)
end end
local function register_craftitem(itemstring, entity_id, description, tt_help, longdesc, usagehelp, icon, creative) local register_craftitem = function(itemstring, entity_id, description, tt_help, longdesc, usagehelp, icon, creative)
entity_mapping[itemstring] = entity_id entity_mapping[itemstring] = entity_id
local groups = { minecart = 1, transport = 1 } local groups = { minecart = 1, transport = 1 }
@ -620,7 +607,7 @@ Register a minecart
local function register_minecart(itemstring, entity_id, description, tt_help, longdesc, usagehelp, mesh, textures, icon, drop, on_rightclick, on_activate_by_rail, creative) local function register_minecart(itemstring, entity_id, description, tt_help, longdesc, usagehelp, mesh, textures, icon, drop, on_rightclick, on_activate_by_rail, creative)
register_entity(entity_id, mesh, textures, drop, on_rightclick, on_activate_by_rail) register_entity(entity_id, mesh, textures, drop, on_rightclick, on_activate_by_rail)
register_craftitem(itemstring, entity_id, description, tt_help, longdesc, usagehelp, icon, creative) register_craftitem(itemstring, entity_id, description, tt_help, longdesc, usagehelp, icon, creative)
if minetest.get_modpath("doc_identifier") then if minetest.get_modpath("doc_identifier") ~= nil then
doc.sub.identifier.register_object(entity_id, "craftitems", itemstring) doc.sub.identifier.register_object(entity_id, "craftitems", itemstring)
end end
end end
@ -659,7 +646,7 @@ register_minecart(
if player then if player then
mcl_player.player_set_animation(player, "sit" , 30) mcl_player.player_set_animation(player, "sit" , 30)
player:set_eye_offset({x=0, y=-5.5, z=0},{x=0, y=-4, z=0}) player:set_eye_offset({x=0, y=-5.5, z=0},{x=0, y=-4, z=0})
mcl_title.set(clicker, "actionbar", {text=S("Sneak to dismount"), color="white", stay=60}) mcl_tmp_message.message(clicker, S("Sneak to dismount"))
end end
end, name) end, name)
end end
@ -830,30 +817,31 @@ minetest.register_craft({
}) })
-- TODO: Re-enable crafting of special minecarts when they have been implemented -- TODO: Re-enable crafting of special minecarts when they have been implemented
--[[minetest.register_craft({ if false then
output = "mcl_minecarts:furnace_minecart", minetest.register_craft({
recipe = { output = "mcl_minecarts:furnace_minecart",
{"mcl_furnaces:furnace"}, recipe = {
{"mcl_minecarts:minecart"}, {"mcl_furnaces:furnace"},
}, {"mcl_minecarts:minecart"},
}) },
})
minetest.register_craft({ minetest.register_craft({
output = "mcl_minecarts:hopper_minecart", output = "mcl_minecarts:hopper_minecart",
recipe = { recipe = {
{"mcl_hoppers:hopper"}, {"mcl_hoppers:hopper"},
{"mcl_minecarts:minecart"}, {"mcl_minecarts:minecart"},
}, },
}) })
minetest.register_craft({
output = "mcl_minecarts:chest_minecart",
recipe = {
{"mcl_chests:chest"},
{"mcl_minecarts:minecart"},
},
})]]
minetest.register_craft({
output = "mcl_minecarts:chest_minecart",
recipe = {
{"mcl_chests:chest"},
{"mcl_minecarts:minecart"},
},
})
end
if has_mcl_wip then if has_mcl_wip then
mcl_wip.register_wip_item("mcl_minecarts:chest_minecart") mcl_wip.register_wip_item("mcl_minecarts:chest_minecart")

View File

@ -33,4 +33,3 @@ Activates minecarts when powered=Active les wagonnets lorsqu'il est alimenté
Emits redstone power when a minecart is detected=Émet de l'énergie redstone lorsqu'un wagonnet est détecté Emits redstone power when a minecart is detected=Émet de l'énergie redstone lorsqu'un wagonnet est détecté
Vehicle for fast travel on rails=Véhicule pour voyager rapidement sur rails Vehicle for fast travel on rails=Véhicule pour voyager rapidement sur rails
Can be ignited by tools or powered activator rail=Peut être allumé par des outils ou un rail d'activation motorisé Can be ignited by tools or powered activator rail=Peut être allumé par des outils ou un rail d'activation motorisé
Sneak to dismount=

View File

@ -1,36 +0,0 @@
# textdomain: mcl_minecarts
Minecart=Wagonik
Minecarts can be used for a quick transportion on rails.=Wagoniki mogą być użyte do szybkiego transportu po torach.
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.=Wagoniki mogą jeździć tylko po torach i zawsze podążają za wytyczoną ścieżką. W przypadku skrzyżowań typu T, gdzie nie ma prostej ścieżki, skręcają w lew. Ich szybkość zależy od typu torów.
You can place the minecart on rails. Right-click it to enter it. Punch it to get it moving.=Możesz postawić wagonik na torach. Kliknij prawym przyciskiem myszy aby do niego wejść. Uderz go by zaczął się poruszać.
To obtain the minecart, punch it while holding down the sneak key.=Aby odzyskać wagonik uderz go podczas skradania.
A minecart with TNT is an explosive vehicle that travels on rail.=Wagonik z TNT jest wybuchowym pojazdem podróżującym po torach.
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.=Postaw go na torach. Uderz by zaczął się poruszać. TNT zapala się krzesiwem lub gdy wagonik jest na zasilonych torach aktywacyjnych.
To obtain the minecart and TNT, punch them while holding down the sneak key. You can't do this if the TNT was ignited.=Aby odzyskać wagonik z TNT uderz go podczas skradania. Nie możesz tego zrobić gdy TNT jest zapalone.
A minecart with furnace is a vehicle that travels on rails. It can propel itself with fuel.=Wagonik z piecem jest pojazdem podróżującym na torach. Napędza on samego siebie za pomocą paliwa.
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.=Postaw go na torach. Jeśli dasz mu nieco węgla piec zacznie palić przez długi czas, a wagonik będzie się sam poruszał. Uderz go by zaczął się poruszać.
To obtain the minecart and furnace, punch them while holding down the sneak key.=Aby odzyskać wagonik z piecem uderz go podczas skradania.
Minecart with Chest=Wagonik ze skrzynią
Minecart with Furnace=Wagonik z piecem
Minecart with Command Block=Wagonik z blokiem poleceń
Minecart with Hopper=Wagonik z lejem
Minecart with TNT=Wagonik z 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.=Postaw je na ziemi by zbudować ścieżkę z torów. Tory automatycznie połączą się ze sobą i zamienią się w zakręty, skrzyżowania typu T, skrzyżowania i równie w zależności od potrzeb.
Rail=Tor
Rails can be used to build transport tracks for minecarts. Normal rails slightly slow down minecarts due to friction.=Tory mogą być wykorzystane do zbudowania torów dla wagoników. Zwyczajne tory nieco spowalniają wagoniki ze względu na tarcie.
Powered Rail=Zasilane tory
Rails can be used to build transport tracks for minecarts. Powered rails are able to accelerate and brake minecarts.=Tory mogą być wykorzystane do zbudowania torów dla wagoników. Zasilane tory mogą przyspieszać lub spowalniać wagoniki.
Without redstone power, the rail will brake minecarts. To make this rail accelerate minecarts, power it with redstone power.=Bez zasilania czerwienitem tory będą spowalniać wagoniki. Aby sprawić by je przyspieszały zasil je czerwienitem.
Activator Rail=Tory aktywacyjne
Rails can be used to build transport tracks for minecarts. Activator rails are used to activate special minecarts.=Tory mogą być wykorzystane do zbudowania torów dla wagoników. Tory aktywacyjne są wykorzystywane do aktywacji specjalnych wagoników.
To make this rail activate minecarts, power it with redstone power and send a minecart over this piece of rail.=Aby ten tor aktywował wagonik, zasil go czerwienitem i spraw by wagonik po nim przejechał.
Detector Rail=Tory z czujnikiem
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.=Tory mogą być wykorzystane do zbudowania torów dla wagoników. Tory z czujnikiem są w stanie wykryć kiedy wagonik po nich przejeżdża i wysłać sygnał do czerwienitowych mechanizmów.
To detect a minecart and provide redstone power, connect it to redstone trails or redstone mechanisms and send any minecart over the rail.=Aby wykryć wagonik i dostarczyć zasilanie czerwienitem podłącz go czerwienitem to mechanizmu i spraw by wagonik po nim przejechał.
Track for minecarts=Tor dla wagoników
Speed up when powered, slow down when not powered=Przyspiesza gdy zasilane, spowalnia gdy nie
Activates minecarts when powered=Aktywuje wagoniki gdy zasilane
Emits redstone power when a minecart is detected=Emituje zasilanie czerwienitem gdy wagonik jest wykryty
Vehicle for fast travel on rails=Pojazd do szybkiej podróży na torach
Can be ignited by tools or powered activator rail=Może być zapalony przez narzędzia, lub zasilane tor aktywacyjne
Sneak to dismount=Zacznij się skradać by zejść

View File

@ -1,6 +1,6 @@
name = mcl_minecarts name = mcl_minecarts
author = Krock author = Krock
description = Minecarts are vehicles to move players quickly on rails. description = Minecarts are vehicles to move players quickly on rails.
depends = mcl_title, mcl_explosions, mcl_core, mcl_sounds, mcl_player, mcl_achievements, mcl_chests, mcl_furnaces, mesecons_commandblock, mcl_hoppers, mcl_tnt, mesecons depends = mcl_explosions, mcl_core, mcl_sounds, mcl_player, mcl_achievements, mcl_chests, mcl_furnaces, mesecons_commandblock, mcl_hoppers, mcl_tnt, mesecons
optional_depends = doc_identifier, mcl_wip optional_depends = doc_identifier, mcl_wip

View File

@ -1,7 +1,7 @@
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator("mcl_minecarts")
-- Template rail function -- Template rail function
local function register_rail(itemstring, tiles, def_extras, creative) local register_rail = function(itemstring, tiles, def_extras, creative)
local groups = {handy=1,pickaxey=1, attached_node=1,rail=1,connect_to_raillike=minetest.raillike_group("rail"),dig_by_water=1,destroy_by_lava_flow=1, transport=1} local groups = {handy=1,pickaxey=1, attached_node=1,rail=1,connect_to_raillike=minetest.raillike_group("rail"),dig_by_water=1,destroy_by_lava_flow=1, transport=1}
if creative == false then if creative == false then
groups.not_in_creative_inventory = 1 groups.not_in_creative_inventory = 1
@ -206,11 +206,11 @@ register_rail("mcl_minecarts:detector_rail_on",
-- Crafting -- Crafting
minetest.register_craft({ minetest.register_craft({
output = "mcl_minecarts:rail 16", output = 'mcl_minecarts:rail 16',
recipe = { recipe = {
{"mcl_core:iron_ingot", "", "mcl_core:iron_ingot"}, {'mcl_core:iron_ingot', '', 'mcl_core:iron_ingot'},
{"mcl_core:iron_ingot", "mcl_core:stick", "mcl_core:iron_ingot"}, {'mcl_core:iron_ingot', 'mcl_core:stick', 'mcl_core:iron_ingot'},
{"mcl_core:iron_ingot", "", "mcl_core:iron_ingot"}, {'mcl_core:iron_ingot', '', 'mcl_core:iron_ingot'},
} }
}) })

View File

@ -11,111 +11,133 @@ local minetest_get_objects_inside_radius = minetest.get_objects_inside_radius
local minetest_get_modpath = minetest.get_modpath local minetest_get_modpath = minetest.get_modpath
local minetest_registered_nodes = minetest.registered_nodes local minetest_registered_nodes = minetest.registered_nodes
local minetest_get_node = minetest.get_node local minetest_get_node = minetest.get_node
--local minetest_get_item_group = minetest.get_item_group local minetest_get_item_group = minetest.get_item_group
local minetest_registered_entities = minetest.registered_entities local minetest_registered_entities = minetest.registered_entities
--local minetest_line_of_sight = minetest.line_of_sight local minetest_line_of_sight = minetest.line_of_sight
--local minetest_after = minetest.after local minetest_after = minetest.after
--local minetest_sound_play = minetest.sound_play local minetest_sound_play = minetest.sound_play
--local minetest_add_particlespawner = minetest.add_particlespawner local minetest_add_particlespawner = minetest.add_particlespawner
--local minetest_registered_items = minetest.registered_items local minetest_registered_items = minetest.registered_items
--local minetest_set_node = minetest.set_node local minetest_set_node = minetest.set_node
local minetest_add_item = minetest.add_item local minetest_add_item = minetest.add_item
--local minetest_get_craft_result = minetest.get_craft_result local minetest_get_craft_result = minetest.get_craft_result
--local minetest_find_path = minetest.find_path local minetest_find_path = minetest.find_path
local minetest_is_protected = minetest.is_protected
local minetest_is_creative_enabled = minetest.is_creative_enabled local minetest_is_creative_enabled = minetest.is_creative_enabled
--local minetest_find_node_near = minetest.find_node_near local minetest_find_node_near = minetest.find_node_near
--local minetest_find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air local minetest_find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air
--local minetest_raycast = minetest.raycast local minetest_raycast = minetest.raycast
--local minetest_get_us_time = minetest.get_us_time local minetest_get_us_time = minetest.get_us_time
local minetest_add_entity = minetest.add_entity local minetest_add_entity = minetest.add_entity
--local minetest_get_natural_light = minetest.get_natural_light local minetest_get_natural_light = minetest.get_natural_light
--local minetest_get_node_or_nil = minetest.get_node_or_nil local minetest_get_node_or_nil = minetest.get_node_or_nil
-- localize math functions -- localize math functions
local math = math local math_pi = math.pi
local math_sin = math.sin
local math_cos = math.cos
local math_abs = math.abs
local math_min = math.min
local math_max = math.max
local math_atan = math.atan
local math_random = math.random
local math_floor = math.floor
-- localize vector functions -- localize vector functions
local vector = vector local vector_new = vector.new
local vector_add = vector.add
local string = string local vector_length = vector.length
local vector_direction = vector.direction
local vector_normalize = vector.normalize
local vector_multiply = vector.multiply
local vector_divide = vector.divide
-- mob constants -- mob constants
--local BREED_TIME = 30 local BREED_TIME = 30
--local BREED_TIME_AGAIN = 300 local BREED_TIME_AGAIN = 300
--local CHILD_GROW_TIME = 60*20 local CHILD_GROW_TIME = 60*20
--local DEATH_DELAY = 0.5 local DEATH_DELAY = 0.5
local DEFAULT_FALL_SPEED = -10 local DEFAULT_FALL_SPEED = -10
--local FLOP_HEIGHT = 5.0 local FLOP_HEIGHT = 5.0
--local FLOP_HOR_SPEED = 1.5 local FLOP_HOR_SPEED = 1.5
local GRAVITY = minetest_settings:get("movement_gravity")-- + 9.81 local GRAVITY = minetest_settings:get("movement_gravity")-- + 9.81
local MAX_MOB_NAME_LENGTH = 30
local MOB_CAP = {}
--[[local MOB_CAP = {}
MOB_CAP.hostile = 70 MOB_CAP.hostile = 70
MOB_CAP.passive = 10 MOB_CAP.passive = 10
MOB_CAP.ambient = 15 MOB_CAP.ambient = 15
MOB_CAP.water = 15 MOB_CAP.water = 15
]]
-- Load main settings -- Load main settings
--local damage_enabled = minetest_settings:get_bool("enable_damage") local damage_enabled = minetest_settings:get_bool("enable_damage")
--local disable_blood = minetest_settings:get_bool("mobs_disable_blood") local disable_blood = minetest_settings:get_bool("mobs_disable_blood")
--local mobs_drop_items = minetest_settings:get_bool("mobs_drop_items") ~= false local mobs_drop_items = minetest_settings:get_bool("mobs_drop_items") ~= false
--local mobs_griefing = minetest_settings:get_bool("mobs_griefing") ~= false local mobs_griefing = minetest_settings:get_bool("mobs_griefing") ~= false
--local spawn_protected = minetest_settings:get_bool("mobs_spawn_protected") ~= false local spawn_protected = minetest_settings:get_bool("mobs_spawn_protected") ~= false
--local remove_far = true local remove_far = true
local difficulty = tonumber(minetest_settings:get("mob_difficulty")) or 1.0 local difficulty = tonumber(minetest_settings:get("mob_difficulty")) or 1.0
--local show_health = false local show_health = false
--local max_per_block = tonumber(minetest_settings:get("max_objects_per_block") or 64) local max_per_block = tonumber(minetest_settings:get("max_objects_per_block") or 64)
---local mobs_spawn_chance = tonumber(minetest_settings:get("mobs_spawn_chance") or 2.5) local mobs_spawn_chance = tonumber(minetest_settings:get("mobs_spawn_chance") or 2.5)
-- pathfinding settings -- pathfinding settings
--local enable_pathfinding = true local enable_pathfinding = true
--local stuck_timeout = 3 -- how long before mob gets stuck in place and starts searching local stuck_timeout = 3 -- how long before mob gets stuck in place and starts searching
--local stuck_path_timeout = 10 -- how long will mob follow path before giving up local stuck_path_timeout = 10 -- how long will mob follow path before giving up
-- default nodes -- default nodes
--local node_ice = "mcl_core:ice" local node_ice = "mcl_core:ice"
--local node_snowblock = "mcl_core:snowblock" local node_snowblock = "mcl_core:snowblock"
--local node_snow = "mcl_core:snow" local node_snow = "mcl_core:snow"
mobs.fallback_node = minetest.registered_aliases["mapgen_dirt"] or "mcl_core:dirt" mobs.fallback_node = minetest.registered_aliases["mapgen_dirt"] or "mcl_core:dirt"
--local mod_weather = minetest_get_modpath("mcl_weather") local mod_weather = minetest_get_modpath("mcl_weather") ~= nil
--local mod_explosions = minetest_get_modpath("mcl_explosions") local mod_explosions = minetest_get_modpath("mcl_explosions") ~= nil
local mod_mobspawners = minetest_get_modpath("mcl_mobspawners") local mod_mobspawners = minetest_get_modpath("mcl_mobspawners") ~= nil
--local mod_hunger = minetest_get_modpath("mcl_hunger") local mod_hunger = minetest_get_modpath("mcl_hunger") ~= nil
--local mod_worlds = minetest_get_modpath("mcl_worlds") local mod_worlds = minetest_get_modpath("mcl_worlds") ~= nil
--local mod_armor = minetest_get_modpath("mcl_armor") local mod_armor = minetest_get_modpath("mcl_armor") ~= nil
--local mod_experience = minetest_get_modpath("mcl_experience") local mod_experience = minetest_get_modpath("mcl_experience") ~= nil
-- random locals I found -- random locals I found
--local los_switcher = false local los_switcher = false
--local height_switcher = false local height_switcher = false
-- Get translator -- Get translator
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator("mcl_mobs")
-- CMI support check -- CMI support check
--local use_cmi = minetest.global_exists("cmi") local use_cmi = minetest.global_exists("cmi")
-- Invisibility mod check
mobs.invis = {}
if minetest.global_exists("invisibility") then
mobs.invis = invisibility
end
-- creative check -- creative check
function mobs.is_creative(name) function mobs.is_creative(name)
return minetest_is_creative_enabled(name) return minetest_is_creative_enabled(name)
end end
--[[local function atan(x)
local atan = function(x)
if not x or x ~= x then if not x or x ~= x then
return 0 return 0
else else
return math.atan(x) return math_atan(x)
end end
end]] end
-- Shows helpful debug info above each mob -- Shows helpful debug info above each mob
--local mobs_debug = minetest_settings:get_bool("mobs_debug", false) local mobs_debug = minetest_settings:get_bool("mobs_debug", false)
-- Peaceful mode message so players will know there are no monsters -- Peaceful mode message so players will know there are no monsters
if minetest_settings:get_bool("only_peaceful_mobs", false) then if minetest_settings:get_bool("only_peaceful_mobs", false) then
@ -129,7 +151,6 @@ end
local api_path = minetest.get_modpath(minetest.get_current_modname()).."/api/mob_functions/" local api_path = minetest.get_modpath(minetest.get_current_modname()).."/api/mob_functions/"
--ignite all parts of the api --ignite all parts of the api
dofile(api_path .. "flow_lib.lua")
dofile(api_path .. "ai.lua") dofile(api_path .. "ai.lua")
dofile(api_path .. "animation.lua") dofile(api_path .. "animation.lua")
dofile(api_path .. "collision.lua") dofile(api_path .. "collision.lua")
@ -170,7 +191,7 @@ function mobs:register_mob(name, def)
if (not value) or (value == default) or (value == special) then if (not value) or (value == default) or (value == special) then
return default return default
else else
return math.max(min, value * difficulty) return math_max(min, value * difficulty)
end end
end end
@ -345,11 +366,15 @@ function mobs:register_mob(name, def)
random_sound_timer_min = 3, random_sound_timer_min = 3,
random_sound_timer_max = 10, random_sound_timer_max = 10,
--head code variables --head code variables
--defaults are for the cow's default --defaults are for the cow's default
--because I don't know what else to set them --because I don't know what else to set them
--to :P --to :P
has_head = def.has_head or false,
head_bone = def.head_bone,
--you must use these to adjust the mob's head positions --you must use these to adjust the mob's head positions
--has_head is used as a logic gate (quick easy check) --has_head is used as a logic gate (quick easy check)
@ -419,7 +444,7 @@ function mobs:register_mob(name, def)
--on_detach_child = mob_detach_child, --on_detach_child = mob_detach_child,
on_activate = function(self, staticdata, dtime) on_activate = function(self, staticdata, dtime)
self.object:set_acceleration(vector.new(0,-GRAVITY, 0)) self.object:set_acceleration(vector_new(0,-GRAVITY, 0))
return mobs.mob_activate(self, staticdata, def, dtime) return mobs.mob_activate(self, staticdata, def, dtime)
end, end,
@ -430,7 +455,7 @@ function mobs:register_mob(name, def)
--harmed_by_heal = def.harmed_by_heal, --harmed_by_heal = def.harmed_by_heal,
}) })
if minetest_get_modpath("doc_identifier") then if minetest_get_modpath("doc_identifier") ~= nil then
doc.sub.identifier.register_object(name, "basics", "mobs") doc.sub.identifier.register_object(name, "basics", "mobs")
end end
@ -531,10 +556,10 @@ function mobs:register_arrow(name, def)
and def.tail_texture then and def.tail_texture then
--do this to prevent clipping through main entity sprite --do this to prevent clipping through main entity sprite
local pos_adjustment = vector.multiply(vector.normalize(vel), -1) local pos_adjustment = vector_multiply(vector_normalize(vel), -1)
local divider = def.tail_distance_divider or 1 local divider = def.tail_distance_divider or 1
pos_adjustment = vector.divide(pos_adjustment, divider) pos_adjustment = vector_divide(pos_adjustment, divider)
local new_pos = vector.add(pos, pos_adjustment) local new_pos = vector_add(pos, pos_adjustment)
minetest.add_particle({ minetest.add_particle({
pos = new_pos, pos = new_pos,
velocity = {x = 0, y = 0, z = 0}, velocity = {x = 0, y = 0, z = 0},
@ -668,12 +693,12 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative)
if pos if pos
--and within_limits(pos, 0) --and within_limits(pos, 0)
and not minetest.is_protected(pos, placer:get_player_name()) then and not minetest_is_protected(pos, placer:get_player_name()) then
local name = placer:get_player_name() local name = placer:get_player_name()
local privs = minetest.get_player_privs(name) local privs = minetest.get_player_privs(name)
if mod_mobspawners and under.name == "mcl_mobspawners:spawner" then if mod_mobspawners and under.name == "mcl_mobspawners:spawner" then
if minetest.is_protected(pointed_thing.under, name) then if minetest_is_protected(pointed_thing.under, name) then
minetest.record_protection_violation(pointed_thing.under, name) minetest.record_protection_violation(pointed_thing.under, name)
return itemstack return itemstack
end end
@ -718,7 +743,7 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative)
nametag = string.sub(nametag, 1, MAX_MOB_NAME_LENGTH) nametag = string.sub(nametag, 1, MAX_MOB_NAME_LENGTH)
end end
ent.nametag = nametag ent.nametag = nametag
--update_tag(ent) update_tag(ent)
end end
-- if not in creative then take item -- if not in creative then take item

View File

@ -1,22 +1,25 @@
local math = math local math_random = math.random
local vector = vector local math_pi = math.pi
local string = string local math_floor = math.floor
local math_round = math.round
local tonumber = tonumber local vector_multiply = vector.multiply
local vector_add = vector.add
local vector_new = vector.new
local vector_distance = vector.distance
local minetest_yaw_to_dir = minetest.yaw_to_dir local minetest_yaw_to_dir = minetest.yaw_to_dir
local minetest_get_item_group = minetest.get_item_group local minetest_get_item_group = minetest.get_item_group
local minetest_get_node = minetest.get_node local minetest_get_node = minetest.get_node
local minetest_line_of_sight = minetest.line_of_sight local minetest_line_of_sight = minetest.line_of_sight
local minetest_get_node_light = minetest.get_node_light local minetest_get_node_light = minetest.get_node_light
local minetest_registered_nodes = minetest.registered_nodes
local flow = mobs.get_flowing_dir
local DOUBLE_PI = math.pi * 2 local DOUBLE_PI = math.pi * 2
local THIRTY_SECONDTH_PI = DOUBLE_PI * 0.03125 local THIRTY_SECONDTH_PI = DOUBLE_PI * 0.03125
--a simple helper function which is too small to move into movement.lua --a simple helper function which is too small to move into movement.lua
local function quick_rotate(self,dtime) local quick_rotate = function(self,dtime)
self.yaw = self.yaw + THIRTY_SECONDTH_PI self.yaw = self.yaw + THIRTY_SECONDTH_PI
if self.yaw > DOUBLE_PI then if self.yaw > DOUBLE_PI then
self.yaw = self.yaw - DOUBLE_PI self.yaw = self.yaw - DOUBLE_PI
@ -25,45 +28,46 @@ end
--a simple helper function for rounding --a simple helper function for rounding
--http://lua-users.org/wiki/SimpleRound --http://lua-users.org/wiki/SimpleRound
local function round2(num, numDecimalPlaces) function round2(num, numDecimalPlaces)
return tonumber(string.format("%." .. (numDecimalPlaces or 0) .. "f", num)) return tonumber(string.format("%." .. (numDecimalPlaces or 0) .. "f", num))
end end
--[[ --[[
_ _ _ _
| | | | | | | |
| | __ _ _ __ __| | | | __ _ _ __ __| |
| | / _` | '_ \ / _` | | | / _` | '_ \ / _` |
| |___| (_| | | | | (_| | | |___| (_| | | | | (_| |
\_____/\__,_|_| |_|\__,_| \_____/\__,_|_| |_|\__,_|
]]-- ]]--
--this is basically reverse jump_check --this is basically reverse jump_check
local function cliff_check(self,dtime) local cliff_check = function(self,dtime)
--mobs will flip out if they are falling without this --mobs will flip out if they are falling without this
if self.object:get_velocity().y ~= 0 then if self.object:get_velocity().y ~= 0 then
return false return false
end end
local pos = self.object:get_pos() local pos = self.object:get_pos()
local dir = minetest_yaw_to_dir(self.yaw) local dir = minetest_yaw_to_dir(self.yaw)
local collisionbox = self.object:get_properties().collisionbox local collisionbox = self.object:get_properties().collisionbox
local radius = collisionbox[4] + 0.5 local radius = collisionbox[4] + 0.5
dir = vector.multiply(dir,radius) dir = vector_multiply(dir,radius)
local free_fall = minetest_line_of_sight( local free_fall, blocker = minetest_line_of_sight(
{x = pos.x + dir.x, y = pos.y, z = pos.z + dir.z}, {x = pos.x + dir.x, y = pos.y, z = pos.z + dir.z},
{x = pos.x + dir.x, y = pos.y - self.fear_height, z = pos.z + dir.z}) {x = pos.x + dir.x, y = pos.y - self.fear_height, z = pos.z + dir.z})
return free_fall return free_fall
end end
-- state switching logic (stand, walk, run, attacks) -- state switching logic (stand, walk, run, attacks)
local land_state_list_wandering = {"stand", "walk"} local land_state_list_wandering = {"stand", "walk"}
local function land_state_switch(self, dtime) local land_state_switch = function(self, dtime)
--do math before sure not attacking, following, or running away so continue --do math before sure not attacking, following, or running away so continue
--doing random walking for mobs if all states are not met --doing random walking for mobs if all states are not met
@ -89,8 +93,8 @@ local function land_state_switch(self, dtime)
end end
--ignore everything else if following --ignore everything else if following
if mobs.check_following(self) and if mobs.check_following(self) and
(not self.breed_lookout_timer or (self.breed_lookout_timer and self.breed_lookout_timer == 0)) and (not self.breed_lookout_timer or (self.breed_lookout_timer and self.breed_lookout_timer == 0)) and
(not self.breed_timer or (self.breed_timer and self.breed_timer == 0)) then (not self.breed_timer or (self.breed_timer and self.breed_timer == 0)) then
self.state = "follow" self.state = "follow"
return return
@ -116,7 +120,7 @@ local function land_state_switch(self, dtime)
end end
-- states are executed here -- states are executed here
local function land_state_execution(self, dtime) local land_state_execution = function(self,dtime)
--[[ -- this is a debug which shows the timer and makes mobs breed 100 times faster --[[ -- this is a debug which shows the timer and makes mobs breed 100 times faster
print(self.breed_timer) print(self.breed_timer)
@ -132,6 +136,7 @@ local function land_state_execution(self, dtime)
if not self.object:get_properties() then if not self.object:get_properties() then
return return
end end
--timer to time out looking for mate --timer to time out looking for mate
if self.breed_lookout_timer and self.breed_lookout_timer > 0 then if self.breed_lookout_timer and self.breed_lookout_timer > 0 then
@ -171,12 +176,12 @@ local function land_state_execution(self, dtime)
if velocity.y < 0 then if velocity.y < 0 then
--lua is acting really weird so we have to help it --lua is acting really weird so we have to help it
if round2(self.object:get_acceleration().y, 1) == -self.gravity then if round2(self.object:get_acceleration().y, 1) == -self.gravity then
self.object:set_acceleration(vector.new(0,0,0)) self.object:set_acceleration(vector_new(0,0,0))
mobs.mob_fall_slow(self) mobs.mob_fall_slow(self)
end end
else else
if round2(self.object:get_acceleration().y, 1) == 0 then if round2(self.object:get_acceleration().y, 1) == 0 then
self.object:set_acceleration(vector.new(0,-self.gravity,0)) self.object:set_acceleration(vector_new(0,-self.gravity,0))
end end
end end
end end
@ -201,13 +206,15 @@ local function land_state_execution(self, dtime)
end end
mobs.lock_yaw(self) mobs.lock_yaw(self)
elseif self.state == "follow" then elseif self.state == "follow" then
--always look at players --always look at players
mobs.set_yaw_while_following(self) mobs.set_yaw_while_following(self)
--check distance --check distance
local distance_from_follow_person = vector.distance(self.object:get_pos(), self.following_person:get_pos()) local distance_from_follow_person = vector_distance(self.object:get_pos(), self.following_person:get_pos())
local distance_2d = mobs.get_2d_distance(self.object:get_pos(), self.following_person:get_pos()) local distance_2d = mobs.get_2d_distance(self.object:get_pos(), self.following_person:get_pos())
--don't push the player if too close --don't push the player if too close
--don't spin around randomly --don't spin around randomly
if self.follow_distance < distance_from_follow_person and self.minimum_follow_distance < distance_2d then if self.follow_distance < distance_from_follow_person and self.minimum_follow_distance < distance_2d then
@ -233,7 +240,7 @@ local function land_state_execution(self, dtime)
self.walk_timer = math.random(1,6) + math.random() self.walk_timer = math.random(1,6) + math.random()
--set the mob into a random direction --set the mob into a random direction
self.yaw = (math.random() * (math.pi * 2)) self.yaw = (math_random() * (math.pi * 2))
end end
--do animation --do animation
@ -246,13 +253,15 @@ local function land_state_execution(self, dtime)
local node_in_front_of = mobs.jump_check(self) local node_in_front_of = mobs.jump_check(self)
if node_in_front_of == 1 then if node_in_front_of == 1 then
mobs.jump(self) mobs.jump(self)
--turn if on the edge of cliff
--(this is written like this because unlike --turn if on the edge of cliff
--jump_check which simply tells the mob to jump --(this is written like this because unlike
--this requires a mob to turn, removing the --jump_check which simply tells the mob to jump
--ease of a full implementation for it in a single --this requires a mob to turn, removing the
--function) --ease of a full implementation for it in a single
--function)
elseif node_in_front_of == 2 or (self.fear_height ~= 0 and cliff_check(self,dtime)) then elseif node_in_front_of == 2 or (self.fear_height ~= 0 and cliff_check(self,dtime)) then
--turn 45 degrees if so --turn 45 degrees if so
quick_rotate(self,dtime) quick_rotate(self,dtime)
@ -283,7 +292,9 @@ local function land_state_execution(self, dtime)
local node_in_front_of = mobs.jump_check(self) local node_in_front_of = mobs.jump_check(self)
if node_in_front_of == 1 then if node_in_front_of == 1 then
mobs.jump(self) mobs.jump(self)
--turn if on the edge of cliff --turn if on the edge of cliff
--(this is written like this because unlike --(this is written like this because unlike
--jump_check which simply tells the mob to jump --jump_check which simply tells the mob to jump
@ -331,7 +342,7 @@ local function land_state_execution(self, dtime)
mobs.set_velocity(self, self.walk_velocity) mobs.set_velocity(self, self.walk_velocity)
--smoosh together basically --smoosh together basically
if vector.distance(self.object:get_pos(), mate:get_pos()) <= self.breed_distance then if vector_distance(self.object:get_pos(), mate:get_pos()) <= self.breed_distance then
mobs.set_mob_animation(self, "stand") mobs.set_mob_animation(self, "stand")
if self.special_breed_timer == 0 then if self.special_breed_timer == 0 then
self.special_breed_timer = 2 --breeding takes 2 seconds self.special_breed_timer = 2 --breeding takes 2 seconds
@ -342,7 +353,7 @@ local function land_state_execution(self, dtime)
--pop a baby out, it's a miracle! --pop a baby out, it's a miracle!
local baby_pos = vector.divide(vector.add(self.object:get_pos(), mate:get_pos()), 2) local baby_pos = vector.divide(vector.add(self.object:get_pos(), mate:get_pos()), 2)
minetest.add_entity(baby_pos, self.name, minetest.serialize({baby = true, grow_up_timer = self.grow_up_goal, bred = true})) local baby_mob = minetest.add_entity(pos, self.name, minetest.serialize({baby = true, grow_up_timer = self.grow_up_goal, bred = true}))
mobs.play_sound_specific(self,"item_drop_pickup") mobs.play_sound_specific(self,"item_drop_pickup")
@ -364,13 +375,14 @@ local function land_state_execution(self, dtime)
mobs.set_velocity(self,0) mobs.set_velocity(self,0)
end end
end end
if float_now then if float_now then
mobs.float(self) mobs.float(self)
else else
local acceleration = self.object:get_acceleration() local acceleration = self.object:get_acceleration()
if acceleration and acceleration.y == 0 then if acceleration and acceleration.y == 0 then
self.object:set_acceleration(vector.new(0,-self.gravity,0)) self.object:set_acceleration(vector_new(0,-self.gravity,0))
end end
end end
end end
@ -379,10 +391,10 @@ end
--[[ --[[
_____ _ _____ _
/ ___| (_) / ___| (_)
\ `--.__ ___ _ __ ___ \ `--.__ ___ _ __ ___
`--. \ \ /\ / / | '_ ` _ \ `--. \ \ /\ / / | '_ ` _ \
/\__/ /\ V V /| | | | | | | /\__/ /\ V V /| | | | | | |
\____/ \_/\_/ |_|_| |_| |_| \____/ \_/\_/ |_|_| |_| |_|
]]-- ]]--
@ -392,7 +404,7 @@ end
-- state switching logic (stand, walk, run, attacks) -- state switching logic (stand, walk, run, attacks)
local swim_state_list_wandering = {"stand", "swim"} local swim_state_list_wandering = {"stand", "swim"}
local function swim_state_switch(self, dtime) local swim_state_switch = function(self, dtime)
self.state_timer = self.state_timer - dtime self.state_timer = self.state_timer - dtime
if self.state_timer <= 0 then if self.state_timer <= 0 then
self.state_timer = math.random(4,10) + math.random() self.state_timer = math.random(4,10) + math.random()
@ -402,40 +414,41 @@ end
--check if a mob needs to turn while swimming --check if a mob needs to turn while swimming
local function swim_turn_check(self,dtime) local swim_turn_check = function(self,dtime)
local pos = self.object:get_pos() local pos = self.object:get_pos()
pos.y = pos.y + 0.1 pos.y = pos.y + 0.1
local dir = minetest_yaw_to_dir(self.yaw) local dir = minetest_yaw_to_dir(self.yaw)
local collisionbox = self.object:get_properties().collisionbox local collisionbox = self.object:get_properties().collisionbox
local radius = collisionbox[4] + 0.5 local radius = collisionbox[4] + 0.5
vector.multiply(dir, radius) vector_multiply(dir, radius)
local test_dir = vector.add(pos,dir) local test_dir = vector.add(pos,dir)
local green_flag_1 = minetest_get_item_group(minetest_get_node(test_dir).name, "solid") ~= 0 local green_flag_1 = minetest_get_item_group(minetest_get_node(test_dir).name, "solid") ~= 0
return green_flag_1 return(green_flag_1)
end end
--this is to swap the built in engine acceleration modifier --this is to swap the built in engine acceleration modifier
local function swim_physics_swapper(self, inside_swim_node) local swim_physics_swapper = function(self,inside_swim_node)
--should be swimming, gravity is applied, switch to floating --should be swimming, gravity is applied, switch to floating
if inside_swim_node and self.object:get_acceleration().y ~= 0 then if inside_swim_node and self.object:get_acceleration().y ~= 0 then
self.object:set_acceleration(vector.new(0,0,0)) self.object:set_acceleration(vector_new(0,0,0))
--not be swim, gravity isn't applied, switch to falling --not be swim, gravity isn't applied, switch to falling
elseif not inside_swim_node and self.object:get_acceleration().y == 0 then elseif not inside_swim_node and self.object:get_acceleration().y == 0 then
self.pitch = 0 self.pitch = 0
self.object:set_acceleration(vector.new(0,-self.gravity,0)) self.object:set_acceleration(vector_new(0,-self.gravity,0))
end end
end end
local random_pitch_multiplier = {-1,1} local random_pitch_multiplier = {-1,1}
-- states are executed here -- states are executed here
local function swim_state_execution(self, dtime) local swim_state_execution = function(self,dtime)
local pos = self.object:get_pos() local pos = self.object:get_pos()
@ -452,7 +465,7 @@ local function swim_state_execution(self, dtime)
end end
--turn gravity on or off --turn gravity on or off
swim_physics_swapper(self, inside_swim_node) swim_physics_swapper(self,inside_swim_node)
--swim properly if inside swim node --swim properly if inside swim node
if inside_swim_node then if inside_swim_node then
@ -469,17 +482,22 @@ local function swim_state_execution(self, dtime)
end end
mobs.lock_yaw(self) mobs.lock_yaw(self)
elseif self.state == "swim" then elseif self.state == "swim" then
self.walk_timer = self.walk_timer - dtime self.walk_timer = self.walk_timer - dtime
--reset the walk timer --reset the walk timer
if self.walk_timer <= 0 then if self.walk_timer <= 0 then
--re-randomize the walk timer --re-randomize the walk timer
self.walk_timer = math.random(1,6) + math.random() self.walk_timer = math.random(1,6) + math.random()
--set the mob into a random direction --set the mob into a random direction
self.yaw = (math.random() * (math.pi * 2)) self.yaw = (math_random() * (math.pi * 2))
--create a truly random pitch, since there is no easy access to pitch math that I can find --create a truly random pitch, since there is no easy access to pitch math that I can find
self.pitch = math.random() * math.random(1,3) * random_pitch_multiplier[math.random(1,2)] self.pitch = math_random() * math.random(1,3) * random_pitch_multiplier[math_random(1,2)]
end end
--do animation --do animation
@ -517,20 +535,20 @@ end
--[[ --[[
______ _ ______ _
| ___| | | ___| |
| |_ | |_ _ | |_ | |_ _
| _| | | | | | | _| | | | | |
| | | | |_| | | | | | |_| |
\_| |_|\__, | \_| |_|\__, |
__/ | __/ |
|___/ |___/
]]-- ]]--
-- state switching logic (stand, walk, run, attacks) -- state switching logic (stand, walk, run, attacks)
local fly_state_list_wandering = {"stand", "fly"} local fly_state_list_wandering = {"stand", "fly"}
local function fly_state_switch(self, dtime) local fly_state_switch = function(self, dtime)
if self.hostile and self.attacking then if self.hostile and self.attacking then
self.state = "attack" self.state = "attack"
@ -546,41 +564,41 @@ end
--check if a mob needs to turn while flying --check if a mob needs to turn while flying
local function fly_turn_check(self, dtime) local fly_turn_check = function(self,dtime)
local pos = self.object:get_pos() local pos = self.object:get_pos()
pos.y = pos.y + 0.1 pos.y = pos.y + 0.1
local dir = minetest_yaw_to_dir(self.yaw) local dir = minetest_yaw_to_dir(self.yaw)
local collisionbox = self.object:get_properties().collisionbox local collisionbox = self.object:get_properties().collisionbox
local radius = collisionbox[4] + 0.5 local radius = collisionbox[4] + 0.5
vector.multiply(dir, radius) vector_multiply(dir, radius)
local test_dir = vector.add(pos,dir) local test_dir = vector.add(pos,dir)
local green_flag_1 = minetest_get_item_group(minetest_get_node(test_dir).name, "solid") ~= 0 local green_flag_1 = minetest_get_item_group(minetest_get_node(test_dir).name, "solid") ~= 0
return green_flag_1 return(green_flag_1)
end end
--this is to swap the built in engine acceleration modifier --this is to swap the built in engine acceleration modifier
local function fly_physics_swapper(self, inside_fly_node) local fly_physics_swapper = function(self,inside_fly_node)
--should be flyming, gravity is applied, switch to floating --should be flyming, gravity is applied, switch to floating
if inside_fly_node and self.object:get_acceleration().y ~= 0 then if inside_fly_node and self.object:get_acceleration().y ~= 0 then
self.object:set_acceleration(vector.new(0,0,0)) self.object:set_acceleration(vector_new(0,0,0))
--not be fly, gravity isn't applied, switch to falling --not be fly, gravity isn't applied, switch to falling
elseif not inside_fly_node and self.object:get_acceleration().y == 0 then elseif not inside_fly_node and self.object:get_acceleration().y == 0 then
self.pitch = 0 self.pitch = 0
self.object:set_acceleration(vector.new(0,-self.gravity,0)) self.object:set_acceleration(vector_new(0,-self.gravity,0))
end end
end end
local random_pitch_multiplier = {-1,1} local random_pitch_multiplier = {-1,1}
-- states are executed here -- states are executed here
local function fly_state_execution(self, dtime) local fly_state_execution = function(self,dtime)
local pos = self.object:get_pos() local pos = self.object:get_pos()
pos.y = pos.y + 0.1 pos.y = pos.y + 0.1
local current_node = minetest_get_node(pos).name local current_node = minetest_get_node(pos).name
@ -617,13 +635,15 @@ local function fly_state_execution(self, dtime)
--reset the walk timer --reset the walk timer
if self.walk_timer <= 0 then if self.walk_timer <= 0 then
--re-randomize the walk timer --re-randomize the walk timer
self.walk_timer = math.random(1,6) + math.random() self.walk_timer = math.random(1,6) + math.random()
--set the mob into a random direction --set the mob into a random direction
self.yaw = (math.random() * (math.pi * 2)) self.yaw = (math_random() * (math.pi * 2))
--create a truly random pitch, since there is no easy access to pitch math that I can find --create a truly random pitch, since there is no easy access to pitch math that I can find
self.pitch = math.random() * math.random(1,3) * random_pitch_multiplier[math.random(1,2)] self.pitch = math_random() * math.random(1,3) * random_pitch_multiplier[math_random(1,2)]
end end
--do animation --do animation
@ -643,7 +663,9 @@ local function fly_state_execution(self, dtime)
--enable rotation locking --enable rotation locking
mobs.movement_rotation_lock(self) mobs.movement_rotation_lock(self)
elseif self.state == "attack" then elseif self.state == "attack" then
--execute mob attack type --execute mob attack type
--if self.attack_type == "explode" then --if self.attack_type == "explode" then
@ -675,39 +697,40 @@ end
--[[ --[[
___ ___
|_ | |_ |
| |_ _ _ __ ___ _ __ | |_ _ _ __ ___ _ __
| | | | | '_ ` _ \| '_ \ | | | | | '_ ` _ \| '_ \
/\__/ / |_| | | | | | | |_) | /\__/ / |_| | | | | | | |_) |
\____/ \__,_|_| |_| |_| .__/ \____/ \__,_|_| |_| |_| .__/
| | | |
|_| |_|
]]-- ]]--
--check if a mob needs to turn while jumping --check if a mob needs to turn while jumping
--[[local function jump_turn_check(self, dtime) local jump_turn_check = function(self,dtime)
local pos = self.object:get_pos()
pos.y = pos.y + 0.1
local dir = minetest_yaw_to_dir(self.yaw)
local collisionbox = self.object:get_properties().collisionbox local pos = self.object:get_pos()
pos.y = pos.y + 0.1
local dir = minetest_yaw_to_dir(self.yaw)
local collisionbox = self.object:get_properties().collisionbox
local radius = collisionbox[4] + 0.5 local radius = collisionbox[4] + 0.5
vector.multiply(dir, radius) vector_multiply(dir, radius)
local test_dir = vector.add(pos,dir) local test_dir = vector.add(pos,dir)
local green_flag_1 = minetest_get_item_group(minetest_get_node(test_dir).name, "solid") ~= 0 local green_flag_1 = minetest_get_item_group(minetest_get_node(test_dir).name, "solid") ~= 0
return green_flag_1 return(green_flag_1)
end]] end
-- state switching logic (stand, jump, run, attacks) -- state switching logic (stand, jump, run, attacks)
local jump_state_list_wandering = {"stand", "jump"} local jump_state_list_wandering = {"stand", "jump"}
local function jump_state_switch(self, dtime) local jump_state_switch = function(self, dtime)
self.state_timer = self.state_timer - dtime self.state_timer = self.state_timer - dtime
if self.state_timer <= 0 then if self.state_timer <= 0 then
self.state_timer = math.random(4,10) + math.random() self.state_timer = math.random(4,10) + math.random()
@ -716,8 +739,8 @@ local function jump_state_switch(self, dtime)
end end
-- states are executed here -- states are executed here
local function jump_state_execution(self, dtime) local jump_state_execution = function(self,dtime)
local node_in_front_of = mobs.jump_check(self)
local pos = self.object:get_pos() local pos = self.object:get_pos()
local collisionbox = self.object:get_properties().collisionbox local collisionbox = self.object:get_properties().collisionbox
--get the center of the mob --get the center of the mob
@ -752,7 +775,7 @@ local function jump_state_execution(self, dtime)
self.walk_timer = math.random(1,6) + math.random() self.walk_timer = math.random(1,6) + math.random()
--set the mob into a random direction --set the mob into a random direction
self.yaw = (math.random() * (math.pi * 2)) self.yaw = (math_random() * (math.pi * 2))
end end
--do animation --do animation
@ -770,10 +793,15 @@ local function jump_state_execution(self, dtime)
mobs.jump_move(self,self.walk_velocity) mobs.jump_move(self,self.walk_velocity)
elseif self.state == "run" then elseif self.state == "run" then
print("run") print("run")
elseif self.state == "attack" then elseif self.state == "attack" then
print("attack") print("attack")
end
end
if float_now then if float_now then
mobs.float(self) mobs.float(self)
end end
@ -783,18 +811,18 @@ end
--[[ --[[
___ ___ _ _ _ ___ ___ _ _ _
| \/ | (_) | | (_) | \/ | (_) | | (_)
| . . | __ _ _ _ __ | | ___ __ _ _ ___ | . . | __ _ _ _ __ | | ___ __ _ _ ___
| |\/| |/ _` | | '_ \ | | / _ \ / _` | |/ __| | |\/| |/ _` | | '_ \ | | / _ \ / _` | |/ __|
| | | | (_| | | | | | | |___| (_) | (_| | | (__ | | | | (_| | | | | | | |___| (_) | (_| | | (__
\_| |_/\__,_|_|_| |_| \_____/\___/ \__, |_|\___| \_| |_/\__,_|_|_| |_| \_____/\___/ \__, |_|\___|
__/ | __/ |
|___/ |___/
]]-- ]]--
--the main loop --the main loop
function mobs.mob_step(self, dtime) mobs.mob_step = function(self, dtime)
--do not continue if non-existent --do not continue if non-existent
if not self or not self.object or not self.object:get_luaentity() then if not self or not self.object or not self.object:get_luaentity() then
@ -831,13 +859,13 @@ function mobs.mob_step(self, dtime)
end end
--color modifier which coincides with the pause_timer --color modifier which coincides with the pause_timer
if self.old_health and self.health < self.old_health then if self.old_health and self.health < self.old_health then
self.object:set_texture_mod("^[colorize:red:120") self.object:set_texture_mod("^[colorize:red:120")
--fix double death sound --fix double death sound
if self.health > 0 then if self.health > 0 then
mobs.play_sound(self,"damage") mobs.play_sound(self,"damage")
end end
end end
self.old_health = self.health self.old_health = self.health
--do death logic (animation, poof, explosion, etc) --do death logic (animation, poof, explosion, etc)
@ -888,6 +916,7 @@ function mobs.mob_step(self, dtime)
elseif self.breath < self.breath_max then elseif self.breath < self.breath_max then
self.breath = self.breath + dtime self.breath = self.breath + dtime
--clean timer reset --clean timer reset
if self.breath > self.breath_max then if self.breath > self.breath_max then
self.breath = self.breath_max self.breath = self.breath_max
@ -909,16 +938,17 @@ function mobs.mob_step(self, dtime)
end end
end end
if self.burn_timer == 0 then if self.burn_timer == 0 and minetest_get_node_light(pos) > 12 and minetest_get_node_light(pos, 0.5) == 15 then
local light_current, light_day = minetest_get_node_light(pos), minetest_get_node_light(pos, 0.5) mcl_burning.set_on_fire(self.object, 1)
if light_current and light_day and light_current > 12 and light_day == 15 then self.burn_timer = 1 --1.7 seconds
mcl_burning.set_on_fire(self.object, 1) self.pause_timer = 0.4
self.burn_timer = 1 --1.7 seconds
self.pause_timer = 0.4
end
end end
end end
--baby grows up --baby grows up
if self.baby then if self.baby then
--print(self.grow_up_timer) --print(self.grow_up_timer)
@ -935,6 +965,8 @@ function mobs.mob_step(self, dtime)
mobs.baby_grow_up(self) mobs.baby_grow_up(self)
end end
end end
--do custom mob instructions --do custom mob instructions
if self.do_custom then if self.do_custom then
@ -980,7 +1012,7 @@ function mobs.mob_step(self, dtime)
self.memory = self.memory - dtime self.memory = self.memory - dtime
--get if memory player is within viewing range --get if memory player is within viewing range
if self.attacking and self.attacking:is_player() then if self.attacking and self.attacking:is_player() then
local distance = vector.distance(self.object:get_pos(), self.attacking:get_pos()) local distance = vector_distance(self.object:get_pos(), self.attacking:get_pos())
if distance > self.view_range then if distance > self.view_range then
self.memory = 0 self.memory = 0
end end
@ -992,7 +1024,7 @@ function mobs.mob_step(self, dtime)
if self.memory <= 0 then if self.memory <= 0 then
--reset states when coming out of hostile state --reset states when coming out of hostile state
if self.attacking then if self.attacking ~= nil then
self.state_timer = -1 self.state_timer = -1
end end
@ -1013,19 +1045,6 @@ function mobs.mob_step(self, dtime)
end end
end end
--mobs flow from Crafter
local pos = self.object:get_pos()
if pos then
local flow_dir = flow(pos)
if flow_dir then
flow_dir = vector.multiply(flow_dir,10)
local vel = self.object:get_velocity()
local acceleration = vector.new(flow_dir.x-vel.x,flow_dir.y-vel.y,flow_dir.z-vel.z)
acceleration = vector.multiply(acceleration, 0.01)
self.object:add_velocity(acceleration)
end
end
--mob is stunned after being hit --mob is stunned after being hit
if self.pause_timer > 0 then if self.pause_timer > 0 then
self.pause_timer = self.pause_timer - dtime self.pause_timer = self.pause_timer - dtime
@ -1068,7 +1087,7 @@ function mobs.mob_step(self, dtime)
--jump only (like slimes) --jump only (like slimes)
if self.jump_only then if self.jump_only then
jump_state_switch(self, dtime) jump_state_switch(self, dtime)
jump_state_execution(self, dtime) jump_state_execution(self, dtime)
--swimming --swimming
elseif self.swim then elseif self.swim then
swim_state_switch(self, dtime) swim_state_switch(self, dtime)
@ -1102,22 +1121,28 @@ function mobs.mob_step(self, dtime)
--overrides absolutely everything --overrides absolutely everything
--mobs get stuck in cobwebs like players --mobs get stuck in cobwebs like players
if not self.ignores_cobwebs then if not self.ignores_cobwebs then
local pos = self.object:get_pos() local pos = self.object:get_pos()
local node = pos and minetest_get_node(pos).name local node = pos and minetest_get_node(pos).name
if node == "mcl_core:cobweb" then if node == "mcl_core:cobweb" then
--fight the rest of the api --fight the rest of the api
if self.object:get_acceleration().y ~= 0 then if self.object:get_acceleration().y ~= 0 then
self.object:set_acceleration(vector.new(0,0,0)) self.object:set_acceleration(vector_new(0,0,0))
end end
mobs.stick_in_cobweb(self) mobs.stick_in_cobweb(self)
self.was_stuck_in_cobweb = true self.was_stuck_in_cobweb = true
else else
--do not override other functions --do not override other functions
if self.was_stuck_in_cobweb == true then if self.was_stuck_in_cobweb == true then
--return the mob back to normal --return the mob back to normal
self.was_stuck_in_cobweb = nil self.was_stuck_in_cobweb = nil
if self.object:get_acceleration().y == 0 and not self.swim and not self.fly then if self.object:get_acceleration().y == 0 and not self.swim and not self.fly then
self.object:set_acceleration(vector.new(0,-self.gravity,0)) self.object:set_acceleration(vector_new(0,-self.gravity,0))
end end
end end
end end

View File

@ -1,7 +1,7 @@
local math = math local math_pi = math.pi
local vector = vector local math_floor = math.floor
local math_random = math.random
local HALF_PI = math.pi/2 local HALF_PI = math_pi/2
local vector_direction = vector.direction local vector_direction = vector.direction
@ -48,7 +48,8 @@ mobs.set_mob_animation = function(self, anim, fixed_frame)
self.animation[anim .. "_speed"] or self.animation.speed_normal or 15, self.animation[anim .. "_speed"] or self.animation.speed_normal or 15,
0, self.animation[anim .. "_loop"] ~= false) 0, self.animation[anim .. "_loop"] ~= false)
self.current_animation = anim
self.current_animation = anim
end end
@ -64,14 +65,14 @@ mobs.death_effect = function(pos, yaw, collisionbox, rotate)
max = { x = 0.5, y = 0.5, z = 0.5 } max = { x = 0.5, y = 0.5, z = 0.5 }
end end
if rotate then if rotate then
min = vector.rotate(min, {x=0, y=yaw, z=math.pi/2}) min = vector.rotate(min, {x=0, y=yaw, z=math_pi/2})
max = vector.rotate(max, {x=0, y=yaw, z=math.pi/2}) max = vector.rotate(max, {x=0, y=yaw, z=math_pi/2})
min, max = vector.sort(min, max) min, max = vector.sort(min, max)
min = vector.multiply(min, 0.5) min = vector.multiply(min, 0.5)
max = vector.multiply(max, 0.5) max = vector.multiply(max, 0.5)
end end
minetest.add_particlespawner({ minetest_add_particlespawner({
amount = 50, amount = 50,
time = 0.001, time = 0.001,
minpos = vector.add(pos, min), minpos = vector.add(pos, min),
@ -87,7 +88,7 @@ mobs.death_effect = function(pos, yaw, collisionbox, rotate)
texture = "mcl_particles_mob_death.png^[colorize:#000000:255", texture = "mcl_particles_mob_death.png^[colorize:#000000:255",
}) })
minetest.sound_play("mcl_mobs_mob_poof", { minetest_sound_play("mcl_mobs_mob_poof", {
pos = pos, pos = pos,
gain = 1.0, gain = 1.0,
max_hear_distance = 8, max_hear_distance = 8,
@ -98,6 +99,7 @@ end
--this allows auto facedir rotation while making it so mobs --this allows auto facedir rotation while making it so mobs
--don't look like wet noodles flopping around --don't look like wet noodles flopping around
mobs.movement_rotation_lock = function(self) mobs.movement_rotation_lock = function(self)
local current_engine_yaw = self.object:get_yaw() local current_engine_yaw = self.object:get_yaw()
local current_lua_yaw = self.yaw local current_lua_yaw = self.yaw
@ -157,7 +159,7 @@ local calculate_pitch = function(self)
return false return false
end end
return minetest_dir_to_yaw(vector_new(vector_distance(vector_new(pos.x,0,pos.z),vector_new(pos2.x,0,pos2.z)),0,pos.y - pos2.y)) + HALF_PI return(minetest_dir_to_yaw(vector_new(vector_distance(vector_new(pos.x,0,pos.z),vector_new(pos2.x,0,pos2.z)),0,pos.y - pos2.y)) + HALF_PI)
end end
--this is a helper function used to make mobs pitch rotation dynamically flow when flying/swimming --this is a helper function used to make mobs pitch rotation dynamically flow when flying/swimming

View File

@ -1,11 +1,11 @@
local vector_direction = vector.direction local vector_direction = vector.direction
--local minetest_dir_to_yaw = minetest.dir_to_yaw local minetest_dir_to_yaw = minetest.dir_to_yaw
local vector_distance = vector.distance local vector_distance = vector.distance
local vector_multiply = vector.multiply local vector_multiply = vector.multiply
local math_random = math.random local math_random = math.random
--[[ --[[
_ _ _ _ _ _ _ _
| | | | | | | | | | | | | | | |
| | | | __ _ _ __ __| | | | | | | | __ _ _ __ __| | | |
| | | | / _` | '_ \ / _` | | | | | | | / _` | '_ \ / _` | | |
@ -16,14 +16,14 @@ local math_random = math.random
--[[ --[[
_____ _ _ _____ _ _
| ___| | | | | | ___| | | | |
| |____ ___ __ | | ___ __| | ___ | |____ ___ __ | | ___ __| | ___
| __\ \/ / '_ \| |/ _ \ / _` |/ _ \ | __\ \/ / '_ \| |/ _ \ / _` |/ _ \
| |___> <| |_) | | (_) | (_| | __/ | |___> <| |_) | | (_) | (_| | __/
\____/_/\_\ .__/|_|\___/ \__,_|\___| \____/_/\_\ .__/|_|\___/ \__,_|\___|
| | | |
|_| |_|
]]-- ]]--
mobs.explode_attack_walk = function(self,dtime) mobs.explode_attack_walk = function(self,dtime)
@ -41,7 +41,7 @@ mobs.explode_attack_walk = function(self,dtime)
--make mob walk up to player within 2 nodes distance then start exploding --make mob walk up to player within 2 nodes distance then start exploding
if distance_from_attacking >= self.reach and if distance_from_attacking >= self.reach and
--don't allow explosion to cancel unless out of the reach boundary --don't allow explosion to cancel unless out of the reach boundary
not (self.explosion_animation and self.explosion_animation > 0 and distance_from_attacking <= self.defuse_reach) then not (self.explosion_animation ~= nil and self.explosion_animation > 0 and distance_from_attacking <= self.defuse_reach) then
mobs.set_velocity(self, self.run_velocity) mobs.set_velocity(self, self.run_velocity)
mobs.set_mob_animation(self,"run") mobs.set_mob_animation(self,"run")
@ -74,6 +74,7 @@ mobs.explode_attack_walk = function(self,dtime)
if node_in_front_of == 1 then if node_in_front_of == 1 then
mobs.jump(self) mobs.jump(self)
end end
--do biggening explosion thing --do biggening explosion thing
if self.explosion_animation and self.explosion_animation > self.explosion_timer then if self.explosion_animation and self.explosion_animation > self.explosion_timer then
@ -85,8 +86,9 @@ end
--this is a small helper function to make working with explosion animations easier --this is a small helper function to make working with explosion animations easier
mobs.reverse_explosion_animation = function(self,dtime) mobs.reverse_explosion_animation = function(self,dtime)
--if explosion animation was greater than 0 then reverse it --if explosion animation was greater than 0 then reverse it
if self.explosion_animation and self.explosion_animation > 0 then if self.explosion_animation ~= nil and self.explosion_animation > 0 then
self.explosion_animation = self.explosion_animation - dtime self.explosion_animation = self.explosion_animation - dtime
if self.explosion_animation < 0 then if self.explosion_animation < 0 then
self.explosion_animation = 0 self.explosion_animation = 0
@ -100,10 +102,10 @@ end
--[[ --[[
______ _ ______ _
| ___ \ | | | ___ \ | |
| |_/ / _ _ __ ___| |__ | |_/ / _ _ __ ___| |__
| __/ | | | '_ \ / __| '_ \ | __/ | | | '_ \ / __| '_ \
| | | |_| | | | | (__| | | | | | | |_| | | | | (__| | | |
\_| \__,_|_| |_|\___|_| |_| \_| \__,_|_| |_|\___|_| |_|
]]-- ]]--
@ -111,6 +113,7 @@ ______ _
mobs.punch_attack_walk = function(self,dtime) mobs.punch_attack_walk = function(self,dtime)
--this needs an exception --this needs an exception
if self.attacking == nil or not self.attacking:is_player() then if self.attacking == nil or not self.attacking:is_player() then
self.attacking = nil self.attacking = nil
@ -184,14 +187,14 @@ end
--[[ --[[
______ _ _ _ _ ______ _ _ _ _
| ___ \ (_) | | (_) | | ___ \ (_) | | (_) |
| |_/ / __ ___ _ ___ ___| |_ _| | ___ | |_/ / __ ___ _ ___ ___| |_ _| | ___
| __/ '__/ _ \| |/ _ \/ __| __| | |/ _ \ | __/ '__/ _ \| |/ _ \/ __| __| | |/ _ \
| | | | | (_) | | __/ (__| |_| | | __/ | | | | | (_) | | __/ (__| |_| | | __/
\_| |_| \___/| |\___|\___|\__|_|_|\___| \_| |_| \___/| |\___|\___|\__|_|_|\___|
_/ | _/ |
|__/ |__/
]]-- ]]--
@ -252,39 +255,40 @@ end
--[[ --[[
_ ______ _ _ _ ______ _ _
| | | ___| | | | | | | ___| | | |
| | | |_ | |_ _ | | | | | |_ | |_ _ | |
| | | _| | | | | | | | | | | _| | | | | | | |
|_| | | | | |_| | |_| |_| | | | | |_| | |_|
(_) \_| |_|\__, | (_) (_) \_| |_|\__, | (_)
__/ | __/ |
|___/ |___/
]]-- ]]--
--[[ --[[
______ _ _ _ _ ______ _ _ _ _
| ___ \ (_) | | (_) | | ___ \ (_) | | (_) |
| |_/ / __ ___ _ ___ ___| |_ _| | ___ | |_/ / __ ___ _ ___ ___| |_ _| | ___
| __/ '__/ _ \| |/ _ \/ __| __| | |/ _ \ | __/ '__/ _ \| |/ _ \/ __| __| | |/ _ \
| | | | | (_) | | __/ (__| |_| | | __/ | | | | | (_) | | __/ (__| |_| | | __/
\_| |_| \___/| |\___|\___|\__|_|_|\___| \_| |_| \___/| |\___|\___|\__|_|_|\___|
_/ | _/ |
|__/ |__/
]]-- ]]--
local random_pitch_multiplier = {-1,1} local random_pitch_multiplier = {-1,1}
mobs.projectile_attack_fly = function(self, dtime) mobs.projectile_attack_fly = function(self, dtime)
--this needs an exception --this needs an exception
if self.attacking == nil or not self.attacking:is_player() then if self.attacking == nil or not self.attacking:is_player() then
self.attacking = nil self.attacking = nil
return return
end end
--this is specifically for random ghast movement --this is specifically for random ghast movement
if self.fly_random_while_attack then if self.fly_random_while_attack then
@ -311,7 +315,7 @@ mobs.projectile_attack_fly = function(self, dtime)
local distance_from_attacking = vector_distance(self.object:get_pos(), self.attacking:get_pos()) local distance_from_attacking = vector_distance(self.object:get_pos(), self.attacking:get_pos())
if distance_from_attacking >= self.reach then if distance_from_attacking >= self.reach then
mobs.set_pitch_while_attacking(self) mobs.set_pitch_while_attacking(self)
mobs.set_fly_velocity(self, self.run_velocity) mobs.set_fly_velocity(self, self.run_velocity)
mobs.set_mob_animation(self,"run") mobs.set_mob_animation(self,"run")

View File

@ -1,7 +1,4 @@
local math = math local disable_physics = function(object, luaentity, ignore_check, reset_movement)
local vector = vector
local function disable_physics(object, luaentity, ignore_check, reset_movement)
if luaentity.physical_state == true or ignore_check == true then if luaentity.physical_state == true or ignore_check == true then
luaentity.physical_state = false luaentity.physical_state = false
object:set_properties({ object:set_properties({
@ -15,7 +12,7 @@ local function disable_physics(object, luaentity, ignore_check, reset_movement)
end end
----For Water Flowing: ----For Water Flowing:
local function enable_physics(object, luaentity, ignore_check) local enable_physics = function(object, luaentity, ignore_check)
if luaentity.physical_state == false or ignore_check == true then if luaentity.physical_state == false or ignore_check == true then
luaentity.physical_state = true luaentity.physical_state = true
object:set_properties({ object:set_properties({
@ -275,7 +272,7 @@ local falling = function(self, pos)
self.object:set_acceleration({ self.object:set_acceleration({
x = 0, x = 0,
y = -self.fall_speed / (math.max(1, v.y) ^ 2), y = -self.fall_speed / (math_max(1, v.y) ^ 2),
z = 0 z = 0
}) })
end end
@ -506,9 +503,9 @@ local follow_flop = function(self)
if sdef and sdef.walkable then if sdef and sdef.walkable then
mob_sound(self, "flop") mob_sound(self, "flop")
self.object:set_velocity({ self.object:set_velocity({
x = math.random(-FLOP_HOR_SPEED, FLOP_HOR_SPEED), x = math_random(-FLOP_HOR_SPEED, FLOP_HOR_SPEED),
y = FLOP_HEIGHT, y = FLOP_HEIGHT,
z = math.random(-FLOP_HOR_SPEED, FLOP_HOR_SPEED), z = math_random(-FLOP_HOR_SPEED, FLOP_HOR_SPEED),
}) })
end end
@ -990,7 +987,7 @@ local check_for_death = function(self, cause, cmi_cause)
item_drop(self, cooked, looting) item_drop(self, cooked, looting)
if mod_experience and ((not self.child) or self.type ~= "animal") and (minetest_get_us_time() - self.xp_timestamp <= 5000000) then if mod_experience and ((not self.child) or self.type ~= "animal") and (minetest_get_us_time() - self.xp_timestamp <= 5000000) then
mcl_experience.throw_experience(self.object:get_pos(), math.random(self.xp_min, self.xp_max)) mcl_experience.throw_experience(self.object:get_pos(), math_random(self.xp_min, self.xp_max))
end end
end end
end end
@ -1364,7 +1361,7 @@ local do_attack = function(self, player)
self.state = "attack" self.state = "attack"
-- TODO: Implement war_cry sound without being annoying -- TODO: Implement war_cry sound without being annoying
--if math.random(0, 100) < 90 then --if math_random(0, 100) < 90 then
--mob_sound(self, "war_cry", true) --mob_sound(self, "war_cry", true)
--end --end
end end
@ -1399,7 +1396,7 @@ local mob_sound = function(self, soundname, is_opinion, fixed_pitch)
pitch = base_pitch pitch = base_pitch
end end
-- randomize the pitch a bit -- randomize the pitch a bit
pitch = pitch + math.random(-10, 10) * 0.005 pitch = pitch + math_random(-10, 10) * 0.005
end end
minetest_sound_play(sound, { minetest_sound_play(sound, {
object = self.object, object = self.object,
@ -1702,7 +1699,7 @@ local do_env_damage = function(self)
end end
if drowning then if drowning then
self.breath = math.max(0, self.breath - 1) self.breath = math_max(0, self.breath - 1)
effect(pos, 2, "bubble.png", nil, nil, 1, nil) effect(pos, 2, "bubble.png", nil, nil, 1, nil)
if self.breath <= 0 then if self.breath <= 0 then
@ -2047,7 +2044,7 @@ local breed = function(self)
-- Give XP -- Give XP
if mod_experience then if mod_experience then
mcl_experience.throw_experience(pos, math.random(1, 7)) mcl_experience.throw_experience(pos, math_random(1, 7))
end end
-- custom breed function -- custom breed function
@ -2064,7 +2061,7 @@ local breed = function(self)
-- Use texture of one of the parents -- Use texture of one of the parents
local p = math.random(1, 2) local p = math_random(1, 2)
if p == 1 then if p == 1 then
ent_c.base_texture = parent1.base_texture ent_c.base_texture = parent1.base_texture
else else
@ -2094,7 +2091,7 @@ local replace = function(self, pos)
or not self.replace_what or not self.replace_what
or self.child == true or self.child == true
or self.object:get_velocity().y ~= 0 or self.object:get_velocity().y ~= 0
or math.random(1, self.replace_rate) > 1 then or math_random(1, self.replace_rate) > 1 then
return return
end end
@ -2102,7 +2099,7 @@ local replace = function(self, pos)
if type(self.replace_what[1]) == "table" then if type(self.replace_what[1]) == "table" then
local num = math.random(#self.replace_what) local num = math_random(#self.replace_what)
what = self.replace_what[num][1] or "" what = self.replace_what[num][1] or ""
with = self.replace_what[num][2] or "" with = self.replace_what[num][2] or ""
@ -2166,7 +2163,7 @@ function do_states(self)
if self.state == "stand" then if self.state == "stand" then
if math.random(1, 4) == 1 then if math_random(1, 4) == 1 then
local lp = nil local lp = nil
local s = self.object:get_pos() local s = self.object:get_pos()
@ -2192,7 +2189,7 @@ function do_states(self)
if lp.x > s.x then yaw = yaw + math_pi end if lp.x > s.x then yaw = yaw + math_pi end
else else
yaw = yaw + math.random(-0.5, 0.5) yaw = yaw + math_random(-0.5, 0.5)
end end
yaw = set_yaw(self, yaw, 8) yaw = set_yaw(self, yaw, 8)
@ -2207,7 +2204,7 @@ function do_states(self)
if self.walk_chance ~= 0 if self.walk_chance ~= 0
and self.facing_fence ~= true and self.facing_fence ~= true
and math.random(1, 100) <= self.walk_chance and math_random(1, 100) <= self.walk_chance
and is_at_cliff_or_danger(self) == false then and is_at_cliff_or_danger(self) == false then
set_velocity(self, self.walk_velocity) set_velocity(self, self.walk_velocity)
@ -2257,7 +2254,7 @@ function do_states(self)
{x = s.x + 5, y = s.y + 1, z = s.z + 5}, {x = s.x + 5, y = s.y + 1, z = s.z + 5},
{"group:solid"}) {"group:solid"})
lp = #lp > 0 and lp[math.random(#lp)] lp = #lp > 0 and lp[math_random(#lp)]
-- did we find land? -- did we find land?
if lp then if lp then
@ -2283,8 +2280,8 @@ function do_states(self)
else else
-- Randomly turn -- Randomly turn
if math.random(1, 100) <= 30 then if math_random(1, 100) <= 30 then
yaw = yaw + math.random(-0.5, 0.5) yaw = yaw + math_random(-0.5, 0.5)
yaw = set_yaw(self, yaw, 8) yaw = set_yaw(self, yaw, 8)
end end
end end
@ -2292,9 +2289,9 @@ function do_states(self)
yaw = set_yaw(self, yaw, 8) yaw = set_yaw(self, yaw, 8)
-- otherwise randomly turn -- otherwise randomly turn
elseif math.random(1, 100) <= 30 then elseif math_random(1, 100) <= 30 then
yaw = yaw + math.random(-0.5, 0.5) yaw = yaw + math_random(-0.5, 0.5)
yaw = set_yaw(self, yaw, 8) yaw = set_yaw(self, yaw, 8)
end end
@ -2305,7 +2302,7 @@ function do_states(self)
end end
if self.facing_fence == true if self.facing_fence == true
or cliff_or_danger or cliff_or_danger
or math.random(1, 100) <= 30 then or math_random(1, 100) <= 30 then
set_velocity(self, 0) set_velocity(self, 0)
self.state = "stand" self.state = "stand"
@ -2605,7 +2602,7 @@ function do_states(self)
self.timer = 0 self.timer = 0
if self.double_melee_attack if self.double_melee_attack
and math.random(1, 2) == 1 then and math_random(1, 2) == 1 then
set_animation(self, "punch2") set_animation(self, "punch2")
else else
set_animation(self, "punch") set_animation(self, "punch")
@ -2672,7 +2669,7 @@ function do_states(self)
if self.shoot_interval if self.shoot_interval
and self.timer > self.shoot_interval and self.timer > self.shoot_interval
and not minetest_raycast(p, self.attack:get_pos(), false, false):next() and not minetest_raycast(p, self.attack:get_pos(), false, false):next()
and math.random(1, 100) <= 60 then and math_random(1, 100) <= 60 then
self.timer = 0 self.timer = 0
set_animation(self, "shoot") set_animation(self, "shoot")
@ -2762,7 +2759,7 @@ end
-- Code to execute before custom on_rightclick handling -- Code to execute before custom on_rightclick handling
local function on_rightclick_prefix(self, clicker) local on_rightclick_prefix = function(self, clicker)
local item = clicker:get_wielded_item() local item = clicker:get_wielded_item()
-- Name mob with nametag -- Name mob with nametag
@ -2788,17 +2785,17 @@ local function on_rightclick_prefix(self, clicker)
return false return false
end end
--[[local function create_mob_on_rightclick(on_rightclick) local create_mob_on_rightclick = function(on_rightclick)
return function(self, clicker) return function(self, clicker)
local stop = on_rightclick_prefix(self, clicker) local stop = on_rightclick_prefix(self, clicker)
if (not stop) and (on_rightclick) then if (not stop) and (on_rightclick) then
on_rightclick(self, clicker) on_rightclick(self, clicker)
end end
end end
end]] end
-- set and return valid yaw -- set and return valid yaw
local function set_yaw(self, yaw, delay, dtime) local set_yaw = function(self, yaw, delay, dtime)
if not yaw or yaw ~= yaw then if not yaw or yaw ~= yaw then
yaw = 0 yaw = 0
@ -2808,7 +2805,7 @@ local function set_yaw(self, yaw, delay, dtime)
if delay == 0 then if delay == 0 then
if self.shaking and dtime then if self.shaking and dtime then
yaw = yaw + (math.random() * 2 - 1) * 5 * dtime yaw = yaw + (math_random() * 2 - 1) * 5 * dtime
end end
self.yaw(yaw) self.yaw(yaw)
update_roll(self) update_roll(self)
@ -2828,7 +2825,8 @@ function mobs:yaw(self, yaw, delay, dtime)
end end
--mob_step = function() mob_step = function()
--if self.state == "die" then --if self.state == "die" then
-- print("need custom die stop moving thing") -- print("need custom die stop moving thing")
-- return -- return
@ -2903,7 +2901,7 @@ end
--end --end
-- mob plays random sound at times -- mob plays random sound at times
--if math.random(1, 70) == 1 then --if math_random(1, 70) == 1 then
-- mob_sound(self, "random", true) -- mob_sound(self, "random", true)
--end --end
@ -2936,11 +2934,11 @@ end
--if is_at_water_danger(self) and self.state ~= "attack" then --if is_at_water_danger(self) and self.state ~= "attack" then
-- if math.random(1, 10) <= 6 then -- if math_random(1, 10) <= 6 then
-- set_velocity(self, 0) -- set_velocity(self, 0)
-- self.state = "stand" -- self.state = "stand"
-- set_animation(self, "stand") -- set_animation(self, "stand")
-- yaw = yaw + math.random(-0.5, 0.5) -- yaw = yaw + math_random(-0.5, 0.5)
-- yaw = set_yaw(self, yaw, 8) -- yaw = set_yaw(self, yaw, 8)
-- end -- end
--end --end
@ -2984,7 +2982,7 @@ end
mcl_burning.extinguish(self.object) mcl_burning.extinguish(self.object)
self.object:remove() self.object:remove()
elseif self.lifetimer <= 10 then elseif self.lifetimer <= 10 then
if math.random(10) < 4 then if math_random(10) < 4 then
self.despawn_immediately = true self.despawn_immediately = true
else else
self.lifetimer = 20 self.lifetimer = 20
@ -2993,4 +2991,4 @@ end
end end
]]-- ]]--
--end end

View File

@ -1,13 +1,14 @@
local minetest_get_objects_inside_radius = minetest.get_objects_inside_radius local minetest_get_objects_inside_radius = minetest.get_objects_inside_radius
local vector = vector local vector_distance = vector.distance
--check to see if someone nearby has some tasty food --check to see if someone nearby has some tasty food
mobs.check_following = function(self) -- returns true or false mobs.check_following = function(self) -- returns true or false
--ignore --ignore
if not self.follow then if not self.follow then
self.following_person = nil self.following_person = nil
return false return(false)
end end
--hey look, this thing works for passive mobs too! --hey look, this thing works for passive mobs too!
@ -19,20 +20,20 @@ mobs.check_following = function(self) -- returns true or false
--safety check --safety check
if not stack then if not stack then
self.following_person = nil self.following_person = nil
return false return(false)
end end
local item_name = stack:get_name() local item_name = stack:get_name()
--all checks have passed, that guy has some good looking food --all checks have passed, that guy has some good looking food
if item_name == self.follow then if item_name == self.follow then
self.following_person = follower self.following_person = follower
return true return(true)
end end
end end
--everything failed --everything failed
self.following_person = nil self.following_person = nil
return false return(false)
end end
--a function which attempts to make mobs enter --a function which attempts to make mobs enter
@ -41,30 +42,30 @@ mobs.enter_breed_state = function(self,clicker)
--do not breed if baby --do not breed if baby
if self.baby then if self.baby then
return false return(false)
end end
--do not do anything if looking for mate or --do not do anything if looking for mate or
--if cooling off from breeding --if cooling off from breeding
if self.breed_lookout_timer > 0 or self.breed_timer > 0 then if self.breed_lookout_timer > 0 or self.breed_timer > 0 then
return false return(false)
end end
--if this is caught, that means something has gone --if this is caught, that means something has gone
--seriously wrong --seriously wrong
if not clicker or not clicker:is_player() then if not clicker or not clicker:is_player() then
return false return(false)
end end
local stack = clicker:get_wielded_item() local stack = clicker:get_wielded_item()
--safety check --safety check
if not stack then if not stack then
return false return(false)
end end
local item_name = stack:get_name() local item_name = stack:get_name()
--all checks have passed, that guy has some good looking food --all checks have passed, that guy has some good looking food
if item_name == self.follow then if item_name == self.follow then
if not minetest.is_creative_enabled(clicker:get_player_name()) then if not minetest.is_creative_enabled(clicker:get_player_name()) then
stack:take_item() stack:take_item()
clicker:set_wielded_item(stack) clicker:set_wielded_item(stack)
@ -72,11 +73,11 @@ mobs.enter_breed_state = function(self,clicker)
self.breed_lookout_timer = self.breed_lookout_timer_goal self.breed_lookout_timer = self.breed_lookout_timer_goal
self.bred = true self.bred = true
mobs.play_sound_specific(self,"mobs_mc_animal_eat_generic") mobs.play_sound_specific(self,"mobs_mc_animal_eat_generic")
return true return(true)
end end
--everything failed --everything failed
return false return(false)
end end
@ -95,23 +96,23 @@ mobs.look_for_mate = function(self)
for _,mate in pairs(minetest_get_objects_inside_radius(pos1, radius)) do for _,mate in pairs(minetest_get_objects_inside_radius(pos1, radius)) do
--look for a breeding mate --look for a breeding mate
if mate and mate:get_luaentity() if mate and mate:get_luaentity()
and mate:get_luaentity()._cmi_is_mob and mate:get_luaentity()._cmi_is_mob
and mate:get_luaentity().name == self.name and mate:get_luaentity().name == self.name
and mate:get_luaentity().breed_lookout_timer > 0 and mate:get_luaentity().breed_lookout_timer > 0
and mate:get_luaentity() ~= self then and mate:get_luaentity() ~= self then
local pos2 = mate:get_pos() local pos2 = mate:get_pos()
local distance = vector.distance(pos1,pos2) local distance = vector_distance(pos1,pos2)
if distance <= radius then if distance <= radius then
if minetest.line_of_sight then if line_of_sight then
--must add eye height or stuff breaks randomly because of --must add eye height or stuff breaks randomly because of
--seethrough nodes being a blocker (like grass) --seethrough nodes being a blocker (like grass)
if minetest.line_of_sight( if minetest_line_of_sight(
vector.new(pos1.x, pos1.y, pos1.z), vector_new(pos1.x, pos1.y, pos1.z),
vector.new(pos2.x, pos2.y + mate:get_properties().eye_height, pos2.z) vector_new(pos2.x, pos2.y + mate:get_properties().eye_height, pos2.z)
) then ) then
mates_detected = mates_detected + 1 mates_detected = mates_detected + 1
mates_in_area[mate] = distance mates_in_area[mate] = distance
@ -140,7 +141,9 @@ mobs.look_for_mate = function(self)
winner_mate = mate winner_mate = mate
end end
end end
return winner_mate
return(winner_mate)
end end
--make the baby grow up --make the baby grow up
@ -157,14 +160,14 @@ mobs.make_baby_grow_faster = function(self,clicker)
if clicker and clicker:is_player() then if clicker and clicker:is_player() then
local stack = clicker:get_wielded_item() local stack = clicker:get_wielded_item()
--safety check --safety check
if not stack then if not stack then
return false return(false)
end end
local item_name = stack:get_name() local item_name = stack:get_name()
--all checks have passed, that guy has some good looking food --all checks have passed, that guy has some good looking food
if item_name == self.follow then if item_name == self.follow then
self.grow_up_timer = self.grow_up_timer - (self.grow_up_timer * 0.10) --take 10 percent off - diminishing returns self.grow_up_timer = self.grow_up_timer - (self.grow_up_timer * 0.10) --take 10 percent off - diminishing returns
if not minetest.is_creative_enabled(clicker:get_player_name()) then if not minetest.is_creative_enabled(clicker:get_player_name()) then
stack:take_item() stack:take_item()
@ -172,8 +175,10 @@ mobs.make_baby_grow_faster = function(self,clicker)
end end
mobs.play_sound_specific(self,"mobs_mc_animal_eat_generic") mobs.play_sound_specific(self,"mobs_mc_animal_eat_generic")
return true
return(true)
end end
end end
return false
return(false)
end end

View File

@ -8,8 +8,10 @@ local vector_direction = vector.direction
local integer_test = {-1,1} local integer_test = {-1,1}
mobs.collision = function(self) mobs.collision = function(self)
local pos = self.object:get_pos() local pos = self.object:get_pos()
if not self or not self.object or not self.object:get_luaentity() then if not self or not self.object or not self.object:get_luaentity() then
return return
end end
@ -18,7 +20,7 @@ mobs.collision = function(self)
local collisionbox = self.object:get_properties().collisionbox local collisionbox = self.object:get_properties().collisionbox
pos.y = pos.y + collisionbox[2] pos.y = pos.y + collisionbox[2]
local collision_boundary = collisionbox[4] local collision_boundary = collisionbox[4]
local radius = collision_boundary local radius = collision_boundary
@ -39,7 +41,7 @@ mobs.collision = function(self)
for _,object in ipairs(minetest_get_objects_inside_radius(pos, radius*1.25)) do for _,object in ipairs(minetest_get_objects_inside_radius(pos, radius*1.25)) do
if object and object ~= self.object and (object:is_player() or (object:get_luaentity() and object:get_luaentity()._cmi_is_mob == true and object:get_luaentity().health > 0)) and if object and object ~= self.object and (object:is_player() or (object:get_luaentity() and object:get_luaentity()._cmi_is_mob == true and object:get_luaentity().health > 0)) and
--don't collide with rider, rider don't collide with thing --don't collide with rider, rider don't collide with thing
(not object:get_attach() or (object:get_attach() and object:get_attach() ~= self.object)) and (not object:get_attach() or (object:get_attach() and object:get_attach() ~= self.object)) and
(not self.object:get_attach() or (self.object:get_attach() and self.object:get_attach() ~= object)) then (not self.object:get_attach() or (self.object:get_attach() and self.object:get_attach() ~= object)) then
--stop infinite loop --stop infinite loop
collision_count = collision_count + 1 collision_count = collision_count + 1
@ -50,7 +52,7 @@ mobs.collision = function(self)
end end
local pos2 = object:get_pos() local pos2 = object:get_pos()
local object_collisionbox = object:get_properties().collisionbox local object_collisionbox = object:get_properties().collisionbox
pos2.y = pos2.y + object_collisionbox[2] pos2.y = pos2.y + object_collisionbox[2]
@ -72,7 +74,7 @@ mobs.collision = function(self)
local dir = vector.direction(pos,pos2) local dir = vector.direction(pos,pos2)
dir.y = 0 dir.y = 0
--eliminate mob being stuck in corners --eliminate mob being stuck in corners
if dir.x == 0 and dir.z == 0 then if dir.x == 0 and dir.z == 0 then
--slightly adjust mob position to prevent equal length --slightly adjust mob position to prevent equal length
@ -82,7 +84,7 @@ mobs.collision = function(self)
end end
local velocity = dir local velocity = dir
--0.5 is the max force multiplier --0.5 is the max force multiplier
local force = 0.5 - (0.5 * distance / (collision_boundary + object_collision_boundary)) local force = 0.5 - (0.5 * distance / (collision_boundary + object_collision_boundary))
@ -102,9 +104,11 @@ mobs.collision = function(self)
end end
end end
end end
self.object:add_velocity(vel1) self.object:add_velocity(vel1)
object:add_velocity(vel2) object:add_velocity(vel2)
end end
end end
end end
end end
@ -112,6 +116,7 @@ end
--this is used for arrow collisions --this is used for arrow collisions
mobs.arrow_hit = function(self, player) mobs.arrow_hit = function(self, player)
player:punch(self.object, 1.0, { player:punch(self.object, 1.0, {
full_punch_interval = 1.0, full_punch_interval = 1.0,
damage_groups = {fleshy = self._damage} damage_groups = {fleshy = self._damage}

View File

@ -1,5 +1,5 @@
local minetest_add_item = minetest.add_item local minetest_add_item = minetest.add_item
--local minetest_sound_play = minetest.sound_play local minetest_sound_play = minetest.sound_play
local math_pi = math.pi local math_pi = math.pi
local math_random = math.random local math_random = math.random
@ -19,7 +19,7 @@ local item_drop = function(self, cooked, looting_level)
return return
end end
local obj, item local obj, item, num
local pos = self.object:get_pos() local pos = self.object:get_pos()
self.drops = self.drops or {} -- nil check self.drops = self.drops or {} -- nil check
@ -56,11 +56,8 @@ local item_drop = function(self, cooked, looting_level)
-- cook items when true -- cook items when true
if cooked then if cooked then
local output = minetest.get_craft_result({ local output = minetest_get_craft_result({
method = "cooking", method = "cooking", width = 1, items = {item}})
width = 1,
items = {item},
})
if output and output.item and not output.item:is_empty() then if output and output.item and not output.item:is_empty() then
item = output.item:get_name() item = output.item:get_name()
@ -120,13 +117,15 @@ mobs.death_logic = function(self, dtime)
--the final POOF of a mob despawning --the final POOF of a mob despawning
if self.death_animation_timer >= 1.25 then if self.death_animation_timer >= 1.25 then
item_drop(self,false,1) item_drop(self,false,1)
mobs.death_effect(self) mobs.death_effect(self)
mcl_experience.throw_xp(self.object:get_pos(), math_random(self.xp_min, self.xp_max))
if self.on_die then mcl_experience.throw_experience(self.object:get_pos(), math_random(self.xp_min, self.xp_max))
self.on_die(self, self.object:get_pos())
end
self.object:remove() self.object:remove()
return return
end end
@ -158,4 +157,4 @@ mobs.death_logic = function(self, dtime)
if self.pause_timer <= 0 then if self.pause_timer <= 0 then
mobs.set_velocity(self,0) mobs.set_velocity(self,0)
end end
end end

View File

@ -1,5 +1,5 @@
local minetest_line_of_sight = minetest.line_of_sight local minetest_line_of_sight = minetest.line_of_sight
--local minetest_dir_to_yaw = minetest.dir_to_yaw local minetest_dir_to_yaw = minetest.dir_to_yaw
local minetest_yaw_to_dir = minetest.yaw_to_dir local minetest_yaw_to_dir = minetest.yaw_to_dir
local minetest_get_node = minetest.get_node local minetest_get_node = minetest.get_node
local minetest_get_item_group = minetest.get_item_group local minetest_get_item_group = minetest.get_item_group
@ -18,16 +18,19 @@ local table_copy = table.copy
local math_abs = math.abs local math_abs = math.abs
-- default function when mobs are blown up with TNT -- default function when mobs are blown up with TNT
--[[local function do_tnt(obj, damage) local do_tnt = function(obj, damage)
obj.object:punch(obj.object, 1.0, { obj.object:punch(obj.object, 1.0, {
full_punch_interval = 1.0, full_punch_interval = 1.0,
damage_groups = {fleshy = damage}, damage_groups = {fleshy = damage},
}, nil) }, nil)
return false, true, {} return false, true, {}
end]] end
--a fast function to be able to detect only players without using objects_in_radius --a fast function to be able to detect only players without using objects_in_radius
mobs.detect_closest_player_within_radius = function(self, line_of_sight, radius, object_height_adder) mobs.detect_closest_player_within_radius = function(self, line_of_sight, radius, object_height_adder)
local pos1 = self.object:get_pos() local pos1 = self.object:get_pos()
local players_in_area = {} local players_in_area = {}
local winner_player = nil local winner_player = nil
@ -46,7 +49,7 @@ mobs.detect_closest_player_within_radius = function(self, line_of_sight, radius,
--must add eye height or stuff breaks randomly because of --must add eye height or stuff breaks randomly because of
--seethrough nodes being a blocker (like grass) --seethrough nodes being a blocker (like grass)
if minetest_line_of_sight( if minetest_line_of_sight(
vector_new(pos1.x, pos1.y + object_height_adder, pos1.z), vector_new(pos1.x, pos1.y + object_height_adder, pos1.z),
vector_new(pos2.x, pos2.y + player:get_properties().eye_height, pos2.z) vector_new(pos2.x, pos2.y + player:get_properties().eye_height, pos2.z)
) then ) then
players_detected = players_detected + 1 players_detected = players_detected + 1
@ -76,7 +79,8 @@ mobs.detect_closest_player_within_radius = function(self, line_of_sight, radius,
winner_player = player winner_player = player
end end
end end
return winner_player
return(winner_player)
end end
@ -103,13 +107,14 @@ mobs.jump_check = function(self,dtime)
if green_flag_1 and green_flag_2 then if green_flag_1 and green_flag_2 then
--can jump over node --can jump over node
return 1 return(1)
elseif green_flag_1 and not green_flag_2 then elseif green_flag_1 and not green_flag_2 then
--wall in front of mob --wall in front of mob
return 2 return(2)
end end
--nothing to jump over --nothing to jump over
return 0 return(0)
end end
-- a helper function to quickly turn neutral passive mobs hostile -- a helper function to quickly turn neutral passive mobs hostile
@ -175,10 +180,15 @@ end
-- check if within physical map limits (-30911 to 30927) -- check if within physical map limits (-30911 to 30927)
-- within_limits, wmin, wmax = nil, -30913, 30928 -- within_limits, wmin, wmax = nil, -30913, 30928
mobs.within_limits = function(pos, radius) mobs.within_limits = function(pos, radius)
local wmin, wmax
if mcl_vars then if mcl_vars then
if mcl_vars.mapgen_edge_min and mcl_vars.mapgen_edge_max then if mcl_vars.mapgen_edge_min and mcl_vars.mapgen_edge_max then
wmin, wmax = mcl_vars.mapgen_edge_min, mcl_vars.mapgen_edge_max wmin, wmax = mcl_vars.mapgen_edge_min, mcl_vars.mapgen_edge_max
within_limits = function(pos, radius)
return pos
and (pos.x - radius) > wmin and (pos.x + radius) < wmax
and (pos.y - radius) > wmin and (pos.y + radius) < wmax
and (pos.z - radius) > wmin and (pos.z + radius) < wmax
end
end end
end end
return pos return pos
@ -221,12 +231,12 @@ mobs.check_for_player_within_area = function(self, radius)
local distance = vector_distance(pos1,pos2) local distance = vector_distance(pos1,pos2)
if distance < radius then if distance < radius then
--found a player --found a player
return true return(true)
end end
end end
end end
--did not find a player --did not find a player
return false return(false)
end end
@ -234,7 +244,7 @@ end
mobs.get_2d_distance = function(pos1,pos2) mobs.get_2d_distance = function(pos1,pos2)
pos1.y = 0 pos1.y = 0
pos2.y = 0 pos2.y = 0
return vector_distance(pos1, pos2) return(vector_distance(pos1, pos2))
end end
-- fall damage onto solid ground -- fall damage onto solid ground

View File

@ -1,78 +0,0 @@
--this is from https://github.com/HybridDog/builtin_item/blob/e6dfd9dce86503b3cbd1474257eca5f6f6ca71c2/init.lua#L50
local
minetest,vector,math,pairs,minetest_get_node,vector_subtract,minetest_registered_nodes
=
minetest,vector,math,pairs,minetest.get_node,vector.subtract,minetest.registered_nodes
local tab
local n
local function get_nodes(pos)
tab,n = {},1
for i = -1,1,2 do
for _,p in pairs({
{x=pos.x+i, y=pos.y, z=pos.z},
{x=pos.x, y=pos.y, z=pos.z+i}
}) do
tab[n] = {p, minetest_get_node(p)}
n = n+1
end
end
return tab
end
local data
local param2
local nd
local par2
local name
local tmp
local c_node
function mobs.get_flowing_dir(pos)
c_node = minetest_get_node(pos).name
if c_node ~= "mcl_core:water_flowing" and c_node ~= "mcl_core:water" then
return nil
end
data = get_nodes(pos)
param2 = minetest_get_node(pos).param2
if param2 > 7 then
return nil
end
if c_node == "mcl_core:water" then
for _,i in pairs(data) do
nd = i[2]
name = nd.name
par2 = nd.param2
if name == "mcl_core:water_flowing" and par2 == 7 then
return(vector_subtract(i[1],pos))
end
end
end
for _,i in pairs(data) do
nd = i[2]
name = nd.name
par2 = nd.param2
if name == "mcl_core:water_flowing" and par2 < param2 then
return(vector_subtract(i[1],pos))
end
end
for _,i in pairs(data) do
nd = i[2]
name = nd.name
par2 = nd.param2
if name == "mcl_core:water_flowing" and par2 >= 11 then
return(vector_subtract(i[1],pos))
end
end
for _,i in pairs(data) do
nd = i[2]
name = nd.name
par2 = nd.param2
tmp = minetest_registered_nodes[name]
if tmp and not tmp.walkable and name ~= "mcl_core:water_flowing" and name ~= "mcl_core:water" then
return(vector_subtract(i[1],pos))
end
end
return nil
end

View File

@ -1,98 +1,112 @@
local math = math local vector_new = vector.new
local vector = vector
--converts yaw to degrees --converts yaw to degrees
local degrees = function(yaw) local degrees = function(yaw)
return yaw*180.0/math.pi return(yaw*180.0/math.pi)
end end
mobs.do_head_logic = function(self,dtime) mobs.do_head_logic = function(self,dtime)
local player = minetest.get_player_by_name("singleplayer") local player = minetest.get_player_by_name("singleplayer")
local look_at = player:get_pos() local look_at = player:get_pos()
look_at.y = look_at.y + player:get_properties().eye_height look_at.y = look_at.y + player:get_properties().eye_height
local pos = self.object:get_pos()
local body_yaw = self.object:get_yaw()
local body_dir = minetest.yaw_to_dir(body_yaw)
pos.y = pos.y + self.head_height_offset
local head_offset = vector.multiply(body_dir, self.head_direction_offset)
pos = vector.add(pos, head_offset)
minetest.add_particle({
pos = pos,
velocity = {x=0, y=0, z=0},
acceleration = {x=0, y=0, z=0},
expirationtime = 0.2,
size = 1,
texture = "default_dirt.png",
})
local bone_pos = vector.new(0,0,0)
--(horizontal)
bone_pos.y = self.head_bone_pos_y
--(vertical)
bone_pos.z = self.head_bone_pos_z
--print(yaw)
--local _, bone_rot = self.object:get_bone_position("head")
--bone_rot.x = bone_rot.x + (dtime * 10)
--bone_rot.z = bone_rot.z + (dtime * 10)
local head_yaw = minetest.dir_to_yaw(vector.direction(pos,look_at)) - body_yaw
if self.reverse_head_yaw then
head_yaw = head_yaw * -1
end
--over rotation protection
--stops radians from going out of spec
if head_yaw > math.pi then
head_yaw = head_yaw - (math.pi * 2)
elseif head_yaw < -math.pi then
head_yaw = head_yaw + (math.pi * 2)
end
local check_failed = false
--upper check + 90 degrees or upper math.radians (3.14/2)
if head_yaw > math.pi - (math.pi/2) then
head_yaw = 0
check_failed = true
--lower check - 90 degrees or lower negative math.radians (-3.14/2)
elseif head_yaw < -math.pi + (math.pi/2) then
head_yaw = 0
check_failed = true
end
local head_pitch = 0
--DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG local pos = self.object:get_pos()
--head_yaw = 0
--DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG
if not check_failed then local body_yaw = self.object:get_yaw()
head_pitch = minetest.dir_to_yaw(vector.new(vector.distance(vector.new(pos.x,0,pos.z),vector.new(look_at.x,0,look_at.z)),0,pos.y-look_at.y))+(math.pi/2)
end
if self.head_pitch_modifier then local body_dir = minetest.yaw_to_dir(body_yaw)
head_pitch = head_pitch + self.head_pitch_modifier
end
if self.swap_y_with_x then
self.object:set_bone_position(self.head_bone, bone_pos, vector.new(degrees(head_pitch),degrees(head_yaw),0)) pos.y = pos.y + self.head_height_offset
else
self.object:set_bone_position(self.head_bone, bone_pos, vector.new(degrees(head_pitch),0,degrees(head_yaw))) local head_offset = vector.multiply(body_dir, self.head_direction_offset)
end
--set_bone_position([bone, position, rotation]) pos = vector.add(pos, head_offset)
minetest.add_particle({
pos = pos,
velocity = {x=0, y=0, z=0},
acceleration = {x=0, y=0, z=0},
expirationtime = 0.2,
size = 1,
texture = "default_dirt.png",
})
local bone_pos = vector_new(0,0,0)
--(horizontal)
bone_pos.y = self.head_bone_pos_y
--(vertical)
bone_pos.z = self.head_bone_pos_z
--print(yaw)
--local _, bone_rot = self.object:get_bone_position("head")
--bone_rot.x = bone_rot.x + (dtime * 10)
--bone_rot.z = bone_rot.z + (dtime * 10)
local head_yaw
head_yaw = minetest.dir_to_yaw(vector.direction(pos,look_at)) - body_yaw
if self.reverse_head_yaw then
head_yaw = head_yaw * -1
end
--over rotation protection
--stops radians from going out of spec
if head_yaw > math.pi then
head_yaw = head_yaw - (math.pi * 2)
elseif head_yaw < -math.pi then
head_yaw = head_yaw + (math.pi * 2)
end
local check_failed = false
--upper check + 90 degrees or upper math.radians (3.14/2)
if head_yaw > math.pi - (math.pi/2) then
head_yaw = 0
check_failed = true
--lower check - 90 degrees or lower negative math.radians (-3.14/2)
elseif head_yaw < -math.pi + (math.pi/2) then
head_yaw = 0
check_failed = true
end
local head_pitch = 0
--DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG
--head_yaw = 0
--DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG
if not check_failed then
head_pitch = minetest.dir_to_yaw(vector.new(vector.distance(vector.new(pos.x,0,pos.z),vector.new(look_at.x,0,look_at.z)),0,pos.y-look_at.y))+(math.pi/2)
end
if self.head_pitch_modifier then
head_pitch = head_pitch + self.head_pitch_modifier
end
if self.swap_y_with_x then
self.object:set_bone_position(self.head_bone, bone_pos, vector_new(degrees(head_pitch),degrees(head_yaw),0))
else
self.object:set_bone_position(self.head_bone, bone_pos, vector_new(degrees(head_pitch),0,degrees(head_yaw)))
end
--set_bone_position([bone, position, rotation])
end end

View File

@ -2,19 +2,22 @@ local minetest_after = minetest.after
local minetest_sound_play = minetest.sound_play local minetest_sound_play = minetest.sound_play
local minetest_dir_to_yaw = minetest.dir_to_yaw local minetest_dir_to_yaw = minetest.dir_to_yaw
local math = math local math_floor = math.floor
local vector = vector local math_min = math.min
local math_random = math.random
local vector_direction = vector.direction
local vector_multiply = vector.multiply
local MAX_MOB_NAME_LENGTH = 30 local MAX_MOB_NAME_LENGTH = 30
local mod_hunger = minetest.get_modpath("mcl_hunger")
mobs.feed_tame = function(self) mobs.feed_tame = function(self)
return nil return nil
end end
-- Code to execute before custom on_rightclick handling -- Code to execute before custom on_rightclick handling
local function on_rightclick_prefix(self, clicker) local on_rightclick_prefix = function(self, clicker)
local item = clicker:get_wielded_item() local item = clicker:get_wielded_item()
-- Name mob with nametag -- Name mob with nametag
@ -57,6 +60,7 @@ end
-- deal damage and effects when mob punched -- deal damage and effects when mob punched
mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir) mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
--don't do anything if the mob is already dead --don't do anything if the mob is already dead
if self.health <= 0 then if self.health <= 0 then
return return
@ -90,13 +94,14 @@ mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
pos2.y = 0 pos2.y = 0
local dir = vector.direction(pos2,pos1) local dir = vector_direction(pos2,pos1)
local yaw = minetest_dir_to_yaw(dir) local yaw = minetest_dir_to_yaw(dir)
self.yaw = yaw self.yaw = yaw
end end
-- custom punch function -- custom punch function
if self.do_punch then if self.do_punch then
-- when false skip going any further -- when false skip going any further
@ -108,20 +113,23 @@ mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
--don't do damage until pause timer resets --don't do damage until pause timer resets
if self.pause_timer > 0 then if self.pause_timer > 0 then
return return
end end
-- error checking when mod profiling is enabled -- error checking when mod profiling is enabled
if not tool_capabilities then if not tool_capabilities then
minetest.log("warning", "[mobs_mc] Mod profiling enabled, damage not enabled") minetest.log("warning", "[mobs_mc] Mod profiling enabled, damage not enabled")
return return
end end
local is_player = hitter:is_player() local is_player = hitter:is_player()
-- punch interval -- punch interval
local weapon = hitter:get_wielded_item() local weapon = hitter:get_wielded_item()
--local punch_interval = 1.4 local punch_interval = 1.4
-- exhaust attacker -- exhaust attacker
if mod_hunger and is_player then if mod_hunger and is_player then
@ -131,6 +139,7 @@ mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
-- calculate mob damage -- calculate mob damage
local damage = 0 local damage = 0
local armor = self.object:get_armor_groups() or {} local armor = self.object:get_armor_groups() or {}
local tmp
--calculate damage groups --calculate damage groups
for group,_ in pairs( (tool_capabilities.damage_groups or {}) ) do for group,_ in pairs( (tool_capabilities.damage_groups or {}) ) do
@ -154,13 +163,13 @@ mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
-- healing -- healing
if damage <= -1 then if damage <= -1 then
self.health = self.health - math.floor(damage) self.health = self.health - math_floor(damage)
return return
end end
--if tool_capabilities then if tool_capabilities then
-- punch_interval = tool_capabilities.full_punch_interval or 1.4 punch_interval = tool_capabilities.full_punch_interval or 1.4
--end end
-- add weapon wear manually -- add weapon wear manually
-- Required because we have custom health handling ("health" property) -- Required because we have custom health handling ("health" property)
@ -174,7 +183,7 @@ mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
local weapon = hitter:get_wielded_item(player) local weapon = hitter:get_wielded_item(player)
local def = weapon:get_definition() local def = weapon:get_definition()
if def.tool_capabilities and def.tool_capabilities.punch_attack_uses then if def.tool_capabilities and def.tool_capabilities.punch_attack_uses then
local wear = math.floor(65535/tool_capabilities.punch_attack_uses) local wear = math_floor(65535/tool_capabilities.punch_attack_uses)
weapon:add_wear(wear) weapon:add_wear(wear)
hitter:set_wielded_item(weapon) hitter:set_wielded_item(weapon)
end end
@ -215,7 +224,7 @@ mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
-- knock back effect -- knock back effect
local velocity = self.object:get_velocity() local velocity = self.object:get_velocity()
--2d direction --2d direction
local pos1 = self.object:get_pos() local pos1 = self.object:get_pos()
pos1.y = 0 pos1.y = 0
@ -231,8 +240,9 @@ mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
up = 0 up = 0
end end
--0.75 for perfect distance to not be too easy, and not be too hard --0.75 for perfect distance to not be too easy, and not be too hard
local multiplier = 0.75 local multiplier = 0.75
-- check if tool already has specific knockback value -- check if tool already has specific knockback value
local knockback_enchant = mcl_enchanting.get_enchantment(hitter:get_wielded_item(), "knockback") local knockback_enchant = mcl_enchanting.get_enchantment(hitter:get_wielded_item(), "knockback")
@ -244,16 +254,21 @@ mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
--it's coming for you --it's coming for you
if self.hostile then if self.hostile then
multiplier = multiplier + 2 multiplier = multiplier + 2
end end
dir = vector.multiply(dir,multiplier)
dir = vector_multiply(dir,multiplier)
dir.y = up dir.y = up
--add the velocity --add the velocity
self.object:add_velocity(dir) self.object:add_velocity(dir)
end end
end end
--do internal per mob projectile calculations --do internal per mob projectile calculations
mobs.shoot_projectile = function(self) mobs.shoot_projectile = function(self)
local pos1 = self.object:get_pos() local pos1 = self.object:get_pos()
--add mob eye height --add mob eye height
pos1.y = pos1.y + self.eye_height pos1.y = pos1.y + self.eye_height
@ -263,7 +278,7 @@ mobs.shoot_projectile = function(self)
pos2.y = pos2.y + self.attacking:get_properties().eye_height pos2.y = pos2.y + self.attacking:get_properties().eye_height
--get direction --get direction
local dir = vector.direction(pos1,pos2) local dir = vector_direction(pos1,pos2)
--call internal shoot_arrow function --call internal shoot_arrow function
self.shoot_arrow(self,pos1,dir) self.shoot_arrow(self,pos1,dir)

View File

@ -1,8 +1,9 @@
local minetest_add_particlespawner = minetest.add_particlespawner local minetest_add_particlespawner = minetest.add_particlespawner
mobs.death_effect = function(self) mobs.death_effect = function(self)
local pos = self.object:get_pos() local pos = self.object:get_pos()
--local yaw = self.object:get_yaw() local yaw = self.object:get_yaw()
local collisionbox = self.object:get_properties().collisionbox local collisionbox = self.object:get_properties().collisionbox
local min, max local min, max
@ -32,7 +33,7 @@ end
mobs.critical_effect = function(self) mobs.critical_effect = function(self)
local pos = self.object:get_pos() local pos = self.object:get_pos()
--local yaw = self.object:get_yaw() local yaw = self.object:get_yaw()
local collisionbox = self.object:get_properties().collisionbox local collisionbox = self.object:get_properties().collisionbox
local min, max local min, max
@ -61,8 +62,9 @@ end
--when feeding a mob --when feeding a mob
mobs.feed_effect = function(self) mobs.feed_effect = function(self)
local pos = self.object:get_pos() local pos = self.object:get_pos()
--local yaw = self.object:get_yaw() local yaw = self.object:get_yaw()
local collisionbox = self.object:get_properties().collisionbox local collisionbox = self.object:get_properties().collisionbox
local min, max local min, max
@ -92,7 +94,7 @@ end
--hearts when tamed --hearts when tamed
mobs.tamed_effect = function(self) mobs.tamed_effect = function(self)
local pos = self.object:get_pos() local pos = self.object:get_pos()
--local yaw = self.object:get_yaw() local yaw = self.object:get_yaw()
local collisionbox = self.object:get_properties().collisionbox local collisionbox = self.object:get_properties().collisionbox
local min, max local min, max
@ -122,7 +124,7 @@ end
--hearts when breeding --hearts when breeding
mobs.breeding_effect = function(self) mobs.breeding_effect = function(self)
local pos = self.object:get_pos() local pos = self.object:get_pos()
--local yaw = self.object:get_yaw() local yaw = self.object:get_yaw()
local collisionbox = self.object:get_properties().collisionbox local collisionbox = self.object:get_properties().collisionbox
local min, max local min, max

View File

@ -1,10 +1,16 @@
-- localize math functions local math_pi = math.pi
local math = math local math_sin = math.sin
local HALF_PI = math.pi / 2 local math_cos = math.cos
local DOUBLE_PI = math.pi * 2 local math_random = math.random
local HALF_PI = math_pi / 2
local DOUBLE_PI = math_pi * 2
-- localize vector functions -- localize vector functions
local vector = vector local vector_new = vector.new
local vector_length = vector.length
local vector_multiply = vector.multiply
local vector_distance = vector.distance
local vector_normalize = vector.normalize
local minetest_yaw_to_dir = minetest.yaw_to_dir local minetest_yaw_to_dir = minetest.yaw_to_dir
local minetest_dir_to_yaw = minetest.dir_to_yaw local minetest_dir_to_yaw = minetest.dir_to_yaw
@ -13,17 +19,18 @@ local DEFAULT_JUMP_HEIGHT = 5
local DEFAULT_FLOAT_SPEED = 4 local DEFAULT_FLOAT_SPEED = 4
local DEFAULT_CLIMB_SPEED = 3 local DEFAULT_CLIMB_SPEED = 3
mobs.stick_in_cobweb = function(self) mobs.stick_in_cobweb = function(self)
local current_velocity = self.object:get_velocity() local current_velocity = self.object:get_velocity()
local goal_velocity = vector.multiply(vector.normalize(current_velocity), 0.4) local goal_velocity = vector_multiply(vector_normalize(current_velocity), 0.4)
goal_velocity.y = -0.5 goal_velocity.y = -0.5
local new_velocity_addition = vector.subtract(goal_velocity,current_velocity) local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
--smooths out mobs a bit --smooths out mobs a bit
if vector.length(new_velocity_addition) >= 0.0001 then if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition) self.object:add_velocity(new_velocity_addition)
end end
end end
@ -31,14 +38,8 @@ end
--this is a generic float function --this is a generic float function
mobs.float = function(self) mobs.float = function(self)
local acceleration = self.object:get_acceleration() if self.object:get_acceleration().y ~= 0 then
self.object:set_acceleration(vector_new(0,0,0))
if not acceleration then
return
end
if acceleration.y ~= 0 then
self.object:set_acceleration({x=0, y=0, z=0})
end end
local current_velocity = self.object:get_velocity() local current_velocity = self.object:get_velocity()
@ -49,13 +50,13 @@ mobs.float = function(self)
z = 0, z = 0,
} }
local new_velocity_addition = vector.subtract(goal_velocity, current_velocity) local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
new_velocity_addition.x = 0 new_velocity_addition.x = 0
new_velocity_addition.z = 0 new_velocity_addition.z = 0
--smooths out mobs a bit --smooths out mobs a bit
if vector.length(new_velocity_addition) >= 0.0001 then if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition) self.object:add_velocity(new_velocity_addition)
end end
end end
@ -77,7 +78,7 @@ mobs.climb = function(self)
new_velocity_addition.z = 0 new_velocity_addition.z = 0
--smooths out mobs a bit --smooths out mobs a bit
if vector.length(new_velocity_addition) >= 0.0001 then if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition) self.object:add_velocity(new_velocity_addition)
end end
end end
@ -85,10 +86,10 @@ end
--[[ --[[
_ _ _ _
| | | | | | | |
| | __ _ _ __ __| | | | __ _ _ __ __| |
| | / _` | '_ \ / _` | | | / _` | '_ \ / _` |
| |___| (_| | | | | (_| | | |___| (_| | | | | (_| |
\_____/\__,_|_| |_|\__,_| \_____/\__,_|_| |_|\__,_|
]] ]]
@ -99,28 +100,28 @@ end
--internal = lua (self.yaw) --internal = lua (self.yaw)
--engine = c++ (self.object:get_yaw()) --engine = c++ (self.object:get_yaw())
mobs.set_velocity = function(self, v) mobs.set_velocity = function(self, v)
local yaw = (self.yaw or 0) local yaw = (self.yaw or 0)
local current_velocity = self.object:get_velocity() local current_velocity = self.object:get_velocity()
local goal_velocity = { local goal_velocity = {
x = (math.sin(yaw) * -v), x = (math_sin(yaw) * -v),
y = 0, y = 0,
z = (math.cos(yaw) * v), z = (math_cos(yaw) * v),
} }
local new_velocity_addition = vector.subtract(goal_velocity,current_velocity) local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
if vector.length(new_velocity_addition) > vector.length(goal_velocity) then if vector_length(new_velocity_addition) > vector_length(goal_velocity) then
vector.multiply(new_velocity_addition, (vector.length(goal_velocity) / vector.length(new_velocity_addition))) vector.multiply(new_velocity_addition, (vector_length(goal_velocity) / vector_length(new_velocity_addition)))
end end
new_velocity_addition.y = 0 new_velocity_addition.y = 0
--smooths out mobs a bit --smooths out mobs a bit
if vector.length(new_velocity_addition) >= 0.0001 then if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition) self.object:add_velocity(new_velocity_addition)
end end
end end
@ -135,7 +136,7 @@ mobs.get_velocity = function(self)
v.y = 0 v.y = 0
if v then if v then
return vector.length(v) return vector_length(v)
end end
return 0 return 0
@ -151,7 +152,7 @@ mobs.jump = function(self, velocity)
--fallback velocity to allow modularity --fallback velocity to allow modularity
velocity = velocity or DEFAULT_JUMP_HEIGHT velocity = velocity or DEFAULT_JUMP_HEIGHT
self.object:add_velocity(vector.new(0,velocity,0)) self.object:add_velocity(vector_new(0,velocity,0))
end end
--make mobs fall slowly --make mobs fall slowly
@ -171,15 +172,15 @@ mobs.mob_fall_slow = function(self)
new_velocity_addition.x = 0 new_velocity_addition.x = 0
new_velocity_addition.z = 0 new_velocity_addition.z = 0
if vector.length(new_velocity_addition) > vector.length(goal_velocity) then if vector_length(new_velocity_addition) > vector_length(goal_velocity) then
vector.multiply(new_velocity_addition, (vector.length(goal_velocity) / vector.length(new_velocity_addition))) vector.multiply(new_velocity_addition, (vector_length(goal_velocity) / vector_length(new_velocity_addition)))
end end
new_velocity_addition.x = 0 new_velocity_addition.x = 0
new_velocity_addition.z = 0 new_velocity_addition.z = 0
--smooths out mobs a bit --smooths out mobs a bit
if vector.length(new_velocity_addition) >= 0.0001 then if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition) self.object:add_velocity(new_velocity_addition)
end end
@ -187,10 +188,10 @@ end
--[[ --[[
_____ _ _____ _
/ ___| (_) / ___| (_)
\ `--.__ ___ _ __ ___ \ `--.__ ___ _ __ ___
`--. \ \ /\ / / | '_ ` _ \ `--. \ \ /\ / / | '_ ` _ \
/\__/ /\ V V /| | | | | | | /\__/ /\ V V /| | | | | | |
\____/ \_/\_/ |_|_| |_| |_| \____/ \_/\_/ |_|_| |_| |_|
]]-- ]]--
@ -211,16 +212,16 @@ mobs.flop = function(self, velocity)
velocity = velocity or DEFAULT_JUMP_HEIGHT velocity = velocity or DEFAULT_JUMP_HEIGHT
--create a random direction (2d yaw) --create a random direction (2d yaw)
local dir = DOUBLE_PI * math.random() local dir = DOUBLE_PI * math_random()
--create a random force value --create a random force value
local force = math.random(0,3) + math.random() local force = math_random(0,3) + math_random()
--convert the yaw to a direction vector then multiply it times the force --convert the yaw to a direction vector then multiply it times the force
local final_additional_force = vector.multiply(minetest_yaw_to_dir(dir), force) local final_additional_force = vector_multiply(minetest_yaw_to_dir(dir), force)
--place in the "flop" velocity to make the mob flop --place in the "flop" velocity to make the mob flop
final_additional_force.y = velocity final_additional_force.y = velocity
self.object:add_velocity(final_additional_force) self.object:add_velocity(final_additional_force)
@ -234,7 +235,7 @@ end
--internal = lua (self.yaw) --internal = lua (self.yaw)
--engine = c++ (self.object:get_yaw()) --engine = c++ (self.object:get_yaw())
mobs.set_swim_velocity = function(self, v) mobs.set_swim_velocity = function(self, v)
local yaw = (self.yaw or 0) local yaw = (self.yaw or 0)
local pitch = (self.pitch or 0) local pitch = (self.pitch or 0)
@ -245,33 +246,33 @@ mobs.set_swim_velocity = function(self, v)
local current_velocity = self.object:get_velocity() local current_velocity = self.object:get_velocity()
local goal_velocity = { local goal_velocity = {
x = (math.sin(yaw) * -v), x = (math_sin(yaw) * -v),
y = pitch, y = pitch,
z = (math.cos(yaw) * v), z = (math_cos(yaw) * v),
} }
local new_velocity_addition = vector.subtract(goal_velocity,current_velocity) local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
if vector.length(new_velocity_addition) > vector.length(goal_velocity) then if vector_length(new_velocity_addition) > vector_length(goal_velocity) then
vector.multiply(new_velocity_addition, (vector.length(goal_velocity) / vector.length(new_velocity_addition))) vector.multiply(new_velocity_addition, (vector_length(goal_velocity) / vector_length(new_velocity_addition)))
end end
--smooths out mobs a bit --smooths out mobs a bit
if vector.length(new_velocity_addition) >= 0.0001 then if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition) self.object:add_velocity(new_velocity_addition)
end end
end end
--[[ --[[
______ _ ______ _
| ___| | | ___| |
| |_ | |_ _ | |_ | |_ _
| _| | | | | | | _| | | | | |
| | | | |_| | | | | | |_| |
\_| |_|\__, | \_| |_|\__, |
__/ | __/ |
|___/ |___/
]]-- ]]--
-- move mob in facing direction -- move mob in facing direction
@ -279,7 +280,7 @@ ______ _
--internal = lua (self.yaw) --internal = lua (self.yaw)
--engine = c++ (self.object:get_yaw()) --engine = c++ (self.object:get_yaw())
mobs.set_fly_velocity = function(self, v) mobs.set_fly_velocity = function(self, v)
local yaw = (self.yaw or 0) local yaw = (self.yaw or 0)
local pitch = (self.pitch or 0) local pitch = (self.pitch or 0)
@ -290,20 +291,20 @@ mobs.set_fly_velocity = function(self, v)
local current_velocity = self.object:get_velocity() local current_velocity = self.object:get_velocity()
local goal_velocity = { local goal_velocity = {
x = (math.sin(yaw) * -v), x = (math_sin(yaw) * -v),
y = pitch, y = pitch,
z = (math.cos(yaw) * v), z = (math_cos(yaw) * v),
} }
local new_velocity_addition = vector.subtract(goal_velocity,current_velocity) local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
if vector.length(new_velocity_addition) > vector.length(goal_velocity) then if vector_length(new_velocity_addition) > vector_length(goal_velocity) then
vector.multiply(new_velocity_addition, (vector.length(goal_velocity) / vector.length(new_velocity_addition))) vector.multiply(new_velocity_addition, (vector_length(goal_velocity) / vector_length(new_velocity_addition)))
end end
--smooths out mobs a bit --smooths out mobs a bit
if vector.length(new_velocity_addition) >= 0.0001 then if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition) self.object:add_velocity(new_velocity_addition)
end end
end end
@ -315,7 +316,7 @@ mobs.calculate_pitch = function(pos1, pos2)
return false return false
end end
return minetest_dir_to_yaw(vector.new(vector.distance(vector.new(pos1.x,0,pos1.z),vector.new(pos2.x,0,pos2.z)),0,pos1.y - pos2.y)) + HALF_PI return(minetest_dir_to_yaw(vector_new(vector_distance(vector_new(pos1.x,0,pos1.z),vector_new(pos2.x,0,pos2.z)),0,pos1.y - pos2.y)) + HALF_PI)
end end
--make mobs fly up or down based on their y difference --make mobs fly up or down based on their y difference
@ -331,14 +332,14 @@ end
--[[ --[[
___ ___
|_ | |_ |
| |_ _ _ __ ___ _ __ | |_ _ _ __ ___ _ __
| | | | | '_ ` _ \| '_ \ | | | | | '_ ` _ \| '_ \
/\__/ / |_| | | | | | | |_) | /\__/ / |_| | | | | | | |_) |
\____/ \__,_|_| |_| |_| .__/ \____/ \__,_|_| |_| |_| .__/
| | | |
|_| |_|
]]-- ]]--
--special mob jump movement --special mob jump movement
@ -352,27 +353,27 @@ mobs.jump_move = function(self, velocity)
mobs.set_velocity(self,0) mobs.set_velocity(self,0)
--fallback velocity to allow modularity --fallback velocity to allow modularity
local jump_height = DEFAULT_JUMP_HEIGHT jump_height = DEFAULT_JUMP_HEIGHT
local yaw = (self.yaw or 0) local yaw = (self.yaw or 0)
local current_velocity = self.object:get_velocity() local current_velocity = self.object:get_velocity()
local goal_velocity = { local goal_velocity = {
x = (math.sin(yaw) * -velocity), x = (math_sin(yaw) * -velocity),
y = jump_height, y = jump_height,
z = (math.cos(yaw) * velocity), z = (math_cos(yaw) * velocity),
} }
local new_velocity_addition = vector.subtract(goal_velocity,current_velocity) local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
if vector.length(new_velocity_addition) > vector.length(goal_velocity) then if vector_length(new_velocity_addition) > vector_length(goal_velocity) then
vector.multiply(new_velocity_addition, (vector.length(goal_velocity) / vector.length(new_velocity_addition))) vector.multiply(new_velocity_addition, (vector_length(goal_velocity) / vector_length(new_velocity_addition)))
end end
--smooths out mobs a bit --smooths out mobs a bit
if vector.length(new_velocity_addition) >= 0.0001 then if vector_length(new_velocity_addition) >= 0.0001 then
self.object:add_velocity(new_velocity_addition) self.object:add_velocity(new_velocity_addition)
end end
end end
@ -387,4 +388,4 @@ mobs.swap_auto_step_height_adjust = function(self)
elseif y_vel ~= 0 and self.stepheight ~= 0 then elseif y_vel ~= 0 and self.stepheight ~= 0 then
self.stepheight = 0 self.stepheight = 0
end end
end end

View File

@ -36,8 +36,9 @@ mobs.shoot_projectile_handling = function(arrow_item, pos, dir, yaw, shooter, po
le._collectable = collectable le._collectable = collectable
--play custom shoot sound --play custom shoot sound
if shooter and shooter.shoot_sound then if shooter ~= nil and shooter.shoot_sound then
minetest.sound_play(shooter.shoot_sound, {pos=pos, max_hear_distance=16}, true) minetest.sound_play(shooter.shoot_sound, {pos=pos, max_hear_distance=16}, true)
end end
return obj return obj
end end

View File

@ -1,12 +1,10 @@
local math_random = math.random local math_random = math.random
local minetest_settings = minetest.settings local minetest_settings = minetest.settings
-- CMI support check
local use_cmi = minetest.global_exists("cmi")
-- get entity staticdata -- get entity staticdata
mobs.mob_staticdata = function(self) mobs.mob_staticdata = function(self)
--despawn mechanism --despawn mechanism
--don't despawned tamed or bred mobs --don't despawned tamed or bred mobs
if not self.tamed and not self.bred then if not self.tamed and not self.bred then
@ -144,6 +142,8 @@ mobs.mob_activate = function(self, staticdata, def, dtime)
self.health = math_random (self.hp_min, self.hp_max) self.health = math_random (self.hp_min, self.hp_max)
end end
if not self.random_sound_timer then if not self.random_sound_timer then
self.random_sound_timer = math_random(self.random_sound_timer_min,self.random_sound_timer_max) self.random_sound_timer = math_random(self.random_sound_timer_min,self.random_sound_timer_max)
end end
@ -185,6 +185,7 @@ mobs.mob_activate = function(self, staticdata, def, dtime)
self.opinion_sound_cooloff = 0 -- used to prevent sound spam of particular sound types self.opinion_sound_cooloff = 0 -- used to prevent sound spam of particular sound types
self.texture_mods = {} self.texture_mods = {}
self.v_start = false self.v_start = false
self.timer = 0 self.timer = 0
@ -198,6 +199,7 @@ mobs.mob_activate = function(self, staticdata, def, dtime)
else else
self.object:set_texture_mod("") self.object:set_texture_mod("")
end end
-- set anything changed above -- set anything changed above
self.object:set_properties(self) self.object:set_properties(self)

View File

@ -1,11 +1,8 @@
-- lib_mount by Blert2112 (edited by TenPlus1) -- lib_mount by Blert2112 (edited by TenPlus1)
--local enable_crash = false local enable_crash = false
--local crash_threshold = 6.5 -- ignored if enable_crash=false local crash_threshold = 6.5 -- ignored if enable_crash=false
local math = math
local vector = vector
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
@ -13,7 +10,7 @@ local vector = vector
-- Helper functions -- Helper functions
-- --
--[[local function node_ok(pos, fallback) local node_ok = function(pos, fallback)
fallback = fallback or mobs.fallback_node fallback = fallback or mobs.fallback_node
@ -24,10 +21,10 @@ local vector = vector
end end
return {name = fallback} return {name = fallback}
end]] end
--[[local function node_is(pos) local function node_is(pos)
local node = node_ok(pos) local node = node_ok(pos)
@ -48,7 +45,7 @@ end]]
end end
return "other" return "other"
end]] end
local function get_sign(i) local function get_sign(i)
@ -63,11 +60,13 @@ local function get_sign(i)
end end
--[[local function get_velocity(v, yaw, y) local function get_velocity(v, yaw, y)
local x = -math.sin(yaw) * v local x = -math.sin(yaw) * v
local z = math.cos(yaw) * v local z = math.cos(yaw) * v
return {x = x, y = y, z = z} return {x = x, y = y, z = z}
end]] end
local function get_v(v) local function get_v(v)
@ -173,7 +172,7 @@ function mobs.detach(player, offset)
--pos = {x = pos.x + offset.x, y = pos.y + 0.2 + offset.y, z = pos.z + offset.z} --pos = {x = pos.x + offset.x, y = pos.y + 0.2 + offset.y, z = pos.z + offset.z}
player:add_velocity(vector.new(math.random(-6,6), math.random(5,8), math.random(-6,6))) --throw the rider off player:add_velocity(vector.new(math.random(-6,6),math.random(5,8),math.random(-6,6))) --throw the rider off
--[[ --[[
minetest.after(0.1, function(name, pos) minetest.after(0.1, function(name, pos)
@ -188,13 +187,13 @@ end
function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
--local rot_view = 0 local rot_view = 0
--if entity.player_rotation.y == 90 then if entity.player_rotation.y == 90 then
-- rot_view = math.pi/2 rot_view = math.pi/2
--end end
--local acce_y = 0 local acce_y = 0
local velo = entity.object:get_velocity() local velo = entity.object:get_velocity()
entity.v = get_v(velo) * get_sign(entity.v) entity.v = get_v(velo) * get_sign(entity.v)
@ -389,6 +388,7 @@ end
-- directional flying routine by D00Med (edited by TenPlus1) -- directional flying routine by D00Med (edited by TenPlus1)
function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim) function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim)
if true then if true then
print("succ") print("succ")
return return

View File

@ -5,21 +5,19 @@ local get_node_light = minetest.get_node_light
local find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air local find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air
local get_biome_name = minetest.get_biome_name local get_biome_name = minetest.get_biome_name
local get_objects_inside_radius = minetest.get_objects_inside_radius local get_objects_inside_radius = minetest.get_objects_inside_radius
local get_connected_players = minetest.get_connected_players
local math_random = math.random local math_random = math.random
local math_floor = math.floor local math_floor = math.floor
--local max = math.max local max = math.max
--local vector_distance = vector.distance local vector_distance = vector.distance
local vector_new = vector.new local vector_new = vector.new
local vector_floor = vector.floor local vector_floor = vector.floor
local table_copy = table.copy local table_copy = table.copy
local table_remove = table.remove local table_remove = table.remove
local pairs = pairs
-- range for mob count -- range for mob count
local aoc_range = 48 local aoc_range = 48
@ -169,7 +167,7 @@ Overworld regular:
-- count how many mobs are in an area -- count how many mobs are in an area
local function count_mobs(pos) local count_mobs = function(pos)
local num = 0 local num = 0
for _,object in pairs(get_objects_inside_radius(pos, aoc_range)) do for _,object in pairs(get_objects_inside_radius(pos, aoc_range)) do
if object and object:get_luaentity() and object:get_luaentity()._cmi_is_mob then if object and object:get_luaentity() and object:get_luaentity()._cmi_is_mob then
@ -244,7 +242,8 @@ function mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_ligh
end end
--[[ --[[
local function spawn_action(pos, node, active_object_count, active_object_count_wider, name) local spawn_action
spawn_action = function(pos, node, active_object_count, active_object_count_wider, name)
local orig_pos = table.copy(pos) local orig_pos = table.copy(pos)
-- is mob actually registered? -- is mob actually registered?
@ -281,7 +280,7 @@ function mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_ligh
end end
-- if toggle set to nil then ignore day/night check -- if toggle set to nil then ignore day/night check
if day_toggle then if day_toggle ~= nil then
local tod = (minetest.get_timeofday() or 0) * 24000 local tod = (minetest.get_timeofday() or 0) * 24000
@ -371,7 +370,7 @@ function mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_ligh
if minetest.registered_nodes[node_ok(pos2).name].walkable == true then if minetest.registered_nodes[node_ok(pos2).name].walkable == true then
-- inside block -- inside block
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too little space!") minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too little space!")
if ent.spawn_small_alternative and (not minetest.registered_nodes[node_ok(pos).name].walkable) then if ent.spawn_small_alternative ~= nil and (not minetest.registered_nodes[node_ok(pos).name].walkable) then
minetest.log("info", "Trying to spawn smaller alternative mob: "..ent.spawn_small_alternative) minetest.log("info", "Trying to spawn smaller alternative mob: "..ent.spawn_small_alternative)
spawn_action(orig_pos, node, active_object_count, active_object_count_wider, ent.spawn_small_alternative) spawn_action(orig_pos, node, active_object_count, active_object_count_wider, ent.spawn_small_alternative)
end end
@ -487,8 +486,7 @@ local axis
local inner = 15 local inner = 15
local outer = 64 local outer = 64
local int = {-1,1} local int = {-1,1}
local position_calculation = function(pos)
local function position_calculation(pos)
pos = vector_floor(pos) pos = vector_floor(pos)
@ -503,7 +501,7 @@ local function position_calculation(pos)
pos.z = pos.z + math_random(inner,outer)*int[math_random(1,2)] pos.z = pos.z + math_random(inner,outer)*int[math_random(1,2)]
pos.x = pos.x + math_random(-outer,outer) pos.x = pos.x + math_random(-outer,outer)
end end
return pos return(pos)
end end
--[[ --[[
@ -542,7 +540,7 @@ if mobs_spawn then
timer = timer + dtime timer = timer + dtime
if timer >= 10 then if timer >= 10 then
timer = 0 timer = 0
for _,player in pairs(get_connected_players()) do for _,player in pairs(minetest.get_connected_players()) do
-- after this line each "break" means "continue" -- after this line each "break" means "continue"
local do_mob_spawning = true local do_mob_spawning = true
repeat repeat
@ -550,15 +548,15 @@ if mobs_spawn then
--they happen in a single server step --they happen in a single server step
local player_pos = player:get_pos() local player_pos = player:get_pos()
local dimension = mcl_worlds.pos_to_dimension(player_pos) local _,dimension = mcl_worlds.y_to_layer(player_pos.y)
if dimension == "void" or dimension == "default" then if dimension == "void" or dimension == "default" then
break -- ignore void and unloaded area break -- ignore void and unloaded area
end end
local min, max = decypher_limits(player_pos.y) local min,max = decypher_limits(player_pos.y)
for i = 1, math_random(1,4) do for i = 1,math_random(1,4) do
-- after this line each "break" means "continue" -- after this line each "break" means "continue"
local do_mob_algorithm = true local do_mob_algorithm = true
repeat repeat
@ -575,10 +573,10 @@ if mobs_spawn then
local spawning_position = spawning_position_list[math_random(1,#spawning_position_list)] local spawning_position = spawning_position_list[math_random(1,#spawning_position_list)]
--Prevent strange behavior --- this is commented out: /too close to player --fixed with inner circle --Prevent strange behavior --- this is commented out: /too close to player --fixed with inner circle
if not spawning_position then -- or vector_distance(player_pos, spawning_position) < 15 if not spawning_position then -- or vector_distance(player_pos, spawning_position) < 15
break break
end end
--hard code mob limit in area to 5 for now --hard code mob limit in area to 5 for now
if count_mobs(spawning_position) >= 5 then if count_mobs(spawning_position) >= 5 then
break break
@ -608,7 +606,7 @@ if mobs_spawn then
local is_lava = get_item_group(gotten_node, "lava") ~= 0 local is_lava = get_item_group(gotten_node, "lava") ~= 0
local mob_def = nil local mob_def = nil
--create a disconnected clone of the spawn dictionary --create a disconnected clone of the spawn dictionary
--prevents memory leak --prevents memory leak
local mob_library_worker_table = table_copy(spawn_dictionary) local mob_library_worker_table = table_copy(spawn_dictionary)

View File

@ -1,5 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator("mcl_mobs")
-- name tag -- name tag
minetest.register_craftitem("mcl_mobs:nametag", { minetest.register_craftitem("mcl_mobs:nametag", {

View File

@ -1,11 +0,0 @@
# textdomain: mcl_mobs
Peaceful mode active! No monsters will spawn.=Tryb pokojowy aktywowany! Potwory nie będą się pojawiać.
This allows you to place a single mob.=To pozwala na przywołanie jednego moba.
Just place it where you want the mob to appear. Animals will spawn tamed, unless you hold down the sneak key while placing. If you place this on a mob spawner, you change the mob it spawns.=Postaw to w miejscu w którym chcesz aby pojawił się mob. Zwierzęta pojawią się jako oswojone chyba, że będziesz się skradał podczas stawiania. Jeśli postawisz to na spawnerze to zmienisz którego moba przywołuje.
You need the “maphack” privilege to change the mob spawner.=Potrzebujesz przywileju "maphack", aby zmienić spawner.
Name Tag=Znacznik
A name tag is an item to name a mob.=Znacznik jest przedmiotem pozwalającym nazwać moba.
Before you use the name tag, you need to set a name at an anvil. Then you can use the name tag to name a mob. This uses up the name tag.=Zanim użyjesz znacznika musisz wybrać imię przy kowadle. Następnie możesz użyć znacznika by nazwać moba. To zużywa znacznik.
Only peaceful mobs allowed!=Tylko pokojowe moby są dozwolone!
Give names to mobs=Nazwij moby
Set name at anvil=Wybierz imię przy kowadle

View File

@ -2,4 +2,4 @@ name = mcl_mobs
author = PilzAdam author = PilzAdam
description = Adds a mob API for mods to add animals or monsters, etc. description = Adds a mob API for mods to add animals or monsters, etc.
depends = mcl_particles depends = mcl_particles
optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, cmi, doc_identifier, mcl_armor, mcl_portals, mcl_experience optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, invisibility, lucky_block, cmi, doc_identifier, mcl_armor, mcl_portals, mcl_experience

View File

@ -1,15 +1,12 @@
mcl_paintings = {} mcl_paintings = {}
local modname = minetest.get_current_modname() dofile(minetest.get_modpath(minetest.get_current_modname()).."/paintings.lua")
dofile(minetest.get_modpath(modname).."/paintings.lua")
local S = minetest.get_translator(modname) local S = minetest.get_translator("mcl_paintings")
local math = math
local wood = "[combine:16x16:-192,0=mcl_paintings_paintings.png" local wood = "[combine:16x16:-192,0=mcl_paintings_paintings.png"
local function is_protected(pos, name) local is_protected = function(pos, name)
if minetest.is_protected(pos, name) then if minetest.is_protected(pos, name) then
minetest.record_protection_violation(pos, name) minetest.record_protection_violation(pos, name)
return true return true
@ -20,7 +17,7 @@ end
-- Check if there's a painting for provided painting size. -- Check if there's a painting for provided painting size.
-- If yes, returns the arguments. -- If yes, returns the arguments.
-- If not, returns the next smaller available painting. -- If not, returns the next smaller available painting.
local function shrink_painting(x, y) local shrink_painting = function(x, y)
if x > 4 or y > 4 then if x > 4 or y > 4 then
return nil return nil
end end
@ -46,7 +43,7 @@ local function shrink_painting(x, y)
end end
end end
local function get_painting(x, y, motive) local get_painting = function(x, y, motive)
local painting = mcl_paintings.paintings[y] and mcl_paintings.paintings[y][x] and mcl_paintings.paintings[y][x][motive] local painting = mcl_paintings.paintings[y] and mcl_paintings.paintings[y][x] and mcl_paintings.paintings[y][x][motive]
if not painting then if not painting then
return nil return nil
@ -56,7 +53,7 @@ local function get_painting(x, y, motive)
return "[combine:"..sx.."x"..sy..":"..px..","..py.."=mcl_paintings_paintings.png" return "[combine:"..sx.."x"..sy..":"..px..","..py.."=mcl_paintings_paintings.png"
end end
local function get_random_painting(x, y) local get_random_painting = function(x, y)
if not mcl_paintings.paintings[y] or not mcl_paintings.paintings[y][x] then if not mcl_paintings.paintings[y] or not mcl_paintings.paintings[y][x] then
return nil return nil
end end
@ -68,7 +65,7 @@ local function get_random_painting(x, y)
return get_painting(x, y, r), r return get_painting(x, y, r), r
end end
--[[local function size_to_minmax(size) local size_to_minmax = function(size)
local min, max local min, max
if size == 2 then if size == 2 then
min = -0.5 min = -0.5
@ -84,13 +81,13 @@ end
max = 0.5 max = 0.5
end end
return min, max return min, max
end]] end
local function size_to_minmax_entity(size) local size_to_minmax_entity = function(size)
return -size/2, size/2 return -size/2, size/2
end end
local function set_entity(object) local set_entity = function(object)
local ent = object:get_luaentity() local ent = object:get_luaentity()
local wallm = ent._facing local wallm = ent._facing
local xsize = ent._xsize local xsize = ent._xsize
@ -172,7 +169,7 @@ minetest.register_entity("mcl_paintings:painting", {
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage) on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
-- Drop as item on punch -- Drop as item on punch
if puncher and puncher:is_player() then if puncher and puncher:is_player() then
local kname = puncher:get_player_name() kname = puncher:get_player_name()
local pos = self._pos local pos = self._pos
if not pos then if not pos then
pos = self.object:get_pos() pos = self.object:get_pos()

View File

@ -1,2 +0,0 @@
# textdomain:mcl_paintings
Painting=Obraz

View File

@ -3,7 +3,7 @@ local TS = 16 -- texture size
mcl_paintings.paintings = { mcl_paintings.paintings = {
[1] = { [1] = {
[1] = { [1] = {
{ cx = 0, cy = 0 }, { cx = 0, cy = 0 },
{ cx = TS, cy = 0 }, { cx = TS, cy = 0 },
{ cx = 2*TS, cy = 0 }, { cx = 2*TS, cy = 0 },
{ cx = 3*TS, cy = 0 }, { cx = 3*TS, cy = 0 },
@ -26,7 +26,7 @@ mcl_paintings.paintings = {
{ cx = 0, cy = 4*TS }, { cx = 0, cy = 4*TS },
{ cx = TS, cy = 4*TS }, { cx = TS, cy = 4*TS },
}, },
[2] = { [2] = {
{ cx = 0, cy = 8*TS }, { cx = 0, cy = 8*TS },
{ cx = 2*TS, cy = 8*TS }, { cx = 2*TS, cy = 8*TS },
{ cx = 4*TS, cy = 8*TS }, { cx = 4*TS, cy = 8*TS },
@ -35,7 +35,7 @@ mcl_paintings.paintings = {
{ cx = 10*TS, cy = 8*TS }, { cx = 10*TS, cy = 8*TS },
}, },
[3] = 2, [3] = 2,
[4] = { [4] = {
{ cx = 0, cy = 6*TS }, { cx = 0, cy = 6*TS },
}, },
}, },

View File

@ -15,7 +15,7 @@ with name "mobs_mc_gameconfig". ]]
-- Set to false in your gameconfig mod if you create your own monster egg nodes. -- Set to false in your gameconfig mod if you create your own monster egg nodes.
mobs_mc.create_monster_egg_nodes = true mobs_mc.create_monster_egg_nodes = true
--mobs_mc.items = {} mobs_mc.items = {}
mobs_mc.items = { mobs_mc.items = {
-- Items defined in mobs_mc -- Items defined in mobs_mc
@ -83,7 +83,7 @@ mobs_mc.items = {
water_source = "default:water_source", water_source = "default:water_source",
water_flowing = "default:water_flowing", water_flowing = "default:water_flowing",
river_water_source = "default:river_water_source", river_water_source = "default:river_water_source",
--water_flowing = "default:river_water_flowing", water_flowing = "default:river_water_flowing",
black_dye = "dye:black", black_dye = "dye:black",
poppy = "flowers:rose", poppy = "flowers:rose",
dandelion = "flowers:dandelion_yellow", dandelion = "flowers:dandelion_yellow",
@ -128,6 +128,7 @@ mobs_mc.items = {
nether_portal = "nether:portal", nether_portal = "nether:portal",
netherrack = "nether:rack", netherrack = "nether:rack",
nether_brick_block = "nether:brick",
-- Wool (Minecraft color scheme) -- Wool (Minecraft color scheme)
wool_white = "wool:white", wool_white = "wool:white",

View File

@ -8,7 +8,7 @@
-- NOTE: Most strings intentionally not marked for translation, other mods already have these items. -- NOTE: Most strings intentionally not marked for translation, other mods already have these items.
-- TODO: Remove this file eventually, most items are already outsourced in other mods. -- TODO: Remove this file eventually, most items are already outsourced in other mods.
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator("mobs_mc")
local c = mobs_mc.is_item_variable_overridden local c = mobs_mc.is_item_variable_overridden
@ -234,8 +234,8 @@ end
if c("ender_eye") and c("blaze_powder") and c("blaze_rod") then if c("ender_eye") and c("blaze_powder") and c("blaze_rod") then
minetest.register_craft({ minetest.register_craft({
type = "shapeless", type = "shapeless",
output = "mobs_mc:ender_eye", output = 'mobs_mc:ender_eye',
recipe = { "mobs_mc:blaze_powder", "mobs_mc:blaze_rod"}, recipe = { 'mobs_mc:blaze_powder', 'mobs_mc:blaze_rod'},
}) })
end end

View File

@ -6,7 +6,7 @@
-- NOTE: Strings intentionally not marked for translation, other mods already have these items. -- NOTE: Strings intentionally not marked for translation, other mods already have these items.
-- TODO: Remove this file eventually, all items here are already outsourced in other mods. -- TODO: Remove this file eventually, all items here are already outsourced in other mods.
--local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator("mobs_mc")
--maikerumines throwing code --maikerumines throwing code
--arrow (weapon) --arrow (weapon)
@ -83,7 +83,7 @@ THROWING_ARROW_ENTITY.on_step = function(self, dtime)
if self.timer>0.2 then if self.timer>0.2 then
local objs = minetest.get_objects_inside_radius({x=pos.x,y=pos.y,z=pos.z}, 1.5) local objs = minetest.get_objects_inside_radius({x=pos.x,y=pos.y,z=pos.z}, 1.5)
for k, obj in pairs(objs) do for k, obj in pairs(objs) do
if obj:get_luaentity() then if obj:get_luaentity() ~= nil then
if obj:get_luaentity().name ~= "mobs_mc:arrow_entity" and obj:get_luaentity().name ~= "__builtin:item" then if obj:get_luaentity().name ~= "mobs_mc:arrow_entity" and obj:get_luaentity().name ~= "__builtin:item" then
local damage = 3 local damage = 3
minetest.sound_play("damage", {pos = pos}, true) minetest.sound_play("damage", {pos = pos}, true)
@ -108,7 +108,7 @@ THROWING_ARROW_ENTITY.on_step = function(self, dtime)
if self.lastpos.x~=nil then if self.lastpos.x~=nil then
if node.name ~= "air" then if node.name ~= "air" then
minetest.sound_play("bowhit1", {pos = pos}, true) minetest.sound_play("bowhit1", {pos = pos}, true)
minetest.add_item(self.lastpos, "mobs_mc:arrow") minetest.add_item(self.lastpos, 'mobs_mc:arrow')
self.object:remove() self.object:remove()
end end
end end
@ -155,7 +155,7 @@ end
if c("arrow") and c("flint") and c("feather") and c("stick") then if c("arrow") and c("flint") and c("feather") and c("stick") then
minetest.register_craft({ minetest.register_craft({
output = "mobs_mc:arrow 4", output = 'mobs_mc:arrow 4',
recipe = { recipe = {
{mobs_mc.items.flint}, {mobs_mc.items.flint},
{mobs_mc.items.stick}, {mobs_mc.items.stick},
@ -181,11 +181,11 @@ if c("bow") then
}) })
minetest.register_craft({ minetest.register_craft({
output = "mobs_mc:bow_wood", output = 'mobs_mc:bow_wood',
recipe = { recipe = {
{mobs_mc.items.string, mobs_mc.items.stick, ""}, {mobs_mc.items.string, mobs_mc.items.stick, ''},
{mobs_mc.items.string, "", mobs_mc.items.stick}, {mobs_mc.items.string, '', mobs_mc.items.stick},
{mobs_mc.items.string, mobs_mc.items.stick, ""}, {mobs_mc.items.string, mobs_mc.items.stick, ''},
} }
}) })
end end
@ -259,7 +259,7 @@ if c("egg") then
}) })
-- shoot egg -- shoot egg
local function mobs_shoot_egg(item, player, pointed_thing) local mobs_shoot_egg = function (item, player, pointed_thing)
local playerpos = player:get_pos() local playerpos = player:get_pos()
@ -349,7 +349,7 @@ mobs:register_arrow("mobs_mc:snowball_entity", {
if c("snowball") then if c("snowball") then
-- shoot snowball -- shoot snowball
local function mobs_shoot_snowball(item, player, pointed_thing) local mobs_shoot_snowball = function (item, player, pointed_thing)
local playerpos = player:get_pos() local playerpos = player:get_pos()

View File

@ -3,9 +3,8 @@
-- NOTE: Strings intentionally not marked for translation, other mods already have these items. -- NOTE: Strings intentionally not marked for translation, other mods already have these items.
-- TODO: Remove this file eventually, all items here are already outsourced in other mods. -- TODO: Remove this file eventually, all items here are already outsourced in other mods.
-- TODO: Add translation.
--local S = local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator("mobs_mc")
-- Heads system -- Heads system

View File

@ -190,10 +190,9 @@ Origin of those models:
* [Spennnyyy](https://freesound.org/people/Spennnyyy/) (CC0) * [Spennnyyy](https://freesound.org/people/Spennnyyy/) (CC0)
* `mcl_totems_totem.ogg` * `mcl_totems_totem.ogg`
* Source: <https://freesound.org/people/Spennnyyy/sounds/323502/> * Source: <https://freesound.org/people/Spennnyyy/sounds/323502/>
* [Baŝto](https://opengameart.org/users/ba%C5%9Dto) (remixer) and [kantouth](https://freesound.org/people/kantouth/) (original author) * [Baŝto](https://opengameart.org/users/ba%C5%9Dto)
* `mobs_mc_skeleton_random.*.ogg` (CC BY 3.0) * `mobs_mc_skeleton_random.*.ogg` (CC BY 3.0)
* Source: <https://opengameart.org/content/walking-skeleton> * Source: <https://opengameart.org/content/walking-skeleton>
* Based on: <https://freesound.org/people/kantouth/sounds/115113/>
* [spookymodem](https://freesound.org/people/spookymodem/) * [spookymodem](https://freesound.org/people/spookymodem/)
* `mobs_mc_skeleton_death.ogg` (CC0) * `mobs_mc_skeleton_death.ogg` (CC0)
* <https://freesound.org/people/spookymodem/sounds/202091/> * <https://freesound.org/people/spookymodem/sounds/202091/>
@ -307,4 +306,4 @@ Origin of those models:
Note: Many of these sounds have been more or less modified to fit the game. Note: Many of these sounds have been more or less modified to fit the game.
Sounds not mentioned here are licensed under CC0. Sounds not mentioned hre are licensed under CC0.

View File

@ -2,7 +2,7 @@
--################### AGENT - seemingly unused --################### AGENT - seemingly unused
--################### --###################
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:agent", { mobs:register_mob("mobs_mc:agent", {
type = "npc", type = "npc",

View File

@ -1,6 +1,6 @@
--License for code WTFPL and otherwise stated in readmes --License for code WTFPL and otherwise stated in readmes
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:bat", { mobs:register_mob("mobs_mc:bat", {
description = S("Bat"), description = S("Bat"),

View File

@ -3,7 +3,7 @@
-- Model and mobs_blaze.png see https://github.com/22i/minecraft-voxel-blender-models -hi 22i ~jordan4ibanez -- Model and mobs_blaze.png see https://github.com/22i/minecraft-voxel-blender-models -hi 22i ~jordan4ibanez
-- blaze.lua partial copy of mobs_mc/ghast.lua -- blaze.lua partial copy of mobs_mc/ghast.lua
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator("mobs_mc")
--################### --###################
--################### BLAZE --################### BLAZE
@ -20,7 +20,7 @@ mobs:register_mob("mobs_mc:blaze", {
xp_max = 10, xp_max = 10,
tilt_fly = false, tilt_fly = false,
hostile = true, hostile = true,
--rotate = 270, rotate = 270,
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.79, 0.3}, collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.79, 0.3},
rotate = -180, rotate = -180,
visual = "mesh", visual = "mesh",

View File

@ -1,6 +1,6 @@
--License for code WTFPL and otherwise stated in readmes --License for code WTFPL and otherwise stated in readmes
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator("mobs_mc")
--################### --###################
--################### CHICKEN --################### CHICKEN

View File

@ -1,6 +1,6 @@
--License for code WTFPL and otherwise stated in readmes --License for code WTFPL and otherwise stated in readmes
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator("mobs_mc")
local cow_def = { local cow_def = {
description = S("Cow"), description = S("Cow"),
@ -89,7 +89,7 @@ local cow_def = {
--head code --head code
has_head = true, has_head = true,
head_bone = "head", head_bone = "head",
swap_y_with_x = false, swap_y_with_x = false,
reverse_head_yaw = false, reverse_head_yaw = false,
@ -168,7 +168,7 @@ mooshroom_def.on_rightclick = function(self, clicker)
pos.y = pos.y + 0.5 pos.y = pos.y + 0.5
minetest.add_item(pos, {name = mobs_mc.items.mushroom_stew}) minetest.add_item(pos, {name = mobs_mc.items.mushroom_stew})
end end
end end
end end
mobs:register_mob("mobs_mc:mooshroom", mooshroom_def) mobs:register_mob("mobs_mc:mooshroom", mooshroom_def)

View File

@ -1,6 +1,6 @@
--License for code WTFPL and otherwise stated in readmes --License for code WTFPL and otherwise stated in readmes
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator("mobs_mc")
--################### --###################
--################### CREEPER --################### CREEPER
@ -37,7 +37,7 @@ mobs:register_mob("mobs_mc:creeper", {
}, },
makes_footstep_sound = false, makes_footstep_sound = false,
walk_velocity = 1.05, walk_velocity = 1.05,
run_velocity = 2.1, run_velocity = 3.25,
runaway_from = { "mobs_mc:ocelot", "mobs_mc:cat" }, runaway_from = { "mobs_mc:ocelot", "mobs_mc:cat" },
attack_type = "explode", attack_type = "explode",
eye_height = 1.25, eye_height = 1.25,
@ -47,8 +47,8 @@ mobs:register_mob("mobs_mc:creeper", {
--explosion_radius = 3, --explosion_radius = 3,
--explosion_damage_radius = 6, --explosion_damage_radius = 6,
--explosiontimer_reset_radius = 6, --explosiontimer_reset_radius = 6,
reach = 3, reach = 1.5,
defuse_reach = 5.2, defuse_reach = 4,
explosion_timer = 0.3, explosion_timer = 0.3,
allow_fuse_reset = true, allow_fuse_reset = true,
stop_to_explode = true, stop_to_explode = true,
@ -72,7 +72,7 @@ mobs:register_mob("mobs_mc:creeper", {
-- TODO: Make creeper flash after doing this as well. -- TODO: Make creeper flash after doing this as well.
-- TODO: Test and debug this code. -- TODO: Test and debug this code.
on_rightclick = function(self, clicker) on_rightclick = function(self, clicker)
if self._forced_explosion_countdown_timer then if self._forced_explosion_countdown_timer ~= nil then
return return
end end
local item = clicker:get_wielded_item() local item = clicker:get_wielded_item()
@ -92,11 +92,10 @@ mobs:register_mob("mobs_mc:creeper", {
end end
end, end,
do_custom = function(self, dtime) do_custom = function(self, dtime)
if self._forced_explosion_countdown_timer then if self._forced_explosion_countdown_timer ~= nil then
self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime
if self._forced_explosion_countdown_timer <= 0 then if self._forced_explosion_countdown_timer <= 0 then
local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false mobs:boom(self, mcl_util.get_object_center(self.object), self.explosion_strength)
mcl_explosions.explode(mcl_util.get_object_center(self.object), self.explosion_strength, { griefing = mobs_griefing, drop_chance = 1.0}, self.object)
end end
end end
end, end,
@ -152,7 +151,6 @@ mobs:register_mob("mobs_mc:creeper_charged", {
description = S("Charged Creeper"), description = S("Charged Creeper"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hostile = true,
hp_min = 20, hp_min = 20,
hp_max = 20, hp_max = 20,
xp_min = 5, xp_min = 5,
@ -188,8 +186,8 @@ mobs:register_mob("mobs_mc:creeper_charged", {
--explosion_radius = 3, --explosion_radius = 3,
--explosion_damage_radius = 6, --explosion_damage_radius = 6,
--explosiontimer_reset_radius = 3, --explosiontimer_reset_radius = 3,
reach = 3, reach = 1.5,
defuse_reach = 5.2, defuse_reach = 4,
explosion_timer = 0.3, explosion_timer = 0.3,
allow_fuse_reset = true, allow_fuse_reset = true,
stop_to_explode = true, stop_to_explode = true,
@ -198,7 +196,7 @@ mobs:register_mob("mobs_mc:creeper_charged", {
-- TODO: Make creeper flash after doing this as well. -- TODO: Make creeper flash after doing this as well.
-- TODO: Test and debug this code. -- TODO: Test and debug this code.
on_rightclick = function(self, clicker) on_rightclick = function(self, clicker)
if self._forced_explosion_countdown_timer then if self._forced_explosion_countdown_timer ~= nil then
return return
end end
local item = clicker:get_wielded_item() local item = clicker:get_wielded_item()
@ -218,11 +216,10 @@ mobs:register_mob("mobs_mc:creeper_charged", {
end end
end, end,
do_custom = function(self, dtime) do_custom = function(self, dtime)
if self._forced_explosion_countdown_timer then if self._forced_explosion_countdown_timer ~= nil then
self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime
if self._forced_explosion_countdown_timer <= 0 then if self._forced_explosion_countdown_timer <= 0 then
local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false mobs:boom(self, mcl_util.get_object_center(self.object), self.explosion_strength)
mcl_explosions.explode(mcl_util.get_object_center(self.object), self.explosion_strength, { griefing = mobs_griefing, drop_chance = 1.0}, self.object)
end end
end end
end, end,

Some files were not shown because too many files have changed in this diff Show More