Compare commits

..

1 Commits

Author SHA1 Message Date
cora 051beeea2e light_source 2 nodes -> prevent complete darkness 2022-08-09 15:43:54 +02:00
734 changed files with 5271 additions and 10610 deletions

View File

@ -2,7 +2,7 @@
So you want to contribute to MineClone2?
Wow, thank you! :-)
MineClone2 is maintained by Nicu and Cora. If you have any
MineClone2 is maintained by Nicu and Fleckenstein. If you have any
problems or questions, contact us (See Links section below).
You can help with MineClone2's development in many different ways,
@ -11,9 +11,18 @@ whether you're a programmer or not.
## MineClone2's development target is to...
- Crucially, create a stable, moddable, free/libre clone of Minecraft
based on the Minetest engine with polished features, usable in both
singleplayer and multiplayer. Currently, a lot of Minecraft features
are already implemented.
Polishing existing features is always welcome.
singleplayer and multiplayer. Currently, most of **Minecraft Java
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
* [Mesehub](https://git.minetest.land/MineClone2/MineClone2)
@ -36,10 +45,8 @@ 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.
Look at our wiki for some concrete guides:
https://git.minetest.land/MineClone2/MineClone2/wiki/
## How you can help as a non-programmer
As someone who does not know how to write programs in Lua or does not
know how to use the Minetest API, you can still help us out a lot. For
example, by opening an issue in the
@ -51,10 +58,12 @@ you can report a bug or request a feature.
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.
Try not to report bugs that have already been reported or request features
that already have been requested. This can often be ambiguous though.
If in doubt open an issue!
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
@ -64,9 +73,6 @@ instead.
an issue, feel free to ask on the Discord / Matrix server or the IRC
channel.
The link to the mesehub registration page is: https://git.minetest.land/user/sign_up
(It appears to sometimes get lost on the page itsself)
### 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
@ -105,28 +111,23 @@ 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 could
still undergo substantial change. Testing these is still helpful however
because that is the reason developers put them up as WIP so other people
can have a look at the PR.
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 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
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. For older Minecraft
features that is mostly enough but a lot of the newer textures in it are
copies or slight modifications of the original MC textures so great caution
needs to be taken when using any textures coming from Minecraft texture
packs.
If you want to make such contributions, join our Discord server. Demands
for textures will be communicated there.
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.
@ -250,25 +251,16 @@ of the results)
* [Official Minecraft Wiki](https://minecraft.fandom.com/wiki/Minecraft_Wiki)
(Include a link to the specific page you used)
### Guidelines
### Stick to our guidelines
#### Git Guidelines
* Pushing to master is disabled - don't even try it.
* Every change is tracked as a PR.
* All but the tiniest changes require at least one approval from a Developer
* To update branches we use rebase not merge (so we don't end up with
excessive git bureaucracy commits in master)
* We use merge to add the commits from a PR/branch to master
* Submodules should only be used if a) upstream is highly reliable and
b) it is 100% certain that no mcl2 specific changes to the code will be
needed (this has never been the case before, hence mcl2 is submodule free so far)
* Commit messages should be descriptive and never contain mcl2 specific
issueids - there are other projects who might use commits from mcl2 and
it will confuse their issue trackers.
* Try to group your submissions best as you can:
* Try to keep your PRs small: In some cases things reasonably be can't
split up but in general multiple small PRs are better than a big one.
* Similarly multiple small commits are better than a giant one. (use git commit -p)
* 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
* Each mod must provide `mod.conf`.
@ -351,23 +343,36 @@ Active and trusted contributors are often granted write access to the
MineClone2 repository.
#### Developer responsibilities
- If you have developer privileges you can just open a new branch in the
mcl2 repository (which is preferred). From that you create a pull request.
This way other people can review your changes and make sure they work
before they get merged.
- If you do not (yet) have developer privs you do your work on a branch
on your private repository e.g. using the "fork" function on mesehub.
- Any developer is welcome to review, test and merge PRs. A PR needs
at least one approval (by someone else than the author) but the maintainers
are usually relatively quick to react to new submissions.
- 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.
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)
@ -375,8 +380,8 @@ merged.
- Resolving conflicts and problems within the community
#### Current maintainers
* Cora - responsible for gameplay review, publishing releases,
technical guidelines
* Fleckenstein - responsible for gameplay review, publishing releases,
technical guidelines and issue/PR delegation
* Nicu - responsible for community related issues
#### Release process

View File

@ -29,10 +29,8 @@
* kabou
* rudzik8
* chmodsayshello
* PrairieWind
* PrarieWind
* RandomLegoBrick
* SumianVoice
* MrRar
## Contributors
* Laurent Rocher
@ -81,10 +79,6 @@
* MrRar
* Lazerbeak12345
* mrminer
* Thunder1035
* opfromthestart
* snowyu
* FaceDeer
## MineClone5
* kay27
@ -94,7 +88,7 @@
* j45
* chmodsayshello
* 3raven
* PrairieWind
* PrarieWind
* Gustavo1
* CableGuy67
* MrRar
@ -135,7 +129,6 @@
* 4Evergreen4
* jordan4ibanez
* paramat
* cora
## 3D Models
* 22i
@ -165,8 +158,6 @@
* Marcin Serwin
* Pepebotella
* Emojigit
* snowyu
* 3raven
## Funders
* 40W

View File

@ -2,7 +2,7 @@
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
Developed by many people. Not developed or endorsed by Mojang AB.
Version: 0.80 (in development)
Version: 0.78 (in development)
### Gameplay
You start in a randomly-generated world made entirely of cubes. You can explore

View File

@ -1,170 +0,0 @@
# MineClone2
Un jeu non-officiel similaire à Minecraft pour Minetest. Forké depuis Mineclone par davedevils. Développé par de nombreuses personnes. Ni développé ou supporté par Mojang AB.
Version: 0.79 (en dévelopment)
### Gameplay
Vous atterissez dans un monde fait entièrement de cubes et généré aléatoirement. Vous pouvez explorer le monde, miner et construire presque n'importe quel bloc pour créer de nouvelles structures. Vous pouvez choisir de jouer en "mode survie" dans lequel vous devez combattre des monstres et la faim et progresser lentement dans différents aspects du jeu, comme l'extraction de minerai, l'agriculture, la construction de machines et ainsi de suite. Ou alors vous pouvez jouer en "mode créatif" où vous pouvez construire à peu près n'importe quoi instantanément.
### Résumé du Gameplay
* Jeu de type bac-à-sable, sans objetifs
* Survie : combattre des monstres hostiles et la faim
* Creuser pour du minerai et d'autres trésors
* Magie : gagner de l'expérience et enchanter les outils
* Utiliser les blocs ramassés pour construire de magnifiques bâtiments, votre imagination est la limite
* Ramasser des fleurs (et d'autres sources de teinture) et colorez votre monde
* Trouvez des graines et commencez à cultiver
* Trouvez ou fabriquez des centaines d'objets
* Construisez un réseau ferroviaire complexe et amusez vous avec les wagonnets
* En mode créatif vous pouvez construire presque n'importe quoi gratuitement et sans limite
## Comment jouer (démarrer rapidement)
### Commencer
* **Frappez un arbre** jusqu'à ce qu'il casse et donne du bois
* Placez le **bois dans la grille 2x2** (la "grille de fabrication" de votre menu d'inventaire) et fabriquez 4 planches de bois
* Placer les 4 planches de bois dans la grille 2x2 et **fabriquez une table d'artisanat**
* **Cliquez droit la table d'artisanat** (icone livre) pour apprendre toutes les recettes possibles
* **Fabriquez une pioche de bois** pour miner la pierre
* Différents outils minent différentes sortes de blocs. Essayez les !
* Continuez à jouer comme vous voulez. Amusez vous !
### Agriculture
* Trouvez des graines
* Fabriquez une houe
* Cliquez droit la terre ou des blocs similaires avec la houe pour créer des terres agricoles
* Placer des graines sur des terres agricoles et regardez les pousser
* Récoltez les plantes une fois matûres
* Les terres agricoles proche de l'eau deviennent humides et accélèrent la croissance
### Four
* Fabriquer un Four
* Le four permet d'obtenir plus d'objets
* L'emplacement du haut doit contienir un objet fondable (par ex : minerai de fer)
* L'emplacement du bas doit contienir un objet combustible (par ex : charbon)
* Voir le guide d'artisanat pour en apprendre plus sur les objets fondables et combustibles
### Aide supplémentaire
Plus d'aide à propos du jeu, des blocs, objets et plus encore peuvent être trouvés dans le jeu. Vous pouvez accéder à l'aide depuis le menu inventaire.
### Objets spéciaux
Les objets suivants sont intéressants pour le mode Créatif et pour les constructeurs de cartes d'aventure. Ils ne peuvent être obtenus dans le jeu ou dans l'inventaire créatif.
* Barrière : `mcl_core:barrier`
Utilisez la commande de chat `/giveme` pour les obtenir. Voir l'aide interne au jeu pour une explication.
## Installation
Ce jeu nécessite [Minetest](http://minetest.net) pour fonctionner (version 5.4.1 ou plus). Vous devez donc installer Minetest d'abord. Seules les versions stables de Minetest sont officielement supportées.
Il n'y a pas de support de MineClone2 dans les versions développement de Minetest.
Pour installer MineClone2 (si ce n'est pas déjà fait), déplacez ce dossier dans le dossier “games” de Minetest. Consultez l'aide de Minetest pour en apprendre plus.
## Liens utiles
Le dépôt de MineClone2 est hébergé sur Mesehub. Pour contribuer ou rapporter des problèmes, aller là-bas.
* Mesehub: <https://git.minetest.land/MineClone2/MineClone2>
* Discord: <https://discord.gg/xE4z8EEpDC>
* YouTube <https://www.youtube.com/channel/UClI_YcsXMF3KNeJtoBfnk9A>
* IRC: <https://web.libera.chat/#mineclone2>
* Matrix: <https://app.element.io/#/room/#mc2:matrix.org>
* Reddit: <https://www.reddit.com/r/MineClone2/>
* Minetest forums: <https://forum.minetest.net/viewtopic.php?f=50&t=16407>
* ContentDB: <https://content.minetest.net/packages/wuzzy/mineclone2/>
* OpenCollective: <https://opencollective.com/mineclone2>
## Objectif
* Créer un clone stable, moddable, libre et gratuit basé sur le moteur de jeu Minetest avec des fonctionalités abouties, utilisable à la fois en mode solo et multijoueur. Actuellement, beaucoup des fonctionalités de **Minecraft Java Edition** sont déjà implémentées et leur amélioration est prioritaire sur les nouvelles demandes.
* Avec une priorité moindre, implémenter les fonctionalités des versions **Minecraft + OptiFine** (OtiFine autant que supporté par le moteur Minetest). Cela signifie que les fonctionalités présentes dans les versions listées sont priorisées.
* Dans l'idéal, créer une expérience performante qui tourne bien sur des ordinateurs à basse performance. Malheureusement, en raison des mécanismes de Minecraft et des limitations du moteur Minetest ainsi que de la petite taille de la communauté de joueurs sur des ordinateurs à basse performances, les optimisations sont difficiles à explorer.
## Statut de complétion
Ce jeu est actuellement au stade **beta**.
Il est jouable mais incomplet en fonctionalités.
La rétro-compatibilité n'est pas entièrement garantie, mettre votre monde à jour peut causer de petits bugs.
Si vous voulez utiliser la version de développement de MineClone2 en production, la branche master est habituellement relativement stable. Les branches de test fusionnent souvent des pull requests expérimentales et doivent être considérées comme moins stable.
Les principales fonctionalités suivantes sont disponibles :
* Outils, armes
* Armure
* Système de fabrication : grille 2x2, table d'artisanat (grille 3x3), four, incluant un guide de fabrication
* Coffres, grands coffres, coffre ender, boite de shulker
* Fours, entonnoirs
* Faim
* La plupart des monstres et animaux
* Tout les minerais de Minecraft
* La plupart des blocs de l'overworld
* Eau et lave
* Météo
* 28 biomes + 5 biomes du nether
* Le Nether, monde souterrain brûlant dans une autre dimension
* Circuits Redstone (partiel)
* Effets de Statut (partiel)
* Expérience
* Enchantement
* Brassage, potions, flèches trempées (partiel)
* Bâteaux
* Feu
* Blocs de construction : escaliers, dalles, portes, trappes, barrière, portillon, muret
* Horloge
* Boussole
* Eponge
* Bloc de slime
* Petites plantes et pousses
* Teintures
* Bannières
* Blocs de décoration : verre, verre teinté, vitres, barres de fer, terre cuites (et couleurs), têtes et plus
* Cadres d'objets
* Juke-boxes
* Livres pour écrire
* Commandes
* Villages
* L'End
* et plus !
Les fonctionalités suivantes sont incomplètes :
* certains monstres et animaux
* certains composants de Redstone
* Wagonnets spéciaux
* quelques blocs et objets non-triviaux
Fonctionalités bonus (absentes de Minecraft) :
* Guide d'artisanat intégré au jeu qui montre les recettes d'artisanat et de cuisson
* Système d'aide intégré au jeu contenant des informations à propos des techniques de base, blocs, objets et plus
* Recettes d'artisanat temporaires. Elles existent uniquement pour rendre des objets accessibles qui ne le seraient pas autrement sauf en mode créatif. Elles seront retirées au cours de l'avancement du développement et de l'ajout de nouvelles fonctionalités.
* Pousses dans les coffres en mapgen v6
* Entièrement moddable (grâce la puissante API lua de Minetest)
* Nouveaux blocs et objets :
* Outil de recherche, montre l'aide de ce qu'il touche
* Plus de dalles et d'escaliers
* Portillon en briques du Nether
* Barrière en briques du Nether rouges
* Portillon en briques du Nether rouges
* Structures de remplacement - ces petites variantes de structures de Minecraft servent de remplacement en attendant qu'on arrive à en faire fonctionner de plus grandes :
* Cabine dans les bois (Manoir des bois)
* Avant-poste du Nether (Forteresse)
Différences techniques avec Minecraft :
* Limite en hauteur de 31000 blocs (bien plus grand que Minecraft)
* Taille horizontale du monde 62000×62000 blocs (bien plus petit que Minecraft mais toujours très grand)
* Toujours assez incomplet et buggé
* Des blocs, objets, ennemis et fonctionalités manquent
* Quelques objets ont des noms légèrement différents pour être plus faciles à distinguer
* Des musiques différentes pour le juke-boxe
* Des textures différentes (Pixel Perfection)
* Des sons différents (sources diverses)
* Un moteur de jeu différent (Minetest)
* Des bonus cachés différents
...et enfin MineClone2 est un logiciel libre !
## Autres fichiers readme
* `LICENSE.txt`: Le texte de la license GPLv3
* `CONTRIBUTING.md`: Information pour ceux qui veulent contribuer
* `API.md`: Pour les modders Minetest qui veulent modder ce jeu
* `LEGAL.md`: Information légale
* `CREDITS.md`: Liste des contributeurs

View File

@ -348,6 +348,12 @@ local function overwrite()
groups = newgroups
})
end
--
if nname ~= "ignore" and ndef.light_source == nil or ndef.light_source < 2 then
minetest.override_item(nname, {
light_source = 2
})
end
end
for tname, tdef in pairs(minetest.registered_tools) do

View File

@ -33,8 +33,6 @@ mcl_damage = {
}
}
local damage_enabled = minetest.settings:get_bool("enabled_damage",true)
function mcl_damage.register_modifier(func, priority)
table.insert(mcl_damage.modifiers, {func = func, priority = priority or 0})
end
@ -141,7 +139,6 @@ function mcl_damage.register_type(name, def)
end
minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
if not damage_enabled then return 0 end
if hp_change < 0 then
if player:get_hp() <= 0 then
return 0
@ -152,7 +149,6 @@ minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
end, true)
minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
if not damage_enabled then return 0 end
if player:get_hp() > 0 then
mt_reason.approved = true
if hp_change < 0 then
@ -165,9 +161,9 @@ minetest.register_on_dieplayer(function(player, mt_reason)
if mt_reason.approved then
mcl_damage.run_death_callbacks(player, mcl_damage.from_mt(mt_reason))
end
minetest.log("action","Player "..player:get_player_name().." died at "..minetest.pos_to_string(vector.round(player:get_pos())))
end)
minetest.register_on_mods_loaded(function()
table.sort(mcl_damage.modifiers, function(a, b) return a.priority < b.priority end)
end)

View File

@ -162,8 +162,7 @@ end
mcl_vars.mg_end_min = -27073 -- Carefully chosen to be at a mapchunk border
mcl_vars.mg_end_max_official = mcl_vars.mg_end_min + minecraft_height_limit
mcl_vars.mg_end_max = mcl_vars.mg_overworld_min - 2000
mcl_vars.mg_end_platform_pos = { x = 100, y = mcl_vars.mg_end_min + 64, z = 0 }
mcl_vars.mg_end_exit_portal_pos = vector.new(0, mcl_vars.mg_end_min + 71, 0)
mcl_vars.mg_end_platform_pos = { x = 100, y = mcl_vars.mg_end_min + 74, z = 0 }
-- Realm barrier used to safely separate the End from the void below the Overworld
mcl_vars.mg_realm_barrier_overworld_end_max = mcl_vars.mg_end_max

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 B

View File

@ -610,95 +610,3 @@ function mcl_util.get_pointed_thing(player, liquid)
end
end
end
-- This following part is 2 wrapper functions + helpers for
-- object:set_bones
-- and player:set_properties preventing them from being resent on
-- every globalstep when they have not changed.
local function roundN(n, d)
if type(n) ~= "number" then return n end
local m = 10^d
return math.floor(n * m + 0.5) / m
end
local function close_enough(a,b)
local rt=true
if type(a) == "table" and type(b) == "table" then
for k,v in pairs(a) do
if roundN(v,2) ~= roundN(b[k],2) then
rt=false
break
end
end
else
rt = roundN(a,2) == roundN(b,2)
end
return rt
end
local function props_changed(props,oldprops)
local changed=false
local p={}
for k,v in pairs(props) do
if not close_enough(v,oldprops[k]) then
p[k]=v
changed=true
end
end
return changed,p
end
--tests for roundN
local test_round1=15
local test_round2=15.00199999999
local test_round3=15.00111111
local test_round4=15.00999999
assert(roundN(test_round1,2)==roundN(test_round1,2))
assert(roundN(test_round1,2)==roundN(test_round2,2))
assert(roundN(test_round1,2)==roundN(test_round3,2))
assert(roundN(test_round1,2)~=roundN(test_round4,2))
-- tests for close_enough
local test_cb = {-0.35,0,-0.35,0.35,0.8,0.35} --collisionboxes
local test_cb_close = {-0.351213,0,-0.35,0.35,0.8,0.351212}
local test_cb_diff = {-0.35,0,-1.35,0.35,0.8,0.35}
local test_eh = 1.65 --eye height
local test_eh_close = 1.65123123
local test_eh_diff = 1.35
local test_nt = { r = 225, b = 225, a = 225, g = 225 } --nametag
local test_nt_diff = { r = 225, b = 225, a = 0, g = 225 }
assert(close_enough(test_cb,test_cb_close))
assert(not close_enough(test_cb,test_cb_diff))
assert(close_enough(test_eh,test_eh_close))
assert(not close_enough(test_eh,test_eh_diff))
assert(not close_enough(test_nt,test_nt_diff)) --no floats involved here
--tests for properties_changed
local test_properties_set1={collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 0.65, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}
local test_properties_set2={collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 1.35, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}
local test_p1,_=props_changed(test_properties_set1,test_properties_set1)
local test_p2,_=props_changed(test_properties_set1,test_properties_set2)
assert(not test_p1)
assert(test_p2)
function mcl_util.set_properties(obj,props)
local changed,p=props_changed(props,obj:get_properties())
if changed then
obj:set_properties(p)
end
end
function mcl_util.set_bone_position(obj,b,p,r) --bone,position,rotation
local oldp,oldr=obj:get_bone_position(b)
if vector.equals(vector.round(oldp),vector.round(p)) and vector.equals(vector.round(oldr),vector.round(r)) then
return
end
obj:set_bone_position(b,p,r)
end

View File

@ -24,10 +24,6 @@ local function is_ice(pos)
return is_group(pos, "ice")
end
local function is_fire(pos)
return is_group(pos, "set_on_fire")
end
local function get_sign(i)
if i == 0 then
return 0
@ -222,10 +218,6 @@ function boat.on_step(self, dtime, moveresult)
on_water = false
if not in_water and is_ice(waterp) then
on_ice = true
elseif is_fire({x=p.x, y=p.y-boat_y_offset, z=p.z}) then
boat.on_death(self, nil)
self.object:remove()
return
else
v_slowdown = 0.04
v_factor = 0.5
@ -413,21 +405,13 @@ end
-- Register one entity for all boat types
minetest.register_entity("mcl_boats:boat", boat)
local cboat = table.copy(boat)
cboat.mesh = "mcl_boats_boat_with_chest.b3d"
cboat.textures = {"mcl_boats_texture_oak_chest_boat.png", "mcl_boats_texture_oak_chest_boat.png", "mcl_boats_texture_oak_chest_boat.png", "mcl_boats_texture_oak_chest_boat.png", "mcl_boats_texture_oak_chest_boat.png"}
cboat._itemstring = "mcl_boats:chest_boat"
minetest.register_entity("mcl_boats:chest_boat", cboat)
mcl_entity_invs.register_inv("mcl_boats:chest_boat","Boat",27)
local boat_ids = { "boat", "boat_spruce", "boat_birch", "boat_jungle", "boat_acacia", "boat_dark_oak", "boat_obsidian", "boat_mangrove", "chest_boat", "chest_boat_spruce", "chest_boat_birch", "chest_boat_jungle", "chest_boat_acacia", "chest_boat_dark_oak", "chest_boat_mangrove" }
local names = { S("Oak Boat"), S("Spruce Boat"), S("Birch Boat"), S("Jungle Boat"), S("Acacia Boat"), S("Dark Oak Boat"), S("Obsidian Boat"), S("Mangrove Boat"), S("Oak Chest Boat"), S("Spruce Chest Boat"), S("Birch Chest Boat"), S("Jungle Chest Boat"), S("Acacia Chest Boat"), S("Dark Oak Chest Boat"), S("Mangrove Chest Boat") }
local boat_ids = { "boat", "boat_spruce", "boat_birch", "boat_jungle", "boat_acacia", "boat_dark_oak", "boat_obsidian" }
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 craftstuffs = {}
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", "mcl_mangrove:mangrove_wood" }
craftstuffs = { "mcl_core:wood", "mcl_core:sprucewood", "mcl_core:birchwood", "mcl_core:junglewood", "mcl_core:acaciawood", "mcl_core:darkwood", "mcl_core:obsidian" }
end
local images = { "oak", "spruce", "birch", "jungle", "acacia", "dark_oak", "obsidian", "mangrove", "oak_chest", "spruce_chest", "birch_chest", "jungle_chest", "acacia_chest", "dark_oak_chest", "mangrove_chest" }
local images = { "oak", "spruce", "birch", "jungle", "acacia", "dark_oak", "obsidian" }
for b=1, #boat_ids do
local itemstring = "mcl_boats:"..boat_ids[b]
@ -477,11 +461,7 @@ for b=1, #boat_ids do
else
pos = vector.add(pos, vector.multiply(dir, boat_y_offset_ground))
end
local boat_ent = "mcl_boats:boat"
if itemstring:find("chest") then
boat_ent = "mcl_boats:chest_boat"
end
local boat = minetest.add_entity(pos, boat_ent)
local boat = minetest.add_entity(pos, "mcl_boats:boat")
local texture = "mcl_boats_texture_"..images[b].."_boat.png"
boat:get_luaentity()._itemstring = itemstring
boat:set_properties({textures = { texture, texture, texture, texture, texture }})
@ -504,22 +484,13 @@ for b=1, #boat_ids do
})
local c = craftstuffs[b]
if not itemstring:find("chest") then
minetest.register_craft({
output = itemstring:gsub(":boat",":chest_boat"),
recipe = {
{"mcl_chests:chest"},
{itemstring},
},
})
minetest.register_craft({
output = itemstring,
recipe = {
{c, "", c},
{c, c, c},
},
})
end
minetest.register_craft({
output = itemstring,
recipe = {
{c, "", c},
{c, c, c},
},
})
end
minetest.register_craft({

View File

@ -9,5 +9,4 @@ Oak Boat=Bateau en Chêne
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Use [Sneak] to leave the boat, punch the boat to make it drop as an item.=Faites un clic droit sur une source d'eau pour placer le bateau. Faites un clic droit sur le bateau pour y entrer. Utilisez [Gauche] et [Droite] pour diriger, [Avant] pour accélérer et [Arrière] pour ralentir ou reculer. Utilisez [Sneak] pour le quitter, frappez le bateau pour le faire tomber en tant qu'objet.
Spruce Boat=Bateau en Sapin
Water vehicle=Véhicule aquatique
Sneak to dismount=Se baisser pour descendre
Obsidian Boat=Bateau en Obsidienne
Sneak to dismount=

View File

@ -10,4 +10,3 @@ Rightclick on a water source to place the boat. Rightclick the boat to enter it.
Spruce Boat=
Water vehicle=
Sneak to dismount=
Obsidian Boat=

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,5 +1,3 @@
local enable_damage = minetest.settings:get_bool("enable_damage")
function mcl_burning.get_storage(obj)
return obj:is_player() and mcl_burning.storage[obj] or obj:get_luaentity()
end
@ -79,7 +77,7 @@ end
-- The effective burn duration is modified by obj's armor protection.
-- If obj was already burning, its burn duration is updated if the current
-- duration is less than burn_time.
-- If obj is dead, fireproof or enable_damage is disabled, this function does nothing.
-- If obj is dead, fireproof or a creative player, this function does nothing.
--
function mcl_burning.set_on_fire(obj, burn_time)
if obj:get_hp() < 0 then
@ -91,9 +89,8 @@ function mcl_burning.set_on_fire(obj, burn_time)
return
end
if obj:is_player() and not enable_damage then
if obj:is_player() and minetest.is_creative_enabled(obj:get_player_name()) then
burn_time = 0
return
else
local max_fire_prot_lvl = 0
local inv = mcl_util.get_inventory(obj)

View File

@ -1,13 +0,0 @@
mcl_entity_invs
===============
Inventories for your entities. It's simple. Depend on mcl_entity_invs and register your entity like so:
* mcl_entity_invs.register_inv("entity:name","Title shown in formspec",inventory_size,disable_on_righclick)
*If disable_on_righclick is true other mods can handle when to show the inventory themselves
* The inventory size can be set dynamically by initializing it with an explicit nil
* mcl_entity_invs.show_inv_form(entity,clicker,[formspec text])
* formspec_text is an additional text that is put after the title
It works by setting up a detached inventory per entity which is accessed by an id/hash generated from the entities position at creation, the progressed gametime at creation and a random salt.

View File

@ -1,170 +0,0 @@
mcl_entity_invs = {}
local open_invs = {}
local function check_distance(inv,player,count)
for _,o in pairs(minetest.get_objects_inside_radius(player:get_pos(),5)) do
local l = o:get_luaentity()
if l and l._inv_id and inv:get_location().name == l._inv_id then return count end
end
return 0
end
local inv_callbacks = {
allow_take = function(inv, listname, index, stack, player)
return check_distance(inv,player,stack:get_count())
end,
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
return check_distance(inv,player,count)
end,
allow_put = function(inv, listname, index, stack, player)
return check_distance(inv,player,stack:get_count())
end,
}
local function load_inv(ent,size)
if not ent._inv_id then return end
local inv = minetest.get_inventory({type="detached", name=ent._inv_id})
if not inv then
inv = minetest.create_detached_inventory(ent._inv_id, inv_callbacks)
inv:set_size("main", size)
if ent._items then
inv:set_list("main",ent._items)
end
end
return inv
end
local function save_inv(ent)
if ent._inv then
ent._items = {}
for i,it in ipairs(ent._inv:get_list("main")) do
ent._items[i] = it:to_string()
end
minetest.remove_detached_inventory(ent._inv_id)
ent._inv = nil
end
end
function mcl_entity_invs.show_inv_form(ent,player,text)
if not ent._inv_id then return end
if not open_invs[ent] then
open_invs[ent] = 0
end
text = text or ""
ent._inv = load_inv(ent,ent._inv_size)
open_invs[ent] = open_invs[ent] + 1
local playername = player:get_player_name()
local rows = 3
local cols = (math.ceil(ent._inv_size/rows))
local spacing = (9 - cols) / 2
local formspec = "size[9,8.75]"
.. "label[0,0;" .. minetest.formspec_escape(
minetest.colorize("#313131", ent._inv_title .. " ".. text)) .. "]"
.. "list[detached:"..ent._inv_id..";main;"..spacing..",0.5;"..cols..","..rows..";]"
.. mcl_formspec.get_itemslot_bg(spacing,0.5,cols,rows)
.. "label[0,4.0;" .. minetest.formspec_escape(
minetest.colorize("#313131", "Inventory")) .. "]"
.. "list[current_player;main;0,4.5;9,3;9]"
.. mcl_formspec.get_itemslot_bg(0,4.5,9,3)
.. "list[current_player;main;0,7.74;9,1;]"
.. mcl_formspec.get_itemslot_bg(0,7.74,9,1)
.. "listring[detached:"..ent._inv_id..";main]"
.. "listring[current_player;main]"
minetest.show_formspec(playername,ent._inv_id,formspec)
end
local function drop_inv(ent)
if not ent._items then return end
local pos = ent.object:get_pos()
for i,it in pairs(ent._items) do
local p = vector.add(pos,vector.new(math.random() - 0.5, math.random()-0.5, math.random()-0.5))
minetest.add_item(p,it)
end
ent._items = nil
end
local function on_remove(self,killer,oldf)
save_inv(self)
drop_inv(self)
if oldf then return oldf(self,killer) end
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
for k,v in pairs(open_invs) do
if formname == k._inv_id then
open_invs[k] = open_invs[k] - 1
if open_invs[k] < 1 then
save_inv(k)
open_invs[k] = nil
end
end
end
end)
function mcl_entity_invs.register_inv(entity_name,show_name,size,no_on_righclick)
assert(minetest.registered_entities[entity_name],"mcl_entity_invs.register_inv called with invalid entity: "..tostring(entity_name))
minetest.registered_entities[entity_name]._inv_size = size
minetest.registered_entities[entity_name]._inv_title = show_name
local old_oa = minetest.registered_entities[entity_name].on_activate
minetest.registered_entities[entity_name].on_activate = function(self,staticdata,dtime_s)
local r
if old_oa then r=old_oa(self,staticdata,dtime_s) end
local d = minetest.deserialize(staticdata)
if type(d) == "table" and d._inv_id then
self._inv_id = d._inv_id
self._items = d._items
self._inv_size = d._inv_size
else
self._inv_id="entity_inv_"..minetest.sha1(minetest.get_gametime()..minetest.pos_to_string(self.object:get_pos())..tostring(math.random()))
--gametime and position for collision safety and math.random salt to protect against position brute-force
end
return r
end
if not no_on_righclick then
local old_rc = minetest.registered_entities[entity_name].on_rightclick
minetest.registered_entities[entity_name].on_rightclick = function(self,clicker)
mcl_entity_invs.show_inv_form(self,clicker,show_name)
if old_rc then return old_rc(self,clicker) end
end
end
local old_gsd = minetest.registered_entities[entity_name].get_staticdata
minetest.registered_entities[entity_name].get_staticdata = function(self)
local old_sd = old_gsd(self)
local d = minetest.deserialize(old_sd)
assert(type(d) == "table","mcl_entity_invs currently only works with entities that return a (serialized) table in get_staticdata. "..tostring(self.name).." returned: "..tostring(old_sd))
d._inv_id = self._inv_id
d._inv_size = self._inv_size
d._items = {}
if self._items then
for i,it in ipairs(self._items) do
d._items[i] = it
end
end
return minetest.serialize(d)
end
local old_ode = minetest.registered_entities[entity_name].on_deactivate
minetest.registered_entities[entity_name].on_deactivate = function(self,removal)
save_inv(self)
if removal then
on_remove(self)
end
if old_ode then return old_ode(self,removal) end
end
local old_od = minetest.registered_entities[entity_name].on_death
minetest.registered_entities[entity_name].on_death = function(self,killer)
if not self.is_mob then
on_remove(self,killer,old_od)
end
end
local old_odi = minetest.registered_entities[entity_name].on_die
minetest.registered_entities[entity_name].on_die = function(self,killer)
if self.is_mob then
on_remove(self,killer,old_od)
end
end
end

View File

@ -1,3 +0,0 @@
name = mcl_entity_invs
author = cora
depends = mcl_formspec

View File

@ -61,8 +61,6 @@ 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:crying_obsidian", "mcl:whosCuttingOnions")
mcl_item_entity.register_pickup_achievement("mcl_nether:ancient_debris", "mcl:hiddenInTheDepths")
mcl_item_entity.register_pickup_achievement("mcl_end:dragon_egg", "mcl:PickUpDragonEgg")
mcl_item_entity.register_pickup_achievement("mcl_armor:elytra", "mcl:skysTheLimit")
local function check_pickup_achievements(object, player)
if has_awards then
@ -849,16 +847,16 @@ minetest.register_entity(":__builtin:item", {
elseif self._flowing == true and not is_in_water and not is_floating then
-- Disable flowing physics if not on/in flowing liquid
self._flowing = false
enable_physics(self.object, self, true)
local pos = self.object:get_pos()
disable_physics(self.object, self, false, false)
return
end
-- If node is not registered or node is walkably solid and resting on nodebox
local nn = minetest.get_node({x=p.x, y=p.y-0.5, z=p.z}).name
local def = minetest.registered_nodes[nn]
local v = self.object:get_velocity()
local is_on_floor = def and (def.walkable
and not def.groups.slippery and v.y == 0)
local is_on_floor = (minetest.registered_nodes[nn].walkable
and not minetest.registered_nodes[nn].groups.slippery and v.y == 0)
if not minetest.registered_nodes[nn]
or is_floating or is_on_floor then

View File

@ -677,8 +677,7 @@ register_minecart(
{ "mcl_chests_normal.png", "mcl_minecarts_minecart.png" },
"mcl_minecarts_minecart_chest.png",
{"mcl_minecarts:minecart", "mcl_chests:chest"},
nil, nil, true)
mcl_entity_invs.register_inv("mcl_minecarts:chest_minecart","Minecart",27)
nil, nil, false)
-- Minecart with Furnace
register_minecart(
@ -731,7 +730,7 @@ register_minecart(
"mcl_minecarts_minecart.png",
}})
end
end, nil, true
end, nil, false
)
-- Minecart with Command Block
@ -831,7 +830,8 @@ minetest.register_craft({
},
})
minetest.register_craft({
-- TODO: Re-enable crafting of special minecarts when they have been implemented
--[[minetest.register_craft({
output = "mcl_minecarts:furnace_minecart",
recipe = {
{"mcl_furnaces:furnace"},
@ -839,16 +839,13 @@ minetest.register_craft({
},
})
-- TODO: Re-enable crafting of special minecarts when they have been implemented
--[[minetest.register_craft({
minetest.register_craft({
output = "mcl_minecarts:hopper_minecart",
recipe = {
{"mcl_hoppers:hopper"},
{"mcl_minecarts:minecart"},
},
})
--]]
minetest.register_craft({
output = "mcl_minecarts:chest_minecart",
@ -856,7 +853,7 @@ minetest.register_craft({
{"mcl_chests:chest"},
{"mcl_minecarts:minecart"},
},
})
})]]
if has_mcl_wip then

View File

@ -33,4 +33,4 @@ 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é
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é
Sneak to dismount=Se baisser pour descendre
Sneak to dismount=

View File

@ -1,5 +1,6 @@
name = mcl_minecarts
author = Krock
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, mcl_entity_invs
depends = mcl_title, 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

View File

@ -1,3 +1,4 @@
-- API for Mobs Redo: MineClone 2 Edition (MRM)
mcl_mobs = {}
@ -13,32 +14,15 @@ local FLOP_HOR_SPEED = 1.5
local ENTITY_CRAMMING_MAX = 24
local CRAMMING_DAMAGE = 3
local MOB_CAP = {}
MOB_CAP.hostile = 70
MOB_CAP.passive = 10
MOB_CAP.ambient = 15
MOB_CAP.water = 15
-- Localize
local S = minetest.get_translator("mcl_mobs")
local function shortest_term_of_yaw_rotatoin(self, rot_origin, rot_target, nums)
if not rot_origin or not rot_target then
return
end
rot_origin = math.deg(rot_origin)
rot_target = math.deg(rot_target)
if math.abs(rot_target - rot_origin) < 180 then
return rot_target - rot_origin
else
if (rot_target - rot_origin) > 0 then
return 360-(rot_target - rot_origin)
else
return (rot_target - rot_origin)+360
end
end
end
-- Invisibility mod check
mcl_mobs.invis = {}
@ -52,7 +36,6 @@ local max = math.max
local atann = math.atan
local random = math.random
local floor = math.floor
local ceil = math.ceil
local atan = function(x)
if not x or x ~= x then
@ -62,6 +45,7 @@ local atan = function(x)
end
end
-- Load settings
local damage_enabled = minetest.settings:get_bool("enable_damage")
local disable_blood = minetest.settings:get_bool("mobs_disable_blood")
@ -71,10 +55,11 @@ local spawn_protected = minetest.settings:get_bool("mobs_spawn_protected") ~= fa
local remove_far = true
local difficulty = tonumber(minetest.settings:get("mob_difficulty")) or 1.0
local show_health = false
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)
-- Shows helpful debug info above each mob
local mobs_debug = minetest.settings:get_bool("mobs_debug", false)
local spawn_logging = minetest.settings:get_bool("mcl_logging_mobs_spawn",true)
-- Peaceful mode message so players will know there are no monsters
if minetest.settings:get_bool("only_peaceful_mobs", false) then
@ -84,13 +69,6 @@ if minetest.settings:get_bool("only_peaceful_mobs", false) then
end)
end
local function dir_to_pitch(dir)
--local dir2 = vector.normalize(dir)
local xz = math.abs(dir.x) + math.abs(dir.z)
return -math.atan2(-dir.y, xz)
end
-- pathfinding settings
local enable_pathfinding = true
local stuck_timeout = 3 -- how long before mob gets stuck in place and starts searching
@ -177,7 +155,7 @@ local mob_sound = function(self, soundname, is_opinion, fixed_pitch)
pitch = base_pitch
end
-- randomize the pitch a bit
pitch = pitch + random(-10, 10) * 0.005
pitch = pitch + math.random(-10, 10) * 0.005
end
minetest.sound_play(sound, {
object = self.object,
@ -235,11 +213,11 @@ end
local collision = function(self)
local pos = self.object:get_pos()
if not pos then return {0,0} end
local vel = self.object:get_velocity()
local x = 0
local z = 0
local width = -self.collisionbox[1] + self.collisionbox[4] + 0.5
for _,object in pairs(minetest.get_objects_inside_radius(pos, width)) do
local ent = object:get_luaentity()
@ -276,14 +254,12 @@ local set_velocity = function(self, v)
end
local yaw = (self.object:get_yaw() or 0) + self.rotate
local vv = self.object:get_velocity()
if vv then
self.object:set_velocity({
x = (sin(yaw) * -v) + c_x,
y = vv.y,
z = (cos(yaw) * v) + c_y,
})
end
self.object:set_velocity({
x = (sin(yaw) * -v) + c_x,
y = self.object:get_velocity().y,
z = (cos(yaw) * v) + c_y,
})
end
@ -310,7 +286,7 @@ local function update_roll(self)
local cbox = table.copy(self.collisionbox)
local acbox = self.object:get_properties().collisionbox
if abs(cbox[2] - acbox[2]) > 0.1 then
if math.abs(cbox[2] - acbox[2]) > 0.1 then
was_Fleckenstein = true
end
@ -332,57 +308,19 @@ local function update_roll(self)
end
-- set and return valid yaw
local set_yaw = function(self, yaw, delay, dtime)
if self.noyaw then return end
if self._kb_turn then
self._turn_to = yaw
end
--clamp our yaw to a 360 range
if math.deg(self.object:get_yaw()) > 360 then
self.object:set_yaw(math.rad(10))
elseif math.deg(self.object:get_yaw()) < 0 then
self.object:set_yaw(math.rad(350))
end
--calculate the shortest way to turn to find our target
local target_shortest_path = shortest_term_of_yaw_rotatoin(self, self.object:get_yaw(), yaw, true)
--turn in the shortest path possible toward our target. if we are attacking, don't dance.
if math.abs(target_shortest_path) > 100 and (self.attack and self.attack:get_pos() or self.following and self.following:get_pos()) then
if self.following then
target_shortest_path = shortest_term_of_yaw_rotatoin(self, self.object:get_yaw(), minetest.dir_to_yaw(vector.direction(self.object:get_pos(), self.following:get_pos())), true)
else
target_shortest_path = shortest_term_of_yaw_rotatoin(self, self.object:get_yaw(), minetest.dir_to_yaw(vector.direction(self.object:get_pos(), self.attack:get_pos())), true)
end
end
local ddtime = 0.05 --set_tick_rate
if dtime then
ddtime = dtime
end
if math.abs(target_shortest_path) > 280*ddtime then
if target_shortest_path > 0 then
self.object:set_yaw(self.object:get_yaw()+3.6*ddtime)
else
self.object:set_yaw(self.object:get_yaw()-3.6*ddtime)
end
if not yaw or yaw ~= yaw then
yaw = 0
end
delay = delay or 0
yaw = self.object:get_yaw()
if delay == 0 then
if self.shaking and dtime then
yaw = yaw + (random() * 2 - 1) * 5 * dtime
yaw = yaw + (math.random() * 2 - 1) * 5 * dtime
end
self.object:set_yaw(yaw)
update_roll(self)
return yaw
end
@ -467,21 +405,17 @@ local set_animation = function(self, anim, fixed_frame)
return
end
if self.jockey then
anim = "jockey"
end
if flight_check(self) and self.fly and anim == "walk" then anim = "fly" end
self._current_animation = self._current_animation or ""
self.animation.current = self.animation.current or ""
if (anim == self._current_animation
if (anim == self.animation.current
or not self.animation[anim .. "_start"]
or not self.animation[anim .. "_end"]) and self.state ~= "die" then
return
end
self._current_animation = anim
self.animation.current = anim
local a_start = self.animation[anim .. "_start"]
local a_end
@ -653,7 +587,7 @@ local damage_effect = function(self, damage)
-- damage particles
if (not disable_blood) and damage > 0 then
local amount_large = floor(damage / 2)
local amount_large = math.floor(damage / 2)
local amount_small = damage % 2
local pos = self.object:get_pos()
@ -779,7 +713,7 @@ local item_drop = function(self, cooked, looting_level)
end
if do_common_looting then
num = num + floor(random(0, looting_level) + 0.5)
num = num + math.floor(math.random(0, looting_level) + 0.5)
end
if num > 0 then
@ -888,7 +822,7 @@ local check_for_death = function(self, cause, cmi_cause)
item_drop(self, cooked, looting)
if ((not self.child) or self.type ~= "animal") and (minetest.get_us_time() - self.xp_timestamp <= 5000000) then
mcl_experience.throw_xp(self.object:get_pos(), random(self.xp_min, self.xp_max))
mcl_experience.throw_xp(self.object:get_pos(), math.random(self.xp_min, self.xp_max))
end
end
end
@ -981,21 +915,23 @@ end
-- check if within physical map limits (-30911 to 30927)
local function within_limits(pos, radius)
local wmin, wmax = -30912, 30928
local within_limits, wmin, wmax = nil, -30913, 30928
within_limits = function(pos, radius)
if mcl_vars 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
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
if radius then
wmin = wmin - radius
wmax = wmax + radius
end
for _,v in pairs(pos) do
if v < wmin or v > wmax then return false end
end
return true
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
@ -1089,6 +1025,15 @@ local node_ok = function(pos, fallback)
return minetest.registered_nodes[fallback]
end
local function get_light(pos, tod)
if minetest.get_node_or_nil(pos) then
local lightfunc = minetest.get_natural_light or minetest.get_node_light
return lightfunc(pos, tod)
else
return 0
end
end
-- environmental damage (water, lava, fire, light etc.)
local do_env_damage = function(self)
@ -1131,10 +1076,9 @@ local do_env_damage = function(self)
end
end
local sunlight = 10
if within_limits(pos,0) then
sunlight = minetest.get_natural_light(pos, self.time_of_day)
end
-- Use get_node_light for Minetest version 5.3 where get_natural_light
-- does not exist yet.
local sunlight = get_light(pos, self.time_of_day)
-- bright light harms mob
if self.light_damage ~= 0 and (sunlight or 0) > 12 then
@ -1259,7 +1203,7 @@ local do_env_damage = function(self)
end
if drowning then
self.breath = max(0, self.breath - 1)
self.breath = math.max(0, self.breath - 1)
effect(pos, 2, "bubble.png", nil, nil, 1, nil)
if self.breath <= 0 then
@ -1277,7 +1221,7 @@ local do_env_damage = function(self)
return true
end
else
self.breath = min(self.breath_max, self.breath + 1)
self.breath = math.min(self.breath_max, self.breath + 1)
end
end
@ -1525,11 +1469,6 @@ local breed = function(self)
z = 0
})
end
self.animation = nil
local anim = self._current_animation
self._current_animation = nil -- Mobs Redo does nothing otherwise
mcl_mobs.set_animation(self, anim)
end
return
@ -1608,7 +1547,7 @@ local breed = function(self)
return
end
mcl_experience.throw_xp(pos, random(1, 7))
mcl_experience.throw_xp(pos, math.random(1, 7))
-- custom breed function
if parent1.on_breed then
@ -1624,7 +1563,7 @@ local breed = function(self)
-- Use texture of one of the parents
local p = random(1, 2)
local p = math.random(1, 2)
if p == 1 then
ent_c.base_texture = parent1.base_texture
else
@ -1786,7 +1725,7 @@ local smart_mobs = function(self, s, p, dist, dtime)
end, self)
end
if abs(vector.subtract(s,target_pos).y) > self.stepheight then
if math.abs(vector.subtract(s,target_pos).y) > self.stepheight then
if height_switcher then
use_pathfind = true
@ -1827,7 +1766,7 @@ local smart_mobs = function(self, s, p, dist, dtime)
if self.fear_height ~= 0 then dropheight = self.fear_height end
local jumpheight = 0
if self.jump and self.jump_height >= 4 then
jumpheight = min(ceil(self.jump_height / 4), 4)
jumpheight = math.min(math.ceil(self.jump_height / 4), 4)
elseif self.stepheight > 0.5 then
jumpheight = 1
end
@ -1858,7 +1797,7 @@ local smart_mobs = function(self, s, p, dist, dtime)
end
end
local sheight = ceil(self.collisionbox[5]) + 1
local sheight = math.ceil(self.collisionbox[5]) + 1
-- assume mob is 2 blocks high so it digs above its head
s.y = s.y + sheight
@ -1969,6 +1908,7 @@ end
-- find someone to attack
local monster_attack = function(self)
if not damage_enabled
or minetest.is_creative_enabled("")
or self.passive ~= false
or self.state == "attack"
or day_docile(self) then
@ -2004,7 +1944,7 @@ local monster_attack = function(self)
-- find specific mob to attack, failing that attack player/npc/animal
if specific_attack(self.specific_attack, name)
and (type == "player" or ( type == "npc" and self.attack_npcs )
and (type == "player" or type == "npc"
or (type == "animal" and self.attack_animals == true)) then
p = player:get_pos()
@ -2295,9 +2235,9 @@ local follow_flop = function(self)
if sdef and sdef.walkable then
mob_sound(self, "flop")
self.object:set_velocity({
x = random(-FLOP_HOR_SPEED, FLOP_HOR_SPEED),
x = math.random(-FLOP_HOR_SPEED, FLOP_HOR_SPEED),
y = FLOP_HEIGHT,
z = random(-FLOP_HOR_SPEED, FLOP_HOR_SPEED),
z = math.random(-FLOP_HOR_SPEED, FLOP_HOR_SPEED),
})
end
@ -2352,8 +2292,8 @@ local function go_to_pos(entity,b)
return true
end
local v = { x = b.x - s.x, z = b.z - s.z }
local yaw = (atann(v.z / v.x) + pi / 2) - entity.rotate
if b.x > s.x then yaw = yaw + pi end
local yaw = (math.atan(v.z / v.x) + math.pi / 2) - entity.rotate
if b.x > s.x then yaw = yaw + math.pi end
entity.object:set_yaw(yaw)
set_velocity(entity,entity.follow_velocity)
mcl_mobs:set_animation(entity, "walk")
@ -3062,7 +3002,6 @@ end
local function check_entity_cramming(self)
local p = self.object:get_pos()
if not p then return end
local oo = minetest.get_objects_inside_radius(p,1)
local mobs = {}
for _,o in pairs(oo) do
@ -3211,10 +3150,6 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
return
end
if minetest.is_creative_enabled(hitter:get_player_name()) then
self.health = 0
end
-- set/update 'drop xp' timestamp if hitted by player
self.xp_timestamp = minetest.get_us_time()
end
@ -3370,13 +3305,6 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
elseif luaentity and luaentity._knockback then
kb = kb + luaentity._knockback
end
--self._kb_turn = false
self._turn_to=self.object:get_yaw()+0.85
minetest.after(0.2, function()
if self and self.object then
self._kb_turn = true
end
end)
self.object:set_velocity({
x = dir.x * kb,
@ -3463,11 +3391,6 @@ end
local mob_detach_child = function(self, child)
if self.detach_child then
if self.detach_child(self, child) then
return
end
end
if self.driver == child then
self.driver = nil
end
@ -3477,20 +3400,21 @@ end
-- get entity staticdata
local mob_staticdata = function(self)
--[[
-- remove mob when out of range unless tamed
if remove_far
and self.can_despawn
and self.remove_ok
and ((not self.nametag) or (self.nametag == ""))
and self.lifetimer <= 20 then
if spawn_logging then
minetest.log("action", "[mcl_mobs] Mob "..tostring(self.name).." despawns in mob_staticdata at "..minetest.pos_to_string(vector.round(self.object:get_pos())))
end
return "remove"-- nil
minetest.log("action", "Mob "..name.." despawns in mob_staticdata at "..minetest.pos_to_string(self.object.get_pos(), 1))
mcl_burning.extinguish(self.object)
self.object:remove()
return ""-- nil
end
--]]
self.remove_ok = true
self.attack = nil
self.following = nil
@ -3516,16 +3440,13 @@ end
-- activate mob and reload settings
local mob_activate = function(self, staticdata, def, dtime)
if not self.object:get_pos() or staticdata == "remove" then
mcl_burning.extinguish(self.object)
self.object:remove()
return
end
-- remove monsters in peaceful mode
if self.type == "monster"
and minetest.settings:get_bool("only_peaceful_mobs", false) then
mcl_burning.extinguish(self.object)
self.object:remove()
return
end
@ -3546,10 +3467,7 @@ local mob_activate = function(self, staticdata, def, dtime)
def.textures = {def.textures}
end
local c = 1
if #def.textures > c then c = #def.textures end
self.base_texture = def.textures[random(c)]
self.base_texture = def.textures[random(1, #def.textures)]
self.base_mesh = def.mesh
self.base_size = self.visual_size
self.base_colbox = self.collisionbox
@ -3661,23 +3579,11 @@ local mob_activate = function(self, staticdata, def, dtime)
if not self.nametag then
self.nametag = def.nametag
end
if not self.custom_visual_size then
-- Remove saved visual_size on old existing entites.
self.visual_size = nil
self.base_size = self.visual_size
if self.child then
self.visual_size = {
x = self.visual_size.x * 0.5,
y = self.visual_size.y * 0.5,
}
end
end
-- set anything changed above
self.object:set_properties(self)
set_yaw(self, (random(0, 360) - 180) / 180 * pi, 6)
update_tag(self)
self._current_animation = nil
set_animation(self, "stand")
-- run on_spawn function if found
@ -3708,7 +3614,6 @@ end
-- main mob function
local mob_step = function(self, dtime)
self.lifetimer = self.lifetimer - dtime
check_item_pickup(self)
check_aggro(self,dtime)
if not self.fire_resistant then
@ -3740,9 +3645,6 @@ local mob_step = function(self, dtime)
end
-- smooth rotation by ThomasMonroe314
if self._turn_to then
set_yaw(self, self._turn_to, .1)
end
if self.delay and self.delay > 0 then
@ -3778,7 +3680,7 @@ local mob_step = function(self, dtime)
self.delay = self.delay - 1
if self.shaking then
yaw = yaw + (random() * 2 - 1) * 5 * dtime
yaw = yaw + (math.random() * 2 - 1) * 5 * dtime
end
self.object:set_yaw(yaw)
update_roll(self)
@ -3786,66 +3688,6 @@ local mob_step = function(self, dtime)
-- end rotation
if self.head_swivel and type(self.head_swivel) == "string" then
local oldp,oldr = self.object:get_bone_position(self.head_swivel)
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 10)) do
if obj:is_player() and not self.attack or obj:get_luaentity() and obj:get_luaentity().name == self.name and self ~= obj:get_luaentity() then
if not self._locked_object then
if math.random(5000/self.curiosity) == 1 then
self._locked_object = obj
end
else
if math.random(10000/self.curiosity) == 1 then
self._locked_object = nil
end
end
end
end
if self.attack then
self._locked_object = self.attack
end
if self._locked_object and (self._locked_object:is_player() or self._locked_object:get_luaentity()) and self._locked_object:get_hp() > 0 then
local _locked_object_eye_height = 1.5
if self._locked_object:get_luaentity() then
_locked_object_eye_height = self._locked_object:get_luaentity().head_eye_height
end
if self._locked_object:is_player() then
_locked_object_eye_height = self._locked_object:get_properties().eye_height
end
local self_rot = self.object:get_rotation()
if self.object:get_attach() then
self_rot = self.object:get_attach():get_rotation()
end
local player_pos = self._locked_object:get_pos()
local direction_player = vector.direction(vector.add(self.object:get_pos(), vector.new(0, self.head_eye_height*.7, 0)), vector.add(player_pos, vector.new(0, _locked_object_eye_height, 0)))
local mob_yaw = math.deg(-(-(self_rot.y)-(-minetest.dir_to_yaw(direction_player))))+self.head_yaw_offset
local mob_pitch = math.deg(-dir_to_pitch(direction_player))*self.head_pitch_multiplier
if (mob_yaw < -60 or mob_yaw > 60) and not (self.attack and self.type == "monster") then
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), vector.multiply(oldr, 0.9))
elseif self.attack and self.type == "monster" then
if self.head_yaw == "y" then
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), vector.new(mob_pitch, mob_yaw, 0))
elseif self.head_yaw == "z" then
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), vector.new(mob_pitch, 0, -mob_yaw))
end
else
if self.head_yaw == "y" then
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), vector.new(((mob_pitch-oldr.x)*.3)+oldr.x, ((mob_yaw-oldr.y)*.3)+oldr.y, 0))
elseif self.head_yaw == "z" then
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), vector.new(((mob_pitch-oldr.x)*.3)+oldr.x, 0, -(((mob_yaw-oldr.y)*.3)+oldr.y)*3))
end
end
elseif not self._locked_object and math.abs(oldr.y) > 3 and math.abs(oldr.x) < 3 then
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), vector.multiply(oldr, 0.9))
else
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), vector.new(0,0,0))
end
end
-- run custom function (defined in mob lua file)
if self.do_custom then
@ -3985,15 +3827,14 @@ local mob_step = function(self, dtime)
and ((not self.nametag) or (self.nametag == ""))
and self.state ~= "attack"
and self.following == nil then
self.lifetimer = self.lifetimer - dtime
if self.despawn_immediately or self.lifetimer <= 0 then
if spawn_logging then
minetest.log("action", "[mcl_mobs] Mob "..self.name.." despawns in mob_step at "..minetest.pos_to_string(pos, 1))
end
minetest.log("action", "Mob "..self.name.." despawns in mob_step at "..minetest.pos_to_string(pos, 1))
mcl_burning.extinguish(self.object)
self.object:remove()
return
elseif self.lifetimer <= 10 then
if random(10) < 4 then
if math.random(10) < 4 then
self.despawn_immediately = true
else
self.lifetimer = 20
@ -4086,14 +3927,6 @@ end
minetest.register_entity(name, {
use_texture_alpha = def.use_texture_alpha,
head_swivel = def.head_swivel or nil, -- bool to activate this function
head_yaw_offset = def.head_yaw_offset or 0, -- for wonkey model bones
head_pitch_multiplier = def.head_pitch_multiplier or 1, --for inverted pitch
bone_eye_height = def.bone_eye_height or 1.4, -- head bone offset
head_eye_height = def.head_eye_height or def.bone_eye_height or 0, -- how hight aproximatly the mobs head is fromm the ground to tell the mob how high to look up at the player
curiosity = def.curiosity or 1, -- how often mob will look at player on idle
head_yaw = def.head_yaw or "y", -- axis to rotate head on
horrizonatal_head_height = def.horrizonatal_head_height or 0,
stepheight = def.stepheight or 0.6,
name = name,
description = def.description,
@ -4106,7 +3939,6 @@ minetest.register_entity(name, {
on_die = def.on_die,
spawn_small_alternative = def.spawn_small_alternative,
do_custom = def.do_custom,
detach_child = def.detach_child,
jump_height = def.jump_height or 4, -- was 6
rotate = math.rad(def.rotate or 0), -- 0=front, 90=side, 180=back, 270=side2
lifetimer = def.lifetimer or 57.73,
@ -4192,7 +4024,6 @@ minetest.register_entity(name, {
dogshoot_count_max = def.dogshoot_count_max or 5,
dogshoot_count2_max = def.dogshoot_count2_max or (def.dogshoot_count_max or 5),
attack_animals = def.attack_animals or false,
attack_npcs = def.attack_npcs or false,
specific_attack = def.specific_attack,
runaway_from = def.runaway_from,
owner_loyal = def.owner_loyal,
@ -4214,7 +4045,6 @@ minetest.register_entity(name, {
texture_mods = {},
shoot_arrow = def.shoot_arrow,
sounds_child = def.sounds_child,
_child_animations = def.child_animations,
pick_up = def.pick_up,
explosion_strength = def.explosion_strength,
suffocation_timer = 0,
@ -4225,7 +4055,6 @@ minetest.register_entity(name, {
ignited_by_sunlight = def.ignited_by_sunlight or false,
spawn_in_group = def.spawn_in_group,
spawn_in_group_min = def.spawn_in_group_min,
noyaw = def.noyaw or false,
-- End of MCL2 extensions
on_spawn = def.on_spawn,
@ -4432,7 +4261,7 @@ end
-- Note: This also introduces the “spawn_egg” group:
-- * spawn_egg=1: Spawn egg (generic mob, no metadata)
-- * spawn_egg=2: Spawn egg (captured/tamed mob, metadata)
function mcl_mobs:register_egg(mob, desc, background_color, overlay_color, addegg, no_creative)
function mcl_mobs:register_egg(mob, desc, background, addegg, no_creative)
local grp = {spawn_egg = 1}
@ -4441,7 +4270,7 @@ function mcl_mobs:register_egg(mob, desc, background_color, overlay_color, addeg
grp.not_in_creative_inventory = 1
end
local invimg = "(spawn_egg.png^[multiply:" .. background_color ..")^(spawn_egg_overlay.png^[multiply:" .. overlay_color .. ")"
local invimg = background
if addegg == 1 then
invimg = "mobs_chicken_egg.png^(" .. invimg ..
@ -4504,8 +4333,7 @@ function mcl_mobs:register_egg(mob, desc, background_color, overlay_color, addeg
pos.y = pos.y - 0.5
local mob = minetest.add_entity(pos, mob)
local entityname = itemstack:get_name()
minetest.log("action", "Player " ..name.." spawned "..entityname.." at "..minetest.pos_to_string(pos))
minetest.log("action", "Mob spawned: "..name.." at "..minetest.pos_to_string(pos))
local ent = mob:get_luaentity()
-- don't set owner if monster or sneak pressed
@ -4665,10 +4493,6 @@ function mcl_mobs:spawn_child(pos, mob_type)
},
})
ent.animation = ent._child_animations
ent._current_animation = nil
set_animation(ent, "stand")
return child
end
@ -4681,7 +4505,7 @@ minetest.register_globalstep(function(dtime)
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 47)) do
local lua = obj:get_luaentity()
if lua and lua.is_mob then
lua.lifetimer = max(20, lua.lifetimer)
lua.lifetimer = math.max(20, lua.lifetimer)
lua.despawn_immediately = false
end
end

View File

@ -259,7 +259,6 @@ functions needed for the mob to work properly which contains the following:
that are bred in a different way.
'pick_up' table of itemstrings the mob will pick up (e.g. for breeding)
'on_pick_up' function that will be called on item pickup - return true to not pickup the item
'custom_visual_size' will not reset visual_size from the base class on reload
mobs:gopath(self,target,callback_arrived) pathfind a way to target and run callback on arrival
@ -434,7 +433,7 @@ true the mob will not spawn.
MineClone 2 extensions
----------------------
mcl_mobs:spawn_child(pos, mob_type)
mobs:spawn_child(pos, mob_type)
This function spawns a mob as a child. The parameter mob_type is the
entitystring of the new mob.
@ -444,7 +443,6 @@ mobs:death_effect(pos, collisionbox)
Create death particles at pos with the given collisionbox.
mcl_mobs.spawn(pos,name/entity name)
Making Arrows
-------------
@ -486,13 +484,13 @@ This function registers a arrow for mobs with the attack type shoot.
Spawn Eggs
----------
mobs:register_egg(name, description, background_color, overlay_color, addegg, no_creative)
mobs:register_egg(name, description, background, addegg, no_creative)
This function registers a spawn egg which can be used by admin to properly spawn in a mob.
'name' this is the name of your new mob to spawn e.g. "mob:sheep"
'description' the name of the new egg you are creating e.g. "Spawn Sheep"
'background_color' and 'overlay_color' define the colors for the texture displayed for the egg in inventory
'background'the texture displayed for the egg in inventory
'addegg' would you like an egg image in front of your texture (1 = yes,
0 = no)
'no_creative' when set to true this stops spawn egg appearing in creative

View File

@ -23,23 +23,21 @@ local table_copy = table.copy
local table_remove = table.remove
local pairs = pairs
local dbg_spawn_attempts = 0
local dbg_spawn_succ = 0
-- range for mob count
local aoc_range = 136
local mob_cap = {
monster = minetest.settings:get_bool("mcl_mob_cap_monster") or 70,
animal = minetest.settings:get_bool("mcl_mob_cap_animal") or 10,
ambient = minetest.settings:get_bool("mcl_mob_cap_ambient") or 15,
water = minetest.settings:get_bool("mcl_mob_cap_water") or 5, --currently unused
water_ambient = minetest.settings:get_bool("mcl_mob_cap_water_ambient") or 20, --currently unused
monster = 70,
animal =10,
ambient =15,
water = 5, --currently unused
water_ambient = 20, --currently unused
}
--do mobs spawn?
local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false
local spawn_protected = minetest.settings:get_bool("mobs_spawn_protected") ~= false
local logging = minetest.settings:get_bool("mcl_logging_mobs_spawn",true)
local noise_params = {
offset = 0,
@ -418,98 +416,36 @@ local function get_water_spawn(p)
end
end
local function spawn_check(pos,spawn_def)
if not spawn_def then return end
dbg_spawn_attempts = dbg_spawn_attempts + 1
local dimension = mcl_worlds.pos_to_dimension(pos)
local mob_type = minetest.registered_entities[spawn_def.name].type
local gotten_node = get_node(pos).name
local gotten_biome = minetest.get_biome_data(pos)
if not gotten_node or not gotten_biome then return end
gotten_biome = get_biome_name(gotten_biome.biome) --makes it easier to work with
local is_ground = minetest.get_item_group(gotten_node,"solid") ~= 0
if not is_ground then
pos.y = pos.y - 1
gotten_node = get_node(pos).name
is_ground = minetest.get_item_group(gotten_node,"solid") ~= 0
end
pos.y = pos.y + 1
local has_room = #minetest.find_nodes_in_area(pos,vector.offset(pos,0,1,0),{"air"}) or 0 >= 2
local is_water = get_item_group(gotten_node, "water") ~= 0
local is_lava = get_item_group(gotten_node, "lava") ~= 0
local is_leaf = get_item_group(gotten_node, "leaves") ~= 0
local is_bedrock = gotten_node == "mcl_core:bedrock"
local is_grass = minetest.get_item_group(gotten_node,"grass_block") ~= 0
local mob_count_wide = count_mobs(pos,aoc_range,mob_type)
local mob_count = count_mobs(pos,32,mob_type)
if pos and spawn_def
and mob_count_wide < (mob_cap[mob_type] or 15)
and mob_count < 5
and pos.y >= spawn_def.min_height
and pos.y <= spawn_def.max_height
and spawn_def.dimension == dimension
and biome_check(spawn_def.biomes, gotten_biome)
and (is_ground or spawn_def.type_of_spawning ~= "ground")
and (spawn_def.type_of_spawning ~= "ground" or not is_leaf)
and (spawn_def.type_of_spawning ~= "ground" or has_room)
and (spawn_def.check_position and spawn_def.check_position(pos) or true)
and (not is_farm_animal(spawn_def.name) or is_grass)
and (spawn_def.type_of_spawning ~= "water" or is_water)
and ( not spawn_protected or not minetest.is_protected(pos, "") )
and not is_bedrock then
--only need to poll for node light if everything else worked
local gotten_light = get_node_light(pos)
if gotten_light >= spawn_def.min_light and gotten_light <= spawn_def.max_light then
return true
end
end
return false
end
function mcl_mobs.spawn(pos,id)
local def = minetest.registered_entities[id] or minetest.registered_entities["mobs_mc:"..id] or minetest.registered_entities["extra_mobs:"..id]
if not def or (def.can_spawn and not def.can_spawn(pos)) or not def.is_mob then
return false
end
return minetest.add_entity(pos, def.name)
end
local dbg_spawn_attempts = 0
local dbg_spawn_succ = 0
local function spawn_group(p,mob,spawn_on,group_max,group_min)
if not group_min then group_min = 1 end
local nn= minetest.find_nodes_in_area_under_air(vector.offset(p,-5,-3,-5),vector.offset(p,5,3,5),spawn_on)
local o
table.shuffle(nn)
if not nn or #nn < 1 then
nn = {}
table.insert(nn,p)
end
for i = 1, math.random(group_min,group_max) do
local sp = vector.offset(nn[math.random(#nn)],0,1,0)
if spawn_check(nn[math.random(#nn)],mob) then
if mob.type_of_spawning == "water" then
sp = get_water_spawn(sp)
end
o = mcl_mobs.spawn(sp,mob.name)
if o then dbg_spawn_succ = dbg_spawn_succ + 1 end
if mob.type_of_spawning == "water" then
sp = get_water_spawn(sp)
end
o = minetest.add_entity(sp,mob.name)
if o then dbg_spawn_succ = dbg_spawn_succ + 1 end
end
return o
end
mcl_mobs.spawn_group = spawn_group
minetest.register_chatcommand("spawn_mob",{
minetest.register_chatcommand("mobstats",{
privs = { debug = true },
func = function(n,param)
local pos = minetest.get_player_by_name(n):get_pos()
if mcl_mobs.spawn(pos,param) then
return true, param.." spawned at "..minetest.pos_to_string(pos),
minetest.log("action", n.." spawned "..param.." at "..minetest.pos_to_string(pos))
end
return false, "Couldn't spawn "..param
minetest.chat_send_player(n,"mobs within 32 radius of player:"..count_mobs(pos,32))
minetest.chat_send_player(n,"total mobs:"..count_mobs_total())
minetest.chat_send_player(n,"spawning attempts since server start:"..dbg_spawn_attempts)
minetest.chat_send_player(n,"successful spawns since server start:"..dbg_spawn_succ)
end
})
@ -518,12 +454,9 @@ if mobs_spawn then
local perlin_noise
local function spawn_a_mob(pos, dimension, y_min, y_max)
--create a disconnected clone of the spawn dictionary
--prevents memory leak
local mob_library_worker_table = table_copy(spawn_dictionary)
dbg_spawn_attempts = dbg_spawn_attempts + 1
local dimension = dimension or mcl_worlds.pos_to_dimension(pos)
local goal_pos = get_next_mob_spawn_pos(pos)
--grab mob that fits into the spawning location
--randomly grab a mob, don't exclude any possibilities
local spawning_position_list = find_nodes_in_area_under_air(
{x = goal_pos.x, y = y_min, z = goal_pos.z},
{x = goal_pos.x, y = y_max, z = goal_pos.z},
@ -532,6 +465,37 @@ if mobs_spawn then
if #spawning_position_list <= 0 then return end
local spawning_position = spawning_position_list[math_random(1, #spawning_position_list)]
local gotten_node = get_node(spawning_position).name
local gotten_biome = minetest.get_biome_data(spawning_position)
if not gotten_node or not gotten_biome then return end
gotten_biome = get_biome_name(gotten_biome.biome) --makes it easier to work with
--add this so mobs don't spawn inside nodes
spawning_position.y = spawning_position.y + 1
--only need to poll for node light if everything else worked
local gotten_light = get_node_light(spawning_position)
local is_water = get_item_group(gotten_node, "water") ~= 0
local is_lava = get_item_group(gotten_node, "lava") ~= 0
local is_leaf = get_item_group(gotten_node, "leaves") ~= 0
local is_bedrock = gotten_node == "mcl_core:bedrock"
local is_ground = not (is_water or is_lava)
local is_grass = minetest.get_item_group(gotten_node,"grass_block") ~= 0
local has_bed = minetest.find_node_near(pos,25,{"group:bed"})
if not is_ground then
spawning_position.y = spawning_position.y - 1
end
local mob_def
--create a disconnected clone of the spawn dictionary
--prevents memory leak
local mob_library_worker_table = table_copy(spawn_dictionary)
--grab mob that fits into the spawning location
--randomly grab a mob, don't exclude any possibilities
perlin_noise = perlin_noise or minetest_get_perlin(noise_params)
local noise = perlin_noise:get_3d(spawning_position)
local current_summary_chance = summary_chance
@ -547,10 +511,27 @@ if mobs_spawn then
step_chance = step_chance + mob_chance
end
local mob_def = mob_library_worker_table[mob_index]
local spawn_in_group = minetest.registered_entities[mob_def.name].spawn_in_group or 4
local spawn_in_group_min = minetest.registered_entities[mob_def.name].spawn_in_group_min or 1
local mob_type = minetest.registered_entities[mob_def.name].type
if spawn_check(spawning_position,mob_def) then
local spawn_in_group = minetest.registered_entities[mob_def.name].spawn_in_group or 4
local mob_count_wide = count_mobs(pos,aoc_range,mob_type)
local mob_count = count_mobs(spawning_position,32,mob_type)
if mob_def
and mob_count_wide < (mob_cap[mob_type] or 15)
and mob_count < 5
and spawning_position.y >= mob_def.min_height
and spawning_position.y <= mob_def.max_height
and mob_def.dimension == dimension
and biome_check(mob_def.biomes, gotten_biome)
and gotten_light >= mob_def.min_light
and gotten_light <= mob_def.max_light
and (is_ground or mob_def.type_of_spawning ~= "ground")
and (mob_def.type_of_spawning ~= "ground" or not is_leaf)
and (mob_def.check_position and mob_def.check_position(spawning_position) or true)
and (not is_farm_animal(mob_def.name) or is_grass)
and (mob_type ~= "npc" or has_bed)
and (mob_def.type_of_spawning ~= "water" or is_water)
and not is_bedrock
then
if mob_def.type_of_spawning == "water" then
spawning_position = get_water_spawn(spawning_position)
if not spawning_position then
@ -562,17 +543,9 @@ if mobs_spawn then
end
--everything is correct, spawn mob
local object
if spawn_in_group and ( mob_type ~= "monster" or math.random(5) == 1 ) then
if logging then
minetest.log("action", "[mcl_mobs] A group of mob " .. mob_def.name .. " spawns at " .. minetest.pos_to_string(spawning_position, 1))
end
object = spawn_group(spawning_position,mob_def,{minetest.get_node(vector.offset(spawning_position,0,-1,0)).name},spawn_in_group,spawn_in_group_min)
else
if logging then
minetest.log("action", "[mcl_mobs] Mob " .. mob_def.name .. " spawns at " .. minetest.pos_to_string(spawning_position, 1))
end
object = mcl_mobs.spawn(spawning_position, mob_def.name)
if spawn_in_group then
object = spawn_group(spawning_position,mob_def,{gotten_node},spawn_in_group,spawn_in_group_min)
else object = minetest.add_entity(spawning_position, mob_def.name)
end
@ -606,14 +579,3 @@ if mobs_spawn then
end
end)
end
minetest.register_chatcommand("mobstats",{
privs = { debug = true },
func = function(n,param)
local pos = minetest.get_player_by_name(n):get_pos()
minetest.chat_send_player(n,"mobs within 32 radius of player:"..count_mobs(pos,32))
minetest.chat_send_player(n,"total mobs:"..count_mobs_total())
minetest.chat_send_player(n,"spawning attempts since server start:"..dbg_spawn_attempts)
minetest.chat_send_player(n,"successful spawns since server start:"..dbg_spawn_succ)
end
})

View File

@ -144,4 +144,4 @@ mobs_mc.water_level-1)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:bat", S("Bat"), "#4c3e30", "#0f0f0f", 0)
mcl_mobs:register_egg("mobs_mc:bat", S("Bat"), "mobs_mc_spawn_icon_bat.png", 0)

View File

@ -26,12 +26,6 @@ mcl_mobs:register_mob("mobs_mc:blaze", {
rotate = -180,
visual = "mesh",
mesh = "mobs_mc_blaze.b3d",
head_swivel = "head.control",
bone_eye_height = 4,
head_eye_height = 3.5,
curiosity = 10,
head_yaw_offset = 180,
head_pitch_multiplier=-1,
textures = {
{"mobs_mc_blaze.png"},
},
@ -208,4 +202,4 @@ mcl_mobs:register_arrow("mobs_mc:blaze_fireball", {
})
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:blaze", S("Blaze"), "#f6b201", "#fff87e", 0)
mcl_mobs:register_egg("mobs_mc:blaze", S("Blaze"), "mobs_mc_spawn_icon_blaze.png", 0)

View File

@ -20,18 +20,12 @@ mcl_mobs:register_mob("mobs_mc:chicken", {
collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.69, 0.2},
runaway = true,
floats = 1,
head_swivel = "head.control",
bone_eye_height = 4,
head_eye_height = 1.5,
horrizonatal_head_height = -.3,
curiosity = 10,
head_yaw="z",
visual_size = {x=1,y=1},
visual = "mesh",
mesh = "mobs_mc_chicken.b3d",
textures = {
{"mobs_mc_chicken.png"},
},
visual_size = {x=2.2, y=2.2},
makes_footstep_sound = true,
walk_velocity = 1,
@ -64,15 +58,12 @@ mcl_mobs:register_mob("mobs_mc:chicken", {
distance = 16,
},
animation = {
stand_start = 0, stand_end = 0,
walk_start = 0, walk_end = 20, walk_speed = 25,
run_start = 0, run_end = 20, run_speed = 50,
},
child_animations = {
stand_start = 31, stand_end = 31,
walk_start = 31, walk_end = 51, walk_speed = 37,
run_start = 31, run_end = 51, run_speed = 75,
stand_speed = 25, walk_speed = 25, run_speed = 50,
stand_start = 0, stand_end = 0,
walk_start = 0, walk_end = 40,
run_start = 0, run_end = 40,
},
follow = {
"mcl_farming:wheat_seeds",
"mcl_farming:melon_seeds",
@ -163,4 +154,4 @@ mobs_mc.water_level,
mcl_vars.mg_overworld_max)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:chicken", S("Chicken"), "#a1a1a1", "#ff0000", 0)
mcl_mobs:register_egg("mobs_mc:chicken", S("Chicken"), "mobs_mc_spawn_icon_chicken.png", 0)

View File

@ -271,4 +271,4 @@ water-16,
water+1)
--spawn egg
mcl_mobs:register_egg("mobs_mc:cod", S("Cod"), "#c1a76a", "#e5c48b", 0)
mcl_mobs:register_egg("mobs_mc:cod", S("Cod"), "extra_mobs_spawn_icon_cod.png", 0)

View File

@ -17,12 +17,7 @@ local cow_def = {
"mobs_mc_cow.png",
"blank.png",
}, },
head_swivel = "head.control",
bone_eye_height = 10,
head_eye_height = 1.1,
horrizonatal_head_height=-1.8,
curiosity = 2,
head_yaw="z",
visual_size = {x=2.8, y=2.8},
makes_footstep_sound = true,
walk_velocity = 1,
drops = {
@ -46,14 +41,11 @@ local cow_def = {
distance = 16,
},
animation = {
stand_start = 0, stand_end = 0,
walk_start = 0, walk_end = 40, walk_speed = 30,
run_start = 0, run_end = 40, run_speed = 40,
},
child_animations = {
stand_start = 41, stand_end = 41,
walk_start = 41, walk_end = 81, walk_speed = 45,
run_start = 41, run_end = 81, run_speed = 60,
stand_speed = 25, walk_speed = 40,
run_speed = 60, stand_start = 0,
stand_end = 0, walk_start = 0,
walk_end = 40, run_start = 0,
run_end = 40,
},
on_rightclick = function(self, clicker)
if mcl_mobs:feed_tame(self, clicker, 1, true, false) then return end
@ -90,6 +82,7 @@ mcl_mobs:register_mob("mobs_mc:cow", cow_def)
-- Mooshroom
local mooshroom_def = table.copy(cow_def)
mooshroom_def.description = S("Mooshroom")
mooshroom_def.mesh = "mobs_mc_cow.b3d"
mooshroom_def.spawn_in_group_min = 4
mooshroom_def.spawn_in_group = 8
mooshroom_def.textures = { {"mobs_mc_mooshroom.png", "mobs_mc_mushroom_red.png"}, {"mobs_mc_mooshroom_brown.png", "mobs_mc_mushroom_brown.png" } }
@ -218,5 +211,5 @@ mcl_vars.mg_overworld_min,
mcl_vars.mg_overworld_max)
-- spawn egg
mcl_mobs:register_egg("mobs_mc:cow", S("Cow"), "#443626", "#a1a1a1", 0)
mcl_mobs:register_egg("mobs_mc:mooshroom", S("Mooshroom"), "#a00f10", "#b7b7b7", 0)
mcl_mobs:register_egg("mobs_mc:cow", S("Cow"), "mobs_mc_spawn_icon_cow.png", 0)
mcl_mobs:register_egg("mobs_mc:mooshroom", S("Mooshroom"), "mobs_mc_spawn_icon_mooshroom.png", 0)

View File

@ -12,7 +12,6 @@ local S = minetest.get_translator("mobs_mc")
mcl_mobs:register_mob("mobs_mc:creeper", {
type = "monster",
spawn_class = "hostile",
spawn_in_group = 1,
hp_min = 20,
hp_max = 20,
xp_min = 5,
@ -21,9 +20,6 @@ mcl_mobs:register_mob("mobs_mc:creeper", {
pathfinding = 1,
visual = "mesh",
mesh = "mobs_mc_creeper.b3d",
head_swivel = "Head_Control",
bone_eye_height = 2.35,
curiosity = 2,
textures = {
{"mobs_mc_creeper.png",
"mobs_mc_empty.png"},
@ -407,4 +403,4 @@ mcl_vars.mg_overworld_min,
mcl_vars.mg_overworld_max)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:creeper", S("Creeper"), "#0da70a", "#000000", 0)
mcl_mobs:register_egg("mobs_mc:creeper", S("Creeper"), "mobs_mc_spawn_icon_creeper.png", 0)

View File

@ -0,0 +1 @@
mcl_mobs

View File

@ -250,4 +250,4 @@ water-16,
water+1)
--spawn egg
mcl_mobs:register_egg("mobs_mc:dolphin", S("Dolphin"), "#223b4d", "#f9f9f9", 0)
mcl_mobs:register_egg("mobs_mc:dolphin", S("Dolphin"), "extra_mobs_spawn_icon_dolphin.png", 0)

View File

@ -4,50 +4,6 @@
local S = minetest.get_translator("mobs_mc")
local BEAM_CHECK_FREQUENCY = 2
local POS_CHECK_FREQUENCY = 15
local HEAL_AMMOUNT = 37
local function heal(self)
local o = self.object
self.health = math.min(self.hp_max,self.health + HEAL_AMMOUNT)
end
local function check_beam(self)
for _, obj in ipairs(minetest.get_objects_inside_radius(self.object:get_pos(), 80)) do
local luaentity = obj:get_luaentity()
if luaentity and luaentity.name == "mcl_end:crystal" then
if luaentity.beam then
if luaentity.beam == self.beam then
heal(self)
break
end
else
if self.beam then
self.beam:remove()
end
minetest.add_entity(self.object:get_pos(), "mcl_end:crystal_beam"):get_luaentity():init(self.object, obj)
break
end
end
end
end
local function check_pos(self)
if self._portal_pos then
-- migrate old format
if type(self._portal_pos) == "string" then
self._portal_pos = minetest.string_to_pos(self._portal_pos)
end
local portal_center = vector.add(self._portal_pos, vector.new(0, 11, 0))
local pos = self.object:get_pos()
if vector.distance(pos, portal_center) > 50 then
self.object:set_pos(self._last_good_pos or portal_center)
else
self._last_good_pos = pos
end
end
end
mcl_mobs:register_mob("mobs_mc:enderdragon", {
description = S("Ender Dragon"),
type = "monster",
@ -67,7 +23,7 @@ mcl_mobs:register_mob("mobs_mc:enderdragon", {
{"mobs_mc_dragon.png"},
},
visual_size = {x=3, y=3},
view_range = 64,
view_range = 35,
walk_velocity = 6,
run_velocity = 6,
can_despawn = false,
@ -105,33 +61,45 @@ mcl_mobs:register_mob("mobs_mc:enderdragon", {
run_start = 0, run_end = 20,
},
ignores_nametag = true,
do_custom = function(self,dtime)
do_custom = function(self)
mcl_bossbars.update_boss(self.object, "Ender Dragon", "light_purple")
if self._pos_timer == nil or self._pos_timer > POS_CHECK_FREQUENCY then
self._pos_timer = 0
check_pos(self)
end
if self._beam_timer == nil or self._beam_timer > BEAM_CHECK_FREQUENCY then
self._beam_timer = 0
check_beam(self)
end
self._beam_timer = self._beam_timer + dtime
self._pos_timer = self._pos_timer + dtime
end,
on_die = function(self, pos, cmi_cause)
if self._portal_pos then
mcl_portals.spawn_gateway_portal()
mcl_structures.place_structure(self._portal_pos,mcl_structures.registered_structures["end_exit_portal_open"],PseudoRandom(minetest.get_mapgen_setting("seed")),-1)
if self._initial then
mcl_experience.throw_xp(pos, 11500) -- 500 + 11500 = 12000
minetest.set_node(vector.add(self._portal_pos, vector.new(0, 5, 0)), {name = "mcl_end:dragon_egg"})
for _, obj in ipairs(minetest.get_objects_inside_radius(self.object:get_pos(), 80)) do
local luaentity = obj:get_luaentity()
if luaentity and luaentity.name == "mcl_end:crystal" then
if luaentity.beam then
if luaentity.beam == self.beam then
break
end
else
if self.beam then
self.beam:remove()
end
minetest.add_entity(self.object:get_pos(), "mcl_end:crystal_beam"):get_luaentity():init(self.object, obj)
break
end
end
end
-- Free The End Advancement
for _,players in pairs(minetest.get_objects_inside_radius(pos,64)) do
if players:is_player() then
awards.unlock(players:get_player_name(), "mcl:freeTheEnd")
if self._portal_pos then
-- migrate old format
if type(self._portal_pos) == "string" then
self._portal_pos = minetest.string_to_pos(self._portal_pos)
end
local portal_center = vector.add(self._portal_pos, vector.new(3, 11, 3))
local pos = self.object:get_pos()
if vector.distance(pos, portal_center) > 50 then
self.object:set_pos(self._last_good_pos or portal_center)
else
self._last_good_pos = pos
end
end
end,
on_die = function(self, pos)
if self._portal_pos then
mcl_portals.spawn_gateway_portal()
mcl_structures.call_struct(self._portal_pos, "end_exit_portal_open")
if self._initial then
mcl_experience.throw_xp(pos, 11500) -- 500 + 11500 = 12000
minetest.set_node(vector.add(self._portal_pos, vector.new(3, 5, 3)), {name = "mcl_end:dragon_egg"})
end
end
end,
@ -170,7 +138,6 @@ mcl_mobs:register_arrow("mobs_mc:dragon_fireball", {
end
})
mcl_mobs:register_egg("mobs_mc:enderdragon", S("Ender Dragon"), "#252525", "#b313c9", 0, true)
mcl_mobs:register_egg("mobs_mc:enderdragon", S("Ender Dragon"), "mobs_mc_spawn_icon_dragon.png", 0, true)
mcl_wip.register_wip_item("mobs_mc:enderdragon")

View File

@ -24,25 +24,7 @@
-- added rain damage.
-- fixed the grass_with_dirt issue.
minetest.register_entity("mobs_mc:ender_eyes", {
visual = "mesh",
mesh = "mobs_mc_spider.b3d",
visual_size = {x=1.01, y=1.01},
textures = {
"mobs_mc_enderman_eyes.png",
},
on_step = function(self)
if self and self.object then
if not self.object:get_attach() then
self.object:remove()
end
end
end,
glow = 50,
})
local S = minetest.get_translator("mobs_mc")
local enable_damage = minetest.settings:get_bool("enable_damage")
local telesound = function(pos, is_source)
local snd
@ -237,7 +219,6 @@ local select_enderman_animation = function(animation_type)
end
local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false
local spawners = {}
mcl_mobs:register_mob("mobs_mc:enderman", {
description = S("Enderman"),
@ -255,19 +236,6 @@ mcl_mobs:register_mob("mobs_mc:enderman", {
textures = create_enderman_textures(),
visual_size = {x=3, y=3},
makes_footstep_sound = true,
on_spawn = function(self)
local spider_eyes=false
for n = 1, #self.object:get_children() do
local obj = self.object:get_children()[n]
if obj:get_luaentity() and self.object:get_luaentity().name == "mobs_mc:ender_eyes" then
spider_eyes = true
end
end
if not spider_eyes then
minetest.add_entity(self.object:get_pos(), "mobs_mc:ender_eyes"):set_attach(self.object, "head.top", vector.new(0,2.54,-1.99), vector.new(90,0,180))
minetest.add_entity(self.object:get_pos(), "mobs_mc:ender_eyes"):set_attach(self.object, "head.top", vector.new(1,2.54,-1.99), vector.new(90,0,180))
end
end,
sounds = {
-- TODO: Custom war cry sound
war_cry = "mobs_sandmonster",
@ -295,42 +263,20 @@ mcl_mobs:register_mob("mobs_mc:enderman", {
do_custom = function(self, dtime)
-- PARTICLE BEHAVIOUR HERE.
local enderpos = self.object:get_pos()
if self._particle_timer and self._particle_timer >= 1 then
for _,player in pairs(minetest.get_connected_players()) do
if not spawners[player] then spawners[player] = {} end
local dst = vector.distance(player:get_pos(),enderpos)
if dst < 128 and not spawners[player][self.object] then
self._particle_timer = 0
spawners[player][self.object] = minetest.add_particlespawner({
amount = 5,
minpos = vector.new(-0.6,0,-0.6),
maxpos = vector.new(0.6,3,0.6),
minvel = vector.new(-0.25,-0.25,-0.25),
maxvel = vector.new(0.25,0.25,0.25),
minacc = vector.new(-0.5,-0.5,-0.5),
maxacc = vector.new(0.5,0.5,0.5),
minexptime = 0.2,
maxexptime = 3,
minsize = 0.2,
maxsize = 1.2,
collisiondetection = true,
vertical = false,
time = 0,
texture = "mcl_portals_particle"..math.random(1, 5)..".png",
attached = self.object,
playername = player:get_player_name(),
})
elseif dst > 128 and spawners[player][self.object] then
minetest.delete_particlespawner(spawners[player][self.object])
spawners[player][self.object] = nil
end
end
elseif not self._particle_timer then
self._particle_timer = 0
local chanceOfParticle = math.random(0, 1)
if chanceOfParticle == 1 then
minetest.add_particle({
pos = {x=enderpos.x+math.random(-1,1)*math.random()/2,y=enderpos.y+math.random(0,3),z=enderpos.z+math.random(-1,1)*math.random()/2},
velocity = {x=math.random(-.25,.25), y=math.random(-.25,.25), z=math.random(-.25,.25)},
acceleration = {x=math.random(-.5,.5), y=math.random(-.5,.5), z=math.random(-.5,.5)},
expirationtime = math.random(),
size = math.random(),
collisiondetection = true,
vertical = false,
texture = "mcl_portals_particle"..math.random(1, 5)..".png",
})
end
self._particle_timer = self._particle_timer + dtime
-- RAIN DAMAGE / EVASIVE WARP BEHAVIOUR HERE.
enderpos = self.object:get_pos()
local dim = mcl_worlds.pos_to_dimension(enderpos)
if dim == "overworld" then
if mcl_weather.state == "rain" or mcl_weather.state == "lightning" then
@ -366,25 +312,24 @@ mcl_mobs:register_mob("mobs_mc:enderman", {
else return end
-- AGRESSIVELY WARP/CHASE PLAYER BEHAVIOUR HERE.
if self.state == "attack" then
if self.attack then
local target = self.attack
local pos = target:get_pos()
if pos ~= nil then
if vector.distance(self.object:get_pos(), target:get_pos()) > 10 then
self:teleport(target)
--if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
--self:teleport(nil)
--self.state = ""
--else
if self.attack then
local target = self.attack
local pos = target:get_pos()
if pos ~= nil then
if vector.distance(self.object:get_pos(), target:get_pos()) > 10 then
self:teleport(target)
end
end
end
end
else --if not attacking try to tp to the dark
local light = minetest.get_node_light(enderpos)
if light and light > minetest.LIGHT_MAX then
self:teleport(nil)
end
--end
end
-- ARROW / DAYTIME PEOPLE AVOIDANCE BEHAVIOUR HERE.
-- Check for arrows and people nearby.
enderpos = self.object:get_pos()
local enderpos = self.object:get_pos()
enderpos.y = enderpos.y + 1.5
local objs = minetest.get_objects_inside_radius(enderpos, 2)
for n = 1, #objs do
@ -413,7 +358,7 @@ mcl_mobs:register_mob("mobs_mc:enderman", {
-- self:teleport(nil)
-- self.state = ""
--else
if self.attack ~= nil and enable_damage then
if self.attack ~= nil and not minetest.settings:get_bool("creative_mode") then
self.state = 'attack'
end
--end
@ -648,14 +593,6 @@ mcl_mobs:register_mob("mobs_mc:enderman", {
attack_type = "dogfight",
})
minetest.register_on_leaveplayer(function(player)
if not spawners[player] then return end
for _,s in pairs(spawners[player]) do
minetest.delete_particlespawner(s)
end
spawners[player] = nil
end)
-- End spawn
mcl_mobs:spawn_specific(
@ -663,12 +600,7 @@ mcl_mobs:spawn_specific(
"end",
"ground",
{
"End",
"EndIsland",
"EndMidlands",
"EndBarrens",
"EndBorder",
"EndSmallIslands"
"End"
},
0,
minetest.LIGHT_MAX+1,
@ -833,7 +765,7 @@ mcl_mobs:spawn_specific(
"ground",
{
"Nether",
"SoulsandValley",
"SoulsandVall3ey",
},
0,
11,
@ -860,4 +792,4 @@ mcl_vars.mg_nether_min,
mcl_vars.mg_nether_max)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:enderman", S("Enderman"), "#252525", "#151515", 0)
mcl_mobs:register_egg("mobs_mc:enderman", S("Enderman"), "mobs_mc_spawn_icon_enderman.png", 0)

View File

@ -38,4 +38,4 @@ mcl_mobs:register_mob("mobs_mc:endermite", {
reach = 1,
})
mcl_mobs:register_egg("mobs_mc:endermite", S("Endermite"), "#161616", "#6d6d6d", 0)
mcl_mobs:register_egg("mobs_mc:endermite", S("Endermite"), "mobs_mc_spawn_icon_endermite.png", 0)

View File

@ -141,4 +141,4 @@ mcl_mobs:register_arrow("mobs_mc:fireball", {
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:ghast", S("Ghast"), "#f9f9f9", "#bcbcbc", 0)
mcl_mobs:register_egg("mobs_mc:ghast", S("Ghast"), "mobs_mc_spawn_icon_ghast.png", 0)

View File

@ -104,4 +104,4 @@ mcl_mobs:register_mob("mobs_mc:guardian", {
--mcl_mobs:spawn_specific("mobs_mc:guardian", { "mcl_core:water_source", "mclx_core:river_water_source" }, { "mcl_core:water_source", "mclx_core:river_water_source" }, 0, minetest.LIGHT_MAX+1, 30, 25000, 2, mcl_vars.mg_overworld_min, mobs_mc.water_level - 10)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:guardian", S("Guardian"), "#5a8272", "#f17d31", 0)
mcl_mobs:register_egg("mobs_mc:guardian", S("Guardian"), "mobs_mc_spawn_icon_guardian.png", 0)

View File

@ -112,6 +112,5 @@ mcl_mobs:register_mob("mobs_mc:guardian_elder", {
-- mcl_mobs:spawn_specific("mobs_mc:guardian_elder", { "mcl_core:water_source", "mclx_core:river_water_source" }, { "mcl_core:water_source", "mclx_core:river_water_source" }, 0, minetest.LIGHT_MAX+1, 30, 40000, 2, mcl_vars.mg_overworld_min, mobs_mc.water_level-18)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:guardian_elder", S("Elder Guardian"), "#ceccba", "#747693", 0)
mcl_mobs:register_egg("mobs_mc:guardian_elder", S("Elder Guardian"), "mobs_mc_spawn_icon_guardian_elder.png", 0)

View File

@ -34,30 +34,6 @@ local horse_extra_texture = function(horse)
return textures
end
local function get_drops(self)
self.drops = {}
table.insert(self.drops,
{name = "mcl_mobitems:leather",
chance = 1,
min = 0,
max = 2,
looting = "common",
})
if self._saddle then
table.insert(self.drops,{name = "mcl_mobitems:saddle",
chance = 1,
min = 1,
max = 1,})
end
if self._chest then
table.insert(self.drops,{name = "mcl_chests:chest",
chance = 1,
min = 1,
max = 1,})
end
end
-- Helper functions to determine equipment rules
local can_equip_horse_armor = function(entity_id)
return entity_id == "mobs_mc:horse" or entity_id == "mobs_mc:skeleton_horse" or entity_id == "mobs_mc:zombie_horse"
@ -261,27 +237,6 @@ local horse = {
local iname = item:get_name()
local heal = 0
if self._inv_id then
if not self._chest and item:get_name() == "mcl_chests:chest" then
item:take_item()
clicker:set_wielded_item(item)
self._chest = true
-- Update texture
if not self._naked_texture then
-- Base horse texture without chest or saddle
self._naked_texture = self.base_texture[2]
end
local tex = horse_extra_texture(self)
self.base_texture = tex
self.object:set_properties({textures = self.base_texture})
get_drops(self)
return
elseif self._chest and clicker:get_player_control().sneak then
mcl_entity_invs.show_inv_form(self,clicker)
return
end
end
-- Taming
self.temper = self.temper or (math.random(1,100))
@ -385,7 +340,6 @@ local horse = {
self.base_texture = tex
self.object:set_properties({textures = self.base_texture})
minetest.sound_play({name = "mcl_armor_equip_leather"}, {gain=0.5, max_hear_distance=12, pos=self.object:get_pos()}, true)
get_drops(self)
-- Put on horse armor if tamed
elseif can_equip_horse_armor(self.name) and not self.driver and not self._horse_armor
@ -564,9 +518,8 @@ donkey.collisionbox = {
donkey.jump = true
donkey.jump_height = 3.75 -- can clear 1 block height
mcl_mobs:register_mob("mobs_mc:donkey", donkey)
mcl_entity_invs.register_inv("mobs_mc:donkey","Donkey",15,true)
-- Mule
local m = 0.94
local mule = table.copy(donkey)
@ -584,7 +537,6 @@ mule.collisionbox = {
horse.collisionbox[6] * m,
}
mcl_mobs:register_mob("mobs_mc:mule", mule)
mcl_entity_invs.register_inv("mobs_mc:mule","Mule",15,true)
--===========================
--Spawn Function
@ -635,8 +587,8 @@ mobs_mc.water_level+3,
mcl_vars.mg_overworld_max)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:horse", S("Horse"), "#c09e7d", "#eee500", 0)
mcl_mobs:register_egg("mobs_mc:skeleton_horse", S("Skeleton Horse"), "#68684f", "#e5e5d8", 0)
--mobs:register_egg("mobs_mc:zombie_horse", S("Zombie Horse"), "#2a5a37", "#84d080", 0)
mcl_mobs:register_egg("mobs_mc:donkey", S("Donkey"), "#534539", "#867566", 0)
mcl_mobs:register_egg("mobs_mc:mule", S("Mule"), "#1b0200", "#51331d", 0)
mcl_mobs:register_egg("mobs_mc:horse", S("Horse"), "mobs_mc_spawn_icon_horse.png", 0)
mcl_mobs:register_egg("mobs_mc:skeleton_horse", S("Skeleton Horse"), "mobs_mc_spawn_icon_horse_skeleton.png", 0)
--mobs:register_egg("mobs_mc:zombie_horse", S("Zombie Horse"), "mobs_mc_spawn_icon_horse_zombie.png", 0)
mcl_mobs:register_egg("mobs_mc:donkey", S("Donkey"), "mobs_mc_spawn_icon_donkey.png", 0)
mcl_mobs:register_egg("mobs_mc:mule", S("Mule"), "mobs_mc_spawn_icon_mule.png", 0)

View File

@ -114,7 +114,6 @@ dofile(path .. "/squid.lua") -- Animation, sound and egg texture by daufinsyd
dofile(path .. "/villager.lua") -- KrupnoPavel Mesh and animation by toby109tt / https://github.com/22i
-- Illagers and witch
dofile(path .. "/pillager.lua") -- Mesh by KrupnoPavel and MrRar, animation by MrRar
dofile(path .. "/villager_evoker.lua") -- Mesh and animation by toby109tt / https://github.com/22i
dofile(path .. "/villager_vindicator.lua") -- Mesh and animation by toby109tt / https://github.com/22i
dofile(path .. "/villager_zombie.lua") -- Mesh and animation by toby109tt / https://github.com/22i

View File

@ -22,9 +22,6 @@ mcl_mobs:register_mob("mobs_mc:iron_golem", {
collisionbox = {-0.7, -0.01, -0.7, 0.7, 2.69, 0.7},
visual = "mesh",
mesh = "mobs_mc_iron_golem.b3d",
head_swivel = "head.control",
bone_eye_height = 3.38,
curiosity = 10,
textures = {
{"mobs_mc_iron_golem.png"},
},
@ -96,7 +93,8 @@ mcl_mobs:register_mob("mobs_mc:iron_golem", {
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:iron_golem", S("Iron Golem"), "#3b3b3b", "#f57223", 0)
mcl_mobs:register_egg("mobs_mc:iron_golem", S("Iron Golem"), "mobs_mc_spawn_icon_iron_golem.png", 0)
--[[ This is to be called when a pumpkin or jack'o lantern has been placed. Recommended: In the on_construct function of the node.
This summons an iron golen if placing the pumpkin created an iron golem summon pattern:

View File

@ -24,29 +24,6 @@ local carpets = {
unicolor_light_blue = { "mcl_wool:light_blue_carpet", "light_blue" },
}
local function get_drops(self)
self.drops = {}
table.insert(self.drops,
{name = "mcl_mobitems:leather",
chance = 1,
min = 0,
max = 2,
looting = "common",
})
if self.carpet then
table.insert(self.drops,{name = self.carpet,
chance = 1,
min = 1,
max = 1,})
end
if self._has_chest then
table.insert(self.drops,{name = "mcl_chests:chest",
chance = 1,
min = 1,
max = 1,})
end
end
mcl_mobs:register_mob("mobs_mc:llama", {
description = S("Llama"),
type = "animal",
@ -58,14 +35,6 @@ mcl_mobs:register_mob("mobs_mc:llama", {
shoot_offset = 1, --3.5 *would* be a good value visually but it somehow messes with the projectiles trajectory
spawn_in_group_min = 4,
spawn_in_group = 6,
head_swivel = "head.control",
bone_eye_height = 11,
head_eye_height = 3,
horrizonatal_head_height=0,
curiosity = 60,
head_yaw = "z",
hp_min = 15,
hp_max = 30,
xp_min = 1,
@ -80,6 +49,7 @@ mcl_mobs:register_mob("mobs_mc:llama", {
{"blank.png", "blank.png", "mobs_mc_llama_white.png"},
{"blank.png", "blank.png", "mobs_mc_llama.png"},
},
visual_size = {x=3, y=3},
makes_footstep_sound = true,
runaway = false,
walk_velocity = 1,
@ -101,28 +71,36 @@ mcl_mobs:register_mob("mobs_mc:llama", {
distance = 16,
},
animation = {
stand_start = 0, stand_end = 0,
walk_start = 0, walk_end = 40, walk_speed = 35,
run_start = 0, run_end = 40, run_speed = 50,
},
child_animations = {
stand_start = 41, stand_end = 41,
walk_start = 41, walk_end = 81, walk_speed = 50,
run_start = 41, run_end = 81, run_speed = 75,
speed_normal = 24,
run_speed = 60,
run_start = 0,
run_end = 40,
stand_start = 0,
stand_end = 0,
walk_start = 0,
walk_end = 40,
hurt_start = 118,
hurt_end = 154,
death_start = 154,
death_end = 179,
eat_start = 49,
eat_end = 78,
look_start = 78,
look_end = 108,
},
follow = { "mcl_farming:wheat_item", "mcl_farming:hay_block" },
view_range = 16,
do_custom = function(self, dtime)
-- set needed values if not already present
if not self.v3 then
self.v3 = 0
if not self.v2 then
self.v2 = 0
self.max_speed_forward = 4
self.max_speed_reverse = 2
self.accel = 4
self.terrain_type = 3
self.driver_attach_at = {x = 0, y = 12.7, z = -5}
self.driver_eye_offset = {x = 0, y = 6, z = 0}
self.driver_attach_at = {x = 0, y = 4.17, z = -1.5}
self.driver_eye_offset = {x = 0, y = 3, z = 0}
self.driver_scale = {x = 1/self.visual_size.x, y = 1/self.visual_size.y}
end
@ -157,20 +135,6 @@ mcl_mobs:register_mob("mobs_mc:llama", {
if item:get_name() == "mcl_farming:hay_block" then
-- Breed with hay bale
if mcl_mobs:feed_tame(self, clicker, 1, true, false) then return end
elseif not self._has_chest and item:get_name() == "mcl_chests:chest" then
item:take_item()
clicker:set_wielded_item(item)
self._has_chest = true
self.base_texture = table.copy(self.base_texture)
self.base_texture[1] = self.base_texture[3]
self.object:set_properties({
textures = self.base_texture,
})
get_drops(self)
return
elseif self._has_chest and clicker:get_player_control().sneak then
mcl_entity_invs.show_inv_form(self,clicker," - Strength "..math.floor(self._inv_size / 3))
return
else
-- Feed with anything else
if mcl_mobs:feed_tame(self, clicker, 1, false, true) then return end
@ -179,36 +143,53 @@ mcl_mobs:register_mob("mobs_mc:llama", {
-- Make sure tamed llama is mature and being clicked by owner only
if self.tamed and not self.child and self.owner == clicker:get_player_name() then
-- Place carpet
if minetest.get_item_group(item:get_name(), "carpet") == 1 and not self.carpet then
for group, carpetdata in pairs(carpets) do
if minetest.get_item_group(item:get_name(), group) == 1 then
if not minetest.is_creative_enabled(clicker:get_player_name()) then
item:take_item()
clicker:set_wielded_item(item)
end
local substr = carpetdata[2]
local tex_carpet = "mobs_mc_llama_decor_"..substr..".png"
self.base_texture = table.copy(self.base_texture)
self.base_texture[2] = tex_carpet
self.object:set_properties({
textures = self.base_texture,
})
self.carpet = item:get_name()
get_drops(self)
return
-- Place carpet
if minetest.get_item_group(item:get_name(), "carpet") == 1 and not self.carpet then
for group, carpetdata in pairs(carpets) do
if minetest.get_item_group(item:get_name(), group) == 1 then
if not minetest.is_creative_enabled(clicker:get_player_name()) then
item:take_item()
clicker:set_wielded_item(item)
end
local substr = carpetdata[2]
local tex_carpet = "mobs_mc_llama_decor_"..substr..".png"
self.base_texture = table.copy(self.base_texture)
self.base_texture[2] = tex_carpet
self.object:set_properties({
textures = self.base_texture,
})
self.carpet = item:get_name()
self.drops = {
{name = "mcl_mobitems:leather",
chance = 1,
min = 0,
max = 2,},
{name = item:get_name(),
chance = 1,
min = 1,
max = 1,},
}
return
end
end
end
-- detatch player already riding llama
if self.driver and clicker == self.driver then
mcl_mobs.detach(clicker, {x = 1, y = 0, z = 1})
-- attach player to llama
elseif not self.driver then
self.object:set_properties({stepheight = 1.1})
mcl_mobs.attach(self, clicker)
end
-- detatch player already riding llama
if self.driver and clicker == self.driver then
mcl_mobs.detach(clicker, {x = 1, y = 0, z = 1})
-- attach player to llama
elseif not self.driver then
self.object:set_properties({stepheight = 1.1})
mcl_mobs.attach(self, clicker)
end
-- Used to capture llama
elseif not self.driver and clicker:get_wielded_item():get_name() ~= "" then
mcl_mobs:capture_mob(self, clicker, 0, 5, 60, false, nil)
end
end,
@ -233,25 +214,8 @@ mcl_mobs:register_mob("mobs_mc:llama", {
return false
end
end,
on_spawn = function(self)
if not self._inv_size then
local r = math.random(1000)
if r < 80 then
self._inv_size = 15
elseif r < 160 then
self._inv_size = 12
elseif r < 488 then
self._inv_size = 9
elseif r < 816 then
self._inv_size = 6
else
self._inv_size = 3
end
end
end,
})
mcl_entity_invs.register_inv("mobs_mc:llama","Llama",nil,true)
})
-- spit arrow (weapon)
mcl_mobs:register_arrow("mobs_mc:llamaspit", {
@ -267,6 +231,10 @@ mcl_mobs:register_arrow("mobs_mc:llamaspit", {
end,
hit_mob = function(self, mob)
mob:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = 1},
}, nil)
end,
hit_node = function(self, pos, node)
@ -284,10 +252,12 @@ mcl_mobs:spawn_specific(
"SavannaM_beach",
"Savanna_beach",
"Savanna_ocean",
"JungleEdge",
"JungleEdgeM",
"ExtremeHills",
"ExtremeHills_beach",
"ExtremeHillsM",
}, --FIXME: Needs Windswept Forest when that is added.
},
0,
minetest.LIGHT_MAX+1,
30,
@ -297,4 +267,4 @@ mobs_mc.water_level+15,
mcl_vars.mg_overworld_max)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:llama", S("Llama"), "#c09e7d", "#995f40", 0)
mcl_mobs:register_egg("mobs_mc:llama", S("Llama"), "mobs_mc_spawn_icon_llama.png", 0)

View File

@ -62,8 +62,3 @@ Weapon Smith=Fabriquant d'arme
Tool Smith=Fabriquant d'outil
Cleric=Clerc
Nitwit=Crétin
Cod=Morue
Salmon=Saumon
Dolphin=Dauphin
Pillager=Pilleur
Tropical fish=Poisson tropical

View File

@ -65,5 +65,3 @@ Nitwit=
Cod=
Salmon=
Dolphin=
Pillager=
Tropical fish=

Binary file not shown.

Binary file not shown.

View File

@ -36,16 +36,11 @@ local ocelot = {
hp_max = 10,
xp_min = 1,
xp_max = 3,
head_swivel = "head.control",
bone_eye_height = 6.2,
head_eye_height = 0.4,
horrizonatal_head_height=-0,
head_yaw="z",
curiosity = 4,
collisionbox = {-0.3, -0.01, -0.3, 0.3, 0.69, 0.3},
visual = "mesh",
mesh = "mobs_mc_cat.b3d",
textures = {"mobs_mc_cat_ocelot.png"},
visual_size = {x=2.0, y=2.0},
makes_footstep_sound = true,
walk_chance = default_walk_chance,
walk_velocity = 1,
@ -62,16 +57,14 @@ local ocelot = {
distance = 16,
},
animation = {
stand_start = 0, stand_end = 0,
walk_start = 0, walk_end = 40, walk_speed = 40,
run_start = 0, run_end = 40, run_speed = 50,
sit_start = 50, sit_end = 50,
},
child_animations = {
stand_start = 51, stand_end = 51,
walk_start = 51, walk_end = 91, walk_speed = 60,
run_start = 51, run_end = 91, run_speed = 75,
sit_start = 101, sit_end = 101,
speed_normal = 25,
run_speed = 50,
stand_start = 0,
stand_end = 0,
walk_start = 0,
walk_end = 40,
run_start = 0,
run_end = 40,
},
follow = follow,
view_range = 12,
@ -239,4 +232,5 @@ mobs:spawn({
]]--
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:ocelot", S("Ocelot"), "#efde7d", "#564434", 0)
-- FIXME: The spawn icon shows a cat texture, not an ocelot texture
mcl_mobs:register_egg("mobs_mc:ocelot", S("Ocelot"), "mobs_mc_spawn_icon_cat.png", 0)

View File

@ -13,20 +13,12 @@ local shoulders = {
right = vector.new(3.75,10.5,0)
}
local function table_get_rand(tbl)
local keys = {}
for k in pairs(tbl) do
table.insert(keys, k)
end
return tbl[keys[math.random(#keys)]]
end
local function get_random_mob_sound()
local t = table.copy(minetest.registered_entities)
table.shuffle(t)
for _,e in pairs(t) do
if e.is_mob and e.sounds and #e.sounds > 0 then
return table_get_rand(e.sounds)
if e.is_mob and e.sounds then
return e.sounds[math.random(#e.sounds)]
end
end
return minetest.registered_entities["mobs_mc:parrot"].sounds.random
@ -100,8 +92,7 @@ local function check_perch(self,dtime)
local n1 = minetest.get_node(vector.offset(p:get_pos(),0,-0.6,0)).name
local n2 = minetest.get_node(vector.offset(p:get_pos(),0,0,0)).name
local n3 = minetest.get_node(vector.offset(p:get_pos(),0,1,0)).name
if ( n1 == "air" or minetest.get_item_group(n2,"water") > 0 or minetest.get_item_group(n2,"lava") > 0) and
not minetest.is_creative_enabled(p:get_player_name()) then
if n1 == "air" or minetest.get_item_group(n2,"water") > 0 or minetest.get_item_group(n2,"lava") > 0 then
o:set_detach()
self.detach_timer = 0
return
@ -127,18 +118,13 @@ end
mcl_mobs:register_mob("mobs_mc:parrot", {
description = S("Parrot"),
type = "animal",
type = "npc",
spawn_class = "passive",
passive = true,
pathfinding = 1,
hp_min = 6,
hp_max = 6,
xp_min = 1,
xp_max = 3,
head_swivel = "head.control",
bone_eye_height = 1.1,
horrizonatal_head_height=0,
curiosity = 10,
collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.89, 0.25},
visual = "mesh",
mesh = "mobs_mc_parrot.b3d",
@ -241,4 +227,4 @@ mobs_mc.water_level+7,
mcl_vars.mg_overworld_max)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:parrot", S("Parrot"), "#0da70a", "#ff0000", 0)
mcl_mobs:register_egg("mobs_mc:parrot", S("Parrot"), "mobs_mc_spawn_icon_parrot.png", 0)

View File

@ -15,15 +15,11 @@ mcl_mobs:register_mob("mobs_mc:pig", {
visual = "mesh",
mesh = "mobs_mc_pig.b3d",
textures = {{
"blank.png", -- baby
"mobs_mc_pig.png", -- base
"blank.png", -- saddle
}},
head_swivel = "head.control",
bone_eye_height = 7.5,
head_eye_height = 0.8,
horrizonatal_head_height=-1,
curiosity = 3,
head_yaw="z",
visual_size = {x=2.5, y=2.5},
makes_footstep_sound = true,
walk_velocity = 1,
run_velocity = 3,
@ -44,14 +40,15 @@ mcl_mobs:register_mob("mobs_mc:pig", {
distance = 16,
},
animation = {
stand_start = 0, stand_end = 0,
walk_start = 0, walk_end = 40, walk_speed = 60,
run_start = 0, run_end = 40, run_speed = 90,
},
child_animations = {
stand_start = 41, stand_end = 41,
walk_start = 41, walk_end = 81, walk_speed = 90,
run_start = 41, run_end = 81, run_speed = 135,
stand_speed = 40,
walk_speed = 40,
run_speed = 90,
stand_start = 0,
stand_end = 0,
walk_start = 0,
walk_end = 40,
run_start = 0,
run_end = 40,
},
follow = {
"mcl_farming:potato_item",
@ -63,17 +60,15 @@ mcl_mobs:register_mob("mobs_mc:pig", {
do_custom = function(self, dtime)
-- set needed values if not already present
if not self.v3 then
self.v3 = 0
if not self.v2 then
self.v2 = 0
self.max_speed_forward = 4
self.max_speed_reverse = 2
self.accel = 4
self.terrain_type = 3
self.driver_attach_at = {x = 0.0, y = 6.5, z = -3.75}
self.driver_attach_at = {x = 0.0, y = 2.75, z = -1.5}
self.driver_eye_offset = {x = 0, y = 3, z = 0}
self.driver_scale = {x = 1/self.visual_size.x, y = 1/self.visual_size.y}
self.base_texture = self.texture_list[1]
self.object:set_properties({textures = self.base_texture})
end
-- if driver present allow control of horse
@ -116,6 +111,7 @@ mcl_mobs:register_mob("mobs_mc:pig", {
local item = clicker:get_wielded_item()
if item:get_name() == "mcl_mobitems:saddle" and self.saddle ~= "yes" then
self.base_texture = {
"blank.png", -- baby
"mobs_mc_pig.png", -- base
"mobs_mc_pig_saddle.png", -- saddle
}
@ -238,4 +234,4 @@ mcl_vars.mg_overworld_min,
mcl_vars.mg_overworld_max)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:pig", S("Pig"), "#f0a5a2", "#db635f", 0)
mcl_mobs:register_egg("mobs_mc:pig", S("Pig"), "mobs_mc_spawn_icon_pig.png", 0)

View File

@ -1,123 +0,0 @@
local S = minetest.get_translator("mobs_mc")
local function reload(self)
if not self.object:get_pos() then return end
minetest.sound_play("mcl_bows_crossbow_drawback_1", {object = self.object, max_hear_distance=16}, true)
local props = self.object:get_properties()
if not props then return end
props.textures[2] = "mcl_bows_crossbow_3.png^[resize:16x16"
self.object:set_properties(props)
end
local function reset_animation(self, animation)
if not self.object:get_pos() or self._current_animation ~= animation then return end
self._current_animation = "stand_reload" -- Mobs Redo won't set the animation unless we do this
mcl_mobs:set_animation(self, animation)
end
pillager = {
description = S("Pillager"),
type = "monster",
spawn_class = "hostile",
hp_min = 24,
hp_max = 24,
xp_min = 6,
xp_max = 6,
breath_max = -1,
eye_height = 1.5,
shoot_interval = 3,
shoot_offset = 1.5,
armor = {fleshy = 100},
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.98, 0.3},
pathfinding = 1,
group_attack = true,
visual = "mesh",
mesh = "mobs_mc_pillager.b3d",
visual_size = {x=2.75, y=2.75},
makes_footstep_sound = true,
walk_velocity = 1.2,
run_velocity = 4,
view_range = 16,
fear_height = 4,
arrow = "mcl_bows:arrow_entity",
attack_type = "dogshoot", -- Alternate punching/shooting
attack_npcs = true,
reach = 0, -- Punching max distance
damage = 0, -- Punching damage
dogshoot_switch = 1, -- Start of shooting
dogshoot_count_max = 5, -- Max time spent shooting (standing)
dogshoot_count2_max = 1, -- Max time spent punching (running)
sounds = {
random = "mobs_mc_pillager_grunt2",
war_cry = "mobs_mc_pillager_grunt1",
death = "mobs_mc_pillager_ow2",
damage = "mobs_mc_pillager_ow1",
distance = 16,
},
textures = {
{
"mobs_mc_pillager.png", -- Skin
"mcl_bows_crossbow_3.png^[resize:16x16", -- Wielded item
}
},
drops = {
{
name = "mcl_bows:arrow",
chance = 1,
min = 0,
max = 2,
looting = "common",
},
{
name = "mcl_bows:crossbow",
chance = 100 / 8.5,
min = 1,
max = 1,
looting = "rare",
},
},
animation = {
unloaded_walk_start = 1, unloaded_walk_end = 40,
unloaded_stand_start = 41, unloaded_stand_end = 60,
reload_stand_start = 61, reload_stand_end = 100, reload_stand_speed = 20,
stand_start = 101, stand_end = 109, stand_speed = 6,
walk_start = 111, walk_end = 150, walk_speed = 30,
run_start = 111, run_end = 150, run_speed = 50,
reload_run_start = 151, reload_run_end = 190, reload_run_speed = 20,
die_start = 191, die_end = 192, die_speed = 15,
stand_unloaded_start = 40, stand_unloaded_end = 59,
die_loop = false,
},
shoot_arrow = function(self, pos, dir)
minetest.sound_play("mcl_bows_crossbow_shoot", {object = self.object, max_hear_distance=16}, true)
local props = self.object:get_properties()
props.textures[2] = "mcl_bows_crossbow_0.png^[resize:16x16"
self.object:set_properties(props)
local old_anim = self._current_animation
if old_anim == "run" or old_anim == "walk" then
mcl_mobs:set_animation(self, "reload_run")
end
if old_anim == "stand" then
mcl_mobs:set_animation(self, "reload_stand")
end
self._current_animation = old_anim -- Mobs Redo will imediately reset the animation otherwise
minetest.after(1, reload, self)
minetest.after(2, reset_animation, self, old_anim)
-- 2-4 damage per arrow
local dmg = math.max(4, math.random(2, 8))
mcl_bows_s.shoot_arrow_crossbow("mcl_bows:arrow", pos, dir, self.object:get_yaw(), self.object, nil, dmg)
-- While we are at it, change the sounds since there is no way to do this in Mobs Redo
if self.sounds and self.sounds.random then
self.sounds = table.copy(self.sounds)
self.sounds.random = "mobs_mc_pillager_grunt" .. math.random(2)
end
-- Randomize reload time
self.shoot_interval = math.random(3, 4)
end,
}
mcl_mobs:register_mob("mobs_mc:pillager", pillager)
mcl_mobs:register_egg("mobs_mc:pillager", S("Pillager"), "#532f36", "#959b9b", 0)

View File

@ -24,12 +24,6 @@ mcl_mobs:register_mob("mobs_mc:polar_bear", {
textures = {
{"mobs_mc_polarbear.png"},
},
head_swivel = "head.control",
bone_eye_height = 2.6,
head_eye_height = 1,
horrizonatal_head_height = 0,
curiosity = 20,
head_yaw="z",
visual_size = {x=3.0, y=3.0},
makes_footstep_sound = true,
damage = 6,
@ -92,4 +86,4 @@ mcl_vars.mg_overworld_min,
mcl_vars.mg_overworld_max)
-- spawn egg
mcl_mobs:register_egg("mobs_mc:polar_bear", S("Polar Bear"), "#f2f2f2", "#959590", 0)
mcl_mobs:register_egg("mobs_mc:polar_bear", S("Polar Bear"), "mobs_mc_spawn_icon_polarbear.png", 0)

View File

@ -15,12 +15,7 @@ local rabbit = {
xp_min = 1,
xp_max = 3,
collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.49, 0.2},
head_swivel = "head.control",
bone_eye_height = 2,
head_eye_height = 0.5,
horrizonatal_head_height = -.3,
curiosity = 20,
head_yaw="z",
visual = "mesh",
mesh = "mobs_mc_rabbit.b3d",
textures = {
@ -31,6 +26,7 @@ local rabbit = {
{"mobs_mc_rabbit_salt.png"},
{"mobs_mc_rabbit_black.png"},
},
visual_size = {x=1.5, y=1.5},
sounds = {
random = "mobs_mc_rabbit_random",
damage = "mobs_mc_rabbit_hurt",
@ -53,14 +49,10 @@ local rabbit = {
},
fear_height = 4,
animation = {
stand_start = 0, stand_end = 0,
walk_start = 0, walk_end = 20, walk_speed = 20,
run_start = 0, run_end = 20, run_speed = 30,
},
child_animations = {
stand_start = 21, stand_end = 21,
walk_start = 21, walk_end = 41, walk_speed = 30,
run_start = 21, run_end = 41, run_speed = 45,
speed_normal = 25, speed_run = 50,
stand_start = 0, stand_end = 0,
walk_start = 0, walk_end = 20,
run_start = 0, run_end = 20,
},
-- Follow (yellow) dangelions, carrots and golden carrots
follow = {
@ -213,7 +205,7 @@ mcl_mobs:spawn(spawn_grass)
]]--
-- Spawn egg
mcl_mobs:register_egg("mobs_mc:rabbit", S("Rabbit"), "#995f40", "#734831", 0)
mcl_mobs:register_egg("mobs_mc:rabbit", S("Rabbit"), "mobs_mc_spawn_icon_rabbit.png", 0)
-- Note: This spawn egg does not exist in Minecraft
mcl_mobs:register_egg("mobs_mc:killer_bunny", S("Killer Bunny"), "#f2f2f2", "#ff0000", 0)
mcl_mobs:register_egg("mobs_mc:killer_bunny", S("Killer Bunny"), "mobs_mc_spawn_icon_rabbit.png^[colorize:#FF0000:192", 0) -- TODO: Update inventory image

View File

@ -225,4 +225,4 @@ water-16,
water+1)
--spawn egg
mcl_mobs:register_egg("mobs_mc:salmon", S("Salmon"), "#a00f10", "#0e8474", 0)
mcl_mobs:register_egg("mobs_mc:salmon", S("Salmon"), "extra_mobs_spawn_icon_salmon.png", 0)

View File

@ -61,13 +61,9 @@ mcl_mobs:register_mob("mobs_mc:sheep", {
xp_min = 1,
xp_max = 3,
collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.29, 0.45},
head_swivel = "head.control",
bone_eye_height = 3.3,
head_eye_height = 1.1,
horrizonatal_head_height=-.7,
curiosity = 6,
head_yaw="z",
visual = "mesh",
visual_size = {x=3, y=3},
mesh = "mobs_mc_sheepfur.b3d",
textures = { sheep_texture("unicolor_white") },
gotten_texture = gotten_texture,
@ -97,14 +93,10 @@ mcl_mobs:register_mob("mobs_mc:sheep", {
distance = 16,
},
animation = {
stand_start = 0, stand_end = 0,
walk_start = 0, walk_end = 40, walk_speed = 30,
run_start = 0, run_end = 40, run_speed = 40,
},
child_animations = {
stand_start = 81, stand_end = 81,
walk_start = 81, walk_end = 121, walk_speed = 45,
run_start = 81, run_end = 121, run_speed = 60,
speed_normal = 25, run_speed = 65,
stand_start = 40, stand_end = 80,
walk_start = 0, walk_end = 40,
run_start = 0, run_end = 40,
},
follow = { "mcl_farming:wheat_item" },
view_range = 12,
@ -365,4 +357,4 @@ mcl_vars.mg_overworld_min,
mcl_vars.mg_overworld_max)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:sheep", S("Sheep"), "#e7e7e7", "#ffb5b5", 0)
mcl_mobs:register_egg("mobs_mc:sheep", S("Sheep"), "mobs_mc_spawn_icon_sheep.png", 0)

View File

@ -9,27 +9,8 @@ local S = minetest.get_translator("mobs_mc")
--################### SHULKER
--###################
local adjacents = {
vector.new(1,0,0),
vector.new(-1,0,0),
vector.new(0,1,0),
vector.new(0,-1,0),
vector.new(0,0,1),
vector.new(0,0,-1),
}
local function check_spot(pos)
pos = vector.offset(pos,0,0.5,0)
local n = minetest.get_node(pos)
if n.name ~="air" then return false end
for _,a in pairs(adjacents) do
local p = vector.add(pos,a)
local pn = minetest.get_node(p)
if minetest.get_item_group(pn.name,"solid") > 0 then return true end
end
return false
end
local pr = PseudoRandom(os.time()*(-334))
-- animation 45-80 is transition between passive and attack stance
mcl_mobs:register_mob("mobs_mc:shulker", {
description = S("Shulker"),
type = "monster",
@ -54,8 +35,6 @@ mcl_mobs:register_mob("mobs_mc:shulker", {
walk_chance = 0,
knock_back = false,
jump = false,
can_despawn = false,
fall_speed = 0,
drops = {
{name = "mcl_mobitems:shulker_shell",
chance = 2,
@ -65,90 +44,15 @@ mcl_mobs:register_mob("mobs_mc:shulker", {
looting_factor = 0.0625},
},
animation = {
stand_speed = 25, walk_speed = 0, run_speed = 50, punch_speed = 25,
stand_speed = 25, walk_speed = 25, run_speed = 50, punch_speed = 25,
speed_normal = 25, speed_run = 50,
stand_start = 0, stand_end = 25,
walk_start = 25, walk_end = 45,
run_start = 45, run_end = 85,
stand_start = 0, stand_end = 45,
walk_start = 0, walk_end = 45,
run_start = 0, run_end = 45,
punch_start = 80, punch_end = 100,
},
view_range = 16,
fear_height = 0,
noyaw = true,
do_custom = function(self,dtime)
local pos = self.object:get_pos()
if math.floor(self.object:get_yaw()) ~=0 then
self.object:set_yaw(0)
mcl_mobs:yaw(self, 0, 0, dtime)
end
if self.state == "walk" or self.state == "stand" then
self.state = "stand"
mcl_mobs:set_animation(self, "stand")
end
if self.state == "attack" then
mcl_mobs:set_animation(self, "punch")
end
self.path.way = false
self.look_at_players = false
if not check_spot(pos) then
self:teleport(nil)
end
end,
do_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
self:teleport(puncher)
end,
do_teleport = function(self, target)
if target ~= nil then
local target_pos = target:get_pos()
-- Find all solid nodes below air in a 10×10×10 cuboid centered on the target
local nodes = minetest.find_nodes_in_area_under_air(vector.subtract(target_pos, 5), vector.add(target_pos, 5), {"group:solid", "group:cracky", "group:crumbly"})
local telepos
if nodes ~= nil then
if #nodes > 0 then
-- Up to 64 attempts to teleport
for n=1, math.min(64, #nodes) do
local r = pr:next(1, #nodes)
local nodepos = nodes[r]
local tg = vector.offset(nodepos,0,1,0)
if check_spot(tg) then
telepos = tg
node_ok = true
end
end
if telepos then
self.object:set_pos(telepos)
end
end
end
else
local pos = self.object:get_pos()
-- Up to 8 top-level attempts to teleport
for n=1, 8 do
local node_ok = false
-- We need to add (or subtract) different random numbers to each vector component, so it couldn't be done with a nice single vector.add() or .subtract():
local randomCube = vector.new( pos.x + 8*(pr:next(0,16)-8), pos.y + 8*(pr:next(0,16)-8), pos.z + 8*(pr:next(0,16)-8) )
local nodes = minetest.find_nodes_in_area_under_air(vector.subtract(randomCube, 4), vector.add(randomCube, 4), {"group:solid", "group:cracky", "group:crumbly"})
if nodes ~= nil then
if #nodes > 0 then
-- Up to 8 low-level (in total up to 8*8 = 64) attempts to teleport
for n=1, math.min(8, #nodes) do
local r = pr:next(1, #nodes)
local nodepos = nodes[r]
local tg = vector.offset(nodepos,0,1,0)
if check_spot(tg) then
self.object:set_pos(tg)
node_ok = true
break
end
end
end
end
if node_ok then
break
end
end
end
end,
fear_height = 4,
})
-- bullet arrow (weapon)
@ -177,9 +81,8 @@ mcl_mobs:register_arrow("mobs_mc:shulkerbullet", {
})
mcl_mobs:register_egg("mobs_mc:shulker", S("Shulker"), "#946694", "#4d3852", 0)
mcl_mobs:register_egg("mobs_mc:shulker", S("Shulker"), "mobs_mc_spawn_icon_shulker.png", 0)
--[[
mcl_mobs:spawn_specific(
"mobs_mc:shulker",
"end",
@ -194,4 +97,3 @@ minetest.LIGHT_MAX+1,
2,
mcl_vars.mg_end_min,
mcl_vars.mg_end_max)
--]]

View File

@ -56,7 +56,7 @@ mcl_mobs:register_mob("mobs_mc:silverfish", {
reach = 1,
})
mcl_mobs:register_egg("mobs_mc:silverfish", S("Silverfish"), "#6d6d6d", "#313131", 0)
mcl_mobs:register_egg("mobs_mc:silverfish", S("Silverfish"), "mobs_mc_spawn_icon_silverfish.png", 0)
-- Monster egg blocks (Minetest Game)
if minetest.get_modpath("default") and mobs_mc.create_monster_egg_nodes then

View File

@ -25,15 +25,13 @@ local skeleton = {
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.98, 0.3},
pathfinding = 1,
group_attack = true,
head_swivel = "Head_Control",
bone_eye_height = 2.38,
curiosity = 6,
visual = "mesh",
mesh = "mobs_mc_skeleton.b3d",
textures = { {
"mcl_bows_bow_0.png", -- bow
"mobs_mc_skeleton.png", -- skeleton
} },
visual_size = {x=1, y=1},
makes_footstep_sound = true,
textures = {
{
@ -80,27 +78,11 @@ local skeleton = {
run_speed = 30,
shoot_start = 70,
shoot_end = 90,
jockey_start = 172,
jockey_end = 172,
die_start = 160,
die_end = 170,
die_speed = 15,
die_loop = false,
},
jock = "mobs_mc:spider",
on_spawn = function(self)
self.jockey = false
if math.random(100) == 1 then -- 1% like from MCwiki
self.jockey = true
local jock = minetest.add_entity(self.object:get_pos(), "mobs_mc:spider")
jock:get_luaentity().docile_by_day = false
self.object:set_attach(jock, "", vector.new(0,0,0), vector.new(0,0,0))
end
return true
end,
on_detach=function(self, parent)
self.jockey = false
end,
ignited_by_sunlight = true,
view_range = 16,
fear_height = 4,
@ -108,9 +90,6 @@ local skeleton = {
arrow = "mcl_bows:arrow_entity",
shoot_arrow = function(self, pos, dir)
if mod_bows then
if self.attack then
self.object:set_yaw(minetest.dir_to_yaw(vector.direction(self.object:get_pos(), self.attack:get_pos())))
end
-- 2-4 damage per arrow
local dmg = math.max(4, math.random(2, 8))
mcl_bows.shoot_arrow("mcl_bows:arrow", pos, dir, self.object:get_yaw(), self.object, nil, dmg)
@ -350,6 +329,5 @@ mcl_vars.mg_overworld_max)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:skeleton", S("Skeleton"), "#c1c1c1", "#494949", 0)
mcl_mobs:register_egg("mobs_mc:stray", S("Stray"), "#5f7476", "#dae8e7", 0)
mcl_mobs:register_egg("mobs_mc:skeleton", S("Skeleton"), "mobs_mc_spawn_icon_skeleton.png", 0)
mcl_mobs:register_egg("mobs_mc:stray", S("Stray"), "mobs_mc_spawn_icon_stray.png", 0)

View File

@ -24,14 +24,11 @@ mcl_mobs:register_mob("mobs_mc:witherskeleton", {
collisionbox = {-0.35, -0.01, -0.35, 0.35, 2.39, 0.35},
visual = "mesh",
mesh = "mobs_mc_witherskeleton.b3d",
head_swivel = "head.control",
bone_eye_height = 2.38,
curiosity = 60,
textures = {
{
"mobs_mc_empty.png", -- armor
"default_tool_stonesword.png", -- sword
"mobs_mc_wither_skeleton.png", -- wither skeleton
"default_tool_stonesword.png", -- sword
}
},
visual_size = {x=1.2, y=1.2},
@ -116,4 +113,4 @@ mcl_vars.mg_nether_min,
mcl_vars.mg_nether_max)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:witherskeleton", S("Wither Skeleton"), "#141414", "#474d4d", 0)
mcl_mobs:register_egg("mobs_mc:witherskeleton", S("Wither Skeleton"), "mobs_mc_spawn_icon_witherskeleton.png", 0)

View File

@ -447,6 +447,5 @@ mmin,
mmax)
-- spawn eggs
mcl_mobs:register_egg("mobs_mc:magma_cube_big", S("Magma Cube"), "#350000", "#fcfc00")
mcl_mobs:register_egg("mobs_mc:slime_big", S("Slime"), "#52a03e", "#7ebf6d")
mcl_mobs:register_egg("mobs_mc:magma_cube_big", S("Magma Cube"), "mobs_mc_spawn_icon_magmacube.png")
mcl_mobs:register_egg("mobs_mc:slime_big", S("Slime"), "mobs_mc_spawn_icon_slime.png")

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