Merge pull request 'master' (#5) from MineClone2/MineClone2:master into master
Reviewed-on: epCode/MineClone2#5
|
@ -7,45 +7,45 @@ But first, some things to note:
|
||||||
MineClone 2's development target is to make a free software clone of Minecraft,
|
MineClone 2's development target is to make a free software clone of Minecraft,
|
||||||
***version 1.11***, ***PC edition***.
|
***version 1.11***, ***PC edition***.
|
||||||
|
|
||||||
MineClone 2 is maintained by one person. Namely, Wuzzy. You can find me,
|
MineClone 2 is maintained by two persons. Namely, kay27 and EliasFleckenstein. You can find us
|
||||||
Wuzzy, in the Minetest forums (forums.minetest.net), in IRC in the #minetest
|
in the Minetest forums (forums.minetest.net), in IRC in the #minetest
|
||||||
channel on irc.freenode.net. And finally, you can send e-mails to
|
channel on irc.freenode.net. And finally, you can send e-mails to
|
||||||
<Wuzzy2@mail.ru>.
|
<eliasfleckenstein@web.de> or <kay27@bk.ru>.
|
||||||
|
|
||||||
There is **no** guarantee I will accept anything from anybody.
|
There is **no** guarantee we will accept anything from anybody.
|
||||||
|
|
||||||
By sending me patches or asking me to include your changes in this game,
|
By sending us patches or asking us to include your changes in this game,
|
||||||
you agree that they fall under the terms of the LGPLv2.1, which basically
|
you agree that they fall under the terms of the LGPLv2.1, which basically
|
||||||
means they will become part of a free software.
|
means they will become part of a free software.
|
||||||
|
|
||||||
## The suggested workflow
|
## The suggested workflow
|
||||||
I don't **dictate** your workflow, but in order to work with me in an efficient
|
We don't **dictate** your workflow, but in order to work with us in an efficient
|
||||||
way, you can follow my suggestions.
|
way, you can follow these suggestions:
|
||||||
|
|
||||||
For small and medium changes:
|
For small and medium changes:
|
||||||
|
|
||||||
* Fork the repository
|
* Fork the repository
|
||||||
* Do your change in a new branch
|
* Do your change in a new branch
|
||||||
* Upload the repository somewhere where it can be accessed from the Internet and
|
* Upload the repository somewhere where it can be accessed from the Internet and
|
||||||
notify me
|
notify us
|
||||||
|
|
||||||
For small changes, sending me a patch is also good.
|
For small changes, sending us a patch is also good.
|
||||||
|
|
||||||
For big changes: Same as above, but consider notifying me first to avoid
|
For big changes: Same as above, but consider notifying us first to avoid
|
||||||
duplicate work and possible tears of rejection. ;-)
|
duplicate work and possible tears of rejection. ;-)
|
||||||
|
|
||||||
For people that I trust, I might give them direct commit access to this
|
For trusted people, we might give them direct commit access to this
|
||||||
repository. In this case, you obviously don't need to fork, but you still
|
repository. In this case, you obviously don't need to fork, but you still
|
||||||
need to show your contributions align with the project goals. I still
|
need to show your contributions align with the project goals. We still
|
||||||
reserve the right to revert everything that I don't like.
|
reserve the right to revert everything that we don't like.
|
||||||
For bigger changes, I strongly recommend to use feature branches and
|
For bigger changes, we strongly recommend to use feature branches and
|
||||||
discuss with me first.
|
discuss with me first.
|
||||||
|
|
||||||
Contributors will be credited in `README.md`.
|
Contributors will be credited in `README.md`.
|
||||||
|
|
||||||
## Quality remarks
|
## Quality remarks
|
||||||
Again: There is ***no*** guarantee I will accept anything from anybody.
|
Again: There is ***no*** guarantee we will accept anything from anybody.
|
||||||
But I will gladly take in code from others when I feel it saves me work
|
But we will gladly take in code from others when we feel it saves us work
|
||||||
in the long run.
|
in the long run.
|
||||||
|
|
||||||
### Inclusion criteria
|
### Inclusion criteria
|
||||||
|
@ -79,9 +79,18 @@ Depending on what you add, the chances for inclusion vary:
|
||||||
## Reporting bugs
|
## Reporting bugs
|
||||||
Report all bugs and missing Minecraft features here:
|
Report all bugs and missing Minecraft features here:
|
||||||
|
|
||||||
<https://git.minetest.land/Wuzzy/MineClone2/issues>
|
<https://git.minetest.land/MineClone2/MineClone2/issues>
|
||||||
|
|
||||||
## Direct discussion
|
## Direct discussion
|
||||||
We have an IRC channel! Join us on #mineclone2 in freenode.net.
|
We have an IRC channel! Join us on #mineclone2 in freenode.net.
|
||||||
|
|
||||||
<ircs://irc.freenode.net:6697/#mineclone2>
|
<ircs://irc.freenode.net:6697/#mineclone2>
|
||||||
|
|
||||||
|
## Creating releases
|
||||||
|
* Launch MineClone2 to make sure it still runs
|
||||||
|
* Update the version number in README.md
|
||||||
|
* Use `git tag <version number>` to tag the latest commit with the version number
|
||||||
|
* Push to repo (don't forget `--tags`!)
|
||||||
|
* Update ContentDB (https://content.minetest.net/packages/Wuzzy/mineclone2/)
|
||||||
|
* Update first post in forum thread (https://forum.minetest.net/viewtopic.php?f=50&t=16407)
|
||||||
|
* Post release announcement and changelog in forums
|
||||||
|
|
|
@ -70,6 +70,7 @@ Please read <http://minecraft.gamepedia.com/Breaking> to learn how digging times
|
||||||
* `coral_fan=X`: Coral fan (1 = alive, 2 = dead)
|
* `coral_fan=X`: Coral fan (1 = alive, 2 = dead)
|
||||||
* `coral_block=X`: Coral block (1 = alive, 2 = dead)
|
* `coral_block=X`: Coral block (1 = alive, 2 = dead)
|
||||||
* `coral_species=X`: Specifies the species of a coral; equal X means equal species
|
* `coral_species=X`: Specifies the species of a coral; equal X means equal species
|
||||||
|
* `set_on_fire=X`: Sets any (not fire-resistant) mob or player on fire for X seconds when touching
|
||||||
|
|
||||||
#### Footnotes
|
#### Footnotes
|
||||||
|
|
||||||
|
@ -96,6 +97,8 @@ Please read <http://minecraft.gamepedia.com/Breaking> to learn how digging times
|
||||||
* `carpet=1:` (Wool) carpet
|
* `carpet=1:` (Wool) carpet
|
||||||
* `stick=1`: Stick
|
* `stick=1`: Stick
|
||||||
* `water_bucket=1`: Bucket containing a liquid of group “water”
|
* `water_bucket=1`: Bucket containing a liquid of group “water”
|
||||||
|
* `enchantability=X`: How good the enchantments are the item gets (1 equals book)
|
||||||
|
* `enchanted=1`: The item is already enchanted, meaning that it can't be enchanted using an enchanting table
|
||||||
|
|
||||||
### Material groups
|
### Material groups
|
||||||
|
|
||||||
|
@ -197,6 +200,7 @@ These groups are used mostly for informational purposes
|
||||||
* `building_block=1`: Block is a building block
|
* `building_block=1`: Block is a building block
|
||||||
* `deco_block=1`: Block is a decorational block
|
* `deco_block=1`: Block is a decorational block
|
||||||
|
|
||||||
|
|
||||||
## Fake item groups
|
## Fake item groups
|
||||||
These groups put similar items together which should all be treated by the gameplay or the GUI as a single item.
|
These groups put similar items together which should all be treated by the gameplay or the GUI as a single item.
|
||||||
You should not add custom items to these groups for no good reason, this is likely to cause a ton of conflicts.
|
You should not add custom items to these groups for no good reason, this is likely to cause a ton of conflicts.
|
||||||
|
|
|
@ -20,7 +20,6 @@ For these features, no easy Lua workaround could be found.
|
||||||
## Interface
|
## Interface
|
||||||
- Inventory: Hold down right mouse button while holding an item stack to drop items into the slots as you move the mouse. Makes crafting MUCH faster
|
- Inventory: Hold down right mouse button while holding an item stack to drop items into the slots as you move the mouse. Makes crafting MUCH faster
|
||||||
- Sneak+Leftclick on crafting output crafts as many items as possible and immediately puts it into the player inventory ([issue 5211](https://github.com/minetest/minetest/issues/5211))
|
- Sneak+Leftclick on crafting output crafts as many items as possible and immediately puts it into the player inventory ([issue 5211](https://github.com/minetest/minetest/issues/5211))
|
||||||
- Sneak+click on inventory slot should be able to put items into additional “fallback inventories” if the first inventory is full. Required for large chests
|
|
||||||
- Sneak+click puts items in different inventories depending on the item type (maybe group-based)? Required for sneak-clicking to armor slots
|
- Sneak+click puts items in different inventories depending on the item type (maybe group-based)? Required for sneak-clicking to armor slots
|
||||||
|
|
||||||
## Workaround theoretically possible
|
## Workaround theoretically possible
|
||||||
|
@ -35,6 +34,7 @@ For these features, a workaround (or hack ;-)) by using Lua is theoretically pos
|
||||||
- Set frequency in which players lose breath. 2 seconds are hardcoded in Minetest, in Minecraft it's 1 second
|
- Set frequency in which players lose breath. 2 seconds are hardcoded in Minetest, in Minecraft it's 1 second
|
||||||
- Set damage frequency of `damage_per_second`. In Minecraft many things damage players every half-second rather than every second
|
- Set damage frequency of `damage_per_second`. In Minecraft many things damage players every half-second rather than every second
|
||||||
- Possible to damage players directly when they are with the head inside. This allows to add Minecraft-like suffocation
|
- Possible to damage players directly when they are with the head inside. This allows to add Minecraft-like suffocation
|
||||||
|
- Sneak+click on inventory slot should be able to put items into additional “fallback inventories” if the first inventory is full. Useful for large chests
|
||||||
|
|
||||||
#### Nice-to-haye
|
#### Nice-to-haye
|
||||||
- Utility function to rotate pillar-like nodes, requiring only 3 possible orientations (X, Y, Z). Basically this is `minetest.rotate_node` but with less orientations; the purpur pillar would mess up if a mirrored rotation would be possible. This is already implemented in MCL2, See `mcl_util` for more infos
|
- Utility function to rotate pillar-like nodes, requiring only 3 possible orientations (X, Y, Z). Basically this is `minetest.rotate_node` but with less orientations; the purpur pillar would mess up if a mirrored rotation would be possible. This is already implemented in MCL2, See `mcl_util` for more infos
|
||||||
|
|
25
README.md
|
@ -1,8 +1,8 @@
|
||||||
# MineClone 2
|
# MineClone 2
|
||||||
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
|
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
|
||||||
Developed by Wuzzy and contributors. Not developed or endorsed by Mojang AB.
|
Developed by many people. Not developed or endorsed by Mojang AB.
|
||||||
|
|
||||||
Version: 0.68.0
|
Version: 0.70.0
|
||||||
|
|
||||||
### Gameplay
|
### Gameplay
|
||||||
You start in a randomly-generated world made entirely of cubes. You can explore
|
You start in a randomly-generated world made entirely of cubes. You can explore
|
||||||
|
@ -14,9 +14,10 @@ Or you can play in “creative mode” in which you can build almost anything in
|
||||||
|
|
||||||
#### Gameplay summary
|
#### Gameplay summary
|
||||||
|
|
||||||
* Sandbox-style gameplay, no goals (for now)
|
* Sandbox-style gameplay, no goals
|
||||||
* Survive: Fight against hostile monsters and hunger
|
* Survive: Fight against hostile monsters and hunger
|
||||||
* Mine for ores and other treasures
|
* Mine for ores and other treasures
|
||||||
|
* Magic: Gain experience and enchant your tools
|
||||||
* Use the collected blocks to create great buildings, your imagination is the limit
|
* Use the collected blocks to create great buildings, your imagination is the limit
|
||||||
* Collect flowers (and other dye sources) and colorize your world
|
* Collect flowers (and other dye sources) and colorize your world
|
||||||
* Find some seeds and start farming
|
* Find some seeds and start farming
|
||||||
|
@ -102,7 +103,7 @@ big bugs (such as “missing node” errors or even crashes).
|
||||||
The following main features are available:
|
The following main features are available:
|
||||||
|
|
||||||
* Tools, weapons
|
* Tools, weapons
|
||||||
* Armor (unbalanced)
|
* Armor
|
||||||
* Crafting system: 2×2 grid, crafting table (3×3 grid), furnace, including a crafting guide
|
* Crafting system: 2×2 grid, crafting table (3×3 grid), furnace, including a crafting guide
|
||||||
* Chests, large chests, ender chests, shulker boxes
|
* Chests, large chests, ender chests, shulker boxes
|
||||||
* Furnaces, hoppers
|
* Furnaces, hoppers
|
||||||
|
@ -117,6 +118,8 @@ The following main features are available:
|
||||||
* Redstone circuits (partially)
|
* Redstone circuits (partially)
|
||||||
* Minecarts (partial)
|
* Minecarts (partial)
|
||||||
* Status effects (partial)
|
* Status effects (partial)
|
||||||
|
* Experience
|
||||||
|
* Enchanting
|
||||||
* Brewing, potions, tipped arrow (partial)
|
* Brewing, potions, tipped arrow (partial)
|
||||||
* Boats
|
* Boats
|
||||||
* Fire
|
* Fire
|
||||||
|
@ -142,12 +145,9 @@ The following main features are available:
|
||||||
The following features are incomplete:
|
The following features are incomplete:
|
||||||
|
|
||||||
* Generated structures (especially villages)
|
* Generated structures (especially villages)
|
||||||
* NPCs
|
|
||||||
* Some monsters and animals
|
* Some monsters and animals
|
||||||
* Redstone-related things
|
* Redstone-related things
|
||||||
* The End
|
* The End
|
||||||
* Enchanting
|
|
||||||
* Experience
|
|
||||||
* Special minecarts
|
* Special minecarts
|
||||||
* A couple of non-trivial blocks and items
|
* A couple of non-trivial blocks and items
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ Technical differences from Minecraft:
|
||||||
## Reporting bugs
|
## Reporting bugs
|
||||||
Please report all bugs and missing Minecraft features here:
|
Please report all bugs and missing Minecraft features here:
|
||||||
|
|
||||||
<https://git.minetest.land/Wuzzy/MineClone2/issues>
|
<https://git.minetest.land/MineClone2/MineClone2/issues>
|
||||||
|
|
||||||
## Other readme files
|
## Other readme files
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ Please report all bugs and missing Minecraft features here:
|
||||||
There are so many people to list (sorry). Check out the respective mod directories for details. This section is only a rough overview of the core authors of this game.
|
There are so many people to list (sorry). Check out the respective mod directories for details. This section is only a rough overview of the core authors of this game.
|
||||||
|
|
||||||
### Coding
|
### Coding
|
||||||
* [Wuzzy](https://forum.minetest.net/memberlist.php?mode=viewprofile&u=3082): Main programmer of most mods
|
* [Wuzzy](https://forum.minetest.net/memberlist.php?mode=viewprofile&u=3082): Main programmer of most mods (retired)
|
||||||
* davedevils: Creator of MineClone on which MineClone 2 is based on
|
* davedevils: Creator of MineClone on which MineClone 2 is based on
|
||||||
* [ex-bart](https://github.com/ex-bart): Redstone comparators
|
* [ex-bart](https://github.com/ex-bart): Redstone comparators
|
||||||
* [Rootyjr](https://github.com/Rootyjr): Fishing rod and bugfixes
|
* [Rootyjr](https://github.com/Rootyjr): Fishing rod and bugfixes
|
||||||
|
@ -203,7 +203,8 @@ There are so many people to list (sorry). Check out the respective mod directori
|
||||||
* [ryvnf](https://github.com/ryvnf): Explosion mechanics
|
* [ryvnf](https://github.com/ryvnf): Explosion mechanics
|
||||||
* MysticTempest: Bugfixes
|
* MysticTempest: Bugfixes
|
||||||
* [bzoss](https://github.com/bzoss): Status effects, potions, brewing stand
|
* [bzoss](https://github.com/bzoss): Status effects, potions, brewing stand
|
||||||
* kay27 <kay27@bk.ru>: Experience system, bugfixes, optimizations
|
* kay27 <kay27@bk.ru>: Experience system, bugfixes, optimizations (Current maintainer)
|
||||||
|
* [EliasFleckenstein03](https://github.com/EliasFleckenstein03): End crystals, enchanting, burning mobs / players, animated chests, bugfixes (Current maintainer)
|
||||||
* 2mac: Fix bug with powered rail
|
* 2mac: Fix bug with powered rail
|
||||||
* Lots of other people: TO BE WRITTEN (see mod directories for details)
|
* Lots of other people: TO BE WRITTEN (see mod directories for details)
|
||||||
|
|
||||||
|
@ -250,6 +251,7 @@ Various sources. See the respective mod directories for details.
|
||||||
### Special thanks
|
### Special thanks
|
||||||
|
|
||||||
* davedevils for starting MineClone, the original version of this game
|
* davedevils for starting MineClone, the original version of this game
|
||||||
|
* Wuzzy for starting and maintaining MineClone2 for several years
|
||||||
* celeron55 for creating Minetest
|
* celeron55 for creating Minetest
|
||||||
* Minetest's modding community for providing a huge selection of mods, some of which ended up in MineClone 2
|
* Minetest's modding community for providing a huge selection of mods, some of which ended up in MineClone 2
|
||||||
* Jordach for the jukebox music compilation from Big Freaking Dig
|
* Jordach for the jukebox music compilation from Big Freaking Dig
|
||||||
|
@ -261,7 +263,6 @@ Various sources. See the respective mod directories for details.
|
||||||
|
|
||||||
## Info for programmers
|
## Info for programmers
|
||||||
You find interesting and useful infos in `API.md`.
|
You find interesting and useful infos in `API.md`.
|
||||||
This project is currently mostly a one-person project.
|
|
||||||
|
|
||||||
## Legal information
|
## Legal information
|
||||||
This is a fan game, not developed or endorsed by Mojang AB.
|
This is a fan game, not developed or endorsed by Mojang AB.
|
||||||
|
@ -270,7 +271,7 @@ Copying is an act of love. Please copy and share! <3
|
||||||
Here's the detailed legalese for those who need it:
|
Here's the detailed legalese for those who need it:
|
||||||
|
|
||||||
### License of source code
|
### License of source code
|
||||||
MineClone 2 (by Wuzzy, davedevils and countless others)
|
MineClone 2 (by kay27, EliasFleckenstein, Wuzzy, davedevils and countless others)
|
||||||
is an imitation of Minecraft.
|
is an imitation of Minecraft.
|
||||||
|
|
||||||
MineClone 2 is free software: you can redistribute it and/or modify
|
MineClone 2 is free software: you can redistribute it and/or modify
|
||||||
|
|
|
@ -32,6 +32,10 @@ local STEP_LENGTH = 0.3
|
||||||
-- How many rays to compute entity exposure to explosion
|
-- How many rays to compute entity exposure to explosion
|
||||||
local N_EXPOSURE_RAYS = 16
|
local N_EXPOSURE_RAYS = 16
|
||||||
|
|
||||||
|
-- Nodes having a blast resistance of this value or higher are treated as
|
||||||
|
-- indestructible
|
||||||
|
local INDESTRUCT_BLASTRES = 1000000
|
||||||
|
|
||||||
minetest.register_on_mods_loaded(function()
|
minetest.register_on_mods_loaded(function()
|
||||||
-- Store blast resistance values by content ids to improve performance.
|
-- Store blast resistance values by content ids to improve performance.
|
||||||
for name, def in pairs(minetest.registered_nodes) do
|
for name, def in pairs(minetest.registered_nodes) do
|
||||||
|
@ -135,14 +139,21 @@ end
|
||||||
-- strength - The strength of each ray
|
-- strength - The strength of each ray
|
||||||
-- raydirs - The directions for each ray
|
-- raydirs - The directions for each ray
|
||||||
-- radius - The maximum distance each ray will go
|
-- radius - The maximum distance each ray will go
|
||||||
-- drop_chance - The chance that destroyed nodes will drop their items
|
-- info - Table containing information about explosion
|
||||||
-- fire - If true, 1/3 of destroyed nodes become fire
|
|
||||||
-- puncher - object that punches other objects (optional)
|
-- puncher - object that punches other objects (optional)
|
||||||
--
|
--
|
||||||
|
-- Values in info:
|
||||||
|
-- drop_chance - The chance that destroyed nodes will drop their items
|
||||||
|
-- fire - If true, 1/3 nodes become fire
|
||||||
|
-- griefing - If true, the explosion will destroy nodes (default: true)
|
||||||
|
-- max_blast_resistance - The explosion will treat all non-indestructible nodes
|
||||||
|
-- as having a blast resistance of no more than this
|
||||||
|
-- value
|
||||||
|
--
|
||||||
-- Note that this function has been optimized, it contains code which has been
|
-- Note that this function has been optimized, it contains code which has been
|
||||||
-- inlined to avoid function calls and unnecessary table creation. This was
|
-- inlined to avoid function calls and unnecessary table creation. This was
|
||||||
-- measured to give a significant performance increase.
|
-- measured to give a significant performance increase.
|
||||||
local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire, puncher, creative_enabled)
|
local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
||||||
local vm = minetest.get_voxel_manip()
|
local vm = minetest.get_voxel_manip()
|
||||||
|
|
||||||
local emin, emax = vm:read_from_map(vector.subtract(pos, radius),
|
local emin, emax = vm:read_from_map(vector.subtract(pos, radius),
|
||||||
|
@ -164,39 +175,49 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
||||||
local data = vm:get_data()
|
local data = vm:get_data()
|
||||||
local destroy = {}
|
local destroy = {}
|
||||||
|
|
||||||
|
local drop_chance = info.drop_chance
|
||||||
|
local fire = info.fire
|
||||||
|
local max_blast_resistance = info.max_blast_resistance
|
||||||
|
|
||||||
-- Trace rays for environment destruction
|
-- Trace rays for environment destruction
|
||||||
for i = 1, #raydirs do
|
if info.griefing then
|
||||||
local rpos_x = pos.x
|
for i = 1, #raydirs do
|
||||||
local rpos_y = pos.y
|
local rpos_x = pos.x
|
||||||
local rpos_z = pos.z
|
local rpos_y = pos.y
|
||||||
local rdir_x = raydirs[i].x
|
local rpos_z = pos.z
|
||||||
local rdir_y = raydirs[i].y
|
local rdir_x = raydirs[i].x
|
||||||
local rdir_z = raydirs[i].z
|
local rdir_y = raydirs[i].y
|
||||||
local rstr = (0.7 + math.random() * 0.6) * strength
|
local rdir_z = raydirs[i].z
|
||||||
|
local rstr = (0.7 + math.random() * 0.6) * strength
|
||||||
|
|
||||||
for r = 0, math.ceil(radius * (1.0 / STEP_LENGTH)) do
|
for r = 0, math.ceil(radius * (1.0 / STEP_LENGTH)) do
|
||||||
local npos_x = math.floor(rpos_x + 0.5)
|
local npos_x = math.floor(rpos_x + 0.5)
|
||||||
local npos_y = math.floor(rpos_y + 0.5)
|
local npos_y = math.floor(rpos_y + 0.5)
|
||||||
local npos_z = math.floor(rpos_z + 0.5)
|
local npos_z = math.floor(rpos_z + 0.5)
|
||||||
local idx = (npos_z - emin_z) * zstride + (npos_y - emin_y) * ystride +
|
local idx = (npos_z - emin_z) * zstride + (npos_y - emin_y) * ystride +
|
||||||
npos_x - emin_x + 1
|
npos_x - emin_x + 1
|
||||||
|
|
||||||
local cid = data[idx]
|
local cid = data[idx]
|
||||||
local br = node_blastres[cid]
|
local br = node_blastres[cid]
|
||||||
local hash = minetest.hash_node_position({x=npos_x, y=npos_y, z=npos_z})
|
if br < INDESTRUCT_BLASTRES and br > max_blast_resistance then
|
||||||
|
br = max_blast_resistance
|
||||||
|
end
|
||||||
|
|
||||||
rpos_x = rpos_x + STEP_LENGTH * rdir_x
|
local hash = minetest.hash_node_position({x=npos_x, y=npos_y, z=npos_z})
|
||||||
rpos_y = rpos_y + STEP_LENGTH * rdir_y
|
|
||||||
rpos_z = rpos_z + STEP_LENGTH * rdir_z
|
|
||||||
|
|
||||||
rstr = rstr - 0.75 * STEP_LENGTH - (br + 0.3) * STEP_LENGTH
|
rpos_x = rpos_x + STEP_LENGTH * rdir_x
|
||||||
|
rpos_y = rpos_y + STEP_LENGTH * rdir_y
|
||||||
|
rpos_z = rpos_z + STEP_LENGTH * rdir_z
|
||||||
|
|
||||||
if rstr <= 0 then
|
rstr = rstr - 0.75 * STEP_LENGTH - (br + 0.3) * STEP_LENGTH
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
if cid ~= minetest.CONTENT_AIR and not minetest.is_protected({x = npos_x, y = npos_y, z = npos_z}, "") then
|
if rstr <= 0 then
|
||||||
destroy[hash] = idx
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
if cid ~= minetest.CONTENT_AIR and not minetest.is_protected({x = npos_x, y = npos_y, z = npos_z}, "") then
|
||||||
|
destroy[hash] = idx
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -284,8 +305,18 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
||||||
impact = 0
|
impact = 0
|
||||||
end
|
end
|
||||||
local damage = math.floor((impact * impact + impact) * 7 * strength + 1)
|
local damage = math.floor((impact * impact + impact) * 7 * strength + 1)
|
||||||
|
local source = puncher or obj
|
||||||
|
|
||||||
|
local sleep_formspec_doesnt_close_mt53 = false
|
||||||
if obj:is_player() then
|
if obj:is_player() then
|
||||||
local name = obj:get_player_name()
|
local name = obj:get_player_name()
|
||||||
|
if mcl_beds then
|
||||||
|
local meta = obj:get_meta()
|
||||||
|
if meta:get_string("mcl_beds:sleeping") == "true" then
|
||||||
|
minetest.close_formspec(name, "") -- ABSOLUTELY NECESSARY FOR MT5.3 -- TODO: REMOVE THIS IN THE FUTURE
|
||||||
|
sleep_formspec_doesnt_close_mt53 = true
|
||||||
|
end
|
||||||
|
end
|
||||||
if mod_death_messages then
|
if mod_death_messages then
|
||||||
mcl_death_messages.player_damage(obj, S("@1 was caught in an explosion.", name))
|
mcl_death_messages.player_damage(obj, S("@1 was caught in an explosion.", name))
|
||||||
end
|
end
|
||||||
|
@ -293,17 +324,21 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
||||||
armor.last_damage_types[name] = "explosion"
|
armor.last_damage_types[name] = "explosion"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local source = puncher
|
|
||||||
if not source then
|
|
||||||
source = obj
|
|
||||||
end
|
|
||||||
obj:punch(source, 10, { damage_groups = { full_punch_interval = 1,
|
|
||||||
fleshy = damage, knockback = impact * 20.0 } }, punch_dir)
|
|
||||||
|
|
||||||
if obj:is_player() then
|
if sleep_formspec_doesnt_close_mt53 then
|
||||||
obj:add_player_velocity(vector.multiply(punch_dir, impact * 20))
|
minetest.after(0.3, function(obj, damage, impact, punch_dir) -- 0.2 is minimum delay for closing old formspec and open died formspec -- TODO: REMOVE THIS IN THE FUTURE
|
||||||
elseif ent.tnt_knockback then
|
if not obj then return end
|
||||||
obj:add_velocity(vector.multiply(punch_dir, impact * 20))
|
obj:punch(obj, 10, { damage_groups = { full_punch_interval = 1, fleshy = damage, knockback = impact * 20.0 } }, punch_dir)
|
||||||
|
obj:add_player_velocity(vector.multiply(punch_dir, impact * 20))
|
||||||
|
end, obj, damage, impact, vector.new(punch_dir))
|
||||||
|
else
|
||||||
|
obj:punch(source, 10, { damage_groups = { full_punch_interval = 1, fleshy = damage, knockback = impact * 20.0 } }, punch_dir)
|
||||||
|
|
||||||
|
if obj:is_player() then
|
||||||
|
obj:add_player_velocity(vector.multiply(punch_dir, impact * 20))
|
||||||
|
elseif ent.tnt_knockback then
|
||||||
|
obj:add_velocity(vector.multiply(punch_dir, impact * 20))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -313,14 +348,14 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
||||||
|
|
||||||
-- Remove destroyed blocks and drop items
|
-- Remove destroyed blocks and drop items
|
||||||
for hash, idx in pairs(destroy) do
|
for hash, idx in pairs(destroy) do
|
||||||
local do_drop = not creative_enabled and math.random() <= drop_chance
|
local do_drop = math.random() <= drop_chance
|
||||||
local on_blast = node_on_blast[data[idx]]
|
local on_blast = node_on_blast[data[idx]]
|
||||||
local remove = true
|
local remove = true
|
||||||
|
|
||||||
if do_drop or on_blast ~= nil then
|
if do_drop or on_blast ~= nil then
|
||||||
local npos = minetest.get_position_from_hash(hash)
|
local npos = minetest.get_position_from_hash(hash)
|
||||||
if on_blast ~= nil then
|
if on_blast ~= nil then
|
||||||
on_blast(npos, 1.0)
|
on_blast(npos, 1.0, do_drop)
|
||||||
remove = false
|
remove = false
|
||||||
else
|
else
|
||||||
local name = minetest.get_name_from_content_id(data[idx])
|
local name = minetest.get_name_from_content_id(data[idx])
|
||||||
|
@ -363,7 +398,6 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
||||||
-- Log explosion
|
-- Log explosion
|
||||||
minetest.log('action', 'Explosion at ' .. minetest.pos_to_string(pos) ..
|
minetest.log('action', 'Explosion at ' .. minetest.pos_to_string(pos) ..
|
||||||
' with strength ' .. strength .. ' and radius ' .. radius)
|
' with strength ' .. strength .. ' and radius ' .. radius)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Create an explosion with strength at pos.
|
-- Create an explosion with strength at pos.
|
||||||
|
@ -371,16 +405,24 @@ end
|
||||||
-- Parameters:
|
-- Parameters:
|
||||||
-- pos - The position where the explosion originates from
|
-- pos - The position where the explosion originates from
|
||||||
-- strength - The blast strength of the explosion (a TNT explosion uses 4)
|
-- strength - The blast strength of the explosion (a TNT explosion uses 4)
|
||||||
-- info - Table containing information about explosion.
|
-- info - Table containing information about explosion
|
||||||
-- puncher - object that is reported as source of punches/damage (optional)
|
-- puncher - object that is reported as source of punches/damage (optional)
|
||||||
--
|
--
|
||||||
-- Values in info:
|
-- Values in info:
|
||||||
-- drop_chance - If specified becomes the drop chance of all nodes in the
|
-- drop_chance - If specified becomes the drop chance of all nodes in the
|
||||||
-- explosion (defaults to 1.0 / strength)
|
-- explosion (default: 1.0 / strength)
|
||||||
-- no_sound - If true then the explosion will not play a sound
|
-- max_blast_resistance - If specified the explosion will treat all
|
||||||
-- no_particle - If true then the explosion will not create particles
|
-- non-indestructible nodes as having a blast resistance
|
||||||
|
-- of no more than this value
|
||||||
|
-- sound - If true, the explosion will play a sound (default: true)
|
||||||
|
-- particles - If true, the explosion will create particles (default: true)
|
||||||
-- fire - If true, 1/3 nodes become fire (default: false)
|
-- fire - If true, 1/3 nodes become fire (default: false)
|
||||||
|
-- griefing - If true, the explosion will destroy nodes (default: true)
|
||||||
function mcl_explosions.explode(pos, strength, info, puncher)
|
function mcl_explosions.explode(pos, strength, info, puncher)
|
||||||
|
if info == nil then
|
||||||
|
info = {}
|
||||||
|
end
|
||||||
|
|
||||||
-- The maximum blast radius (in the air)
|
-- The maximum blast radius (in the air)
|
||||||
local radius = math.ceil(1.3 * strength / (0.3 * 0.75) * 0.3)
|
local radius = math.ceil(1.3 * strength / (0.3 * 0.75) * 0.3)
|
||||||
|
|
||||||
|
@ -389,13 +431,31 @@ function mcl_explosions.explode(pos, strength, info, puncher)
|
||||||
end
|
end
|
||||||
local shape = sphere_shapes[radius]
|
local shape = sphere_shapes[radius]
|
||||||
|
|
||||||
local creative_enabled = minetest.is_creative_enabled("")
|
-- Default values
|
||||||
trace_explode(pos, strength, shape, radius, (info and info.drop_chance) or 1 / strength, info.fire == true, puncher, creative_enabled)
|
if info.drop_chance == nil then info.drop_chance = 1 / strength end
|
||||||
|
if info.particles == nil then info.particles = true end
|
||||||
|
if info.sound == nil then info.sound = true end
|
||||||
|
if info.fire == nil then info.fire = false end
|
||||||
|
if info.griefing == nil then info.griefing = true end
|
||||||
|
if info.max_blast_resistance == nil then
|
||||||
|
info.max_blast_resistance = INDESTRUCT_BLASTRES
|
||||||
|
end
|
||||||
|
|
||||||
if not (info and info.no_particle) then
|
-- For backwards compatibility
|
||||||
|
if info.no_particle then info.particles = false end
|
||||||
|
if info.no_sound then info.sound = false end
|
||||||
|
|
||||||
|
-- Dont do drops in creative mode
|
||||||
|
if minetest.is_creative_enabled("") then
|
||||||
|
info.drop_chance = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
trace_explode(pos, strength, shape, radius, info, puncher)
|
||||||
|
|
||||||
|
if info.particles then
|
||||||
add_particles(pos, radius)
|
add_particles(pos, radius)
|
||||||
end
|
end
|
||||||
if not (info and info.no_sound) then
|
if info.sound then
|
||||||
minetest.sound_play("tnt_explode", {
|
minetest.sound_play("tnt_explode", {
|
||||||
pos = pos, gain = 1.0,
|
pos = pos, gain = 1.0,
|
||||||
max_hear_distance = strength * 16
|
max_hear_distance = strength * 16
|
||||||
|
|
|
@ -25,6 +25,7 @@ mcl_vars.inventory_header = ""
|
||||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||||
local minecraft_height_limit = 256
|
local minecraft_height_limit = 256
|
||||||
local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
|
local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
|
||||||
|
local singlenode = mg_name == "singlenode"
|
||||||
|
|
||||||
-- Calculate mapgen_edge_min/mapgen_edge_max
|
-- Calculate mapgen_edge_min/mapgen_edge_max
|
||||||
mcl_vars.chunksize = math.max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5)
|
mcl_vars.chunksize = math.max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5)
|
||||||
|
@ -45,7 +46,7 @@ local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / chunk_size_in_
|
||||||
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * chunk_size_in_nodes
|
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * chunk_size_in_nodes
|
||||||
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * chunk_size_in_nodes
|
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * chunk_size_in_nodes
|
||||||
|
|
||||||
if not superflat then
|
if not superflat and not singlenode then
|
||||||
-- Normal mode
|
-- Normal mode
|
||||||
--[[ Realm stacking (h is for height)
|
--[[ Realm stacking (h is for height)
|
||||||
- Overworld (h>=256)
|
- Overworld (h>=256)
|
||||||
|
@ -66,6 +67,14 @@ if not superflat then
|
||||||
mcl_vars.mg_lava = true
|
mcl_vars.mg_lava = true
|
||||||
mcl_vars.mg_bedrock_is_rough = true
|
mcl_vars.mg_bedrock_is_rough = true
|
||||||
|
|
||||||
|
elseif singlenode then
|
||||||
|
mcl_vars.mg_overworld_min = -66
|
||||||
|
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
||||||
|
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
|
||||||
|
mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min
|
||||||
|
mcl_vars.mg_lava = false
|
||||||
|
mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min
|
||||||
|
mcl_vars.mg_bedrock_is_rough = false
|
||||||
else
|
else
|
||||||
-- Classic superflat
|
-- Classic superflat
|
||||||
local ground = minetest.get_mapgen_setting("mgflat_ground_level")
|
local ground = minetest.get_mapgen_setting("mgflat_ground_level")
|
||||||
|
@ -128,3 +137,4 @@ minetest.craftitemdef_default.stack_max = 64
|
||||||
|
|
||||||
-- Set random seed for all other mods (Remember to make sure no other mod calls this function)
|
-- Set random seed for all other mods (Remember to make sure no other mod calls this function)
|
||||||
math.randomseed(os.time())
|
math.randomseed(os.time())
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,15 @@ Parameters:
|
||||||
stacks_max = 3, -- Maximum number of item stacks to get. Default: 1
|
stacks_max = 3, -- Maximum number of item stacks to get. Default: 1
|
||||||
items = { -- Table of possible loot items. This function selects between stacks_min and stacks_max of these.
|
items = { -- Table of possible loot items. This function selects between stacks_min and stacks_max of these.
|
||||||
{
|
{
|
||||||
|
weight = 5, -- Likelihood of this item being selected (see below). Optional (default: 1)
|
||||||
|
|
||||||
|
itemstack = ItemStack("example:item1"), -- Itemstack to select
|
||||||
|
-- OR
|
||||||
itemstring = "example:item1", -- Which item to select
|
itemstring = "example:item1", -- Which item to select
|
||||||
amount_min = 1, -- Minimum size of itemstack. Must not be larger than 6553. Optional (default: 1)
|
amount_min = 1, -- Minimum size of itemstack. Must not be larger than 6553. Optional (default: 1)
|
||||||
amount_max = 10, -- Maximum size of item stack. Must not be larger than item definition's stack_max or 6553. Optional (default: 1)
|
amount_max = 10, -- Maximum size of item stack. Must not be larger than item definition's stack_max or 6553. Optional (default: 1)
|
||||||
wear_min = 1, -- Minimum wear value. Must be at least 1. Optional (default: no wear)
|
wear_min = 1, -- Minimum wear value. Must be at least 1. Optional (default: no wear)
|
||||||
wear_max = 1, -- Maxiumum wear value. Must be at least 1. Optional (default: no wear)
|
wear_max = 1, -- Maxiumum wear value. Must be at least 1. Optional (default: no wear)
|
||||||
weight = 5, -- Likelihood of this item being selected (see below). Optional (default: 1)
|
|
||||||
},
|
},
|
||||||
{ -- more tables like above, one table per item stack }
|
{ -- more tables like above, one table per item stack }
|
||||||
}
|
}
|
||||||
|
@ -56,24 +59,29 @@ function mcl_loot.get_loot(loot_definitions, pr)
|
||||||
end
|
end
|
||||||
if item then
|
if item then
|
||||||
local itemstring = item.itemstring
|
local itemstring = item.itemstring
|
||||||
if item.amount_min and item.amount_max then
|
local itemstack = item.itemstack
|
||||||
itemstring = itemstring .. " " .. pr:next(item.amount_min, item.amount_max)
|
if itemstring then
|
||||||
end
|
if item.amount_min and item.amount_max then
|
||||||
if item.wear_min and item.wear_max then
|
itemstring = itemstring .. " " .. pr:next(item.amount_min, item.amount_max)
|
||||||
-- Sadly, PseudoRandom only allows very narrow ranges, so we set wear in steps of 10
|
|
||||||
local wear_min = math.floor(item.wear_min / 10)
|
|
||||||
local wear_max = math.floor(item.wear_max / 10)
|
|
||||||
local wear = pr:next(wear_min, wear_max) * 10
|
|
||||||
|
|
||||||
if not item.amount_min and not item.amount_max then
|
|
||||||
itemstring = itemstring .. " 1"
|
|
||||||
end
|
end
|
||||||
|
if item.wear_min and item.wear_max then
|
||||||
|
-- Sadly, PseudoRandom only allows very narrow ranges, so we set wear in steps of 10
|
||||||
|
local wear_min = math.floor(item.wear_min / 10)
|
||||||
|
local wear_max = math.floor(item.wear_max / 10)
|
||||||
|
local wear = pr:next(wear_min, wear_max) * 10
|
||||||
|
|
||||||
itemstring = itemstring .. " " .. tostring(wear)
|
if not item.amount_min and not item.amount_max then
|
||||||
|
itemstring = itemstring .. " 1"
|
||||||
|
end
|
||||||
|
|
||||||
|
itemstring = itemstring .. " " .. tostring(wear)
|
||||||
|
end
|
||||||
|
table.insert(items, itemstring)
|
||||||
|
elseif itemstack then
|
||||||
|
table.insert(items, itemstack)
|
||||||
|
else
|
||||||
|
minetest.log("error", "[mcl_loot] INTERNAL ERROR! Failed to select random loot item!")
|
||||||
end
|
end
|
||||||
table.insert(items, itemstring)
|
|
||||||
else
|
|
||||||
minetest.log("error", "[mcl_loot] INTERNAL ERROR! Failed to select random loot item!")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -395,4 +395,13 @@ function mcl_util.generate_on_place_plant_function(condition)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- adjust the y level of an object to the center of its collisionbox
|
||||||
|
-- used to get the origin position of entity explosions
|
||||||
|
function mcl_util.get_object_center(obj)
|
||||||
|
local collisionbox = obj:get_properties().collisionbox
|
||||||
|
local pos = obj:get_pos()
|
||||||
|
local ymin = collisionbox[2]
|
||||||
|
local ymax = collisionbox[5]
|
||||||
|
pos.y = pos.y + (ymax - ymin) / 2.0
|
||||||
|
return pos
|
||||||
|
end
|
||||||
|
|
|
@ -50,8 +50,10 @@ local boat = {
|
||||||
mesh = "mcl_boats_boat.b3d",
|
mesh = "mcl_boats_boat.b3d",
|
||||||
textures = {"mcl_boats_texture_oak_boat.png"},
|
textures = {"mcl_boats_texture_oak_boat.png"},
|
||||||
visual_size = boat_visual_size,
|
visual_size = boat_visual_size,
|
||||||
|
hp_max = 4,
|
||||||
|
|
||||||
_driver = nil, -- Attached driver (player) or nil if none
|
_driver = nil, -- Attached driver (player) or nil if none
|
||||||
|
_passenger = nil,
|
||||||
_v = 0, -- Speed
|
_v = 0, -- Speed
|
||||||
_last_v = 0, -- Temporary speed variable
|
_last_v = 0, -- Temporary speed variable
|
||||||
_removed = false, -- If true, boat entity is considered removed (e.g. after punch) and should be ignored
|
_removed = false, -- If true, boat entity is considered removed (e.g. after punch) and should be ignored
|
||||||
|
@ -59,54 +61,81 @@ local boat = {
|
||||||
_animation = 0, -- 0: not animated; 1: paddling forwards; -1: paddling forwards
|
_animation = 0, -- 0: not animated; 1: paddling forwards; -1: paddling forwards
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local function detach_player(player, change_pos)
|
||||||
|
player:set_detach()
|
||||||
|
player:set_properties({visual_size = {x=1, y=1}})
|
||||||
|
mcl_player.player_attached[player:get_player_name()] = false
|
||||||
|
mcl_player.player_set_animation(player, "stand" , 30)
|
||||||
|
if change_pos then
|
||||||
|
player:set_pos(vector.add(player:get_pos(), vector.new(0, 0.2, 0)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function check_object(obj)
|
||||||
|
return obj and (obj:is_player() or obj:get_luaentity()) and obj
|
||||||
|
end
|
||||||
|
|
||||||
|
local function set_attach(boat)
|
||||||
|
boat._driver:set_attach(boat.object, "",
|
||||||
|
{x = 0, y = 0.42, z = -1}, {x = 0, y = 0, z = 0})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function set_double_attach(boat)
|
||||||
|
boat._driver:set_attach(boat.object, "",
|
||||||
|
{x = 0, y = 0.42, z = 0.8}, {x = 0, y = 0, z = 0})
|
||||||
|
boat._passenger:set_attach(boat.object, "",
|
||||||
|
{x = 0, y = 0.42, z = -2.2}, {x = 0, y = 0, z = 0})
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_on_respawnplayer(detach_player)
|
||||||
|
|
||||||
function boat.on_rightclick(self, clicker)
|
function boat.on_rightclick(self, clicker)
|
||||||
if not clicker or not clicker:is_player() then
|
if self._passenger or not clicker or clicker:get_attach() then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local name = clicker:get_player_name()
|
local name = clicker:get_player_name()
|
||||||
if self._driver and clicker == self._driver then
|
--[[if attach and attach:get_luaentity() then
|
||||||
self._driver = nil
|
local luaentity = attach:get_luaentity()
|
||||||
|
if luaentity._driver then
|
||||||
|
luaentity._driver = nil
|
||||||
|
end
|
||||||
clicker:set_detach()
|
clicker:set_detach()
|
||||||
clicker:set_properties({visual_size = {x=1, y=1}})
|
clicker:set_properties({visual_size = {x=1, y=1}})
|
||||||
mcl_player.player_attached[name] = false
|
end--]]
|
||||||
mcl_player.player_set_animation(clicker, "stand" , 30)
|
if self._driver then
|
||||||
local pos = clicker:get_pos()
|
if self._driver:is_player() then
|
||||||
pos = {x = pos.x, y = pos.y + 0.2, z = pos.z}
|
self._passenger = clicker
|
||||||
clicker:set_pos(pos)
|
else
|
||||||
elseif not self._driver then
|
-- for later use: transport mobs in boats
|
||||||
local attach = clicker:get_attach()
|
self._passenger = self._driver
|
||||||
if attach and attach:get_luaentity() then
|
self._driver = clicker
|
||||||
local luaentity = attach:get_luaentity()
|
|
||||||
if luaentity._driver then
|
|
||||||
luaentity._driver = nil
|
|
||||||
end
|
|
||||||
clicker:set_detach()
|
|
||||||
clicker:set_properties({visual_size = {x=1, y=1}})
|
|
||||||
end
|
end
|
||||||
|
set_double_attach(self)
|
||||||
|
else
|
||||||
self._driver = clicker
|
self._driver = clicker
|
||||||
clicker:set_attach(self.object, "",
|
set_attach(self)
|
||||||
{x = 0, y = 0.42, z = -1}, {x = 0, y = 0, z = 0})
|
|
||||||
clicker:set_properties({ visual_size = driver_visual_size })
|
|
||||||
mcl_player.player_attached[name] = true
|
|
||||||
minetest.after(0.2, function(name)
|
|
||||||
local player = minetest.get_player_by_name(name)
|
|
||||||
if player then
|
|
||||||
mcl_player.player_set_animation(player, "sit" , 30)
|
|
||||||
end
|
|
||||||
end, name)
|
|
||||||
clicker:set_look_horizontal(self.object:get_yaw())
|
|
||||||
end
|
end
|
||||||
|
clicker:set_properties({ visual_size = driver_visual_size })
|
||||||
|
mcl_player.player_attached[name] = true
|
||||||
|
minetest.after(0.2, function(name)
|
||||||
|
local player = minetest.get_player_by_name(name)
|
||||||
|
if player then
|
||||||
|
mcl_player.player_set_animation(player, "sit" , 30)
|
||||||
|
end
|
||||||
|
end, name)
|
||||||
|
clicker:set_look_horizontal(self.object:get_yaw())
|
||||||
|
mcl_tmp_message.message(clicker, S("Sneak to dismount"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function boat.on_activate(self, staticdata, dtime_s)
|
function boat.on_activate(self, staticdata, dtime_s)
|
||||||
self.object:set_armor_groups({immortal = 1})
|
--self.object:set_armor_groups({immortal = 1})
|
||||||
local data = minetest.deserialize(staticdata)
|
local data = minetest.deserialize(staticdata)
|
||||||
if type(data) == "table" then
|
if type(data) == "table" then
|
||||||
self._v = data.v
|
self._v = data.v
|
||||||
self._last_v = self._v
|
self._last_v = self._v
|
||||||
self._itemstring = data.itemstring
|
self._itemstring = data.itemstring
|
||||||
self.object:set_properties({textures=data.textures})
|
self.object:set_properties({textures = data.textures, damage_texture_modifier = ""})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -120,32 +149,26 @@ function boat.get_staticdata(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function boat.on_punch(self, puncher)
|
function boat.on_death(self, killer)
|
||||||
if not puncher or not puncher:is_player() or self._removed then
|
if killer and killer:is_player() and minetest.is_creative_enabled(killer:get_player_name()) then
|
||||||
return
|
local inv = killer:get_inventory()
|
||||||
end
|
if not inv:contains_item("main", self._itemstring) then
|
||||||
if self._driver and puncher == self._driver then
|
inv:add_item("main", self._itemstring)
|
||||||
self._driver = nil
|
|
||||||
puncher:set_detach()
|
|
||||||
puncher:set_properties({visual_size = {x=1, y=1}})
|
|
||||||
mcl_player.player_attached[puncher:get_player_name()] = false
|
|
||||||
end
|
|
||||||
if not self._driver then
|
|
||||||
self._removed = true
|
|
||||||
-- Drop boat as item on the ground after punching
|
|
||||||
if not minetest.is_creative_enabled(puncher:get_player_name()) then
|
|
||||||
minetest.add_item(self.object:get_pos(), self._itemstring)
|
|
||||||
else
|
|
||||||
local inv = puncher:get_inventory()
|
|
||||||
if not inv:contains_item("main", self._itemstring) then
|
|
||||||
inv:add_item("main", self._itemstring)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
self.object:remove()
|
else
|
||||||
|
minetest.add_item(self.object:get_pos(), self._itemstring)
|
||||||
end
|
end
|
||||||
|
if self._driver then
|
||||||
|
detach_player(self._driver)
|
||||||
|
end
|
||||||
|
if self._passenger then
|
||||||
|
detach_player(self._passenger)
|
||||||
|
end
|
||||||
|
self._driver = nil
|
||||||
|
self._passenger = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function boat.on_step(self, dtime)
|
function boat.on_step(self, dtime, moveresult)
|
||||||
self._v = get_v(self.object:get_velocity()) * get_sign(self._v)
|
self._v = get_v(self.object:get_velocity()) * get_sign(self._v)
|
||||||
local on_water = true
|
local on_water = true
|
||||||
local in_water = false
|
local in_water = false
|
||||||
|
@ -163,8 +186,43 @@ function boat.on_step(self, dtime)
|
||||||
v_slowdown = 0.05
|
v_slowdown = 0.05
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if moveresult and moveresult.collides then
|
||||||
|
for _, collision in ipairs(moveresult.collisions) do
|
||||||
|
local pos = collision.node_pos
|
||||||
|
if collision.type == "node" and minetest.get_node_group(minetest.get_node(pos).name, "dig_by_boat") > 0 then
|
||||||
|
minetest.dig_node(pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local had_passenger = self._passenger
|
||||||
|
|
||||||
|
self._driver = check_object(self._driver)
|
||||||
|
self._passenger = check_object(self._passenger)
|
||||||
|
|
||||||
|
if self._passenger then
|
||||||
|
if not self._driver then
|
||||||
|
self._driver = self._passenger
|
||||||
|
self._passenger = nil
|
||||||
|
else
|
||||||
|
local ctrl = self._passenger:get_player_control()
|
||||||
|
if ctrl and ctrl.sneak then
|
||||||
|
detach_player(self._passenger, true)
|
||||||
|
self._passenger = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if self._driver then
|
if self._driver then
|
||||||
|
if had_passenger and not self._passenger then
|
||||||
|
set_attach(self)
|
||||||
|
end
|
||||||
local ctrl = self._driver:get_player_control()
|
local ctrl = self._driver:get_player_control()
|
||||||
|
if ctrl and ctrl.sneak then
|
||||||
|
detach_player(self._driver, true)
|
||||||
|
self._driver = nil
|
||||||
|
return
|
||||||
|
end
|
||||||
local yaw = self.object:get_yaw()
|
local yaw = self.object:get_yaw()
|
||||||
if ctrl.up then
|
if ctrl.up then
|
||||||
-- Forwards
|
-- Forwards
|
||||||
|
@ -191,13 +249,13 @@ function boat.on_step(self, dtime)
|
||||||
self._animation = 0
|
self._animation = 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if ctrl.left then
|
if ctrl and ctrl.left then
|
||||||
if self._v < 0 then
|
if self._v < 0 then
|
||||||
self.object:set_yaw(yaw - (1 + dtime) * 0.03 * v_factor)
|
self.object:set_yaw(yaw - (1 + dtime) * 0.03 * v_factor)
|
||||||
else
|
else
|
||||||
self.object:set_yaw(yaw + (1 + dtime) * 0.03 * v_factor)
|
self.object:set_yaw(yaw + (1 + dtime) * 0.03 * v_factor)
|
||||||
end
|
end
|
||||||
elseif ctrl.right then
|
elseif ctrl and ctrl.right then
|
||||||
if self._v < 0 then
|
if self._v < 0 then
|
||||||
self.object:set_yaw(yaw + (1 + dtime) * 0.03 * v_factor)
|
self.object:set_yaw(yaw + (1 + dtime) * 0.03 * v_factor)
|
||||||
else
|
else
|
||||||
|
|
|
@ -0,0 +1,304 @@
|
||||||
|
local S = minetest.get_translator("mcl_burning")
|
||||||
|
|
||||||
|
function mcl_burning.get_default(datatype)
|
||||||
|
local default_table = {string = "", float = 0.0, int = 0, bool = false}
|
||||||
|
return default_table[datatype]
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_burning.get(obj, datatype, name)
|
||||||
|
local key
|
||||||
|
if obj:is_player() then
|
||||||
|
local meta = obj:get_meta()
|
||||||
|
return meta["get_" .. datatype](meta, "mcl_burning:" .. name)
|
||||||
|
else
|
||||||
|
local luaentity = obj:get_luaentity()
|
||||||
|
return luaentity and luaentity["mcl_burning_" .. name] or mcl_burning.get_default(datatype)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_burning.set(obj, datatype, name, value)
|
||||||
|
if obj:is_player() then
|
||||||
|
local meta = obj:get_meta()
|
||||||
|
meta["set_" .. datatype](meta, "mcl_burning:" .. name, value or mcl_burning.get_default(datatype))
|
||||||
|
else
|
||||||
|
local luaentity = obj:get_luaentity()
|
||||||
|
if mcl_burning.get_default(datatype) == value then
|
||||||
|
value = nil
|
||||||
|
end
|
||||||
|
luaentity["mcl_burning_" .. name] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_burning.is_burning(obj)
|
||||||
|
return mcl_burning.get(obj, "float", "burn_time") > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_burning.is_affected_by_rain(obj)
|
||||||
|
return mcl_weather.get_weather() == "rain" and mcl_weather.is_outdoor(obj:get_pos())
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_burning.get_collisionbox(obj, smaller)
|
||||||
|
local box = obj:get_properties().collisionbox
|
||||||
|
local minp, maxp = vector.new(box[1], box[2], box[3]), vector.new(box[4], box[5], box[6])
|
||||||
|
if smaller then
|
||||||
|
local s_vec = vector.new(0.1, 0.1, 0.1)
|
||||||
|
minp = vector.add(minp, s_vec)
|
||||||
|
maxp = vector.subtract(maxp, s_vec)
|
||||||
|
end
|
||||||
|
return minp, maxp
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_burning.get_touching_nodes(obj, nodenames)
|
||||||
|
local pos = obj:get_pos()
|
||||||
|
local box = obj:get_properties().collisionbox
|
||||||
|
local minp, maxp = mcl_burning.get_collisionbox(obj, true)
|
||||||
|
local nodes = minetest.find_nodes_in_area(vector.add(pos, minp), vector.add(pos, maxp), nodenames)
|
||||||
|
return nodes
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_burning.get_highest_group_value(obj, groupname)
|
||||||
|
local nodes = mcl_burning.get_touching_nodes(obj, "group:" .. groupname, true)
|
||||||
|
local highest_group_value = 0
|
||||||
|
|
||||||
|
for _, pos in pairs(nodes) do
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
local group_value = minetest.get_item_group(node.name, groupname)
|
||||||
|
if group_value > highest_group_value then
|
||||||
|
highest_group_value = group_value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return highest_group_value
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_burning.damage(obj)
|
||||||
|
local luaentity = obj:get_luaentity()
|
||||||
|
local health
|
||||||
|
|
||||||
|
if luaentity then
|
||||||
|
health = luaentity.health
|
||||||
|
end
|
||||||
|
|
||||||
|
local hp = health or obj:get_hp()
|
||||||
|
|
||||||
|
if hp <= 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local do_damage = true
|
||||||
|
|
||||||
|
if obj:is_player() then
|
||||||
|
if mcl_potions.player_has_effect(obj, "fire_proof") then
|
||||||
|
do_damage = false
|
||||||
|
else
|
||||||
|
local name = obj:get_player_name()
|
||||||
|
armor.last_damage_types[name] = "fire"
|
||||||
|
local deathmsg = S("@1 burned to death.", name)
|
||||||
|
local reason = mcl_burning.get(obj, "string", "reason")
|
||||||
|
if reason ~= "" then
|
||||||
|
deathmsg = S("@1 was burned by @2.", name, reason)
|
||||||
|
end
|
||||||
|
mcl_death_messages.player_damage(obj, deathmsg)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if luaentity.fire_damage_resistant then
|
||||||
|
do_damage = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if do_damage then
|
||||||
|
local damage = mcl_burning.get(obj, "float", "damage")
|
||||||
|
if damage == 0 then
|
||||||
|
damage = 1
|
||||||
|
end
|
||||||
|
local new_hp = hp - damage
|
||||||
|
if health then
|
||||||
|
luaentity.health = new_hp
|
||||||
|
else
|
||||||
|
obj:set_hp(new_hp)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_burning.set_on_fire(obj, burn_time, damage, reason)
|
||||||
|
local luaentity = obj:get_luaentity()
|
||||||
|
if luaentity and luaentity.fire_resistant then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local old_burn_time = mcl_burning.get(obj, "float", "burn_time")
|
||||||
|
local max_fire_prot_lvl = 0
|
||||||
|
|
||||||
|
if obj:is_player() then
|
||||||
|
if minetest.is_creative_enabled(obj:get_player_name()) then
|
||||||
|
burn_time = burn_time / 100
|
||||||
|
end
|
||||||
|
|
||||||
|
local inv = obj:get_inventory()
|
||||||
|
|
||||||
|
for i = 2, 5 do
|
||||||
|
local stack = inv:get_stack("armor", i)
|
||||||
|
|
||||||
|
local fire_prot_lvl = mcl_enchanting.get_enchantment(stack, "fire_protection")
|
||||||
|
max_fire_prot_lvl = math.max(max_fire_prot_lvl, fire_prot_lvl)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if max_fire_prot_lvl > 0 then
|
||||||
|
burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15)
|
||||||
|
end
|
||||||
|
|
||||||
|
if old_burn_time <= burn_time then
|
||||||
|
local sound_id = mcl_burning.get(obj, "int", "sound_id")
|
||||||
|
if sound_id == 0 then
|
||||||
|
sound_id = minetest.sound_play("fire_fire", {
|
||||||
|
object = obj,
|
||||||
|
gain = 0.18,
|
||||||
|
max_hear_distance = 16,
|
||||||
|
loop = true,
|
||||||
|
}) + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local hud_id
|
||||||
|
if obj:is_player() then
|
||||||
|
hud_id = mcl_burning.get(obj, "int", "hud_id")
|
||||||
|
if hud_id == 0 then
|
||||||
|
hud_id = obj:hud_add({
|
||||||
|
hud_elem_type = "image",
|
||||||
|
position = {x = 0.5, y = 0.5},
|
||||||
|
scale = {x = -100, y = -100},
|
||||||
|
text = "fire_basic_flame.png",
|
||||||
|
z_index = 1000,
|
||||||
|
}) + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
mcl_burning.set(obj, "float", "burn_time", burn_time)
|
||||||
|
mcl_burning.set(obj, "float", "damage", damage)
|
||||||
|
mcl_burning.set(obj, "string", "reason", reason)
|
||||||
|
mcl_burning.set(obj, "int", "hud_id", hud_id)
|
||||||
|
mcl_burning.set(obj, "int", "sound_id", sound_id)
|
||||||
|
|
||||||
|
local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire")
|
||||||
|
local minp, maxp = mcl_burning.get_collisionbox(obj)
|
||||||
|
local obj_size = obj:get_properties().visual_size
|
||||||
|
|
||||||
|
local vertical_grow_factor = 1.2
|
||||||
|
local horizontal_grow_factor = 1.1
|
||||||
|
local grow_vector = vector.new(horizontal_grow_factor, vertical_grow_factor, horizontal_grow_factor)
|
||||||
|
|
||||||
|
local size = vector.subtract(maxp, minp)
|
||||||
|
size = vector.multiply(size, grow_vector)
|
||||||
|
size = vector.divide(size, obj_size)
|
||||||
|
local offset = vector.new(0, size.y * 10 / 2, 0)
|
||||||
|
|
||||||
|
fire_entity:set_properties({visual_size = size})
|
||||||
|
fire_entity:set_attach(obj, "", offset, {x = 0, y = 0, z = 0})
|
||||||
|
mcl_burning.update_animation_frame(obj, fire_entity, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_burning.extinguish(obj)
|
||||||
|
if mcl_burning.is_burning(obj) then
|
||||||
|
local sound_id = mcl_burning.get(obj, "int", "sound_id") - 1
|
||||||
|
minetest.sound_stop(sound_id)
|
||||||
|
|
||||||
|
if obj:is_player() then
|
||||||
|
local hud_id = mcl_burning.get(obj, "int", "hud_id") - 1
|
||||||
|
obj:hud_remove(hud_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
mcl_burning.set(obj, "float", "damage")
|
||||||
|
mcl_burning.set(obj, "string", "reason")
|
||||||
|
mcl_burning.set(obj, "float", "burn_time")
|
||||||
|
mcl_burning.set(obj, "float", "damage_timer")
|
||||||
|
mcl_burning.set(obj, "int", "hud_id")
|
||||||
|
mcl_burning.set(obj, "int", "sound_id")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_burning.catch_fire_tick(obj, dtime)
|
||||||
|
if mcl_burning.is_affected_by_rain(obj) or #mcl_burning.get_touching_nodes(obj, "group:puts_out_fire") > 0 then
|
||||||
|
mcl_burning.extinguish(obj)
|
||||||
|
else
|
||||||
|
local set_on_fire_value = mcl_burning.get_highest_group_value(obj, "set_on_fire")
|
||||||
|
|
||||||
|
if set_on_fire_value > 0 then
|
||||||
|
mcl_burning.set_on_fire(obj, set_on_fire_value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_burning.tick(obj, dtime)
|
||||||
|
local burn_time = mcl_burning.get(obj, "float", "burn_time") - dtime
|
||||||
|
|
||||||
|
if burn_time <= 0 then
|
||||||
|
mcl_burning.extinguish(obj)
|
||||||
|
else
|
||||||
|
mcl_burning.set(obj, "float", "burn_time", burn_time)
|
||||||
|
|
||||||
|
local damage_timer = mcl_burning.get(obj, "float", "damage_timer") + dtime
|
||||||
|
|
||||||
|
if damage_timer >= 1 then
|
||||||
|
damage_timer = 0
|
||||||
|
mcl_burning.damage(obj)
|
||||||
|
end
|
||||||
|
|
||||||
|
mcl_burning.set(obj, "float", "damage_timer", damage_timer)
|
||||||
|
end
|
||||||
|
|
||||||
|
mcl_burning.catch_fire_tick(obj, dtime)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_burning.update_animation_frame(obj, fire_entity, animation_frame)
|
||||||
|
local fire_texture = "mcl_burning_entity_flame_animated.png^[opacity:180^[verticalframe:" .. mcl_burning.animation_frames .. ":" .. animation_frame
|
||||||
|
local fire_HUD_texture = "mcl_burning_hud_flame_animated.png^[opacity:180^[verticalframe:" .. mcl_burning.animation_frames .. ":" .. animation_frame
|
||||||
|
fire_entity:set_properties({textures = {"blank.png", "blank.png", fire_texture, fire_texture, fire_texture, fire_texture}})
|
||||||
|
if obj:is_player() then
|
||||||
|
local hud_id = mcl_burning.get(obj, "int", "hud_id") - 1
|
||||||
|
obj:hud_change(hud_id, "text", fire_HUD_texture)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_burning.fire_entity_step(self, dtime)
|
||||||
|
if self.removed then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local obj = self.object
|
||||||
|
local parent = obj:get_attach()
|
||||||
|
local do_remove
|
||||||
|
|
||||||
|
self.doing_step = true
|
||||||
|
|
||||||
|
if not parent or not mcl_burning.is_burning(parent) then
|
||||||
|
do_remove = true
|
||||||
|
else
|
||||||
|
for _, other in ipairs(minetest.get_objects_inside_radius(obj:get_pos(), 0)) do
|
||||||
|
local luaentity = obj:get_luaentity()
|
||||||
|
if luaentity and luaentity.name == "mcl_burning:fire" and not luaentity.doing_step and not luaentity.removed then
|
||||||
|
do_remove = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.doing_step = false
|
||||||
|
|
||||||
|
if do_remove then
|
||||||
|
self.removed = true
|
||||||
|
obj:remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local animation_timer = self.animation_timer + dtime
|
||||||
|
if animation_timer >= 0.015 then
|
||||||
|
animation_timer = 0
|
||||||
|
local animation_frame = self.animation_frame + 1
|
||||||
|
if animation_frame > mcl_burning.animation_frames - 1 then
|
||||||
|
animation_frame = 0
|
||||||
|
end
|
||||||
|
mcl_burning.update_animation_frame(parent, obj, animation_frame)
|
||||||
|
self.animation_frame = animation_frame
|
||||||
|
end
|
||||||
|
self.animation_timer = animation_timer
|
||||||
|
end
|
|
@ -0,0 +1,36 @@
|
||||||
|
local S = minetest.get_translator("mcl_burning")
|
||||||
|
local modpath = minetest.get_modpath("mcl_burning")
|
||||||
|
|
||||||
|
mcl_burning = {
|
||||||
|
animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8
|
||||||
|
}
|
||||||
|
|
||||||
|
dofile(modpath .. "/engine.lua")
|
||||||
|
|
||||||
|
minetest.register_entity("mcl_burning:fire", {
|
||||||
|
initial_properties = {
|
||||||
|
physical = false,
|
||||||
|
collisionbox = {0, 0, 0, 0, 0, 0},
|
||||||
|
visual = "cube",
|
||||||
|
pointable = false,
|
||||||
|
glow = -1,
|
||||||
|
},
|
||||||
|
|
||||||
|
animation_frame = 0,
|
||||||
|
animation_timer = 0,
|
||||||
|
on_step = mcl_burning.fire_entity_step,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_globalstep(function(dtime)
|
||||||
|
for _, player in ipairs(minetest.get_connected_players()) do
|
||||||
|
mcl_burning.tick(player, dtime)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_respawnplayer(function(player)
|
||||||
|
mcl_burning.extinguish(player)
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_leaveplayer(function(player)
|
||||||
|
mcl_burning.set(player, "int", "hud_id")
|
||||||
|
end)
|
|
@ -0,0 +1,3 @@
|
||||||
|
name = mcl_burning
|
||||||
|
description = Burning Objects for MineClone2
|
||||||
|
author = Fleckenstein
|
|
@ -2,6 +2,7 @@
|
||||||
local item_drop_settings = {} --settings table
|
local item_drop_settings = {} --settings table
|
||||||
item_drop_settings.age = 1.0 --how old a dropped item (_insta_collect==false) has to be before collecting
|
item_drop_settings.age = 1.0 --how old a dropped item (_insta_collect==false) has to be before collecting
|
||||||
item_drop_settings.radius_magnet = 2.0 --radius of item magnet. MUST BE LARGER THAN radius_collect!
|
item_drop_settings.radius_magnet = 2.0 --radius of item magnet. MUST BE LARGER THAN radius_collect!
|
||||||
|
item_drop_settings.xp_radius_magnet = 7.25 --radius of xp magnet. MUST BE LARGER THAN radius_collect!
|
||||||
item_drop_settings.radius_collect = 0.2 --radius of collection
|
item_drop_settings.radius_collect = 0.2 --radius of collection
|
||||||
item_drop_settings.player_collect_height = 1.0 --added to their pos y value
|
item_drop_settings.player_collect_height = 1.0 --added to their pos y value
|
||||||
item_drop_settings.collection_safety = false --do this to prevent items from flying away on laggy servers
|
item_drop_settings.collection_safety = false --do this to prevent items from flying away on laggy servers
|
||||||
|
@ -60,8 +61,8 @@ minetest.register_globalstep(function(dtime)
|
||||||
local checkpos = {x=pos.x,y=pos.y + item_drop_settings.player_collect_height,z=pos.z}
|
local checkpos = {x=pos.x,y=pos.y + item_drop_settings.player_collect_height,z=pos.z}
|
||||||
|
|
||||||
--magnet and collection
|
--magnet and collection
|
||||||
for _,object in ipairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.radius_magnet)) do
|
for _,object in ipairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do
|
||||||
if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
|
if not object:is_player() and vector.distance(checkpos, object:get_pos()) < item_drop_settings.radius_magnet and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
|
||||||
object:get_luaentity()._magnet_timer = object:get_luaentity()._magnet_timer + dtime
|
object:get_luaentity()._magnet_timer = object:get_luaentity()._magnet_timer + dtime
|
||||||
local collected = false
|
local collected = false
|
||||||
if object:get_luaentity()._magnet_timer >= 0 and object:get_luaentity()._magnet_timer < item_drop_settings.magnet_time and inv and inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
|
if object:get_luaentity()._magnet_timer >= 0 and object:get_luaentity()._magnet_timer < item_drop_settings.magnet_time and inv and inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
|
||||||
|
@ -193,6 +194,12 @@ local check_can_drop = function(node_name, tool_capabilities)
|
||||||
if toolgroupcaps[plus] then
|
if toolgroupcaps[plus] then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
for e=1,5 do
|
||||||
|
local effplus = plus .. "_efficiency_" .. e
|
||||||
|
if toolgroupcaps[effplus] then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
for b=1, #basegroups do
|
for b=1, #basegroups do
|
||||||
|
@ -204,6 +211,12 @@ local check_can_drop = function(node_name, tool_capabilities)
|
||||||
if toolgroupcaps[plus] then
|
if toolgroupcaps[plus] then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
for e=1,5 do
|
||||||
|
local effplus = plus .. "_efficiency_" .. e
|
||||||
|
if toolgroupcaps[effplus] then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -262,7 +275,7 @@ function minetest.handle_node_drops(pos, drops, digger)
|
||||||
-- by hand. Creative Mode is intentionally ignored in this case.
|
-- by hand. Creative Mode is intentionally ignored in this case.
|
||||||
|
|
||||||
local doTileDrops = minetest.settings:get_bool("mcl_doTileDrops", true)
|
local doTileDrops = minetest.settings:get_bool("mcl_doTileDrops", true)
|
||||||
if (digger ~= nil and minetest.is_creative_enabled(digger:get_player_name())) or doTileDrops == false then
|
if (digger and digger:is_player() and minetest.is_creative_enabled(digger:get_player_name())) or doTileDrops == false then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -319,7 +332,7 @@ function minetest.handle_node_drops(pos, drops, digger)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- Fixed Behavior
|
-- Fixed Behavior
|
||||||
local drop = get_fortune_drops(fortune_drops, fortune_level)
|
local drop = get_fortune_drops(fortune_drop, fortune_level)
|
||||||
drops = get_drops(drop, tool:get_name(), dug_node.param2, nodedef.paramtype2)
|
drops = get_drops(drop, tool:get_name(), dug_node.param2, nodedef.paramtype2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -632,12 +645,15 @@ minetest.register_entity(":__builtin:item", {
|
||||||
local fg = minetest.get_item_group(nn, "fire")
|
local fg = minetest.get_item_group(nn, "fire")
|
||||||
local dg = minetest.get_item_group(nn, "destroys_items")
|
local dg = minetest.get_item_group(nn, "destroys_items")
|
||||||
if (def and (lg ~= 0 or fg ~= 0 or dg == 1)) then
|
if (def and (lg ~= 0 or fg ~= 0 or dg == 1)) then
|
||||||
if dg ~= 2 then
|
--Wait 2 seconds to allow mob drops to be cooked, & picked up instead of instantly destroyed.
|
||||||
minetest.sound_play("builtin_item_lava", {pos = self.object:get_pos(), gain = 0.5}, true)
|
if self.age > 2 then
|
||||||
|
if dg ~= 2 then
|
||||||
|
minetest.sound_play("builtin_item_lava", {pos = self.object:get_pos(), gain = 0.5})
|
||||||
|
end
|
||||||
|
self._removed = true
|
||||||
|
self.object:remove()
|
||||||
|
return
|
||||||
end
|
end
|
||||||
self._removed = true
|
|
||||||
self.object:remove()
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Push item out when stuck inside solid opaque node
|
-- Push item out when stuck inside solid opaque node
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
mobs = {}
|
mobs = {}
|
||||||
mobs.mod = "mrm"
|
mobs.mod = "mrm"
|
||||||
mobs.version = "20180531" -- don't rely too much on this, rarely updated, if ever
|
mobs.version = "20210106" -- don't rely too much on this, rarely updated, if ever
|
||||||
|
|
||||||
local MAX_MOB_NAME_LENGTH = 30
|
local MAX_MOB_NAME_LENGTH = 30
|
||||||
local HORNY_TIME = 30
|
local HORNY_TIME = 30
|
||||||
|
@ -226,7 +226,7 @@ local collision = function(self)
|
||||||
local z = 0
|
local z = 0
|
||||||
local width = -self.collisionbox[1] + self.collisionbox[4] + 0.5
|
local width = -self.collisionbox[1] + self.collisionbox[4] + 0.5
|
||||||
|
|
||||||
for _,object in ipairs(minetest.env:get_objects_inside_radius(pos, width)) do
|
for _,object in ipairs(minetest.get_objects_inside_radius(pos, width)) do
|
||||||
|
|
||||||
if object:is_player()
|
if object:is_player()
|
||||||
or (object:get_luaentity()._cmi_is_mob == true and object ~= self.object) then
|
or (object:get_luaentity()._cmi_is_mob == true and object ~= self.object) then
|
||||||
|
@ -276,13 +276,16 @@ end
|
||||||
local get_velocity = function(self)
|
local get_velocity = function(self)
|
||||||
|
|
||||||
local v = self.object:get_velocity()
|
local v = self.object:get_velocity()
|
||||||
|
if v then
|
||||||
|
return (v.x * v.x + v.z * v.z) ^ 0.5
|
||||||
|
end
|
||||||
|
|
||||||
return (v.x * v.x + v.z * v.z) ^ 0.5
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- set and return valid yaw
|
-- set and return valid yaw
|
||||||
local set_yaw = function(self, yaw, delay)
|
local set_yaw = function(self, yaw, delay, dtime)
|
||||||
|
|
||||||
if not yaw or yaw ~= yaw then
|
if not yaw or yaw ~= yaw then
|
||||||
yaw = 0
|
yaw = 0
|
||||||
|
@ -291,6 +294,9 @@ local set_yaw = function(self, yaw, delay)
|
||||||
delay = delay or 0
|
delay = delay or 0
|
||||||
|
|
||||||
if delay == 0 then
|
if delay == 0 then
|
||||||
|
if self.shaking and dtime then
|
||||||
|
yaw = yaw + (math.random() * 2 - 1) * 5 * dtime
|
||||||
|
end
|
||||||
self.object:set_yaw(yaw)
|
self.object:set_yaw(yaw)
|
||||||
return yaw
|
return yaw
|
||||||
end
|
end
|
||||||
|
@ -302,8 +308,8 @@ local set_yaw = function(self, yaw, delay)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- global function to set mob yaw
|
-- global function to set mob yaw
|
||||||
function mobs:yaw(self, yaw, delay)
|
function mobs:yaw(self, yaw, delay, dtime)
|
||||||
set_yaw(self, yaw, delay)
|
set_yaw(self, yaw, delay, dtime)
|
||||||
end
|
end
|
||||||
|
|
||||||
local add_texture_mod = function(self, mod)
|
local add_texture_mod = function(self, mod)
|
||||||
|
@ -390,7 +396,7 @@ local is_node_dangerous = function(self, nodename)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if minetest.registered_nodes[nn].damage_per_second > 0 then
|
if minetest.registered_nodes[nn].damage_per_second and minetest.registered_nodes[nn].damage_per_second > 0 then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
|
@ -643,11 +649,13 @@ end
|
||||||
|
|
||||||
|
|
||||||
-- drop items
|
-- drop items
|
||||||
local item_drop = function(self, cooked)
|
local item_drop = function(self, cooked, looting_level)
|
||||||
|
|
||||||
-- no drops if disabled by setting
|
-- no drops if disabled by setting
|
||||||
if not mobs_drop_items then return end
|
if not mobs_drop_items then return end
|
||||||
|
|
||||||
|
looting_level = looting_level or 0
|
||||||
|
|
||||||
-- no drops for child mobs (except monster)
|
-- no drops for child mobs (except monster)
|
||||||
if (self.child and self.type ~= "monster") then
|
if (self.child and self.type ~= "monster") then
|
||||||
return
|
return
|
||||||
|
@ -659,11 +667,33 @@ local item_drop = function(self, cooked)
|
||||||
self.drops = self.drops or {} -- nil check
|
self.drops = self.drops or {} -- nil check
|
||||||
|
|
||||||
for n = 1, #self.drops do
|
for n = 1, #self.drops do
|
||||||
|
local dropdef = self.drops[n]
|
||||||
|
local chance = 1 / dropdef.chance
|
||||||
|
local looting_type = dropdef.looting
|
||||||
|
|
||||||
if random(1, self.drops[n].chance) == 1 then
|
if looting_level > 0 then
|
||||||
|
local chance_function = dropdef.looting_chance_function
|
||||||
|
if chance_function then
|
||||||
|
chance = chance_function(looting_level)
|
||||||
|
elseif looting_type == "rare" then
|
||||||
|
chance = chance + (dropdef.looting_factor or 0.01) * looting_level
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
num = random(self.drops[n].min or 1, self.drops[n].max or 1)
|
local num = 0
|
||||||
item = self.drops[n].name
|
local do_common_looting = (looting_level > 0 and looting_type == "common")
|
||||||
|
if random() < chance then
|
||||||
|
num = random(dropdef.min or 1, dropdef.max or 1)
|
||||||
|
elseif not dropdef.looting_ignore_chance then
|
||||||
|
do_common_looting = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if do_common_looting then
|
||||||
|
num = num + math.floor(math.random(0, looting_level) + 0.5)
|
||||||
|
end
|
||||||
|
|
||||||
|
if num > 0 then
|
||||||
|
item = dropdef.name
|
||||||
|
|
||||||
-- cook items when true
|
-- cook items when true
|
||||||
if cooked then
|
if cooked then
|
||||||
|
@ -752,15 +782,22 @@ local check_for_death = function(self, cause, cmi_cause)
|
||||||
local function death_handle(self)
|
local function death_handle(self)
|
||||||
-- dropped cooked item if mob died in fire or lava
|
-- dropped cooked item if mob died in fire or lava
|
||||||
if cause == "lava" or cause == "fire" then
|
if cause == "lava" or cause == "fire" then
|
||||||
item_drop(self, true)
|
item_drop(self, true, 0)
|
||||||
else
|
else
|
||||||
item_drop(self, nil)
|
local wielditem = ItemStack()
|
||||||
end
|
if cause == "hit" then
|
||||||
|
local puncher = cmi_cause.puncher
|
||||||
|
if puncher then
|
||||||
|
wielditem = puncher:get_wielded_item()
|
||||||
|
|
||||||
local pos = self.object:get_pos()
|
if mod_experience and ((not self.child) or self.type ~= "animal") then
|
||||||
|
mcl_experience.throw_experience(self.object:get_pos(), math.random(self.xp_min, self.xp_max))
|
||||||
if mod_experience and ((not self.child) or self.type ~= "animal") then
|
end
|
||||||
mcl_experience.throw_experience(pos, math.random(self.xp_min, self.xp_max))
|
end
|
||||||
|
end
|
||||||
|
local cooked = mcl_burning.is_burning(self.object) or mcl_enchanting.has_enchantment(wielditem, "fire_aspect")
|
||||||
|
local looting = mcl_enchanting.get_enchantment(wielditem, "looting")
|
||||||
|
item_drop(self, cooked, looting)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -768,7 +805,7 @@ local check_for_death = function(self, cause, cmi_cause)
|
||||||
if self.on_die then
|
if self.on_die then
|
||||||
|
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
local on_die_exit = self.on_die(self, pos)
|
local on_die_exit = self.on_die(self, pos, cmi_cause)
|
||||||
if on_die_exit ~= true then
|
if on_die_exit ~= true then
|
||||||
death_handle(self)
|
death_handle(self)
|
||||||
end
|
end
|
||||||
|
@ -779,6 +816,7 @@ local check_for_death = function(self, cause, cmi_cause)
|
||||||
|
|
||||||
if on_die_exit == true then
|
if on_die_exit == true then
|
||||||
self.state = "die"
|
self.state = "die"
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -841,6 +879,7 @@ local check_for_death = function(self, cause, cmi_cause)
|
||||||
local dpos = self.object:get_pos()
|
local dpos = self.object:get_pos()
|
||||||
local cbox = self.collisionbox
|
local cbox = self.collisionbox
|
||||||
local yaw = self.object:get_rotation().y
|
local yaw = self.object:get_rotation().y
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
mobs.death_effect(dpos, yaw, cbox, not self.instant_death)
|
mobs.death_effect(dpos, yaw, cbox, not self.instant_death)
|
||||||
end
|
end
|
||||||
|
@ -989,6 +1028,7 @@ local do_env_damage = function(self)
|
||||||
|
|
||||||
-- remove mob if beyond map limits
|
-- remove mob if beyond map limits
|
||||||
if not within_limits(pos, 0) then
|
if not within_limits(pos, 0) then
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -1017,8 +1057,11 @@ local do_env_damage = function(self)
|
||||||
if mod_worlds then
|
if mod_worlds then
|
||||||
_, dim = mcl_worlds.y_to_layer(pos.y)
|
_, dim = mcl_worlds.y_to_layer(pos.y)
|
||||||
end
|
end
|
||||||
if self.sunlight_damage ~= 0 and (minetest.get_node_light(pos) or 0) >= minetest.LIGHT_MAX and dim == "overworld" then
|
if (self.sunlight_damage ~= 0 or self.ignited_by_sunlight) and (minetest.get_node_light(pos) or 0) >= minetest.LIGHT_MAX and dim == "overworld" then
|
||||||
if deal_light_damage(self, pos, self.sunlight_damage) then
|
if self.ignited_by_sunlight then
|
||||||
|
mcl_burning.set_on_fire(self.object, 10, self.sunlight_damage or 1)
|
||||||
|
else
|
||||||
|
deal_light_damage(self, pos, self.sunlight_damage)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1106,7 +1149,7 @@ local do_env_damage = function(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- damage_per_second node check
|
-- damage_per_second node check
|
||||||
elseif nodef.damage_per_second ~= 0 then
|
elseif nodef.damage_per_second ~= 0 and not nodef.groups.lava and not nodef.groups.fire then
|
||||||
|
|
||||||
self.health = self.health - nodef.damage_per_second
|
self.health = self.health - nodef.damage_per_second
|
||||||
|
|
||||||
|
@ -1238,7 +1281,7 @@ local do_jump = function(self)
|
||||||
}, "air")
|
}, "air")
|
||||||
|
|
||||||
-- we don't attempt to jump if there's a stack of blocks blocking
|
-- we don't attempt to jump if there's a stack of blocks blocking
|
||||||
if minetest.registered_nodes[nodTop.name] == true then
|
if minetest.registered_nodes[nodTop.name].walkable == true then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1269,7 +1312,7 @@ local do_jump = function(self)
|
||||||
end
|
end
|
||||||
self.object:set_acceleration({
|
self.object:set_acceleration({
|
||||||
x = v.x * 2,
|
x = v.x * 2,
|
||||||
y = 0,
|
y = -10,
|
||||||
z = v.z * 2,
|
z = v.z * 2,
|
||||||
})
|
})
|
||||||
end, self, v)
|
end, self, v)
|
||||||
|
@ -2059,6 +2102,7 @@ local follow_flop = function(self)
|
||||||
or self.order == "follow")
|
or self.order == "follow")
|
||||||
and not self.following
|
and not self.following
|
||||||
and self.state ~= "attack"
|
and self.state ~= "attack"
|
||||||
|
and self.order ~= "sit"
|
||||||
and self.state ~= "runaway" then
|
and self.state ~= "runaway" then
|
||||||
|
|
||||||
local s = self.object:get_pos()
|
local s = self.object:get_pos()
|
||||||
|
@ -2079,6 +2123,7 @@ local follow_flop = function(self)
|
||||||
if self.type == "npc"
|
if self.type == "npc"
|
||||||
and self.order == "follow"
|
and self.order == "follow"
|
||||||
and self.state ~= "attack"
|
and self.state ~= "attack"
|
||||||
|
and self.order ~= "sit"
|
||||||
and self.owner ~= "" then
|
and self.owner ~= "" then
|
||||||
|
|
||||||
-- npc stop following player if not owner
|
-- npc stop following player if not owner
|
||||||
|
@ -2211,7 +2256,6 @@ local dogswitch = function(self, dtime)
|
||||||
return self.dogshoot_switch
|
return self.dogshoot_switch
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- execute current state (stand, walk, run, attacks)
|
-- execute current state (stand, walk, run, attacks)
|
||||||
-- returns true if mob has died
|
-- returns true if mob has died
|
||||||
local do_states = function(self, dtime)
|
local do_states = function(self, dtime)
|
||||||
|
@ -2364,6 +2408,8 @@ local do_states = function(self, dtime)
|
||||||
set_velocity(self, 0)
|
set_velocity(self, 0)
|
||||||
self.state = "stand"
|
self.state = "stand"
|
||||||
set_animation(self, "stand")
|
set_animation(self, "stand")
|
||||||
|
local yaw = self.object:get_yaw() or 0
|
||||||
|
yaw = set_yaw(self, yaw + 0.78, 8)
|
||||||
else
|
else
|
||||||
|
|
||||||
set_velocity(self, self.walk_velocity)
|
set_velocity(self, self.walk_velocity)
|
||||||
|
@ -2390,6 +2436,8 @@ local do_states = function(self, dtime)
|
||||||
set_velocity(self, 0)
|
set_velocity(self, 0)
|
||||||
self.state = "stand"
|
self.state = "stand"
|
||||||
set_animation(self, "stand")
|
set_animation(self, "stand")
|
||||||
|
local yaw = self.object:get_yaw() or 0
|
||||||
|
yaw = set_yaw(self, yaw + 0.78, 8)
|
||||||
else
|
else
|
||||||
set_velocity(self, self.run_velocity)
|
set_velocity(self, self.run_velocity)
|
||||||
set_animation(self, "run")
|
set_animation(self, "run")
|
||||||
|
@ -2434,7 +2482,7 @@ local do_states = function(self, dtime)
|
||||||
|
|
||||||
if p.x > s.x then yaw = yaw + pi end
|
if p.x > s.x then yaw = yaw + pi end
|
||||||
|
|
||||||
yaw = set_yaw(self, yaw)
|
yaw = set_yaw(self, yaw, 0, dtime)
|
||||||
|
|
||||||
local node_break_radius = self.explosion_radius or 1
|
local node_break_radius = self.explosion_radius or 1
|
||||||
local entity_damage_radius = self.explosion_damage_radius
|
local entity_damage_radius = self.explosion_damage_radius
|
||||||
|
@ -2499,7 +2547,7 @@ local do_states = function(self, dtime)
|
||||||
|
|
||||||
if mod_explosions then
|
if mod_explosions then
|
||||||
if mobs_griefing and not minetest.is_protected(pos, "") then
|
if mobs_griefing and not minetest.is_protected(pos, "") then
|
||||||
mcl_explosions.explode(self.object:get_pos(), self.explosion_strength, { drop_chance = 1.0 }, self.object)
|
mcl_explosions.explode(mcl_util.get_object_center(self.object), self.explosion_strength, { drop_chance = 1.0 }, self.object)
|
||||||
else
|
else
|
||||||
minetest.sound_play(self.sounds.explode, {
|
minetest.sound_play(self.sounds.explode, {
|
||||||
pos = pos,
|
pos = pos,
|
||||||
|
@ -2511,6 +2559,7 @@ local do_states = function(self, dtime)
|
||||||
effect(pos, 32, "mcl_particles_smoke.png", nil, nil, node_break_radius, 1, 0)
|
effect(pos, 32, "mcl_particles_smoke.png", nil, nil, node_break_radius, 1, 0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -2606,7 +2655,7 @@ local do_states = function(self, dtime)
|
||||||
|
|
||||||
if p.x > s.x then yaw = yaw + pi end
|
if p.x > s.x then yaw = yaw + pi end
|
||||||
|
|
||||||
yaw = set_yaw(self, yaw)
|
yaw = set_yaw(self, yaw, 0, dtime)
|
||||||
|
|
||||||
-- move towards enemy if beyond mob reach
|
-- move towards enemy if beyond mob reach
|
||||||
if dist > self.reach then
|
if dist > self.reach then
|
||||||
|
@ -2622,6 +2671,8 @@ local do_states = function(self, dtime)
|
||||||
|
|
||||||
set_velocity(self, 0)
|
set_velocity(self, 0)
|
||||||
set_animation(self, "stand")
|
set_animation(self, "stand")
|
||||||
|
local yaw = self.object:get_yaw() or 0
|
||||||
|
yaw = set_yaw(self, yaw + 0.78, 8)
|
||||||
else
|
else
|
||||||
|
|
||||||
if self.path.stuck then
|
if self.path.stuck then
|
||||||
|
@ -2709,12 +2760,16 @@ local do_states = function(self, dtime)
|
||||||
|
|
||||||
if p.x > s.x then yaw = yaw + pi end
|
if p.x > s.x then yaw = yaw + pi end
|
||||||
|
|
||||||
yaw = set_yaw(self, yaw)
|
yaw = set_yaw(self, yaw, 0, dtime)
|
||||||
|
|
||||||
set_velocity(self, 0)
|
set_velocity(self, 0)
|
||||||
|
|
||||||
|
local p = self.object:get_pos()
|
||||||
|
p.y = p.y + (self.collisionbox[2] + self.collisionbox[5]) / 2
|
||||||
|
|
||||||
if self.shoot_interval
|
if self.shoot_interval
|
||||||
and self.timer > self.shoot_interval
|
and self.timer > self.shoot_interval
|
||||||
|
and not minetest.raycast(p, self.attack:get_pos(), false, false):next()
|
||||||
and random(1, 100) <= 60 then
|
and random(1, 100) <= 60 then
|
||||||
|
|
||||||
self.timer = 0
|
self.timer = 0
|
||||||
|
@ -2723,10 +2778,6 @@ local do_states = function(self, dtime)
|
||||||
-- play shoot attack sound
|
-- play shoot attack sound
|
||||||
mob_sound(self, "shoot_attack")
|
mob_sound(self, "shoot_attack")
|
||||||
|
|
||||||
local p = self.object:get_pos()
|
|
||||||
|
|
||||||
p.y = p.y + (self.collisionbox[2] + self.collisionbox[5]) / 2
|
|
||||||
|
|
||||||
-- Shoot arrow
|
-- Shoot arrow
|
||||||
if minetest.registered_entities[self.arrow] then
|
if minetest.registered_entities[self.arrow] then
|
||||||
|
|
||||||
|
@ -2915,6 +2966,13 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if weapon then
|
||||||
|
local fire_aspect_level = mcl_enchanting.get_enchantment(weapon, "fire_aspect")
|
||||||
|
if fire_aspect_level > 0 then
|
||||||
|
mcl_burning.set_on_fire(self.object, 4, fire_aspect_level * 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- check for tool immunity or special damage
|
-- check for tool immunity or special damage
|
||||||
for n = 1, #self.immune_to do
|
for n = 1, #self.immune_to do
|
||||||
|
|
||||||
|
@ -3019,6 +3077,18 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
kb = kb * 1.5
|
kb = kb * 1.5
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local luaentity
|
||||||
|
if hitter then
|
||||||
|
luaentity = hitter:get_luaentity()
|
||||||
|
end
|
||||||
|
if hitter and hitter:is_player() then
|
||||||
|
local wielditem = hitter:get_wielded_item()
|
||||||
|
kb = kb + 3 * mcl_enchanting.get_enchantment(wielditem, "knockback")
|
||||||
|
elseif luaentity and luaentity._knockback then
|
||||||
|
kb = kb + luaentity._knockback
|
||||||
|
end
|
||||||
|
|
||||||
self.object:set_velocity({
|
self.object:set_velocity({
|
||||||
x = dir.x * kb,
|
x = dir.x * kb,
|
||||||
y = dir.y * kb + up,
|
y = dir.y * kb + up,
|
||||||
|
@ -3121,7 +3191,8 @@ local mob_staticdata = function(self)
|
||||||
and ((not self.nametag) or (self.nametag == ""))
|
and ((not self.nametag) or (self.nametag == ""))
|
||||||
and self.lifetimer <= 20 then
|
and self.lifetimer <= 20 then
|
||||||
|
|
||||||
minetest.log("action", "Mob "..name.." despawns in mob_staticdata at "..minetest.pos_to_string(self.object.get_pos()))
|
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()
|
self.object:remove()
|
||||||
|
|
||||||
return ""-- nil
|
return ""-- nil
|
||||||
|
@ -3160,7 +3231,7 @@ local mob_activate = function(self, staticdata, def, dtime)
|
||||||
-- remove monsters in peaceful mode
|
-- remove monsters in peaceful mode
|
||||||
if self.type == "monster"
|
if self.type == "monster"
|
||||||
and minetest.settings:get_bool("only_peaceful_mobs", false) then
|
and minetest.settings:get_bool("only_peaceful_mobs", false) then
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -3324,6 +3395,10 @@ end
|
||||||
-- main mob function
|
-- main mob function
|
||||||
local mob_step = function(self, dtime)
|
local mob_step = function(self, dtime)
|
||||||
|
|
||||||
|
if not self.fire_resistant then
|
||||||
|
mcl_burning.tick(self.object, dtime)
|
||||||
|
end
|
||||||
|
|
||||||
if use_cmi then
|
if use_cmi then
|
||||||
cmi.notify_step(self.object, dtime)
|
cmi.notify_step(self.object, dtime)
|
||||||
end
|
end
|
||||||
|
@ -3385,6 +3460,9 @@ local mob_step = function(self, dtime)
|
||||||
end
|
end
|
||||||
|
|
||||||
self.delay = self.delay - 1
|
self.delay = self.delay - 1
|
||||||
|
if self.shaking then
|
||||||
|
yaw = yaw + (math.random() * 2 - 1) * 5 * dtime
|
||||||
|
end
|
||||||
self.object:set_yaw(yaw)
|
self.object:set_yaw(yaw)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -3516,39 +3594,27 @@ local mob_step = function(self, dtime)
|
||||||
set_velocity(self, 0)
|
set_velocity(self, 0)
|
||||||
self.state = "stand"
|
self.state = "stand"
|
||||||
set_animation(self, "stand")
|
set_animation(self, "stand")
|
||||||
|
local yaw = self.object:get_yaw() or 0
|
||||||
|
yaw = set_yaw(self, yaw + 0.78, 8)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Despawning: when lifetimer expires, remove mob
|
-- Despawning: when lifetimer expires, remove mob
|
||||||
if remove_far
|
if remove_far
|
||||||
and self.can_despawn == true
|
and self.can_despawn == true
|
||||||
and ((not self.nametag) or (self.nametag == "")) then
|
and ((not self.nametag) or (self.nametag == ""))
|
||||||
|
and self.state ~= "attack"
|
||||||
|
and self.following == nil then
|
||||||
|
|
||||||
self.lifetimer = self.lifetimer - dtime
|
self.lifetimer = self.lifetimer - dtime
|
||||||
if self.lifetimer <= 10 then
|
if self.despawn_immediately or self.lifetimer <= 0 then
|
||||||
|
minetest.log("action", "Mob "..self.name.." despawns in mob_step at "..minetest.pos_to_string(pos, 1))
|
||||||
-- only despawn away from player
|
mcl_burning.extinguish(self.object)
|
||||||
local far_objs = minetest.get_objects_inside_radius(pos, 48)
|
self.object:remove()
|
||||||
for n = 1, #far_objs do
|
elseif self.lifetimer <= 10 then
|
||||||
|
if math.random(10) < 4 then
|
||||||
if far_objs[n]:is_player() then
|
self.despawn_immediately = true
|
||||||
|
else
|
||||||
local close_objs = minetest.get_objects_inside_radius(pos, 16)
|
self.lifetimer = 20
|
||||||
for n = 1, #close_objs do
|
|
||||||
if close_objs[n]:is_player() then
|
|
||||||
self.lifetimer = 20
|
|
||||||
else
|
|
||||||
if math.random(1,10) <= 3 then
|
|
||||||
minetest.log("action", "Mob "..self.name.." despawns in mob_step at "..minetest.pos_to_string(pos))
|
|
||||||
self.object:remove()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
minetest.log("action", "Mob "..self.name.." despawns in mob_step at "..minetest.pos_to_string(pos))
|
|
||||||
self.object:remove()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3750,6 +3816,9 @@ minetest.register_entity(name, {
|
||||||
suffocation_timer = 0,
|
suffocation_timer = 0,
|
||||||
follow_velocity = def.follow_velocity or 2.4,
|
follow_velocity = def.follow_velocity or 2.4,
|
||||||
instant_death = def.instant_death or false,
|
instant_death = def.instant_death or false,
|
||||||
|
fire_resistant = def.fire_resistant or false,
|
||||||
|
fire_damage_resistant = def.fire_damage_resistant or false,
|
||||||
|
ignited_by_sunlight = def.ignited_by_sunlight or false,
|
||||||
-- End of MCL2 extensions
|
-- End of MCL2 extensions
|
||||||
|
|
||||||
on_spawn = def.on_spawn,
|
on_spawn = def.on_spawn,
|
||||||
|
@ -3930,7 +3999,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
|
||||||
pos.y = pos.y + 1
|
pos.y = pos.y + 1
|
||||||
|
|
||||||
-- only spawn away from player
|
-- only spawn away from player
|
||||||
local objs = minetest.get_objects_inside_radius(pos, 10)
|
local objs = minetest.get_objects_inside_radius(pos, 24)
|
||||||
|
|
||||||
for n = 1, #objs do
|
for n = 1, #objs do
|
||||||
|
|
||||||
|
@ -4106,7 +4175,7 @@ function mobs:register_arrow(name, def)
|
||||||
if self.switch == 0
|
if self.switch == 0
|
||||||
or self.timer > 150
|
or self.timer > 150
|
||||||
or not within_limits(pos, 0) then
|
or not within_limits(pos, 0) then
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
self.object:remove();
|
self.object:remove();
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -4489,3 +4558,20 @@ function mobs:alias_mob(old_name, new_name)
|
||||||
})
|
})
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local timer = 0
|
||||||
|
minetest.register_globalstep(function(dtime)
|
||||||
|
timer = timer + dtime
|
||||||
|
if timer < 1 then return end
|
||||||
|
for _, player in ipairs(minetest.get_connected_players()) do
|
||||||
|
local pos = player:get_pos()
|
||||||
|
for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 47)) do
|
||||||
|
local lua = obj:get_luaentity()
|
||||||
|
if lua and lua._cmi_is_mob then
|
||||||
|
lua.lifetimer = math.max(20, lua.lifetimer)
|
||||||
|
lua.despawn_immediately = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
timer = 0
|
||||||
|
end)
|
||||||
|
|
|
@ -249,6 +249,9 @@ functions needed for the mob to work properly which contains the following:
|
||||||
'instant_death' If true, mob dies instantly (no death animation or delay) (default: false)
|
'instant_death' If true, mob dies instantly (no death animation or delay) (default: false)
|
||||||
'xp_min' the minimum XP it drops on death (default: 0)
|
'xp_min' the minimum XP it drops on death (default: 0)
|
||||||
'xp_max' the maximum XP it drops on death (default: 0)
|
'xp_max' the maximum XP it drops on death (default: 0)
|
||||||
|
'fire_resistant' If true, the mob can't burn
|
||||||
|
'fire_damage_resistant' If true the mob will not take damage when burning
|
||||||
|
'ignited_by_sunlight' If true the mod will burn at daytime. (Takes sunlight_damage per second)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,20 @@
|
||||||
|
local function is_forbidden_node(pos, node)
|
||||||
|
node = node or minetest.get_node(pos)
|
||||||
|
return minetest.get_item_group(node.name, "stair") > 0 or minetest.get_item_group(node.name, "slab") > 0 or minetest.get_item_group(node.name, "carpet") > 0
|
||||||
|
end
|
||||||
|
|
||||||
function mobs:spawn_abm_check(pos, node, name)
|
function mobs:spawn_abm_check(pos, node, name)
|
||||||
-- Don't spawn monsters on mycelium
|
-- Don't spawn monsters on mycelium
|
||||||
if (node.name == "mcl_core:mycelium" or node.name == "mcl_core:mycelium_snow") and minetest.registered_entities[name].type == "monster" then
|
if (node.name == "mcl_core:mycelium" or node.name == "mcl_core:mycelium_snow") and minetest.registered_entities[name].type == "monster" then
|
||||||
return true
|
return true
|
||||||
|
--Don't Spawn mobs on stairs, slabs, or carpets
|
||||||
|
elseif is_forbidden_node(pos, node) or is_forbidden_node(vector.add(pos, vector.new(0, 1, 0))) then
|
||||||
|
return true
|
||||||
-- Spawn on opaque or liquid nodes
|
-- Spawn on opaque or liquid nodes
|
||||||
elseif minetest.get_item_group(node.name, "opaque") ~= 0 or minetest.registered_nodes[node.name].liquidtype ~= "none" then
|
elseif minetest.get_item_group(node.name, "opaque") ~= 0 or minetest.registered_nodes[node.name].liquidtype ~= "none" then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Reject everything else
|
-- Reject everything else
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,7 +41,8 @@ mobs:register_mob("mobs_mc:blaze", {
|
||||||
{name = mobs_mc.items.blaze_rod,
|
{name = mobs_mc.items.blaze_rod,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "common",},
|
||||||
},
|
},
|
||||||
animation = {
|
animation = {
|
||||||
stand_speed = 25,
|
stand_speed = 25,
|
||||||
|
@ -73,6 +74,7 @@ mobs:register_mob("mobs_mc:blaze", {
|
||||||
makes_footstep_sound = false,
|
makes_footstep_sound = false,
|
||||||
fear_height = 0,
|
fear_height = 0,
|
||||||
glow = 14,
|
glow = 14,
|
||||||
|
fire_resistant = true,
|
||||||
})
|
})
|
||||||
|
|
||||||
mobs:spawn_specific("mobs_mc:blaze", mobs_mc.spawn.nether_fortress, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 5000, 3, mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_max)
|
mobs:spawn_specific("mobs_mc:blaze", mobs_mc.spawn.nether_fortress, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 5000, 3, mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_max)
|
||||||
|
@ -89,6 +91,7 @@ mobs:register_arrow("mobs_mc:blaze_fireball", {
|
||||||
if rawget(_G, "armor") and armor.last_damage_types then
|
if rawget(_G, "armor") and armor.last_damage_types then
|
||||||
armor.last_damage_types[player:get_player_name()] = "fireball"
|
armor.last_damage_types[player:get_player_name()] = "fireball"
|
||||||
end
|
end
|
||||||
|
mcl_burning.set_on_fire(player, 5, 1, "blaze")
|
||||||
player:punch(self.object, 1.0, {
|
player:punch(self.object, 1.0, {
|
||||||
full_punch_interval = 1.0,
|
full_punch_interval = 1.0,
|
||||||
damage_groups = {fleshy = 5},
|
damage_groups = {fleshy = 5},
|
||||||
|
@ -96,6 +99,7 @@ mobs:register_arrow("mobs_mc:blaze_fireball", {
|
||||||
end,
|
end,
|
||||||
|
|
||||||
hit_mob = function(self, mob)
|
hit_mob = function(self, mob)
|
||||||
|
mcl_burning.set_on_fire(mob, 5)
|
||||||
mob:punch(self.object, 1.0, {
|
mob:punch(self.object, 1.0, {
|
||||||
full_punch_interval = 1.0,
|
full_punch_interval = 1.0,
|
||||||
damage_groups = {fleshy = 5},
|
damage_groups = {fleshy = 5},
|
||||||
|
|
|
@ -32,11 +32,13 @@ mobs:register_mob("mobs_mc:chicken", {
|
||||||
{name = mobs_mc.items.chicken_raw,
|
{name = mobs_mc.items.chicken_raw,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "common",},
|
||||||
{name = mobs_mc.items.feather,
|
{name = mobs_mc.items.feather,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 2,},
|
max = 2,
|
||||||
|
looting = "common",},
|
||||||
},
|
},
|
||||||
fall_damage = 0,
|
fall_damage = 0,
|
||||||
fall_speed = -2.25,
|
fall_speed = -2.25,
|
||||||
|
|
|
@ -23,11 +23,13 @@ local cow_def = {
|
||||||
{name = mobs_mc.items.beef_raw,
|
{name = mobs_mc.items.beef_raw,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 3,},
|
max = 3,
|
||||||
|
looting = "common",},
|
||||||
{name = mobs_mc.items.leather,
|
{name = mobs_mc.items.leather,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 2,},
|
max = 2,
|
||||||
|
looting = "common",},
|
||||||
},
|
},
|
||||||
runaway = true,
|
runaway = true,
|
||||||
sounds = {
|
sounds = {
|
||||||
|
|
|
@ -71,17 +71,21 @@ mobs:register_mob("mobs_mc:creeper", {
|
||||||
if self._forced_explosion_countdown_timer ~= nil then
|
if self._forced_explosion_countdown_timer ~= nil then
|
||||||
self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime
|
self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime
|
||||||
if self._forced_explosion_countdown_timer <= 0 then
|
if self._forced_explosion_countdown_timer <= 0 then
|
||||||
mobs:boom(self, self.object:get_pos(), self.explosion_strength)
|
mobs:boom(self, mcl_util.get_object_center(self.object), self.explosion_strength)
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
on_die = function(self, pos)
|
on_die = function(self, pos, cmi_cause)
|
||||||
-- Drop a random music disc
|
-- Drop a random music disc when killed by skeleton or stray
|
||||||
-- TODO: Only do this if killed by skeleton
|
if cmi_cause and cmi_cause.type == "punch" then
|
||||||
if math.random(1, 200) == 1 then
|
local luaentity = cmi_cause.puncher and cmi_cause.puncher:get_luaentity()
|
||||||
local r = math.random(1, #mobs_mc.items.music_discs)
|
if luaentity and luaentity.name:find("arrow") then
|
||||||
minetest.add_item({x=pos.x, y=pos.y+1, z=pos.z}, mobs_mc.items.music_discs[r])
|
local shooter_luaentity = luaentity._shooter and luaentity._shooter:get_luaentity()
|
||||||
|
if shooter_luaentity and (shooter_luaentity.name == "mobs_mc:skeleton" or shooter_luaentity.name == "mobs_mc:stray") then
|
||||||
|
minetest.add_item({x=pos.x, y=pos.y+1, z=pos.z}, mobs_mc.items.music_discs[math.random(1, #mobs_mc.items.music_discs)])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
maxdrops = 2,
|
maxdrops = 2,
|
||||||
|
@ -89,7 +93,8 @@ mobs:register_mob("mobs_mc:creeper", {
|
||||||
{name = mobs_mc.items.gunpowder,
|
{name = mobs_mc.items.gunpowder,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 2,},
|
max = 2,
|
||||||
|
looting = "common",},
|
||||||
|
|
||||||
-- Head
|
-- Head
|
||||||
-- TODO: Only drop if killed by charged creeper
|
-- TODO: Only drop if killed by charged creeper
|
||||||
|
|
|
@ -49,6 +49,8 @@ mobs:register_mob("mobs_mc:enderdragon", {
|
||||||
arrow = "mobs_mc:dragon_fireball",
|
arrow = "mobs_mc:dragon_fireball",
|
||||||
shoot_interval = 0.5,
|
shoot_interval = 0.5,
|
||||||
shoot_offset = -1.0,
|
shoot_offset = -1.0,
|
||||||
|
xp_min = 12000,
|
||||||
|
xp_max = 12000,
|
||||||
animation = {
|
animation = {
|
||||||
fly_speed = 8, stand_speed = 8,
|
fly_speed = 8, stand_speed = 8,
|
||||||
stand_start = 0, stand_end = 20,
|
stand_start = 0, stand_end = 20,
|
||||||
|
@ -65,7 +67,8 @@ mobs:register_mob("mobs_mc:enderdragon", {
|
||||||
--end
|
--end
|
||||||
end
|
end
|
||||||
minetest.add_item(own_pos, mobs_mc.items.dragon_egg)
|
minetest.add_item(own_pos, mobs_mc.items.dragon_egg)
|
||||||
end
|
end,
|
||||||
|
fire_resistant = true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -43,10 +43,10 @@ end
|
||||||
local pr = PseudoRandom(os.time()*(-334))
|
local pr = PseudoRandom(os.time()*(-334))
|
||||||
|
|
||||||
-- How freqeuntly to take and place blocks, in seconds
|
-- How freqeuntly to take and place blocks, in seconds
|
||||||
local take_frequency_min = 25
|
local take_frequency_min = 235
|
||||||
local take_frequency_max = 90
|
local take_frequency_max = 245
|
||||||
local place_frequency_min = 10
|
local place_frequency_min = 235
|
||||||
local place_frequency_max = 30
|
local place_frequency_max = 245
|
||||||
|
|
||||||
-- Create the textures table for the enderman, depending on which kind of block
|
-- Create the textures table for the enderman, depending on which kind of block
|
||||||
-- the enderman holds (if any).
|
-- the enderman holds (if any).
|
||||||
|
@ -220,7 +220,8 @@ mobs:register_mob("mobs_mc:enderman", {
|
||||||
{name = mobs_mc.items.ender_pearl,
|
{name = mobs_mc.items.ender_pearl,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "common"},
|
||||||
},
|
},
|
||||||
animation = select_enderman_animation("normal"),
|
animation = select_enderman_animation("normal"),
|
||||||
_taken_node = "",
|
_taken_node = "",
|
||||||
|
@ -273,10 +274,10 @@ mobs:register_mob("mobs_mc:enderman", {
|
||||||
end
|
end
|
||||||
-- AGRESSIVELY WARP/CHASE PLAYER BEHAVIOUR HERE.
|
-- AGRESSIVELY WARP/CHASE PLAYER BEHAVIOUR HERE.
|
||||||
if self.state == "attack" then
|
if self.state == "attack" then
|
||||||
if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
--if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||||
self:teleport(nil)
|
--self:teleport(nil)
|
||||||
self.state = ""
|
--self.state = ""
|
||||||
else
|
--else
|
||||||
if self.attack then
|
if self.attack then
|
||||||
local target = self.attack
|
local target = self.attack
|
||||||
local pos = target:get_pos()
|
local pos = target:get_pos()
|
||||||
|
@ -286,7 +287,7 @@ mobs:register_mob("mobs_mc:enderman", {
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
--end
|
||||||
end
|
end
|
||||||
-- ARROW / DAYTIME PEOPLE AVOIDANCE BEHAVIOUR HERE.
|
-- ARROW / DAYTIME PEOPLE AVOIDANCE BEHAVIOUR HERE.
|
||||||
-- Check for arrows and people nearby.
|
-- Check for arrows and people nearby.
|
||||||
|
@ -297,9 +298,9 @@ mobs:register_mob("mobs_mc:enderman", {
|
||||||
if obj then
|
if obj then
|
||||||
if minetest.is_player(obj) then
|
if minetest.is_player(obj) then
|
||||||
-- Warp from players during day.
|
-- Warp from players during day.
|
||||||
if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
--if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||||
self:teleport(nil)
|
-- self:teleport(nil)
|
||||||
end
|
--end
|
||||||
else
|
else
|
||||||
local lua = obj:get_luaentity()
|
local lua = obj:get_luaentity()
|
||||||
if lua then
|
if lua then
|
||||||
|
@ -314,14 +315,14 @@ mobs:register_mob("mobs_mc:enderman", {
|
||||||
local enderpos = self.object:get_pos()
|
local enderpos = self.object:get_pos()
|
||||||
if self.provoked == "broke_contact" then
|
if self.provoked == "broke_contact" then
|
||||||
self.provoked = "false"
|
self.provoked = "false"
|
||||||
if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
--if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||||
self:teleport(nil)
|
-- self:teleport(nil)
|
||||||
self.state = ""
|
-- self.state = ""
|
||||||
else
|
--else
|
||||||
if self.attack ~= nil then
|
if self.attack ~= nil then
|
||||||
self.state = 'attack'
|
self.state = 'attack'
|
||||||
end
|
end
|
||||||
end
|
--end
|
||||||
end
|
end
|
||||||
-- Check to see if people are near by enough to look at us.
|
-- Check to see if people are near by enough to look at us.
|
||||||
local objs = minetest.get_objects_inside_radius(enderpos, 64)
|
local objs = minetest.get_objects_inside_radius(enderpos, 64)
|
||||||
|
@ -527,13 +528,13 @@ mobs:register_mob("mobs_mc:enderman", {
|
||||||
do_punch = function(self, hitter, tflp, tool_caps, dir)
|
do_punch = function(self, hitter, tflp, tool_caps, dir)
|
||||||
-- damage from rain caused by itself so we don't want it to attack itself.
|
-- damage from rain caused by itself so we don't want it to attack itself.
|
||||||
if hitter ~= self.object and hitter ~= nil then
|
if hitter ~= self.object and hitter ~= nil then
|
||||||
if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
--if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||||
self:teleport(nil)
|
-- self:teleport(nil)
|
||||||
else
|
--else
|
||||||
self:teleport(hitter)
|
self:teleport(hitter)
|
||||||
self.attack=hitter
|
self.attack=hitter
|
||||||
self.state="attack"
|
self.state="attack"
|
||||||
end
|
--end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
armor = { fleshy = 100, water_vulnerable = 100 },
|
armor = { fleshy = 100, water_vulnerable = 100 },
|
||||||
|
|
|
@ -38,8 +38,8 @@ mobs:register_mob("mobs_mc:ghast", {
|
||||||
walk_velocity = 1.6,
|
walk_velocity = 1.6,
|
||||||
run_velocity = 3.2,
|
run_velocity = 3.2,
|
||||||
drops = {
|
drops = {
|
||||||
{name = mobs_mc.items.gunpowder, chance = 1, min = 0, max = 2,},
|
{name = mobs_mc.items.gunpowder, chance = 1, min = 0, max = 2, looting = "common"},
|
||||||
{name = mobs_mc.items.ghast_tear, chance = 3,min = 0,max = 1,},
|
{name = mobs_mc.items.ghast_tear, chance = 10/6, min = 0, max = 1, looting = "common", looting_ignore_chance = true},
|
||||||
},
|
},
|
||||||
animation = {
|
animation = {
|
||||||
stand_speed = 50, walk_speed = 50, run_speed = 50,
|
stand_speed = 50, walk_speed = 50, run_speed = 50,
|
||||||
|
@ -62,6 +62,7 @@ mobs:register_mob("mobs_mc:ghast", {
|
||||||
fly = true,
|
fly = true,
|
||||||
makes_footstep_sound = false,
|
makes_footstep_sound = false,
|
||||||
instant_death = true,
|
instant_death = true,
|
||||||
|
fire_resistant = true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,8 @@ mobs:register_mob("mobs_mc:guardian", {
|
||||||
{name = mobs_mc.items.prismarine_shard,
|
{name = mobs_mc.items.prismarine_shard,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 32,},
|
max = 32,
|
||||||
|
looting = "common",},
|
||||||
-- TODO: Reduce of drops when ocean monument is ready.
|
-- TODO: Reduce of drops when ocean monument is ready.
|
||||||
|
|
||||||
-- The following drops are approximations
|
-- The following drops are approximations
|
||||||
|
@ -54,29 +55,39 @@ mobs:register_mob("mobs_mc:guardian", {
|
||||||
{name = mobs_mc.items.fish_raw,
|
{name = mobs_mc.items.fish_raw,
|
||||||
chance = 4,
|
chance = 4,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "common",},
|
||||||
{name = mobs_mc.items.prismarine_crystals,
|
{name = mobs_mc.items.prismarine_crystals,
|
||||||
chance = 4,
|
chance = 4,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 2,},
|
max = 2,
|
||||||
|
looting = "common",},
|
||||||
|
|
||||||
-- Rare drop: fish
|
-- Rare drop: fish
|
||||||
{name = mobs_mc.items.fish_raw,
|
{name = mobs_mc.items.fish_raw,
|
||||||
chance = 160, -- 2.5% / 4
|
chance = 160, -- 2.5% / 4
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_factor = 0.0025,},
|
||||||
{name = mobs_mc.items.salmon_raw,
|
{name = mobs_mc.items.salmon_raw,
|
||||||
chance = 160,
|
chance = 160,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_factor = 0.0025,},
|
||||||
{name = mobs_mc.items.clownfish_raw,
|
{name = mobs_mc.items.clownfish_raw,
|
||||||
chance = 160,
|
chance = 160,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_factor = 0.0025,},
|
||||||
{name = mobs_mc.items.pufferfish_raw,
|
{name = mobs_mc.items.pufferfish_raw,
|
||||||
chance = 160,
|
chance = 160,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_factor = 0.0025,},
|
||||||
},
|
},
|
||||||
fly = true,
|
fly = true,
|
||||||
makes_footstep_sound = false,
|
makes_footstep_sound = false,
|
||||||
|
|
|
@ -51,7 +51,8 @@ mobs:register_mob("mobs_mc:guardian_elder", {
|
||||||
{name = mobs_mc.items.prismarine_shard,
|
{name = mobs_mc.items.prismarine_shard,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 64,},
|
max = 64,
|
||||||
|
looting = "common",},
|
||||||
|
|
||||||
-- TODO: Only drop if killed by player
|
-- TODO: Only drop if killed by player
|
||||||
{name = mobs_mc.items.wet_sponge,
|
{name = mobs_mc.items.wet_sponge,
|
||||||
|
@ -64,29 +65,39 @@ mobs:register_mob("mobs_mc:guardian_elder", {
|
||||||
{name = mobs_mc.items.fish_raw,
|
{name = mobs_mc.items.fish_raw,
|
||||||
chance = 4,
|
chance = 4,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "common",},
|
||||||
{name = mobs_mc.items.prismarine_crystals,
|
{name = mobs_mc.items.prismarine_crystals,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 10,},
|
max = 10,
|
||||||
|
looting = "common",},
|
||||||
|
|
||||||
-- Rare drop: fish
|
-- Rare drop: fish
|
||||||
{name = mobs_mc.items.fish_raw,
|
{name = mobs_mc.items.fish_raw,
|
||||||
chance = 160, -- 2.5% / 4
|
chance = 160, -- 2.5% / 4
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_factor = 0.01 / 4,},
|
||||||
{name = mobs_mc.items.salmon_raw,
|
{name = mobs_mc.items.salmon_raw,
|
||||||
chance = 160,
|
chance = 160,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_factor = 0.01 / 4,},
|
||||||
{name = mobs_mc.items.clownfish_raw,
|
{name = mobs_mc.items.clownfish_raw,
|
||||||
chance = 160,
|
chance = 160,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_factor = 0.01 / 4,},
|
||||||
{name = mobs_mc.items.pufferfish_raw,
|
{name = mobs_mc.items.pufferfish_raw,
|
||||||
chance = 160,
|
chance = 160,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_factor = 0.01 / 4,},
|
||||||
},
|
},
|
||||||
fly = true,
|
fly = true,
|
||||||
makes_footstep_sound = false,
|
makes_footstep_sound = false,
|
||||||
|
|
|
@ -127,7 +127,8 @@ local horse = {
|
||||||
{name = mobs_mc.items.leather,
|
{name = mobs_mc.items.leather,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 2,},
|
max = 2,
|
||||||
|
looting = "common",},
|
||||||
},
|
},
|
||||||
|
|
||||||
do_custom = function(self, dtime)
|
do_custom = function(self, dtime)
|
||||||
|
|
|
@ -54,7 +54,8 @@ mobs:register_mob("mobs_mc:llama", {
|
||||||
{name = mobs_mc.items.leather,
|
{name = mobs_mc.items.leather,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 2,},
|
max = 2,
|
||||||
|
looting = "common",},
|
||||||
},
|
},
|
||||||
fear_height = 4,
|
fear_height = 4,
|
||||||
sounds = {
|
sounds = {
|
||||||
|
|
|
@ -37,7 +37,8 @@ mobs:register_mob("mobs_mc:parrot", {
|
||||||
{name = mobs_mc.items.feather,
|
{name = mobs_mc.items.feather,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 2,},
|
max = 2,
|
||||||
|
looting = "common",},
|
||||||
},
|
},
|
||||||
animation = {
|
animation = {
|
||||||
stand_speed = 50,
|
stand_speed = 50,
|
||||||
|
|
|
@ -27,7 +27,8 @@ mobs:register_mob("mobs_mc:pig", {
|
||||||
{name = mobs_mc.items.porkchop_raw,
|
{name = mobs_mc.items.porkchop_raw,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 3,},
|
max = 3,
|
||||||
|
looting = "common",},
|
||||||
},
|
},
|
||||||
fear_height = 4,
|
fear_height = 4,
|
||||||
sounds = {
|
sounds = {
|
||||||
|
|
|
@ -36,12 +36,14 @@ mobs:register_mob("mobs_mc:polar_bear", {
|
||||||
{name = mobs_mc.items.fish_raw,
|
{name = mobs_mc.items.fish_raw,
|
||||||
chance = 2,
|
chance = 2,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 2,},
|
max = 2,
|
||||||
|
looting = "common",},
|
||||||
-- 1/4 to drop raw salmon
|
-- 1/4 to drop raw salmon
|
||||||
{name = mobs_mc.items.salmon_raw,
|
{name = mobs_mc.items.salmon_raw,
|
||||||
chance = 4,
|
chance = 4,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 2,},
|
max = 2,
|
||||||
|
looting = "common",},
|
||||||
|
|
||||||
},
|
},
|
||||||
floats = 1,
|
floats = 1,
|
||||||
|
|
|
@ -41,11 +41,9 @@ local rabbit = {
|
||||||
runaway = true,
|
runaway = true,
|
||||||
jump = true,
|
jump = true,
|
||||||
drops = {
|
drops = {
|
||||||
{name = mobs_mc.items.rabbit_raw, chance = 1, min = 0, max = 1},
|
{name = mobs_mc.items.rabbit_raw, chance = 1, min = 0, max = 1, looting = "common",},
|
||||||
{name = mobs_mc.items.rabbit_hide, chance = 1, min = 0, max = 1},
|
{name = mobs_mc.items.rabbit_hide, chance = 1, min = 0, max = 1, looting = "common",},
|
||||||
{name = mobs_mc.items.rabbit_foot, chance = 10, min = 0, max = 1},
|
{name = mobs_mc.items.rabbit_foot, chance = 10, min = 0, max = 1, looting = "rare", looting_factor = 0.03,},
|
||||||
-- TODO: Drop rabbit's foot when it's useful
|
|
||||||
--{name = mobs_mc.items.rabbit_foot, chance = 10, min = 1, max = 1},
|
|
||||||
},
|
},
|
||||||
fear_height = 4,
|
fear_height = 4,
|
||||||
animation = {
|
animation = {
|
||||||
|
|
|
@ -63,11 +63,13 @@ mobs:register_mob("mobs_mc:sheep", {
|
||||||
{name = mobs_mc.items.mutton_raw,
|
{name = mobs_mc.items.mutton_raw,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 2,},
|
max = 2,
|
||||||
|
looting = "common",},
|
||||||
{name = colors["unicolor_white"][1],
|
{name = colors["unicolor_white"][1],
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "common",},
|
||||||
},
|
},
|
||||||
fear_height = 4,
|
fear_height = 4,
|
||||||
sounds = {
|
sounds = {
|
||||||
|
|
|
@ -35,9 +35,11 @@ mobs:register_mob("mobs_mc:shulker", {
|
||||||
jump = false,
|
jump = false,
|
||||||
drops = {
|
drops = {
|
||||||
{name = mobs_mc.items.shulker_shell,
|
{name = mobs_mc.items.shulker_shell,
|
||||||
chance = 1,
|
chance = 2,
|
||||||
min = 0,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_factor = 0.0625},
|
||||||
},
|
},
|
||||||
animation = {
|
animation = {
|
||||||
stand_speed = 25, walk_speed = 25, run_speed = 50, punch_speed = 25,
|
stand_speed = 25, walk_speed = 25, run_speed = 50, punch_speed = 25,
|
||||||
|
|
|
@ -46,15 +46,18 @@ local skeleton = {
|
||||||
{name = mobs_mc.items.arrow,
|
{name = mobs_mc.items.arrow,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 2,},
|
max = 2,
|
||||||
|
looting = "common",},
|
||||||
{name = mobs_mc.items.bow,
|
{name = mobs_mc.items.bow,
|
||||||
chance = 11,
|
chance = 100 / 8.5,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",},
|
||||||
{name = mobs_mc.items.bone,
|
{name = mobs_mc.items.bone,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 2,},
|
max = 2,
|
||||||
|
looting = "common",},
|
||||||
|
|
||||||
-- Head
|
-- Head
|
||||||
-- TODO: Only drop if killed by charged creeper
|
-- TODO: Only drop if killed by charged creeper
|
||||||
|
@ -78,7 +81,7 @@ local skeleton = {
|
||||||
die_speed = 15,
|
die_speed = 15,
|
||||||
die_loop = false,
|
die_loop = false,
|
||||||
},
|
},
|
||||||
sunlight_damage = 1,
|
ignited_by_sunlight = true,
|
||||||
view_range = 16,
|
view_range = 16,
|
||||||
fear_height = 4,
|
fear_height = 4,
|
||||||
attack_type = "dogshoot",
|
attack_type = "dogshoot",
|
||||||
|
@ -116,12 +119,21 @@ stray.textures = {
|
||||||
-- TODO: different sound (w/ echo)
|
-- TODO: different sound (w/ echo)
|
||||||
-- TODO: stray's arrow inflicts slowness status
|
-- TODO: stray's arrow inflicts slowness status
|
||||||
table.insert(stray.drops, {
|
table.insert(stray.drops, {
|
||||||
-- Chance to drop additional arrow.
|
name = "mcl_potions:slowness_arrow",
|
||||||
-- TODO: Should be tipped arrow of slowness
|
|
||||||
name = mobs_mc.items.arrow,
|
|
||||||
chance = 2,
|
chance = 2,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_chance_function = function(lvl)
|
||||||
|
local chance = 0.5
|
||||||
|
for i = 1, lvl do
|
||||||
|
if chance > 1 then
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
chance = chance + (1 - chance) / 2
|
||||||
|
end
|
||||||
|
return chance
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
mobs:register_mob("mobs_mc:stray", stray)
|
mobs:register_mob("mobs_mc:stray", stray)
|
||||||
|
|
|
@ -45,17 +45,20 @@ mobs:register_mob("mobs_mc:witherskeleton", {
|
||||||
{name = mobs_mc.items.coal,
|
{name = mobs_mc.items.coal,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "common",},
|
||||||
{name = mobs_mc.items.bone,
|
{name = mobs_mc.items.bone,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 2,},
|
max = 2,
|
||||||
|
looting = "common",},
|
||||||
|
|
||||||
-- Head
|
-- Head
|
||||||
{name = mobs_mc.items.head_wither_skeleton,
|
{name = mobs_mc.items.head_wither_skeleton,
|
||||||
chance = 40, -- 2.5% chance
|
chance = 40, -- 2.5% chance
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",},
|
||||||
},
|
},
|
||||||
animation = {
|
animation = {
|
||||||
stand_start = 0,
|
stand_start = 0,
|
||||||
|
@ -87,6 +90,7 @@ mobs:register_mob("mobs_mc:witherskeleton", {
|
||||||
dogshoot_count_max =0.5,
|
dogshoot_count_max =0.5,
|
||||||
fear_height = 4,
|
fear_height = 4,
|
||||||
harmed_by_heal = true,
|
harmed_by_heal = true,
|
||||||
|
fire_resistant = true,
|
||||||
})
|
})
|
||||||
|
|
||||||
--spawn
|
--spawn
|
||||||
|
|
|
@ -108,7 +108,8 @@ local slime_big = {
|
||||||
jump_height = 5.2,
|
jump_height = 5.2,
|
||||||
fear_height = 0,
|
fear_height = 0,
|
||||||
spawn_small_alternative = "mobs_mc:slime_small",
|
spawn_small_alternative = "mobs_mc:slime_small",
|
||||||
on_die = spawn_children_on_die("mobs_mc:slime_small", 4, 1.0, 1.5)
|
on_die = spawn_children_on_die("mobs_mc:slime_small", 4, 1.0, 1.5),
|
||||||
|
fire_resistant = true,
|
||||||
}
|
}
|
||||||
mobs:register_mob("mobs_mc:slime_big", slime_big)
|
mobs:register_mob("mobs_mc:slime_big", slime_big)
|
||||||
|
|
||||||
|
@ -220,7 +221,8 @@ local magma_cube_big = {
|
||||||
walk_chance = 0,
|
walk_chance = 0,
|
||||||
fear_height = 0,
|
fear_height = 0,
|
||||||
spawn_small_alternative = "mobs_mc:magma_cube_small",
|
spawn_small_alternative = "mobs_mc:magma_cube_small",
|
||||||
on_die = spawn_children_on_die("mobs_mc:magma_cube_small", 3, 0.8, 1.5)
|
on_die = spawn_children_on_die("mobs_mc:magma_cube_small", 3, 0.8, 1.5),
|
||||||
|
fire_resistant = true,
|
||||||
}
|
}
|
||||||
mobs:register_mob("mobs_mc:magma_cube_big", magma_cube_big)
|
mobs:register_mob("mobs_mc:magma_cube_big", magma_cube_big)
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,10 @@ local spider = {
|
||||||
view_range = 16,
|
view_range = 16,
|
||||||
floats = 1,
|
floats = 1,
|
||||||
drops = {
|
drops = {
|
||||||
{name = mobs_mc.items.string, chance = 1, min = 0, max = 2,},
|
{name = mobs_mc.items.string, chance = 1, min = 0, max = 2, looting = "common"},
|
||||||
{name = mobs_mc.items.spider_eye, chance = 3, min = 1, max = 1,},
|
{name = mobs_mc.items.spider_eye, chance = 3, min = 1, max = 1, looting = "common", looting_chance_function = function(lvl)
|
||||||
|
return 1 - 2 / (lvl + 3)
|
||||||
|
end},
|
||||||
},
|
},
|
||||||
specific_attack = { "player", "mobs_mc:iron_golem" },
|
specific_attack = { "player", "mobs_mc:iron_golem" },
|
||||||
fear_height = 4,
|
fear_height = 4,
|
||||||
|
|
|
@ -42,7 +42,8 @@ mobs:register_mob("mobs_mc:squid", {
|
||||||
{name = mobs_mc.items.black_dye,
|
{name = mobs_mc.items.black_dye,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 3,},
|
max = 3,
|
||||||
|
looting = "common",},
|
||||||
},
|
},
|
||||||
visual_size = {x=3, y=3},
|
visual_size = {x=3, y=3},
|
||||||
makes_footstep_sound = false,
|
makes_footstep_sound = false,
|
||||||
|
|
|
@ -99,8 +99,7 @@ local professions = {
|
||||||
{
|
{
|
||||||
{ { "mcl_fishing:fish_raw", 6, 6, "mcl_core:emerald", 1, 1 }, { "mcl_fishing:fish_cooked", 6, 6 } },
|
{ { "mcl_fishing:fish_raw", 6, 6, "mcl_core:emerald", 1, 1 }, { "mcl_fishing:fish_cooked", 6, 6 } },
|
||||||
{ { "mcl_mobitems:string", 15, 20 }, E1 },
|
{ { "mcl_mobitems:string", 15, 20 }, E1 },
|
||||||
-- TODO: replace with enchanted fishing rod
|
{ { "mcl_core:emerald", 3, 11 }, { "mcl_fishing:fishing_rod_enchanted", 1, 1} },
|
||||||
{ { "mcl_core:emerald", 3, 11 }, { "mcl_fishing:fishing_rod", 1, 1} },
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -154,23 +153,27 @@ local professions = {
|
||||||
trades = {
|
trades = {
|
||||||
{
|
{
|
||||||
{ { "mcl_core:paper", 24, 36 }, E1 },
|
{ { "mcl_core:paper", 24, 36 }, E1 },
|
||||||
-- TODO: enchanted book
|
|
||||||
{ { "mcl_books:book", 8, 10 }, E1 },
|
{ { "mcl_books:book", 8, 10 }, E1 },
|
||||||
{ { "mcl_core:emerald", 10, 12 }, { "mcl_compass:compass", 1 ,1 }},
|
{ { "mcl_core:emerald", 10, 12 }, { "mcl_compass:compass", 1 ,1 }},
|
||||||
{ { "mcl_core:emerald", 3, 4 }, { "mcl_books:bookshelf", 1 ,1 }},
|
{ { "mcl_core:emerald", 3, 4 }, { "mcl_books:bookshelf", 1 ,1 }},
|
||||||
|
{ { "mcl_core:emerald", 5, 64 }, { "mcl_enchanting:book_enchanted", 1 ,1 }},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
{ { "mcl_books:written_book", 2, 2 }, E1 },
|
{ { "mcl_books:written_book", 2, 2 }, E1 },
|
||||||
{ { "mcl_core:emerald", 10, 12 }, { "mcl_clock:clock", 1, 1 } },
|
{ { "mcl_core:emerald", 10, 12 }, { "mcl_clock:clock", 1, 1 } },
|
||||||
{ E1, { "mcl_core:glass", 3, 5 } },
|
{ E1, { "mcl_core:glass", 3, 5 } },
|
||||||
|
{ { "mcl_core:emerald", 5, 64 }, { "mcl_enchanting:book_enchanted", 1 ,1 }},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
{ E1, { "mcl_core:glass", 3, 5 } },
|
{ E1, { "mcl_core:glass", 3, 5 } },
|
||||||
|
{ { "mcl_core:emerald", 5, 64 }, { "mcl_enchanting:book_enchanted", 1 ,1 }},
|
||||||
},
|
},
|
||||||
|
|
||||||
-- TODO: 2 enchanted book tiers
|
{
|
||||||
|
{ { "mcl_core:emerald", 5, 64 }, { "mcl_enchanting:book_enchanted", 1 ,1 }},
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
{ { "mcl_core:emerald", 20, 22 }, { "mcl_mobs:nametag", 1, 1 } },
|
{ { "mcl_core:emerald", 20, 22 }, { "mcl_mobs:nametag", 1, 1 } },
|
||||||
|
@ -214,8 +217,7 @@ local professions = {
|
||||||
|
|
||||||
{
|
{
|
||||||
{ { "mcl_core:diamond", 3, 4 }, E1 },
|
{ { "mcl_core:diamond", 3, 4 }, E1 },
|
||||||
-- TODO: enchant
|
{ { "mcl_core:emerald", 16, 19 }, { "mcl_armor:chestplate_diamond_enchanted", 1, 1 } },
|
||||||
{ { "mcl_core:emerald", 16, 19 }, { "mcl_armor:chestplate_diamond", 1, 1 } },
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -236,8 +238,7 @@ local professions = {
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
-- TODO: enchant
|
{ { "mcl_core:emerald", 7, 12 }, { "mcl_armor:chestplate_leather_enchanted", 1, 1 } },
|
||||||
{ { "mcl_core:emerald", 7, 12 }, { "mcl_armor:chestplate_leather", 1, 1 } },
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -272,16 +273,13 @@ local professions = {
|
||||||
|
|
||||||
{
|
{
|
||||||
{ { "mcl_core:iron_ingot", 7, 9 }, E1 },
|
{ { "mcl_core:iron_ingot", 7, 9 }, E1 },
|
||||||
-- TODO: enchant
|
{ { "mcl_core:emerald", 9, 10 }, { "mcl_tools:sword_iron_enchanted", 1, 1 } },
|
||||||
{ { "mcl_core:emerald", 9, 10 }, { "mcl_tools:sword_iron", 1, 1 } },
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
{ { "mcl_core:diamond", 3, 4 }, E1 },
|
{ { "mcl_core:diamond", 3, 4 }, E1 },
|
||||||
-- TODO: enchant
|
{ { "mcl_core:emerald", 12, 15 }, { "mcl_tools:sword_diamond_enchanted", 1, 1 } },
|
||||||
{ { "mcl_core:emerald", 12, 15 }, { "mcl_tools:sword_diamond", 1, 1 } },
|
{ { "mcl_core:emerald", 9, 12 }, { "mcl_tools:axe_diamond_enchanted", 1, 1 } },
|
||||||
-- TODO: enchant
|
|
||||||
{ { "mcl_core:emerald", 9, 12 }, { "mcl_tools:axe_diamond", 1, 1 } },
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -291,20 +289,17 @@ local professions = {
|
||||||
trades = {
|
trades = {
|
||||||
{
|
{
|
||||||
{ { "mcl_core:coal_lump", 16, 24 }, E1 },
|
{ { "mcl_core:coal_lump", 16, 24 }, E1 },
|
||||||
-- TODO: enchant
|
{ { "mcl_core:emerald", 5, 7 }, { "mcl_tools:shovel_iron_enchanted", 1, 1 } },
|
||||||
{ { "mcl_core:emerald", 5, 7 }, { "mcl_tools:shovel_iron", 1, 1 } },
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
{ { "mcl_core:iron_ingot", 7, 9 }, E1 },
|
{ { "mcl_core:iron_ingot", 7, 9 }, E1 },
|
||||||
-- TODO: enchant
|
{ { "mcl_core:emerald", 9, 11 }, { "mcl_tools:pick_iron_enchanted", 1, 1 } },
|
||||||
{ { "mcl_core:emerald", 9, 11 }, { "mcl_tools:pick_iron", 1, 1 } },
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
{ { "mcl_core:diamond", 3, 4 }, E1 },
|
{ { "mcl_core:diamond", 3, 4 }, E1 },
|
||||||
-- TODO: enchant
|
{ { "mcl_core:emerald", 12, 15 }, { "mcl_tools:pick_diamond_enchanted", 1, 1 } },
|
||||||
{ { "mcl_core:emerald", 12, 15 }, { "mcl_tools:pick_diamond", 1, 1 } },
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -328,7 +323,10 @@ local professions = {
|
||||||
TRADE_V6_RED_SANDSTONE,
|
TRADE_V6_RED_SANDSTONE,
|
||||||
},
|
},
|
||||||
|
|
||||||
-- TODO: Bottle 'o enchanting
|
{
|
||||||
|
{ { "mcl_nether:nether_wart_item", 22, 22 }, E1 },
|
||||||
|
{ { "mcl_core:emerald", 3, 3 }, { "mcl_experience:bottle", 1, 1 } },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nitwit = {
|
nitwit = {
|
||||||
|
@ -408,6 +406,15 @@ local init_trades = function(self, inv)
|
||||||
local offered_item = trade[2][1]
|
local offered_item = trade[2][1]
|
||||||
local offered_count = math.random(trade[2][2], trade[2][3])
|
local offered_count = math.random(trade[2][2], trade[2][3])
|
||||||
|
|
||||||
|
local offered_stack = ItemStack({name = offered_item, count = offered_count})
|
||||||
|
if mcl_enchanting.is_enchanted(offered_item) then
|
||||||
|
if mcl_enchanting.is_book(offered_item) then
|
||||||
|
offered_stack = mcl_enchanting.get_uniform_randomly_enchanted_book({"soul_speed"})
|
||||||
|
else
|
||||||
|
mcl_enchanting.enchant_randomly(offered_stack, math.random(5, 19), false, false, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local wanted = { wanted1_item .. " " ..wanted1_count }
|
local wanted = { wanted1_item .. " " ..wanted1_count }
|
||||||
if trade[1][4] then
|
if trade[1][4] then
|
||||||
local wanted2_item = trade[1][4]
|
local wanted2_item = trade[1][4]
|
||||||
|
@ -417,7 +424,7 @@ local init_trades = function(self, inv)
|
||||||
|
|
||||||
table.insert(trades, {
|
table.insert(trades, {
|
||||||
wanted = wanted,
|
wanted = wanted,
|
||||||
offered = offered_item .. " " .. offered_count,
|
offered = offered_stack:to_table(),
|
||||||
tier = tiernum, -- tier of this trade
|
tier = tiernum, -- tier of this trade
|
||||||
traded_once = false, -- true if trade was traded at least once
|
traded_once = false, -- true if trade was traded at least once
|
||||||
trade_counter = 0, -- how often the this trade was mate after the last time it got unlocked
|
trade_counter = 0, -- how often the this trade was mate after the last time it got unlocked
|
||||||
|
@ -426,6 +433,7 @@ local init_trades = function(self, inv)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self._trades = minetest.serialize(trades)
|
self._trades = minetest.serialize(trades)
|
||||||
|
minetest.deserialize(self._trades)
|
||||||
end
|
end
|
||||||
|
|
||||||
local set_trade = function(trader, player, inv, concrete_tradenum)
|
local set_trade = function(trader, player, inv, concrete_tradenum)
|
||||||
|
@ -513,7 +521,7 @@ local function show_trade_formspec(playername, trader, tradenum)
|
||||||
.."item_image[2,1;1,1;"..wanted1:to_string().."]"
|
.."item_image[2,1;1,1;"..wanted1:to_string().."]"
|
||||||
.."tooltip[2,1;0.8,0.8;"..F(wanted1:get_description()).."]"
|
.."tooltip[2,1;0.8,0.8;"..F(wanted1:get_description()).."]"
|
||||||
..w2_formspec
|
..w2_formspec
|
||||||
.."item_image[5.76,1;1,1;"..offered:to_string().."]"
|
.."item_image[5.76,1;1,1;"..offered:get_name().." "..offered:get_count().."]"
|
||||||
.."tooltip[5.76,1;0.8,0.8;"..F(offered:get_description()).."]"
|
.."tooltip[5.76,1;0.8,0.8;"..F(offered:get_description()).."]"
|
||||||
.."list["..tradeinv..";input;2,2.5;2,1;]"
|
.."list["..tradeinv..";input;2,2.5;2,1;]"
|
||||||
.."list["..tradeinv..";output;5.76,2.55;1,1;]"
|
.."list["..tradeinv..";output;5.76,2.55;1,1;]"
|
||||||
|
@ -954,6 +962,7 @@ mobs:register_mob("mobs_mc:villager", {
|
||||||
walk_velocity = 1.2,
|
walk_velocity = 1.2,
|
||||||
run_velocity = 2.4,
|
run_velocity = 2.4,
|
||||||
drops = {},
|
drops = {},
|
||||||
|
can_despawn = false,
|
||||||
-- TODO: sounds
|
-- TODO: sounds
|
||||||
animation = {
|
animation = {
|
||||||
stand_speed = 25,
|
stand_speed = 25,
|
||||||
|
|
|
@ -55,7 +55,8 @@ mobs:register_mob("mobs_mc:evoker", {
|
||||||
{name = mobs_mc.items.emerald,
|
{name = mobs_mc.items.emerald,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "common",},
|
||||||
{name = mobs_mc.items.totem,
|
{name = mobs_mc.items.totem,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 1,
|
min = 1,
|
||||||
|
|
|
@ -41,11 +41,13 @@ mobs:register_mob("mobs_mc:vindicator", {
|
||||||
{name = mobs_mc.items.emerald,
|
{name = mobs_mc.items.emerald,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "common",},
|
||||||
{name = mobs_mc.items.iron_axe,
|
{name = mobs_mc.items.iron_axe,
|
||||||
chance = 11,
|
chance = 100 / 8.5,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",},
|
||||||
},
|
},
|
||||||
-- TODO: sounds
|
-- TODO: sounds
|
||||||
animation = {
|
animation = {
|
||||||
|
@ -66,7 +68,6 @@ mobs:register_mob("mobs_mc:vindicator", {
|
||||||
},
|
},
|
||||||
view_range = 16,
|
view_range = 16,
|
||||||
fear_height = 4,
|
fear_height = 4,
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
-- spawn eggs
|
-- spawn eggs
|
||||||
|
|
|
@ -5,12 +5,25 @@
|
||||||
|
|
||||||
local S = minetest.get_translator("mobs_mc")
|
local S = minetest.get_translator("mobs_mc")
|
||||||
|
|
||||||
-- TODO: Turn villagers to zombie villager
|
|
||||||
|
|
||||||
--###################
|
--###################
|
||||||
--################### ZOMBIE VILLAGER
|
--################### ZOMBIE VILLAGER
|
||||||
--###################
|
--###################
|
||||||
|
|
||||||
|
local professions = {
|
||||||
|
farmer = "mobs_mc_villager_farmer.png",
|
||||||
|
fisherman = "mobs_mc_villager_farmer.png",
|
||||||
|
fletcher = "mobs_mc_villager_farmer.png",
|
||||||
|
shepherd = "mobs_mc_villager_farmer.png",
|
||||||
|
librarian = "mobs_mc_villager_librarian.png",
|
||||||
|
cartographer = "mobs_mc_villager_librarian.png",
|
||||||
|
armorer = "mobs_mc_villager_smith.png",
|
||||||
|
leatherworker = "mobs_mc_villager_butcher.png",
|
||||||
|
butcher = "mobs_mc_villager_butcher.png",
|
||||||
|
weapon_smith = "mobs_mc_villager_smith.png",
|
||||||
|
tool_smith = "mobs_mc_villager_smith.png",
|
||||||
|
cleric = "mobs_mc_villager_priest.png",
|
||||||
|
nitwit = "mobs_mc_villager.png",
|
||||||
|
}
|
||||||
|
|
||||||
mobs:register_mob("mobs_mc:villager_zombie", {
|
mobs:register_mob("mobs_mc:villager_zombie", {
|
||||||
type = "monster",
|
type = "monster",
|
||||||
|
@ -44,19 +57,26 @@ mobs:register_mob("mobs_mc:villager_zombie", {
|
||||||
{name = mobs_mc.items.rotten_flesh,
|
{name = mobs_mc.items.rotten_flesh,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 2,},
|
max = 2,
|
||||||
|
looting = "common",},
|
||||||
{name = mobs_mc.items.iron_ingot,
|
{name = mobs_mc.items.iron_ingot,
|
||||||
chance = 120, -- 2.5% / 3
|
chance = 120, -- 2.5% / 3
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_factor = 0.01 / 3,},
|
||||||
{name = mobs_mc.items.carrot,
|
{name = mobs_mc.items.carrot,
|
||||||
chance = 120, -- 2.5% / 3
|
chance = 120, -- 2.5% / 3
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_factor = 0.01 / 3,},
|
||||||
{name = mobs_mc.items.potato,
|
{name = mobs_mc.items.potato,
|
||||||
chance = 120, -- 2.5% / 3
|
chance = 120, -- 2.5% / 3
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_factor = 0.01 / 3,},
|
||||||
},
|
},
|
||||||
sounds = {
|
sounds = {
|
||||||
random = "mobs_mc_zombie_growl",
|
random = "mobs_mc_zombie_growl",
|
||||||
|
@ -75,14 +95,60 @@ mobs:register_mob("mobs_mc:villager_zombie", {
|
||||||
run_start = 0,
|
run_start = 0,
|
||||||
run_end = 20,
|
run_end = 20,
|
||||||
},
|
},
|
||||||
sunlight_damage = 1,
|
on_rightclick = function(self, clicker)
|
||||||
|
if not self._curing and clicker and clicker:is_player() then
|
||||||
|
local wielditem = clicker:get_wielded_item()
|
||||||
|
-- ToDo: Only cure if zombie villager has the weakness effect
|
||||||
|
if wielditem:get_name() == "mcl_core:apple_gold" then
|
||||||
|
wielditem:take_item()
|
||||||
|
clicker:set_wielded_item(wielditem)
|
||||||
|
self._curing = math.random(3 * 60, 5 * 60)
|
||||||
|
self.shaking = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
do_custom = function(self, dtime)
|
||||||
|
if self._curing then
|
||||||
|
self._curing = self._curing - dtime
|
||||||
|
local obj = self.object
|
||||||
|
if self._curing <= 0 then
|
||||||
|
local villager_obj = minetest.add_entity(obj:get_pos(), "mobs_mc:villager")
|
||||||
|
local villager = villager_obj:get_luaentity()
|
||||||
|
local yaw = obj:get_yaw()
|
||||||
|
villager_obj:set_yaw(yaw)
|
||||||
|
villager.target_yaw = yaw
|
||||||
|
villager.nametag = self.nametag
|
||||||
|
local texture = self.base_texture[1]:gsub("zombie", "villager")
|
||||||
|
if texture == "mobs_mc_villager_villager.png" then
|
||||||
|
texture = "mobs_mc_villager.png"
|
||||||
|
end
|
||||||
|
local textures = {texture}
|
||||||
|
villager.base_texture = textures
|
||||||
|
villager_obj:set_properties({textures = textures})
|
||||||
|
local matches = {}
|
||||||
|
for prof, tex in pairs(professions) do
|
||||||
|
if texture == tex then
|
||||||
|
table.insert(matches, prof)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
villager._profession = matches[math.random(#matches)]
|
||||||
|
self._curing = nil
|
||||||
|
mcl_burning.extinguish(obj)
|
||||||
|
obj:remove()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
sunlight_damage = 2,
|
||||||
|
ignited_by_sunlight = true,
|
||||||
view_range = 16,
|
view_range = 16,
|
||||||
fear_height = 4,
|
fear_height = 4,
|
||||||
harmed_by_heal = true,
|
harmed_by_heal = true,
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
mobs:spawn_specific("mobs_mc:villager_zombie", mobs_mc.spawn.village, {"air"}, 0, 7, 30, 4090, 4, mobs_mc.spawn_height.water+1, mobs_mc.spawn_height.overworld_max)
|
mobs:spawn_specific("mobs_mc:villager_zombie", mobs_mc.spawn.village, {"air"}, 0, 7, 30, 4090, 4, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max)
|
||||||
|
mobs:spawn_specific("mobs_mc:villager_zombie", mobs_mc.spawn.solid, {"air"}, 0, 7, 30, 60000, 4, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max)
|
||||||
|
|
||||||
-- spawn eggs
|
-- spawn eggs
|
||||||
mobs:register_egg("mobs_mc:villager_zombie", S("Zombie Villager"), "mobs_mc_spawn_icon_zombie_villager.png", 0)
|
mobs:register_egg("mobs_mc:villager_zombie", S("Zombie Villager"), "mobs_mc_spawn_icon_zombie_villager.png", 0)
|
||||||
|
|
||||||
|
|
|
@ -41,13 +41,13 @@ mobs:register_mob("mobs_mc:witch", {
|
||||||
dogshoot_count_max =1.8,
|
dogshoot_count_max =1.8,
|
||||||
max_drops = 3,
|
max_drops = 3,
|
||||||
drops = {
|
drops = {
|
||||||
{name = mobs_mc.items.glass_bottle, chance = 8, min = 0, max = 2,},
|
{name = mobs_mc.items.glass_bottle, chance = 8, min = 0, max = 2, looting = "common",},
|
||||||
{name = mobs_mc.items.glowstone_dust, chance = 8, min = 0, max = 2,},
|
{name = mobs_mc.items.glowstone_dust, chance = 8, min = 0, max = 2, looting = "common",},
|
||||||
{name = mobs_mc.items.gunpowder, chance = 8, min = 0, max = 2,},
|
{name = mobs_mc.items.gunpowder, chance = 8, min = 0, max = 2, looting = "common",},
|
||||||
{name = mobs_mc.items.redstone, chance = 8, min = 0, max = 2,},
|
{name = mobs_mc.items.redstone, chance = 8, min = 0, max = 2, looting = "common",},
|
||||||
{name = mobs_mc.items.spider_eye, chance = 8, min = 0, max = 2,},
|
{name = mobs_mc.items.spider_eye, chance = 8, min = 0, max = 2, looting = "common",},
|
||||||
{name = mobs_mc.items.sugar, chance = 8, min = 0, max = 2,},
|
{name = mobs_mc.items.sugar, chance = 8, min = 0, max = 2, looting = "common",},
|
||||||
{name = mobs_mc.items.stick, chance = 4, min = 0, max = 2,},
|
{name = mobs_mc.items.stick, chance = 4, min = 0, max = 2, looting = "common",},
|
||||||
},
|
},
|
||||||
-- TODO: sounds
|
-- TODO: sounds
|
||||||
animation = {
|
animation = {
|
||||||
|
@ -68,7 +68,6 @@ mobs:register_mob("mobs_mc:witch", {
|
||||||
},
|
},
|
||||||
view_range = 16,
|
view_range = 16,
|
||||||
fear_height = 4,
|
fear_height = 4,
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
-- potion projectile (EXPERIMENTAL)
|
-- potion projectile (EXPERIMENTAL)
|
||||||
|
|
|
@ -13,19 +13,26 @@ local drops_common = {
|
||||||
{name = mobs_mc.items.rotten_flesh,
|
{name = mobs_mc.items.rotten_flesh,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 2,},
|
max = 2,
|
||||||
|
looting = "common",},
|
||||||
{name = mobs_mc.items.iron_ingot,
|
{name = mobs_mc.items.iron_ingot,
|
||||||
chance = 120, -- 2.5% / 3
|
chance = 120, -- 2.5% / 3
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_factor = 0.01 / 3,},
|
||||||
{name = mobs_mc.items.carrot,
|
{name = mobs_mc.items.carrot,
|
||||||
chance = 120, -- 2.5% / 3
|
chance = 120, -- 2.5% / 3
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_factor = 0.01 / 3,},
|
||||||
{name = mobs_mc.items.potato,
|
{name = mobs_mc.items.potato,
|
||||||
chance = 120, -- 2.5% / 3
|
chance = 120, -- 2.5% / 3
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare",
|
||||||
|
looting_factor = 0.01 / 3,},
|
||||||
}
|
}
|
||||||
|
|
||||||
local drops_zombie = table.copy(drops_common)
|
local drops_zombie = table.copy(drops_common)
|
||||||
|
@ -78,6 +85,7 @@ local zombie = {
|
||||||
walk_start = 0, walk_end = 40,
|
walk_start = 0, walk_end = 40,
|
||||||
run_start = 0, run_end = 40,
|
run_start = 0, run_end = 40,
|
||||||
},
|
},
|
||||||
|
ignited_by_sunlight = true,
|
||||||
sunlight_damage = 2,
|
sunlight_damage = 2,
|
||||||
view_range = 16,
|
view_range = 16,
|
||||||
attack_type = "dogfight",
|
attack_type = "dogfight",
|
||||||
|
@ -104,6 +112,7 @@ mobs:register_mob("mobs_mc:baby_zombie", baby_zombie)
|
||||||
-- Desert variant of the zombie
|
-- Desert variant of the zombie
|
||||||
local husk = table.copy(zombie)
|
local husk = table.copy(zombie)
|
||||||
husk.textures = {{"mobs_mc_husk.png"}}
|
husk.textures = {{"mobs_mc_husk.png"}}
|
||||||
|
husk.ignited_by_sunlight = false
|
||||||
husk.sunlight_damage = 0
|
husk.sunlight_damage = 0
|
||||||
husk.drops = drops_common
|
husk.drops = drops_common
|
||||||
-- TODO: Husks avoid water
|
-- TODO: Husks avoid water
|
||||||
|
|
|
@ -19,7 +19,6 @@ local pigman = {
|
||||||
hp_max = 20,
|
hp_max = 20,
|
||||||
xp_min = 6,
|
xp_min = 6,
|
||||||
xp_max = 6,
|
xp_max = 6,
|
||||||
breath_max = -1,
|
|
||||||
armor = {undead = 90, fleshy = 90},
|
armor = {undead = 90, fleshy = 90},
|
||||||
attack_type = "dogfight",
|
attack_type = "dogfight",
|
||||||
group_attack = { "mobs_mc:pigman", "mobs_mc:baby_pigman" },
|
group_attack = { "mobs_mc:pigman", "mobs_mc:baby_pigman" },
|
||||||
|
@ -50,19 +49,23 @@ local pigman = {
|
||||||
{name = mobs_mc.items.rotten_flesh,
|
{name = mobs_mc.items.rotten_flesh,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "common"},
|
||||||
{name = mobs_mc.items.gold_nugget,
|
{name = mobs_mc.items.gold_nugget,
|
||||||
chance = 1,
|
chance = 1,
|
||||||
min = 0,
|
min = 0,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "common"},
|
||||||
{name = mobs_mc.items.gold_ingot,
|
{name = mobs_mc.items.gold_ingot,
|
||||||
chance = 40, -- 2.5%
|
chance = 40, -- 2.5%
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare"},
|
||||||
{name = mobs_mc.items.gold_sword,
|
{name = mobs_mc.items.gold_sword,
|
||||||
chance = 12, -- 8.333%, approximation to 8.5%
|
chance = 100 / 8.5,
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 1,},
|
max = 1,
|
||||||
|
looting = "rare"},
|
||||||
},
|
},
|
||||||
animation = {
|
animation = {
|
||||||
stand_speed = 25,
|
stand_speed = 25,
|
||||||
|
@ -82,6 +85,7 @@ local pigman = {
|
||||||
fear_height = 4,
|
fear_height = 4,
|
||||||
view_range = 16,
|
view_range = 16,
|
||||||
harmed_by_heal = true,
|
harmed_by_heal = true,
|
||||||
|
fire_damage_resistant = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
mobs:register_mob("mobs_mc:pigman", pigman)
|
mobs:register_mob("mobs_mc:pigman", pigman)
|
||||||
|
|
|
@ -65,7 +65,7 @@ minetest.register_globalstep(function(dtime)
|
||||||
if is_immortal or not enable_damage then
|
if is_immortal or not enable_damage then
|
||||||
-- If damage is disabled, we can't kill players.
|
-- If damage is disabled, we can't kill players.
|
||||||
-- So we just teleport the player back to spawn.
|
-- So we just teleport the player back to spawn.
|
||||||
local spawn = mcl_spawn.get_spawn_pos(player)
|
local spawn = mcl_spawn.get_player_spawn_pos(player)
|
||||||
player:set_pos(spawn)
|
player:set_pos(spawn)
|
||||||
mcl_worlds.dimension_change(player, mcl_worlds.pos_to_dimension(spawn))
|
mcl_worlds.dimension_change(player, mcl_worlds.pos_to_dimension(spawn))
|
||||||
minetest.chat_send_player(player:get_player_name(), S("The void is off-limits to you!"))
|
minetest.chat_send_player(player:get_player_name(), S("The void is off-limits to you!"))
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
local modpath = minetest.get_modpath("mcl_weather");
|
local modpath = minetest.get_modpath("mcl_weather")
|
||||||
|
|
||||||
mcl_weather = {}
|
mcl_weather = {}
|
||||||
|
|
||||||
-- If not located then embeded skycolor mod version will be loaded.
|
-- If not located then embeded skycolor mod version will be loaded.
|
||||||
if minetest.get_modpath("skycolor") == nil then
|
if minetest.get_modpath("skycolor") == nil then
|
||||||
dofile(modpath.."/skycolor.lua")
|
dofile(modpath.."/skycolor.lua")
|
||||||
end
|
end
|
||||||
|
|
||||||
dofile(modpath.."/weather_core.lua")
|
dofile(modpath.."/weather_core.lua")
|
||||||
|
@ -13,5 +13,5 @@ dofile(modpath.."/rain.lua")
|
||||||
dofile(modpath.."/nether_dust.lua")
|
dofile(modpath.."/nether_dust.lua")
|
||||||
|
|
||||||
if minetest.get_modpath("lightning") ~= nil then
|
if minetest.get_modpath("lightning") ~= nil then
|
||||||
dofile(modpath.."/thunder.lua")
|
dofile(modpath.."/thunder.lua")
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,11 +24,8 @@ end
|
||||||
local timer = 0
|
local timer = 0
|
||||||
minetest.register_globalstep(function(dtime)
|
minetest.register_globalstep(function(dtime)
|
||||||
timer = timer + dtime
|
timer = timer + dtime
|
||||||
if timer >= 0.7 then
|
if timer < 0.7 then return end
|
||||||
timer = 0
|
timer = 0
|
||||||
else
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, player in ipairs(minetest.get_connected_players()) do
|
for _, player in ipairs(minetest.get_connected_players()) do
|
||||||
if not mcl_worlds.has_dust(player:get_pos()) then
|
if not mcl_worlds.has_dust(player:get_pos()) then
|
||||||
|
|
|
@ -2,198 +2,198 @@ local PARTICLES_COUNT_RAIN = 30
|
||||||
local PARTICLES_COUNT_THUNDER = 45
|
local PARTICLES_COUNT_THUNDER = 45
|
||||||
|
|
||||||
mcl_weather.rain = {
|
mcl_weather.rain = {
|
||||||
-- max rain particles created at time
|
-- max rain particles created at time
|
||||||
particles_count = PARTICLES_COUNT_RAIN,
|
particles_count = PARTICLES_COUNT_RAIN,
|
||||||
|
|
||||||
-- flag to turn on/off extinguish fire for rain
|
-- flag to turn on/off extinguish fire for rain
|
||||||
extinguish_fire = true,
|
extinguish_fire = true,
|
||||||
|
|
||||||
-- flag useful when mixing weathers
|
-- flag useful when mixing weathers
|
||||||
raining = false,
|
raining = false,
|
||||||
|
|
||||||
-- keeping last timeofday value (rounded).
|
-- keeping last timeofday value (rounded).
|
||||||
-- Defaulted to non-existing value for initial comparing.
|
-- Defaulted to non-existing value for initial comparing.
|
||||||
sky_last_update = -1,
|
sky_last_update = -1,
|
||||||
|
|
||||||
init_done = false,
|
init_done = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
mcl_weather.rain.sound_handler = function(player)
|
mcl_weather.rain.sound_handler = function(player)
|
||||||
return minetest.sound_play("weather_rain", {
|
return minetest.sound_play("weather_rain", {
|
||||||
to_player = player:get_player_name(),
|
to_player = player:get_player_name(),
|
||||||
loop = true,
|
loop = true,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- set skybox based on time (uses skycolor api)
|
-- set skybox based on time (uses skycolor api)
|
||||||
mcl_weather.rain.set_sky_box = function()
|
mcl_weather.rain.set_sky_box = function()
|
||||||
if mcl_weather.state == "rain" then
|
if mcl_weather.state == "rain" then
|
||||||
mcl_weather.skycolor.add_layer(
|
mcl_weather.skycolor.add_layer(
|
||||||
"weather-pack-rain-sky",
|
"weather-pack-rain-sky",
|
||||||
{{r=0, g=0, b=0},
|
{{r=0, g=0, b=0},
|
||||||
{r=85, g=86, b=98},
|
{r=85, g=86, b=98},
|
||||||
{r=135, g=135, b=151},
|
{r=135, g=135, b=151},
|
||||||
{r=85, g=86, b=98},
|
{r=85, g=86, b=98},
|
||||||
{r=0, g=0, b=0}})
|
{r=0, g=0, b=0}})
|
||||||
mcl_weather.skycolor.active = true
|
mcl_weather.skycolor.active = true
|
||||||
for _, player in pairs(minetest.get_connected_players()) do
|
for _, player in pairs(minetest.get_connected_players()) do
|
||||||
player:set_clouds({color="#5D5D5FE8"})
|
player:set_clouds({color="#5D5D5FE8"})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- creating manually parctiles instead of particles spawner because of easier to control
|
-- creating manually parctiles instead of particles spawner because of easier to control
|
||||||
-- spawn position.
|
-- spawn position.
|
||||||
mcl_weather.rain.add_rain_particles = function(player)
|
mcl_weather.rain.add_rain_particles = function(player)
|
||||||
|
|
||||||
mcl_weather.rain.last_rp_count = 0
|
mcl_weather.rain.last_rp_count = 0
|
||||||
for i=mcl_weather.rain.particles_count, 1,-1 do
|
for i=mcl_weather.rain.particles_count, 1,-1 do
|
||||||
local random_pos_x, random_pos_y, random_pos_z = mcl_weather.get_random_pos_by_player_look_dir(player)
|
local random_pos_x, random_pos_y, random_pos_z = mcl_weather.get_random_pos_by_player_look_dir(player)
|
||||||
if mcl_weather.is_outdoor({x=random_pos_x, y=random_pos_y, z=random_pos_z}) then
|
if mcl_weather.is_outdoor({x=random_pos_x, y=random_pos_y, z=random_pos_z}) then
|
||||||
mcl_weather.rain.last_rp_count = mcl_weather.rain.last_rp_count + 1
|
mcl_weather.rain.last_rp_count = mcl_weather.rain.last_rp_count + 1
|
||||||
minetest.add_particle({
|
minetest.add_particle({
|
||||||
pos = {x=random_pos_x, y=random_pos_y, z=random_pos_z},
|
pos = {x=random_pos_x, y=random_pos_y, z=random_pos_z},
|
||||||
velocity = {x=0, y=-10, z=0},
|
velocity = {x=0, y=-10, z=0},
|
||||||
acceleration = {x=0, y=-30, z=0},
|
acceleration = {x=0, y=-30, z=0},
|
||||||
expirationtime = 1.0,
|
expirationtime = 1.0,
|
||||||
size = math.random(0.5, 3),
|
size = math.random(0.5, 3),
|
||||||
collisiondetection = true,
|
collisiondetection = true,
|
||||||
collision_removal = true,
|
collision_removal = true,
|
||||||
vertical = true,
|
vertical = true,
|
||||||
texture = mcl_weather.rain.get_texture(),
|
texture = mcl_weather.rain.get_texture(),
|
||||||
playername = player:get_player_name()
|
playername = player:get_player_name()
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Simple random texture getter
|
-- Simple random texture getter
|
||||||
mcl_weather.rain.get_texture = function()
|
mcl_weather.rain.get_texture = function()
|
||||||
local texture_name
|
local texture_name
|
||||||
local random_number = math.random()
|
local random_number = math.random()
|
||||||
if random_number > 0.33 then
|
if random_number > 0.33 then
|
||||||
texture_name = "weather_pack_rain_raindrop_1.png"
|
texture_name = "weather_pack_rain_raindrop_1.png"
|
||||||
elseif random_number > 0.66 then
|
elseif random_number > 0.66 then
|
||||||
texture_name = "weather_pack_rain_raindrop_2.png"
|
texture_name = "weather_pack_rain_raindrop_2.png"
|
||||||
else
|
else
|
||||||
texture_name = "weather_pack_rain_raindrop_3.png"
|
texture_name = "weather_pack_rain_raindrop_3.png"
|
||||||
end
|
end
|
||||||
return texture_name;
|
return texture_name;
|
||||||
end
|
end
|
||||||
|
|
||||||
-- register player for rain weather.
|
-- register player for rain weather.
|
||||||
-- basically needs for origin sky reference and rain sound controls.
|
-- basically needs for origin sky reference and rain sound controls.
|
||||||
mcl_weather.rain.add_player = function(player)
|
mcl_weather.rain.add_player = function(player)
|
||||||
if mcl_weather.players[player:get_player_name()] == nil then
|
if mcl_weather.players[player:get_player_name()] == nil then
|
||||||
local player_meta = {}
|
local player_meta = {}
|
||||||
player_meta.origin_sky = {player:get_sky()}
|
player_meta.origin_sky = {player:get_sky()}
|
||||||
mcl_weather.players[player:get_player_name()] = player_meta
|
mcl_weather.players[player:get_player_name()] = player_meta
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- remove player from player list effected by rain.
|
-- remove player from player list effected by rain.
|
||||||
-- be sure to remove sound before removing player otherwise soundhandler reference will be lost.
|
-- be sure to remove sound before removing player otherwise soundhandler reference will be lost.
|
||||||
mcl_weather.rain.remove_player = function(player)
|
mcl_weather.rain.remove_player = function(player)
|
||||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||||
if player_meta ~= nil and player_meta.origin_sky ~= nil then
|
if player_meta ~= nil and player_meta.origin_sky ~= nil then
|
||||||
player:set_clouds({color="#FFF0F0E5"})
|
player:set_clouds({color="#FFF0F0E5"})
|
||||||
mcl_weather.players[player:get_player_name()] = nil
|
mcl_weather.players[player:get_player_name()] = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
mcl_worlds.register_on_dimension_change(function(player, dimension)
|
mcl_worlds.register_on_dimension_change(function(player, dimension)
|
||||||
if dimension ~= "overworld" and dimension ~= "void" then
|
if dimension ~= "overworld" and dimension ~= "void" then
|
||||||
mcl_weather.rain.remove_sound(player)
|
mcl_weather.rain.remove_sound(player)
|
||||||
mcl_weather.rain.remove_player(player)
|
mcl_weather.rain.remove_player(player)
|
||||||
elseif dimension == "overworld" then
|
elseif dimension == "overworld" then
|
||||||
mcl_weather.rain.update_sound(player)
|
mcl_weather.rain.update_sound(player)
|
||||||
if mcl_weather.rain.raining then
|
if mcl_weather.rain.raining then
|
||||||
mcl_weather.rain.add_rain_particles(player)
|
mcl_weather.rain.add_rain_particles(player)
|
||||||
mcl_weather.rain.add_player(player)
|
mcl_weather.rain.add_player(player)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- adds and removes rain sound depending how much rain particles around player currently exist.
|
-- adds and removes rain sound depending how much rain particles around player currently exist.
|
||||||
-- have few seconds delay before each check to avoid on/off sound too often
|
-- have few seconds delay before each check to avoid on/off sound too often
|
||||||
-- when player stay on 'edge' where sound should play and stop depending from random raindrop appearance.
|
-- when player stay on 'edge' where sound should play and stop depending from random raindrop appearance.
|
||||||
mcl_weather.rain.update_sound = function(player)
|
mcl_weather.rain.update_sound = function(player)
|
||||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||||
if player_meta ~= nil then
|
if player_meta ~= nil then
|
||||||
if player_meta.sound_updated ~= nil and player_meta.sound_updated + 5 > minetest.get_gametime() then
|
if player_meta.sound_updated ~= nil and player_meta.sound_updated + 5 > minetest.get_gametime() then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
if player_meta.sound_handler ~= nil then
|
if player_meta.sound_handler ~= nil then
|
||||||
if mcl_weather.rain.last_rp_count == 0 then
|
if mcl_weather.rain.last_rp_count == 0 then
|
||||||
minetest.sound_fade(player_meta.sound_handler, -0.5, 0.0)
|
minetest.sound_fade(player_meta.sound_handler, -0.5, 0.0)
|
||||||
player_meta.sound_handler = nil
|
player_meta.sound_handler = nil
|
||||||
end
|
end
|
||||||
elseif mcl_weather.rain.last_rp_count > 0 then
|
elseif mcl_weather.rain.last_rp_count > 0 then
|
||||||
player_meta.sound_handler = mcl_weather.rain.sound_handler(player)
|
player_meta.sound_handler = mcl_weather.rain.sound_handler(player)
|
||||||
end
|
end
|
||||||
|
|
||||||
player_meta.sound_updated = minetest.get_gametime()
|
player_meta.sound_updated = minetest.get_gametime()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- rain sound removed from player.
|
-- rain sound removed from player.
|
||||||
mcl_weather.rain.remove_sound = function(player)
|
mcl_weather.rain.remove_sound = function(player)
|
||||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||||
if player_meta ~= nil and player_meta.sound_handler ~= nil then
|
if player_meta ~= nil and player_meta.sound_handler ~= nil then
|
||||||
minetest.sound_fade(player_meta.sound_handler, -0.5, 0.0)
|
minetest.sound_fade(player_meta.sound_handler, -0.5, 0.0)
|
||||||
player_meta.sound_handler = nil
|
player_meta.sound_handler = nil
|
||||||
player_meta.sound_updated = nil
|
player_meta.sound_updated = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- callback function for removing rain
|
-- callback function for removing rain
|
||||||
mcl_weather.rain.clear = function()
|
mcl_weather.rain.clear = function()
|
||||||
mcl_weather.rain.raining = false
|
mcl_weather.rain.raining = false
|
||||||
mcl_weather.rain.sky_last_update = -1
|
mcl_weather.rain.sky_last_update = -1
|
||||||
mcl_weather.rain.init_done = false
|
mcl_weather.rain.init_done = false
|
||||||
mcl_weather.rain.set_particles_mode("rain")
|
mcl_weather.rain.set_particles_mode("rain")
|
||||||
mcl_weather.skycolor.remove_layer("weather-pack-rain-sky")
|
mcl_weather.skycolor.remove_layer("weather-pack-rain-sky")
|
||||||
for _, player in ipairs(minetest.get_connected_players()) do
|
for _, player in ipairs(minetest.get_connected_players()) do
|
||||||
mcl_weather.rain.remove_sound(player)
|
mcl_weather.rain.remove_sound(player)
|
||||||
mcl_weather.rain.remove_player(player)
|
mcl_weather.rain.remove_player(player)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_globalstep(function(dtime)
|
minetest.register_globalstep(function(dtime)
|
||||||
if mcl_weather.state ~= "rain" then
|
if mcl_weather.state ~= "rain" then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
mcl_weather.rain.make_weather()
|
mcl_weather.rain.make_weather()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
mcl_weather.rain.make_weather = function()
|
mcl_weather.rain.make_weather = function()
|
||||||
if mcl_weather.rain.init_done == false then
|
if mcl_weather.rain.init_done == false then
|
||||||
mcl_weather.rain.raining = true
|
mcl_weather.rain.raining = true
|
||||||
mcl_weather.rain.set_sky_box()
|
mcl_weather.rain.set_sky_box()
|
||||||
mcl_weather.rain.set_particles_mode(mcl_weather.mode)
|
mcl_weather.rain.set_particles_mode(mcl_weather.mode)
|
||||||
mcl_weather.rain.init_done = true
|
mcl_weather.rain.init_done = true
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, player in ipairs(minetest.get_connected_players()) do
|
for _, player in ipairs(minetest.get_connected_players()) do
|
||||||
if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos())) then
|
if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos())) then
|
||||||
mcl_weather.rain.remove_sound(player)
|
mcl_weather.rain.remove_sound(player)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
mcl_weather.rain.add_player(player)
|
mcl_weather.rain.add_player(player)
|
||||||
mcl_weather.rain.add_rain_particles(player)
|
mcl_weather.rain.add_rain_particles(player)
|
||||||
mcl_weather.rain.update_sound(player)
|
mcl_weather.rain.update_sound(player)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Switch the number of raindrops: "thunder" for many raindrops, otherwise for normal raindrops
|
-- Switch the number of raindrops: "thunder" for many raindrops, otherwise for normal raindrops
|
||||||
mcl_weather.rain.set_particles_mode = function(mode)
|
mcl_weather.rain.set_particles_mode = function(mode)
|
||||||
if mode == "thunder" then
|
if mode == "thunder" then
|
||||||
mcl_weather.rain.particles_count = PARTICLES_COUNT_THUNDER
|
mcl_weather.rain.particles_count = PARTICLES_COUNT_THUNDER
|
||||||
else
|
else
|
||||||
mcl_weather.rain.particles_count = PARTICLES_COUNT_RAIN
|
mcl_weather.rain.particles_count = PARTICLES_COUNT_RAIN
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if mcl_weather.allow_abm then
|
if mcl_weather.allow_abm then
|
||||||
|
@ -266,16 +266,16 @@ if mcl_weather.allow_abm then
|
||||||
end
|
end
|
||||||
|
|
||||||
if mcl_weather.reg_weathers.rain == nil then
|
if mcl_weather.reg_weathers.rain == nil then
|
||||||
mcl_weather.reg_weathers.rain = {
|
mcl_weather.reg_weathers.rain = {
|
||||||
clear = mcl_weather.rain.clear,
|
clear = mcl_weather.rain.clear,
|
||||||
light_factor = 0.6,
|
light_factor = 0.6,
|
||||||
-- 10min - 20min
|
-- 10min - 20min
|
||||||
min_duration = 600,
|
min_duration = 600,
|
||||||
max_duration = 1200,
|
max_duration = 1200,
|
||||||
transitions = {
|
transitions = {
|
||||||
[65] = "none",
|
[65] = "none",
|
||||||
[70] = "snow",
|
[70] = "snow",
|
||||||
[100] = "thunder",
|
[100] = "thunder",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -81,17 +81,16 @@ end)
|
||||||
|
|
||||||
-- register snow weather
|
-- register snow weather
|
||||||
if mcl_weather.reg_weathers.snow == nil then
|
if mcl_weather.reg_weathers.snow == nil then
|
||||||
mcl_weather.reg_weathers.snow = {
|
mcl_weather.reg_weathers.snow = {
|
||||||
clear = mcl_weather.snow.clear,
|
clear = mcl_weather.snow.clear,
|
||||||
light_factor = 0.6,
|
light_factor = 0.6,
|
||||||
-- 10min - 20min
|
-- 10min - 20min
|
||||||
min_duration = 600,
|
min_duration = 600,
|
||||||
max_duration = 1200,
|
max_duration = 1200,
|
||||||
transitions = {
|
transitions = {
|
||||||
[65] = "none",
|
[65] = "none",
|
||||||
[80] = "rain",
|
[80] = "rain",
|
||||||
[100] = "thunder",
|
[100] = "thunder",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@ mcl_weather.state = "none"
|
||||||
-- player list for saving player meta info
|
-- player list for saving player meta info
|
||||||
mcl_weather.players = {}
|
mcl_weather.players = {}
|
||||||
|
|
||||||
-- default weather recalculation interval
|
-- default weather check interval for global step
|
||||||
mcl_weather.check_interval = 300
|
mcl_weather.check_interval = 5
|
||||||
|
|
||||||
-- weather min duration
|
-- weather min duration
|
||||||
mcl_weather.min_duration = 600
|
mcl_weather.min_duration = 600
|
||||||
|
@ -25,14 +25,14 @@ mcl_weather.reg_weathers = {}
|
||||||
mcl_weather.allow_abm = true
|
mcl_weather.allow_abm = true
|
||||||
|
|
||||||
mcl_weather.reg_weathers["none"] = {
|
mcl_weather.reg_weathers["none"] = {
|
||||||
min_duration = mcl_weather.min_duration,
|
min_duration = mcl_weather.min_duration,
|
||||||
max_duration = mcl_weather.max_duration,
|
max_duration = mcl_weather.max_duration,
|
||||||
light_factor = nil,
|
light_factor = nil,
|
||||||
transitions = {
|
transitions = {
|
||||||
[50] = "rain",
|
[50] = "rain",
|
||||||
[100] = "snow",
|
[100] = "snow",
|
||||||
},
|
},
|
||||||
clear = function() end,
|
clear = function() end,
|
||||||
}
|
}
|
||||||
|
|
||||||
local storage = minetest.get_mod_storage()
|
local storage = minetest.get_mod_storage()
|
||||||
|
@ -45,211 +45,230 @@ end
|
||||||
minetest.register_on_shutdown(save_weather)
|
minetest.register_on_shutdown(save_weather)
|
||||||
|
|
||||||
mcl_weather.get_rand_end_time = function(min_duration, max_duration)
|
mcl_weather.get_rand_end_time = function(min_duration, max_duration)
|
||||||
local r
|
local r
|
||||||
if min_duration ~= nil and max_duration ~= nil then
|
if min_duration ~= nil and max_duration ~= nil then
|
||||||
r = math.random(min_duration, max_duration);
|
r = math.random(min_duration, max_duration)
|
||||||
else
|
else
|
||||||
r = math.random(mcl_weather.min_duration, mcl_weather.max_duration);
|
r = math.random(mcl_weather.min_duration, mcl_weather.max_duration)
|
||||||
end
|
end
|
||||||
return minetest.get_gametime() + r
|
return minetest.get_gametime() + r
|
||||||
end
|
end
|
||||||
|
|
||||||
mcl_weather.get_current_light_factor = function()
|
mcl_weather.get_current_light_factor = function()
|
||||||
if mcl_weather.state == "none" then
|
if mcl_weather.state == "none" then
|
||||||
return nil
|
return nil
|
||||||
else
|
else
|
||||||
return mcl_weather.reg_weathers[mcl_weather.state].light_factor
|
return mcl_weather.reg_weathers[mcl_weather.state].light_factor
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Returns true if pos is outdoor.
|
-- Returns true if pos is outdoor.
|
||||||
-- Outdoor is defined as any node in the Overworld under open sky.
|
-- Outdoor is defined as any node in the Overworld under open sky.
|
||||||
-- FIXME: Nodes below glass also count as “outdoor”, this should not be the case.
|
-- FIXME: Nodes below glass also count as “outdoor”, this should not be the case.
|
||||||
mcl_weather.is_outdoor = function(pos)
|
mcl_weather.is_outdoor = function(pos)
|
||||||
local cpos = {x=pos.x, y=pos.y+1, z=pos.z}
|
local cpos = {x=pos.x, y=pos.y+1, z=pos.z}
|
||||||
local dim = mcl_worlds.pos_to_dimension(cpos)
|
local dim = mcl_worlds.pos_to_dimension(cpos)
|
||||||
if minetest.get_node_light(cpos, 0.5) == 15 and dim == "overworld" then
|
if minetest.get_node_light(cpos, 0.5) == 15 and dim == "overworld" then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- checks if player is undewater. This is needed in order to
|
-- checks if player is undewater. This is needed in order to
|
||||||
-- turn off weather particles generation.
|
-- turn off weather particles generation.
|
||||||
mcl_weather.is_underwater = function(player)
|
mcl_weather.is_underwater = function(player)
|
||||||
local ppos = player:get_pos()
|
local ppos = player:get_pos()
|
||||||
local offset = player:get_eye_offset()
|
local offset = player:get_eye_offset()
|
||||||
local player_eye_pos = {x = ppos.x + offset.x,
|
local player_eye_pos = {x = ppos.x + offset.x,
|
||||||
y = ppos.y + offset.y + 1.5,
|
y = ppos.y + offset.y + 1.5,
|
||||||
z = ppos.z + offset.z}
|
z = ppos.z + offset.z}
|
||||||
local node_level = minetest.get_node_level(player_eye_pos)
|
local node_level = minetest.get_node_level(player_eye_pos)
|
||||||
if node_level == 8 or node_level == 7 then
|
if node_level == 8 or node_level == 7 then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- trying to locate position for particles by player look direction for performance reason.
|
-- trying to locate position for particles by player look direction for performance reason.
|
||||||
-- it is costly to generate many particles around player so goal is focus mainly on front view.
|
-- it is costly to generate many particles around player so goal is focus mainly on front view.
|
||||||
mcl_weather.get_random_pos_by_player_look_dir = function(player)
|
mcl_weather.get_random_pos_by_player_look_dir = function(player)
|
||||||
local look_dir = player:get_look_dir()
|
local look_dir = player:get_look_dir()
|
||||||
local player_pos = player:get_pos()
|
local player_pos = player:get_pos()
|
||||||
|
|
||||||
local random_pos_x = 0
|
local random_pos_x = 0
|
||||||
local random_pos_y = 0
|
local random_pos_y = 0
|
||||||
local random_pos_z = 0
|
local random_pos_z = 0
|
||||||
|
|
||||||
if look_dir.x > 0 then
|
if look_dir.x > 0 then
|
||||||
if look_dir.z > 0 then
|
if look_dir.z > 0 then
|
||||||
random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 5)
|
random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 5)
|
||||||
random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5)
|
random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5)
|
||||||
else
|
else
|
||||||
random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 5)
|
random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 5)
|
||||||
random_pos_z = math.random() + math.random(player_pos.z - 5, player_pos.z + 2.5)
|
random_pos_z = math.random() + math.random(player_pos.z - 5, player_pos.z + 2.5)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if look_dir.z > 0 then
|
if look_dir.z > 0 then
|
||||||
random_pos_x = math.random() + math.random(player_pos.x - 5, player_pos.x + 2.5)
|
random_pos_x = math.random() + math.random(player_pos.x - 5, player_pos.x + 2.5)
|
||||||
random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5)
|
random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5)
|
||||||
else
|
else
|
||||||
random_pos_x = math.random() + math.random(player_pos.x - 5, player_pos.x + 2.5)
|
random_pos_x = math.random() + math.random(player_pos.x - 5, player_pos.x + 2.5)
|
||||||
random_pos_z = math.random() + math.random(player_pos.z - 5, player_pos.z + 2.5)
|
random_pos_z = math.random() + math.random(player_pos.z - 5, player_pos.z + 2.5)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
random_pos_y = math.random() + math.random(player_pos.y + 10, player_pos.y + 15)
|
random_pos_y = math.random() + math.random(player_pos.y + 10, player_pos.y + 15)
|
||||||
return random_pos_x, random_pos_y, random_pos_z
|
return random_pos_x, random_pos_y, random_pos_z
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local t, wci = 0, mcl_weather.check_interval
|
||||||
minetest.register_globalstep(function(dtime)
|
minetest.register_globalstep(function(dtime)
|
||||||
if mcl_weather.end_time == nil then
|
t = t + dtime
|
||||||
mcl_weather.end_time = mcl_weather.get_rand_end_time()
|
if t < wci then return end
|
||||||
end
|
t = 0
|
||||||
-- recalculate weather
|
|
||||||
if mcl_weather.end_time <= minetest.get_gametime() then
|
if mcl_weather.end_time == nil then
|
||||||
local changeWeather = minetest.settings:get_bool("mcl_doWeatherCycle")
|
mcl_weather.end_time = mcl_weather.get_rand_end_time()
|
||||||
if changeWeather == nil then
|
end
|
||||||
changeWeather = true
|
-- recalculate weather
|
||||||
end
|
if mcl_weather.end_time <= minetest.get_gametime() then
|
||||||
if changeWeather then
|
local changeWeather = minetest.settings:get_bool("mcl_doWeatherCycle")
|
||||||
mcl_weather.set_random_weather(mcl_weather.state, mcl_weather.reg_weathers[mcl_weather.state])
|
if changeWeather == nil then
|
||||||
else
|
changeWeather = true
|
||||||
mcl_weather.end_time = mcl_weather.get_rand_end_time()
|
end
|
||||||
end
|
if changeWeather then
|
||||||
end
|
mcl_weather.set_random_weather(mcl_weather.state, mcl_weather.reg_weathers[mcl_weather.state])
|
||||||
|
else
|
||||||
|
mcl_weather.end_time = mcl_weather.get_rand_end_time()
|
||||||
|
end
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Sets random weather (which could be 'none' (no weather)).
|
-- Sets random weather (which could be 'none' (no weather)).
|
||||||
mcl_weather.set_random_weather = function(weather_name, weather_meta)
|
mcl_weather.set_random_weather = function(weather_name, weather_meta)
|
||||||
if (weather_meta ~= nil) then
|
if weather_meta == nil then return end
|
||||||
local transitions = weather_meta.transitions
|
local transitions = weather_meta.transitions
|
||||||
local random_roll = math.random(0,100)
|
local random_roll = math.random(0,100)
|
||||||
local new_weather
|
local new_weather
|
||||||
for v, weather in pairs(transitions) do
|
for v, weather in pairs(transitions) do
|
||||||
if random_roll < v then
|
if random_roll < v then
|
||||||
new_weather = weather
|
new_weather = weather
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if new_weather then
|
if new_weather then
|
||||||
mcl_weather.change_weather(new_weather)
|
mcl_weather.change_weather(new_weather)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Change weather to new_weather.
|
-- Change weather to new_weather.
|
||||||
-- * explicit_end_time is OPTIONAL. If specified, explicitly set the
|
-- * explicit_end_time is OPTIONAL. If specified, explicitly set the
|
||||||
-- gametime (minetest.get_gametime) in which the weather ends.
|
-- gametime (minetest.get_gametime) in which the weather ends.
|
||||||
mcl_weather.change_weather = function(new_weather, explicit_end_time)
|
-- * changer is OPTIONAL, for logging purposes.
|
||||||
if (mcl_weather.reg_weathers ~= nil and mcl_weather.reg_weathers[new_weather] ~= nil) then
|
mcl_weather.change_weather = function(new_weather, explicit_end_time, changer_name)
|
||||||
if (mcl_weather.state ~= nil and mcl_weather.reg_weathers[mcl_weather.state] ~= nil) then
|
local changer_name = changer_name or debug.getinfo(2).name.."()"
|
||||||
mcl_weather.reg_weathers[mcl_weather.state].clear()
|
|
||||||
end
|
if (mcl_weather.reg_weathers ~= nil and mcl_weather.reg_weathers[new_weather] ~= nil) then
|
||||||
mcl_weather.state = new_weather
|
if (mcl_weather.state ~= nil and mcl_weather.reg_weathers[mcl_weather.state] ~= nil) then
|
||||||
local weather_meta = mcl_weather.reg_weathers[mcl_weather.state]
|
mcl_weather.reg_weathers[mcl_weather.state].clear()
|
||||||
if explicit_end_time then
|
end
|
||||||
mcl_weather.end_time = explicit_end_time
|
|
||||||
else
|
local old_weather = mcl_weather.state
|
||||||
mcl_weather.end_time = mcl_weather.get_rand_end_time(weather_meta.min_duration, weather_meta.max_duration)
|
|
||||||
end
|
mcl_weather.state = new_weather
|
||||||
mcl_weather.skycolor.update_sky_color()
|
|
||||||
save_weather()
|
if old_weather == "none" then
|
||||||
return true
|
old_weather = "clear"
|
||||||
end
|
end
|
||||||
return false
|
if new_weather == "none" then
|
||||||
|
new_weather = "clear"
|
||||||
|
end
|
||||||
|
minetest.log("action", "[mcl_weather] " .. changer_name .. " changed the weather from " .. old_weather .. " to " .. new_weather)
|
||||||
|
|
||||||
|
local weather_meta = mcl_weather.reg_weathers[mcl_weather.state]
|
||||||
|
if explicit_end_time then
|
||||||
|
mcl_weather.end_time = explicit_end_time
|
||||||
|
else
|
||||||
|
mcl_weather.end_time = mcl_weather.get_rand_end_time(weather_meta.min_duration, weather_meta.max_duration)
|
||||||
|
end
|
||||||
|
mcl_weather.skycolor.update_sky_color()
|
||||||
|
save_weather()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
mcl_weather.get_weather = function()
|
mcl_weather.get_weather = function()
|
||||||
return mcl_weather.state
|
return mcl_weather.state
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_privilege("weather_manager", {
|
minetest.register_privilege("weather_manager", {
|
||||||
description = S("Gives ability to control weather"),
|
description = S("Gives ability to control weather"),
|
||||||
give_to_singleplayer = false
|
give_to_singleplayer = false
|
||||||
})
|
})
|
||||||
|
|
||||||
-- Weather command definition. Set
|
-- Weather command definition. Set
|
||||||
minetest.register_chatcommand("weather", {
|
minetest.register_chatcommand("weather", {
|
||||||
params = "(clear | rain | snow | thunder) [<duration>]",
|
params = "(clear | rain | snow | thunder) [<duration>]",
|
||||||
description = S("Changes the weather to the specified parameter."),
|
description = S("Changes the weather to the specified parameter."),
|
||||||
privs = {weather_manager = true},
|
privs = {weather_manager = true},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
if (param == "") then
|
if (param == "") then
|
||||||
return false, S("Error: No weather specified.")
|
return false, S("Error: No weather specified.")
|
||||||
end
|
end
|
||||||
local new_weather, end_time
|
local new_weather, end_time
|
||||||
local parse1, parse2 = string.match(param, "(%w+) ?(%d*)")
|
local parse1, parse2 = string.match(param, "(%w+) ?(%d*)")
|
||||||
if parse1 then
|
if parse1 then
|
||||||
if parse1 == "clear" then
|
if parse1 == "clear" then
|
||||||
new_weather = "none"
|
new_weather = "none"
|
||||||
else
|
else
|
||||||
new_weather = parse1
|
new_weather = parse1
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
return false, S("Error: Invalid parameters.")
|
return false, S("Error: Invalid parameters.")
|
||||||
end
|
end
|
||||||
if parse2 then
|
if parse2 then
|
||||||
if type(tonumber(parse2)) == "number" then
|
if type(tonumber(parse2)) == "number" then
|
||||||
local duration = tonumber(parse2)
|
local duration = tonumber(parse2)
|
||||||
if duration < 1 then
|
if duration < 1 then
|
||||||
return false, S("Error: Duration can't be less than 1 second.")
|
return false, S("Error: Duration can't be less than 1 second.")
|
||||||
end
|
end
|
||||||
end_time = minetest.get_gametime() + duration
|
end_time = minetest.get_gametime() + duration
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local success = mcl_weather.change_weather(new_weather, end_time)
|
local success = mcl_weather.change_weather(new_weather, end_time, name)
|
||||||
if success then
|
if success then
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
return false, S("Error: Invalid weather specified. Use “clear”, “rain”, “snow” or “thunder”.")
|
return false, S("Error: Invalid weather specified. Use “clear”, “rain”, “snow” or “thunder”.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand("toggledownfall", {
|
minetest.register_chatcommand("toggledownfall", {
|
||||||
params = "",
|
params = "",
|
||||||
description = S("Toggles between clear weather and weather with downfall (randomly rain, thunderstorm or snow)"),
|
description = S("Toggles between clear weather and weather with downfall (randomly rain, thunderstorm or snow)"),
|
||||||
privs = {weather_manager = true},
|
privs = {weather_manager = true},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
-- Currently rain/thunder/snow: Set weather to clear
|
-- Currently rain/thunder/snow: Set weather to clear
|
||||||
if mcl_weather.state ~= "none" then
|
if mcl_weather.state ~= "none" then
|
||||||
return mcl_weather.change_weather("none")
|
return mcl_weather.change_weather("none", nil, name)
|
||||||
|
|
||||||
-- Currently clear: Set weather randomly to rain/thunder/snow
|
-- Currently clear: Set weather randomly to rain/thunder/snow
|
||||||
else
|
else
|
||||||
local new = { "rain", "thunder", "snow" }
|
local new = { "rain", "thunder", "snow" }
|
||||||
local r = math.random(1, #new)
|
local r = math.random(1, #new)
|
||||||
return mcl_weather.change_weather(new[r])
|
return mcl_weather.change_weather(new[r], nil, name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
-- Configuration setting which allows user to disable ABM for weathers (if they use it).
|
-- Configuration setting which allows user to disable ABM for weathers (if they use it).
|
||||||
-- Weather mods expected to be use this flag before registering ABM.
|
-- Weather mods expected to be use this flag before registering ABM.
|
||||||
local weather_allow_abm = minetest.settings:get_bool("weather_allow_abm")
|
local weather_allow_abm = minetest.settings:get_bool("weather_allow_abm")
|
||||||
if weather_allow_abm ~= nil and weather_allow_abm == false then
|
if weather_allow_abm ~= nil and weather_allow_abm == false then
|
||||||
mcl_weather.allow_abm = false
|
mcl_weather.allow_abm = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1109,7 +1109,13 @@ if progressive_mode then
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
local data = player_data[name]
|
local data = player_data[name]
|
||||||
|
|
||||||
meta:set_string("inv_items", serialize(data.inv_items))
|
if not data then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local inv_items = data.inv_items or {}
|
||||||
|
|
||||||
|
meta:set_string("inv_items", serialize(inv_items))
|
||||||
end
|
end
|
||||||
|
|
||||||
M.register_on_leaveplayer(function(player)
|
M.register_on_leaveplayer(function(player)
|
||||||
|
|
|
@ -77,6 +77,8 @@ hud_manager.add_hud = function(player,hud_name,def)
|
||||||
size = def.size,
|
size = def.size,
|
||||||
offset = def.offset,
|
offset = def.offset,
|
||||||
z_index = def.z_index,
|
z_index = def.z_index,
|
||||||
|
alignment = def.alignment,
|
||||||
|
scale = def.scale,
|
||||||
})
|
})
|
||||||
-- create new 3d array here
|
-- create new 3d array here
|
||||||
-- depends.txt is not needed
|
-- depends.txt is not needed
|
||||||
|
@ -148,7 +150,7 @@ function mcl_experience.set_player_xp_level(player,level)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
pool[name].level = level
|
pool[name].level = level
|
||||||
pool[name].xp, pool[name].bar_step, pool[name].next_level = mcl_experience.bar_to_xp(pool[name].bar, level)
|
pool[name].xp, pool[name].bar_step, pool[name].xp_next_level = mcl_experience.bar_to_xp(pool[name].bar, level)
|
||||||
hud_manager.change_hud({player = player, hud_name = "xp_level", element = "text", data = tostring(level)})
|
hud_manager.change_hud({player = player, hud_name = "xp_level", element = "text", data = tostring(level)})
|
||||||
-- we may don't update the bar
|
-- we may don't update the bar
|
||||||
end
|
end
|
||||||
|
@ -164,21 +166,21 @@ minetest.register_on_joinplayer(function(player)
|
||||||
|
|
||||||
hud_manager.add_hud(player,"experience_bar",
|
hud_manager.add_hud(player,"experience_bar",
|
||||||
{
|
{
|
||||||
hud_elem_type = "statbar", position = {x=0.5, y=1},
|
hud_elem_type = "image",
|
||||||
name = "experience bar",
|
name = "experience bar",
|
||||||
text = "experience_bar.png",
|
text = "experience_bar_background.png^[lowpart:" .. math.floor(temp_pool.bar / 36 * 100) .. ":experience_bar.png^[transformR270",
|
||||||
text2 = "experience_bar_background.png",
|
position = {x=0.5, y=1},
|
||||||
number = temp_pool.bar, item = 36,
|
offset = {x = (-9 * 28) - 3, y = -(48 + 24 + 16 - 5)},
|
||||||
direction = 0,
|
scale = {x = 2.8, y = 3.0},
|
||||||
offset = {x = (-8 * 28) - 29, y = -(48 + 24 + 16)},
|
alignment = { x = 1, y = 1 },
|
||||||
size = { x=28, y=28 }, z_index = 11,
|
z_index = 11,
|
||||||
})
|
})
|
||||||
|
|
||||||
hud_manager.add_hud(player,"xp_level",
|
hud_manager.add_hud(player,"xp_level",
|
||||||
{
|
{
|
||||||
hud_elem_type = "text", position = {x=0.5, y=1},
|
hud_elem_type = "text", position = {x=0.5, y=1},
|
||||||
name = "xp_level", text = tostring(temp_pool.level),
|
name = "xp_level", text = tostring(temp_pool.level),
|
||||||
number = 0xFFFFFF,
|
number = 0x80FF20,
|
||||||
offset = {x = 0, y = -(48 + 24 + 24)},
|
offset = {x = 0, y = -(48 + 24 + 24)},
|
||||||
z_index = 12,
|
z_index = 12,
|
||||||
})
|
})
|
||||||
|
@ -247,7 +249,7 @@ function mcl_experience.add_experience(player, experience)
|
||||||
end
|
end
|
||||||
|
|
||||||
if old_bar ~= temp_pool.bar then
|
if old_bar ~= temp_pool.bar then
|
||||||
hud_manager.change_hud({player = player, hud_name = "experience_bar", element = "number", data = math.floor(temp_pool.bar)})
|
hud_manager.change_hud({player = player, hud_name = "experience_bar", element = "text", data = "experience_bar_background.png^[lowpart:" .. math.floor(temp_pool.bar / 36 * 100) .. ":experience_bar.png^[transformR270",})
|
||||||
end
|
end
|
||||||
|
|
||||||
if experience > 0 and minetest.get_us_time()/1000000 - temp_pool.last_time > 0.01 then
|
if experience > 0 and minetest.get_us_time()/1000000 - temp_pool.last_time > 0.01 then
|
||||||
|
@ -283,7 +285,7 @@ minetest.register_on_dieplayer(function(player)
|
||||||
temp_pool.bar, temp_pool.bar_step, temp_pool.xp_next_level = mcl_experience.xp_to_bar(temp_pool.xp, temp_pool.level)
|
temp_pool.bar, temp_pool.bar_step, temp_pool.xp_next_level = mcl_experience.xp_to_bar(temp_pool.xp, temp_pool.level)
|
||||||
|
|
||||||
hud_manager.change_hud({player = player, hud_name = "xp_level", element = "text", data = tostring(temp_pool.level)})
|
hud_manager.change_hud({player = player, hud_name = "xp_level", element = "text", data = tostring(temp_pool.level)})
|
||||||
hud_manager.change_hud({player = player, hud_name = "experience_bar", element = "number", data = math.floor(temp_pool.bar)})
|
hud_manager.change_hud({player = player, hud_name = "experience_bar", element = "text", data = "experience_bar_background.png^[lowpart:" .. math.floor(temp_pool.bar / 36 * 100) .. ":experience_bar.png^[transformR270",})
|
||||||
|
|
||||||
mcl_experience.throw_experience(player:get_pos(), xp_amount)
|
mcl_experience.throw_experience(player:get_pos(), xp_amount)
|
||||||
end)
|
end)
|
||||||
|
@ -304,14 +306,14 @@ local function xp_step(self, dtime)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
collector = minetest.get_player_by_name(self.collector)
|
collector = minetest.get_player_by_name(self.collector)
|
||||||
if collector and collector:get_hp() > 0 and vector.distance(self.object:get_pos(),collector:get_pos()) < 5 then
|
if collector and collector:get_hp() > 0 and vector.distance(self.object:get_pos(),collector:get_pos()) < 7.25 then
|
||||||
self.object:set_acceleration(vector.new(0,0,0))
|
self.object:set_acceleration(vector.new(0,0,0))
|
||||||
self.disable_physics(self)
|
self.disable_physics(self)
|
||||||
--get the variables
|
--get the variables
|
||||||
pos = self.object:get_pos()
|
pos = self.object:get_pos()
|
||||||
pos2 = collector:get_pos()
|
pos2 = collector:get_pos()
|
||||||
|
|
||||||
player_velocity = collector:get_player_velocity()
|
player_velocity = collector:get_velocity() or collector:get_player_velocity()
|
||||||
|
|
||||||
pos2.y = pos2.y + 0.8
|
pos2.y = pos2.y + 0.8
|
||||||
|
|
||||||
|
@ -330,8 +332,79 @@ local function xp_step(self, dtime)
|
||||||
goal = velocity
|
goal = velocity
|
||||||
acceleration = vector.new(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
|
acceleration = vector.new(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
|
||||||
self.object:add_velocity(vector.add(acceleration,player_velocity))
|
self.object:add_velocity(vector.add(acceleration,player_velocity))
|
||||||
elseif distance < 0.4 then
|
elseif distance < 0.8 then
|
||||||
mcl_experience.add_experience(collector, self._xp)
|
local xp = self._xp
|
||||||
|
local inv = collector:get_inventory()
|
||||||
|
local candidates = {
|
||||||
|
{list = "main", index = collector:get_wield_index()},
|
||||||
|
{list = "armor", index = 2},
|
||||||
|
{list = "armor", index = 3},
|
||||||
|
{list = "armor", index = 4},
|
||||||
|
{list = "armor", index = 5},
|
||||||
|
}
|
||||||
|
local final_candidates = {}
|
||||||
|
for _, can in ipairs(candidates) do
|
||||||
|
local stack = inv:get_stack(can.list, can.index)
|
||||||
|
local wear = stack:get_wear()
|
||||||
|
if mcl_enchanting.has_enchantment(stack, "mending") and wear > 0 then
|
||||||
|
can.stack = stack
|
||||||
|
can.wear = wear
|
||||||
|
table.insert(final_candidates, can)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #final_candidates > 0 then
|
||||||
|
local can = final_candidates[math.random(#final_candidates)]
|
||||||
|
local stack, list, index, wear = can.stack, can.list, can.index, can.wear
|
||||||
|
local unbreaking_level = mcl_enchanting.get_enchantment(stack, "unbreaking")
|
||||||
|
local uses
|
||||||
|
local armor_uses = minetest.get_item_group(stack:get_name(), "mcl_armor_uses")
|
||||||
|
if armor_uses > 0 then
|
||||||
|
uses = armor_uses
|
||||||
|
if unbreaking_level > 0 then
|
||||||
|
uses = uses / (0.6 + 0.4 / (unbreaking_level + 1))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local def = stack:get_definition()
|
||||||
|
if def then
|
||||||
|
local fixed_uses = def._mcl_uses
|
||||||
|
if fixed_uses then
|
||||||
|
uses = fixed_uses
|
||||||
|
if unbreaking_level > 0 then
|
||||||
|
uses = uses * (unbreaking_level + 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not uses then
|
||||||
|
local toolcaps = stack:get_tool_capabilities()
|
||||||
|
local groupcaps = toolcaps.groupcaps
|
||||||
|
for _, v in pairs(groupcaps) do
|
||||||
|
uses = v.uses
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
uses = uses or 0
|
||||||
|
local multiplier = 2 * 65535 / uses
|
||||||
|
local repair = xp * multiplier
|
||||||
|
local new_wear = wear - repair
|
||||||
|
if new_wear < 0 then
|
||||||
|
xp = math.floor(-new_wear / multiplier + 0.5)
|
||||||
|
new_wear = 0
|
||||||
|
else
|
||||||
|
xp = 0
|
||||||
|
end
|
||||||
|
stack:set_wear(math.floor(new_wear))
|
||||||
|
inv:set_stack(list, index, stack)
|
||||||
|
if can.list == "armor" then
|
||||||
|
local armor_inv = minetest.get_inventory({type = "detached", name = collector:get_player_name() .. "_armor"})
|
||||||
|
armor_inv:set_stack(list, index, stack)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if xp > 0 then
|
||||||
|
mcl_experience.add_experience(collector, xp)
|
||||||
|
else
|
||||||
|
minetest.sound_play("experience",{gain=0.1,to_player = name,pitch=math.random(75,99)/100})
|
||||||
|
end
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
|
@ -534,3 +607,47 @@ function mcl_experience.throw_experience(pos, amount)
|
||||||
j = j + 1
|
j = j + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
minetest.register_entity("mcl_experience:bottle",{
|
||||||
|
textures = {"mcl_experience_bottle.png"},
|
||||||
|
hp_max = 1,
|
||||||
|
visual_size = {x = 0.35, y = 0.35},
|
||||||
|
collisionbox = {-0.1, -0.1, -0.1, 0.1, 0.1, 0.1},
|
||||||
|
pointable = false,
|
||||||
|
on_step = function(self, dtime)
|
||||||
|
local pos = self.object:get_pos()
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
local n = node.name
|
||||||
|
if n ~= "air" and n ~= "mcl_portals:portal" and n ~= "mcl_portals:portal_end" and minetest.get_node_group(n, "liquid") == 0 then
|
||||||
|
minetest.sound_play("mcl_potions_breaking_glass", {pos = pos, max_hear_distance = 16, gain = 1})
|
||||||
|
mcl_experience.throw_experience(pos, math.random(3, 11))
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
local function throw_xp_bottle(pos, dir, velocity)
|
||||||
|
minetest.sound_play("mcl_throwing_throw", {pos = pos, gain = 0.4, max_hear_distance = 16}, true)
|
||||||
|
local obj = minetest.add_entity(pos, "mcl_experience:bottle")
|
||||||
|
obj:set_velocity(vector.multiply(dir, velocity))
|
||||||
|
local acceleration = vector.multiply(dir, -3)
|
||||||
|
acceleration.y = -9.81
|
||||||
|
obj:set_acceleration(acceleration)
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_craftitem("mcl_experience:bottle", {
|
||||||
|
description = "Bottle o' Enchanting",
|
||||||
|
inventory_image = "mcl_experience_bottle.png",
|
||||||
|
wield_image = "mcl_experience_bottle.png",
|
||||||
|
stack_max = 64,
|
||||||
|
on_use = function(itemstack, placer, pointed_thing)
|
||||||
|
throw_xp_bottle(vector.add(placer:get_pos(), vector.new(0, 1.5, 0)), placer:get_look_dir(), 10)
|
||||||
|
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
||||||
|
itemstack:take_item()
|
||||||
|
end
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
|
_on_dispense = function(_, pos, _, _, dir)
|
||||||
|
throw_xp_bottle(vector.add(pos, vector.multiply(dir, 0.51)), dir, 10)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# textdomain: mcl_experience
|
||||||
|
[[<player>] <xp>]=[[<Spieler>] <EP>]
|
||||||
|
Gives a player some XP=Gibt einen Spieler ein paar EP
|
||||||
|
Error: Too many parameters!=Fehler: Zu viele Parameter!
|
||||||
|
Error: Incorrect value of XP=Fehler: Ungültiger EP-Wert
|
||||||
|
Error: Player not found=Fehler: Spieler nicht gefunden
|
||||||
|
Added @1 XP to @2, total: @3, experience level: @4=@1 EP an @2 gegeben, gesamt: @3, Erfahrungsstufe: @4
|
|
@ -1,3 +1,4 @@
|
||||||
|
# textdomain: mcl_experience
|
||||||
[[<player>] <xp>]=[[<игрок>] <xp>]
|
[[<player>] <xp>]=[[<игрок>] <xp>]
|
||||||
Gives a player some XP=Даёт игроку XP
|
Gives a player some XP=Даёт игроку XP
|
||||||
Error: Too many parameters!=Ошибка: слишком много параметров!
|
Error: Too many parameters!=Ошибка: слишком много параметров!
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# textdomain: mcl_experience
|
||||||
[[<player>] <xp>]=[[<joueur>] <xp>]
|
[[<player>] <xp>]=[[<joueur>] <xp>]
|
||||||
Gives a player some XP=Donne de l'XP à un joueur
|
Gives a player some XP=Donne de l'XP à un joueur
|
||||||
Error: Too many parameters!=Erreur: Trop de paramètres!
|
Error: Too many parameters!=Erreur: Trop de paramètres!
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
# textdomain: mcl_experience
|
||||||
[[<player>] <xp>]=
|
[[<player>] <xp>]=
|
||||||
Gives a player some XP=
|
Gives a player some XP=
|
||||||
Error: Too many parameters!=
|
Error: Too many parameters!=
|
||||||
Error: Incorrect value of XP=
|
Error: Incorrect value of XP=
|
||||||
Error: Player not found=
|
Error: Player not found=
|
||||||
Added @1 XP to @2, total: @3, experience level: @4=
|
Added @1 XP to @2, total: @3, experience level: @4=
|
||||||
XP are disabled!=
|
|
||||||
|
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 337 B |
|
@ -16,6 +16,18 @@ for _, f in pairs(builtin_filter_ids) do
|
||||||
inventory_lists[f] = {}
|
inventory_lists[f] = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function replace_enchanted_books(tbl)
|
||||||
|
for k, item in ipairs(tbl) do
|
||||||
|
if item:find("mcl_enchanting:book_enchanted") == 1 then
|
||||||
|
local _, enchantment, level = item:match("(%a+) ([_%w]+) (%d+)")
|
||||||
|
level = level and tonumber(level)
|
||||||
|
if enchantment and level then
|
||||||
|
tbl[k] = mcl_enchanting.enchant(ItemStack("mcl_enchanting:book_enchanted"), enchantment, level)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--[[ Populate all the item tables. We only do this once. Note this mod must be
|
--[[ Populate all the item tables. We only do this once. Note this mod must be
|
||||||
loaded after _mcl_autogroup for this to work, because it required certain
|
loaded after _mcl_autogroup for this to work, because it required certain
|
||||||
groups to be set. ]]
|
groups to be set. ]]
|
||||||
|
@ -82,11 +94,33 @@ do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
for ench, def in pairs(mcl_enchanting.enchantments) do
|
||||||
|
local str = "mcl_enchanting:book_enchanted " .. ench .. " " .. def.max_level
|
||||||
|
if def.inv_tool_tab then
|
||||||
|
table.insert(inventory_lists["tools"], str)
|
||||||
|
end
|
||||||
|
if def.inv_combat_tab then
|
||||||
|
table.insert(inventory_lists["combat"], str)
|
||||||
|
end
|
||||||
|
table.insert(inventory_lists["all"], str)
|
||||||
|
end
|
||||||
|
|
||||||
for _, to_sort in pairs(inventory_lists) do
|
for _, to_sort in pairs(inventory_lists) do
|
||||||
table.sort(to_sort)
|
table.sort(to_sort)
|
||||||
|
replace_enchanted_books(to_sort)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function filter_item(name, description, lang, filter)
|
||||||
|
local desc
|
||||||
|
if not lang then
|
||||||
|
desc = string.lower(description)
|
||||||
|
else
|
||||||
|
desc = string.lower(minetest.get_translated_string(lang, description))
|
||||||
|
end
|
||||||
|
return string.find(name, filter) or string.find(desc, filter)
|
||||||
|
end
|
||||||
|
|
||||||
local function set_inv_search(filter, player)
|
local function set_inv_search(filter, player)
|
||||||
local playername = player:get_player_name()
|
local playername = player:get_player_name()
|
||||||
local inv = minetest.get_inventory({type="detached", name="creative_"..playername})
|
local inv = minetest.get_inventory({type="detached", name="creative_"..playername})
|
||||||
|
@ -94,19 +128,21 @@ local function set_inv_search(filter, player)
|
||||||
local lang = minetest.get_player_information(playername).lang_code
|
local lang = minetest.get_player_information(playername).lang_code
|
||||||
for name,def in pairs(minetest.registered_items) do
|
for name,def in pairs(minetest.registered_items) do
|
||||||
if (not def.groups.not_in_creative_inventory or def.groups.not_in_creative_inventory == 0) and def.description and def.description ~= "" then
|
if (not def.groups.not_in_creative_inventory or def.groups.not_in_creative_inventory == 0) and def.description and def.description ~= "" then
|
||||||
local name = string.lower(def.name)
|
if filter_item(string.lower(def.name), def.description, lang, filter) then
|
||||||
local desc
|
|
||||||
if not lang then
|
|
||||||
desc = string.lower(def.description)
|
|
||||||
else
|
|
||||||
desc = string.lower(minetest.get_translated_string(lang, def.description))
|
|
||||||
end
|
|
||||||
if string.find(name, filter) or string.find(desc, filter) then
|
|
||||||
table.insert(creative_list, name)
|
table.insert(creative_list, name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
for ench, def in pairs(mcl_enchanting.enchantments) do
|
||||||
|
for i = 1, def.max_level do
|
||||||
|
local stack = mcl_enchanting.enchant(ItemStack("mcl_enchanting:book_enchanted"), ench, i)
|
||||||
|
if filter_item("mcl_enchanting:book_enchanted", minetest.strip_colors(stack:get_description()), lang, filter) then
|
||||||
|
table.insert(creative_list, "mcl_enchanting:book_enchanted " .. ench .. " " .. i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
table.sort(creative_list)
|
table.sort(creative_list)
|
||||||
|
replace_enchanted_books(creative_list)
|
||||||
|
|
||||||
inv:set_size("main", #creative_list)
|
inv:set_size("main", #creative_list)
|
||||||
inv:set_list("main", creative_list)
|
inv:set_list("main", creative_list)
|
||||||
|
@ -589,7 +625,9 @@ if minetest.is_creative_enabled("") then
|
||||||
|
|
||||||
function minetest.handle_node_drops(pos, drops, digger)
|
function minetest.handle_node_drops(pos, drops, digger)
|
||||||
if not digger or not digger:is_player() then
|
if not digger or not digger:is_player() then
|
||||||
return
|
for _,item in ipairs(drops) do
|
||||||
|
minetest.add_item(pos, item)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
local inv = digger:get_inventory()
|
local inv = digger:get_inventory()
|
||||||
if inv then
|
if inv then
|
||||||
|
|
|
@ -141,7 +141,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
return_fields(player,"craft")
|
return_fields(player,"craft")
|
||||||
return_fields(player,"enchanting_lapis")
|
return_fields(player,"enchanting_lapis")
|
||||||
return_fields(player,"enchanting_item")
|
return_fields(player,"enchanting_item")
|
||||||
mcl_enchanting.reload_inventory(player)
|
|
||||||
if not minetest.is_creative_enabled(player:get_player_name()) and (formname == "" or formname == "main") then
|
if not minetest.is_creative_enabled(player:get_player_name()) and (formname == "" or formname == "main") then
|
||||||
set_inventory(player)
|
set_inventory(player)
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
mcl_tmp_message = {}
|
||||||
|
|
||||||
|
local huds = {}
|
||||||
|
local hud_hide_timeouts = {}
|
||||||
|
|
||||||
|
function mcl_tmp_message.message(player, message)
|
||||||
|
local name = player:get_player_name()
|
||||||
|
player:hud_change(huds[name], "text", message)
|
||||||
|
hud_hide_timeouts[name] = 3
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_on_joinplayer(function(player)
|
||||||
|
huds[player:get_player_name()] = player:hud_add({
|
||||||
|
hud_elem_type = "text",
|
||||||
|
position = {x=0.5, y=1},
|
||||||
|
offset = {x = 0, y = -210},
|
||||||
|
alignment = {x=0, y=0},
|
||||||
|
number = 0xFFFFFF ,
|
||||||
|
text = "",
|
||||||
|
z_index = 100,
|
||||||
|
})
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_leaveplayer(function(player)
|
||||||
|
local name = player:get_player_name()
|
||||||
|
huds[name] = nil
|
||||||
|
hud_hide_timeouts[name] = nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_globalstep(function(dtime)
|
||||||
|
local new_timeouts = {}
|
||||||
|
for name, timeout in pairs(hud_hide_timeouts) do
|
||||||
|
timeout = timeout - dtime
|
||||||
|
if timeout <= 0 then
|
||||||
|
local player = minetest.get_player_by_name(name)
|
||||||
|
if player then
|
||||||
|
player:hud_change(huds[name], "text", "")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
new_timeouts[name] = timeout
|
||||||
|
end
|
||||||
|
end
|
||||||
|
hud_hide_timeouts = new_timeouts
|
||||||
|
end)
|
|
@ -24,7 +24,7 @@ local rules_up = {{ x = 0, y = -1, z = 0, spread = true }}
|
||||||
|
|
||||||
function mcl_observers.observer_activate(pos)
|
function mcl_observers.observer_activate(pos)
|
||||||
minetest.after(mcl_vars.redstone_tick, function(pos)
|
minetest.after(mcl_vars.redstone_tick, function(pos)
|
||||||
node = minetest.get_node(pos)
|
local node = minetest.get_node(pos)
|
||||||
if not node then
|
if not node then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -284,6 +284,7 @@ if realtime then
|
||||||
mcl_observers.set_node = minetest.set_node
|
mcl_observers.set_node = minetest.set_node
|
||||||
mcl_observers.swap_node = minetest.swap_node
|
mcl_observers.swap_node = minetest.swap_node
|
||||||
mcl_observers.remove_node = minetest.remove_node
|
mcl_observers.remove_node = minetest.remove_node
|
||||||
|
mcl_observers.bulk_set_node = minetest.bulk_set_node
|
||||||
|
|
||||||
minetest.add_node=function(pos,node)
|
minetest.add_node=function(pos,node)
|
||||||
mcl_observers.add_node(pos,node)
|
mcl_observers.add_node(pos,node)
|
||||||
|
@ -393,6 +394,35 @@ if realtime then
|
||||||
mcl_observers.observer_activate({x=pos.x,y=pos.y+1,z=pos.z})
|
mcl_observers.observer_activate({x=pos.x,y=pos.y+1,z=pos.z})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
minetest.bulk_set_node=function(lst, node)
|
||||||
|
mcl_observers.bulk_set_node(lst, node)
|
||||||
|
for _, pos in pairs(lst) do
|
||||||
|
local n=minetest.get_node({x=pos.x+1,y=pos.y,z=pos.z})
|
||||||
|
if n and n.name and string.sub(n.name,1,24)=="mcl_observers:observer_o" and minetest.facedir_to_dir(n.param2).x==-1 then
|
||||||
|
mcl_observers.observer_activate({x=pos.x+1,y=pos.y,z=pos.z})
|
||||||
|
end
|
||||||
|
n=minetest.get_node({x=pos.x-1,y=pos.y,z=pos.z})
|
||||||
|
if n and n.name and string.sub(n.name,1,24)=="mcl_observers:observer_o" and minetest.facedir_to_dir(n.param2).x==1 then
|
||||||
|
mcl_observers.observer_activate({x=pos.x-1,y=pos.y,z=pos.z})
|
||||||
|
end
|
||||||
|
n=minetest.get_node({x=pos.x,y=pos.y,z=pos.z+1})
|
||||||
|
if n and n.name and string.sub(n.name,1,24)=="mcl_observers:observer_o" and minetest.facedir_to_dir(n.param2).z==-1 then
|
||||||
|
mcl_observers.observer_activate({x=pos.x,y=pos.y,z=pos.z+1})
|
||||||
|
end
|
||||||
|
n=minetest.get_node({x=pos.x,y=pos.y,z=pos.z-1})
|
||||||
|
if n and n.name and string.sub(n.name,1,24)=="mcl_observers:observer_o" and minetest.facedir_to_dir(n.param2).z==1 then
|
||||||
|
mcl_observers.observer_activate({x=pos.x,y=pos.y,z=pos.z-1})
|
||||||
|
end
|
||||||
|
n=minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z})
|
||||||
|
if n and n.name and string.sub(n.name,1,24)=="mcl_observers:observer_u" then
|
||||||
|
mcl_observers.observer_activate({x=pos.x,y=pos.y-1,z=pos.z})
|
||||||
|
end
|
||||||
|
n=minetest.get_node({x=pos.x,y=pos.y+1,z=pos.z})
|
||||||
|
if n and n.name and string.sub(n.name,1,24)=="mcl_observers:observer_d" then
|
||||||
|
mcl_observers.observer_activate({x=pos.x,y=pos.y+1,z=pos.z})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
else -- if realtime then ^^^ else:
|
else -- if realtime then ^^^ else:
|
||||||
minetest.register_abm({
|
minetest.register_abm({
|
||||||
|
|
|
@ -145,7 +145,7 @@ function mesecon.mvps_get_stack(pos, dir, maximum, piston_pos)
|
||||||
|
|
||||||
if not node_replaceable(nn.name) then
|
if not node_replaceable(nn.name) then
|
||||||
if #nodes >= maximum then return nil, false end
|
if #nodes >= maximum then return nil, false end
|
||||||
table.insert(nodes, {node = nn, pos = np})
|
table.insert(nodes, {node = nn, pos = {x=np.x, y=np.y, z=np.z}})
|
||||||
|
|
||||||
-- add connected nodes to frontiers, connected is a vector list
|
-- add connected nodes to frontiers, connected is a vector list
|
||||||
-- the vectors must be absolute positions
|
-- the vectors must be absolute positions
|
||||||
|
@ -195,10 +195,9 @@ function mesecon.mvps_set_owner(pos, placer)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function are_protected(positions, player_name)
|
local function are_protected(nodes, player_name)
|
||||||
local name = player_name
|
for _, node in pairs(nodes) do
|
||||||
for _, pos in pairs(positions) do
|
if minetest.is_protected(node.pos, player_name) then
|
||||||
if is_protected(pos, name) then
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -97,7 +97,7 @@ local piston_on = function (pos, node)
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
local success, stack, oldstack = mesecon.mvps_push(np, dir, PISTON_MAXIMUM_PUSH, meta:get_string("owner"), pos)
|
local success, stack, oldstack = mesecon.mvps_push(np, dir, PISTON_MAXIMUM_PUSH, meta:get_string("owner"), pos)
|
||||||
if success then
|
if success then
|
||||||
minetest.set_node(pos, {param2 = node.param2, name = pistonspec.onname})
|
minetest.swap_node(pos, {param2 = node.param2, name = pistonspec.onname})
|
||||||
minetest.set_node(np, {param2 = node.param2, name = pistonspec.pusher})
|
minetest.set_node(np, {param2 = node.param2, name = pistonspec.pusher})
|
||||||
local below = minetest.get_node({x=np.x,y=np.y-1,z=np.z})
|
local below = minetest.get_node({x=np.x,y=np.y-1,z=np.z})
|
||||||
if below.name == "mcl_farming:soil" or below.name == "mcl_farming:soil_wet" then
|
if below.name == "mcl_farming:soil" or below.name == "mcl_farming:soil_wet" then
|
||||||
|
@ -115,7 +115,7 @@ end
|
||||||
|
|
||||||
local piston_off = function (pos, node)
|
local piston_off = function (pos, node)
|
||||||
local pistonspec = minetest.registered_nodes[node.name].mesecons_piston
|
local pistonspec = minetest.registered_nodes[node.name].mesecons_piston
|
||||||
minetest.add_node(pos, {param2 = node.param2, name = pistonspec.offname})
|
minetest.swap_node(pos, {param2 = node.param2, name = pistonspec.offname})
|
||||||
piston_remove_pusher (pos, node)
|
piston_remove_pusher (pos, node)
|
||||||
if not pistonspec.sticky then
|
if not pistonspec.sticky then
|
||||||
return
|
return
|
||||||
|
|
|
@ -554,7 +554,7 @@ minetest.register_on_player_hpchange(function(player, hp_change, reason)
|
||||||
epf = epf + blast_protection_level * 2
|
epf = epf + blast_protection_level * 2
|
||||||
end
|
end
|
||||||
local fire_protection_level = enchantments.fire_protection or 0
|
local fire_protection_level = enchantments.fire_protection or 0
|
||||||
if fire_protection_level > 0 and (damage_type == "fireball" or reason.type == "node_damage" and
|
if fire_protection_level > 0 and (damage_type == "burning" or damage_type == "fireball" or reason.type == "node_damage" and
|
||||||
(reason.node == "mcl_fire:fire" or reason.node == "mcl_core:lava_source" or reason.node == "mcl_core:lava_flowing")) then
|
(reason.node == "mcl_fire:fire" or reason.node == "mcl_core:lava_source" or reason.node == "mcl_core:lava_flowing")) then
|
||||||
epf = epf + fire_protection_level * 2
|
epf = epf + fire_protection_level * 2
|
||||||
end
|
end
|
||||||
|
|
|
@ -223,7 +223,7 @@ minetest.register_node("mcl_armor_stand:armor_stand", {
|
||||||
after_destruct = function(pos)
|
after_destruct = function(pos)
|
||||||
update_entity(pos)
|
update_entity(pos)
|
||||||
end,
|
end,
|
||||||
on_blast = function(pos)
|
on_blast = function(pos, _, do_drop)
|
||||||
local object = get_stand_object(pos)
|
local object = get_stand_object(pos)
|
||||||
if object then
|
if object then
|
||||||
object:remove()
|
object:remove()
|
||||||
|
@ -231,6 +231,10 @@ minetest.register_node("mcl_armor_stand:armor_stand", {
|
||||||
minetest.after(1, function(pos)
|
minetest.after(1, function(pos)
|
||||||
update_entity(pos)
|
update_entity(pos)
|
||||||
end, pos)
|
end, pos)
|
||||||
|
minetest.remove_node(pos)
|
||||||
|
if do_drop then
|
||||||
|
minetest.add_item(pos, "mcl_armor_stand:armor_stand")
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
on_rotate = function(pos, node, user, mode)
|
on_rotate = function(pos, node, user, mode)
|
||||||
if mode == screwdriver.ROTATE_FACE then
|
if mode == screwdriver.ROTATE_FACE then
|
||||||
|
|
|
@ -1,23 +1,24 @@
|
||||||
local S = minetest.get_translator("mcl_beds")
|
local S = minetest.get_translator("mcl_beds")
|
||||||
|
|
||||||
local reverse = true
|
local function destruct_bed(pos, oldnode)
|
||||||
|
local node = oldnode or minetest.get_node(pos)
|
||||||
local function destruct_bed(pos, is_top)
|
if not node then return end
|
||||||
local node = minetest.get_node(pos)
|
|
||||||
local other
|
|
||||||
local dir = minetest.facedir_to_dir(node.param2)
|
local dir = minetest.facedir_to_dir(node.param2)
|
||||||
if is_top then
|
local pos2, node2
|
||||||
other = vector.subtract(pos, dir)
|
if string.sub(node.name, -4) == "_top" then
|
||||||
else
|
pos2 = vector.subtract(pos, dir)
|
||||||
other = vector.add(pos, dir)
|
node2 = minetest.get_node(pos2)
|
||||||
end
|
if node2 and string.sub(node2.name, -7) == "_bottom" then
|
||||||
|
minetest.remove_node(pos2)
|
||||||
if reverse then
|
end
|
||||||
reverse = not reverse
|
minetest.check_for_falling(pos)
|
||||||
minetest.remove_node(other)
|
elseif string.sub(node.name, -7) == "_bottom" then
|
||||||
minetest.check_for_falling(other)
|
minetest.add_item(pos, node.name)
|
||||||
else
|
pos2 = vector.add(pos, dir)
|
||||||
reverse = not reverse
|
node2 = minetest.get_node(pos2)
|
||||||
|
if node2 and string.sub(node2.name, -4) == "_top" then
|
||||||
|
minetest.remove_node(pos2)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -86,6 +87,7 @@ function mcl_beds.register_bed(name, def)
|
||||||
node_box = node_box_bottom,
|
node_box = node_box_bottom,
|
||||||
selection_box = selection_box_bottom,
|
selection_box = selection_box_bottom,
|
||||||
collision_box = collision_box_bottom,
|
collision_box = collision_box_bottom,
|
||||||
|
drop = "",
|
||||||
on_place = function(itemstack, placer, pointed_thing)
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
local under = pointed_thing.under
|
local under = pointed_thing.under
|
||||||
|
|
||||||
|
@ -139,10 +141,9 @@ function mcl_beds.register_bed(name, def)
|
||||||
return itemstack
|
return itemstack
|
||||||
end,
|
end,
|
||||||
|
|
||||||
on_destruct = function(pos)
|
after_destruct = destruct_bed,
|
||||||
destruct_bed(pos, false)
|
|
||||||
kick_player_after_destruct(pos)
|
on_destruct = kick_player_after_destruct,
|
||||||
end,
|
|
||||||
|
|
||||||
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
||||||
mcl_beds.on_rightclick(pos, clicker, false)
|
mcl_beds.on_rightclick(pos, clicker, false)
|
||||||
|
@ -205,7 +206,7 @@ function mcl_beds.register_bed(name, def)
|
||||||
_mcl_hardness = 0.2,
|
_mcl_hardness = 0.2,
|
||||||
_mcl_blast_resistance = 1,
|
_mcl_blast_resistance = 1,
|
||||||
sounds = def.sounds or default_sounds,
|
sounds = def.sounds or default_sounds,
|
||||||
drop = name .. "_bottom",
|
drop = "",
|
||||||
node_box = node_box_top,
|
node_box = node_box_top,
|
||||||
selection_box = selection_box_top,
|
selection_box = selection_box_top,
|
||||||
collision_box = collision_box_top,
|
collision_box = collision_box_top,
|
||||||
|
@ -214,10 +215,7 @@ function mcl_beds.register_bed(name, def)
|
||||||
return itemstack
|
return itemstack
|
||||||
end,
|
end,
|
||||||
on_rotate = false,
|
on_rotate = false,
|
||||||
on_destruct = function(pos)
|
after_destruct = destruct_bed,
|
||||||
destruct_bed(pos, true)
|
|
||||||
kick_player_after_destruct(pos)
|
|
||||||
end,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_alias(name, name .. "_bottom")
|
minetest.register_alias(name, name .. "_bottom")
|
||||||
|
|
|
@ -75,16 +75,19 @@ local function lay_down(player, pos, bed_pos, state, skip)
|
||||||
bed_pos2 = {x = bed_pos.x - dir.x, y = bed_pos.y, z = bed_pos.z - dir.z}
|
bed_pos2 = {x = bed_pos.x - dir.x, y = bed_pos.y, z = bed_pos.z - dir.z}
|
||||||
bed_center = {x = bed_pos.x - dir.x/2, y = bed_pos.y + 0.1, z = bed_pos.z - dir.z/2}
|
bed_center = {x = bed_pos.x - dir.x/2, y = bed_pos.y + 0.1, z = bed_pos.z - dir.z/2}
|
||||||
|
|
||||||
|
-- save respawn position when entering bed
|
||||||
|
if minetest.get_modpath("mcl_spawn") and mcl_spawn.set_spawn_pos(player, bed_pos, false) then
|
||||||
|
minetest.chat_send_player(name, S("New respawn position set!"))
|
||||||
|
end
|
||||||
|
|
||||||
-- No sleeping if too far away
|
-- No sleeping if too far away
|
||||||
if vector.distance(bed_pos, pos) > 2 and vector.distance(bed_pos2, pos) > 2 then
|
if vector.distance(bed_pos, pos) > 2 and vector.distance(bed_pos2, pos) > 2 then
|
||||||
minetest.chat_send_player(name, S("You can't sleep, the bed's too far away!"))
|
return false, S("You can't sleep, the bed's too far away!")
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, other_pos in pairs(mcl_beds.bed_pos) do
|
for _, other_pos in pairs(mcl_beds.bed_pos) do
|
||||||
if vector.distance(bed_pos, other_pos) < 0.1 then
|
if vector.distance(bed_pos, other_pos) < 0.1 then
|
||||||
minetest.chat_send_player(name, S("This bed is already occupied!"))
|
return false, S("This bed is already occupied!")
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -92,9 +95,8 @@ local function lay_down(player, pos, bed_pos, state, skip)
|
||||||
-- FIXME: Velocity threshold should be 0.01 but Minetest 5.3.0
|
-- FIXME: Velocity threshold should be 0.01 but Minetest 5.3.0
|
||||||
-- sometimes reports incorrect Y speed. A velocity threshold
|
-- sometimes reports incorrect Y speed. A velocity threshold
|
||||||
-- of 0.125 still seems good enough.
|
-- of 0.125 still seems good enough.
|
||||||
if vector.length(player:get_player_velocity()) > 0.125 then
|
if vector.length(player:get_velocity() or player:get_player_velocity()) > 0.125 then
|
||||||
minetest.chat_send_player(name, S("You have to stop moving before going to bed!"))
|
return false, S("You have to stop moving before going to bed!")
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- No sleeping if monsters nearby.
|
-- No sleeping if monsters nearby.
|
||||||
|
@ -109,9 +111,8 @@ local function lay_down(player, pos, bed_pos, state, skip)
|
||||||
-- Approximation of monster detection range
|
-- Approximation of monster detection range
|
||||||
if def._cmi_is_mob and ((mobname ~= "mobs_mc:pigman" and def.type == "monster" and not monster_exceptions[mobname]) or (mobname == "mobs_mc:pigman" and ent.state == "attack")) then
|
if def._cmi_is_mob and ((mobname ~= "mobs_mc:pigman" and def.type == "monster" and not monster_exceptions[mobname]) or (mobname == "mobs_mc:pigman" and ent.state == "attack")) then
|
||||||
if math.abs(bed_pos.y - obj:get_pos().y) <= 5 then
|
if math.abs(bed_pos.y - obj:get_pos().y) <= 5 then
|
||||||
minetest.chat_send_player(name, S("You can't sleep now, monsters are nearby!"))
|
return false, S("You can't sleep now, monsters are nearby!")
|
||||||
end
|
end
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -154,32 +155,16 @@ local function lay_down(player, pos, bed_pos, state, skip)
|
||||||
local def1 = minetest.registered_nodes[n1.name]
|
local def1 = minetest.registered_nodes[n1.name]
|
||||||
local def2 = minetest.registered_nodes[n2.name]
|
local def2 = minetest.registered_nodes[n2.name]
|
||||||
if def1.walkable or def2.walkable then
|
if def1.walkable or def2.walkable then
|
||||||
minetest.chat_send_player(name, S("You can't sleep, the bed is obstructed!"))
|
return false, S("You can't sleep, the bed is obstructed!")
|
||||||
return false
|
|
||||||
elseif (def1.damage_per_second ~= nil and def1.damage_per_second > 0) or (def2.damage_per_second ~= nil and def2.damage_per_second > 0) then
|
elseif (def1.damage_per_second ~= nil and def1.damage_per_second > 0) or (def2.damage_per_second ~= nil and def2.damage_per_second > 0) then
|
||||||
minetest.chat_send_player(name, S("It's too dangerous to sleep here!"))
|
return false, S("It's too dangerous to sleep here!")
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local spawn_changed = false
|
|
||||||
if minetest.get_modpath("mcl_spawn") then
|
|
||||||
-- save respawn position when entering bed
|
|
||||||
spawn_changed = mcl_spawn.set_spawn_pos(player, bed_pos, false)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check day of time and weather
|
-- Check day of time and weather
|
||||||
local tod = minetest.get_timeofday() * 24000
|
local tod = minetest.get_timeofday() * 24000
|
||||||
-- Values taken from Minecraft Wiki with offset of +6000
|
-- Values taken from Minecraft Wiki with offset of +6000
|
||||||
if tod < 18541 and tod > 5458 and (not weather_mod or (mcl_weather.get_weather() ~= "thunder")) then
|
if tod < 18541 and tod > 5458 and (not weather_mod or (mcl_weather.get_weather() ~= "thunder")) then
|
||||||
if spawn_changed then
|
return false, S("You can only sleep at night or during a thunderstorm.")
|
||||||
minetest.chat_send_player(name, S("New respawn position set! But you can only sleep at night or during a thunderstorm."))
|
|
||||||
else
|
|
||||||
minetest.chat_send_player(name, S("You can only sleep at night or during a thunderstorm."))
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
if spawn_changed then
|
|
||||||
minetest.chat_send_player(name, S("New respawn position set!"))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
mcl_beds.player[name] = 1
|
mcl_beds.player[name] = 1
|
||||||
|
@ -329,13 +314,17 @@ function mcl_beds.on_rightclick(pos, player, is_top)
|
||||||
|
|
||||||
-- move to bed
|
-- move to bed
|
||||||
if not mcl_beds.player[name] then
|
if not mcl_beds.player[name] then
|
||||||
|
local success, message
|
||||||
if is_top then
|
if is_top then
|
||||||
lay_down(player, ppos, pos)
|
success, message = lay_down(player, ppos, pos)
|
||||||
else
|
else
|
||||||
local node = minetest.get_node(pos)
|
local node = minetest.get_node(pos)
|
||||||
local dir = minetest.facedir_to_dir(node.param2)
|
local dir = minetest.facedir_to_dir(node.param2)
|
||||||
local other = vector.add(pos, dir)
|
local other = vector.add(pos, dir)
|
||||||
lay_down(player, ppos, other)
|
success, message = lay_down(player, ppos, other)
|
||||||
|
end
|
||||||
|
if message then
|
||||||
|
mcl_tmp_message.message(player, message)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
lay_down(player, nil, nil, false)
|
lay_down(player, nil, nil, false)
|
||||||
|
@ -362,15 +351,15 @@ minetest.register_on_joinplayer(function(player)
|
||||||
-- Make player awake on joining server
|
-- Make player awake on joining server
|
||||||
meta:set_string("mcl_beds:sleeping", "false")
|
meta:set_string("mcl_beds:sleeping", "false")
|
||||||
end
|
end
|
||||||
|
|
||||||
playerphysics.remove_physics_factor(player, "speed", "mcl_beds:sleeping")
|
playerphysics.remove_physics_factor(player, "speed", "mcl_beds:sleeping")
|
||||||
playerphysics.remove_physics_factor(player, "jump", "mcl_beds:sleeping")
|
playerphysics.remove_physics_factor(player, "jump", "mcl_beds:sleeping")
|
||||||
update_formspecs(false)
|
update_formspecs(false)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
minetest.register_on_leaveplayer(function(player)
|
minetest.register_on_leaveplayer(function(player)
|
||||||
local name = player:get_player_name()
|
|
||||||
lay_down(player, nil, nil, false, true)
|
|
||||||
local players = minetest.get_connected_players()
|
local players = minetest.get_connected_players()
|
||||||
|
local name = player:get_player_name()
|
||||||
for n, player in ipairs(players) do
|
for n, player in ipairs(players) do
|
||||||
if player:get_player_name() == name then
|
if player:get_player_name() == name then
|
||||||
players[n] = nil
|
players[n] = nil
|
||||||
|
|
|
@ -26,7 +26,7 @@ S("An arrow fired from a bow has a regular damage of 1-9. At full charge, there'
|
||||||
S("Arrows might get stuck on solid blocks and can be retrieved again. They are also capable of pushing wooden buttons."),
|
S("Arrows might get stuck on solid blocks and can be retrieved again. They are also capable of pushing wooden buttons."),
|
||||||
_doc_items_usagehelp = S("To use arrows as ammunition for a bow, just put them anywhere in your inventory, they will be used up automatically. To use arrows as ammunition for a dispenser, place them in the dispenser's inventory. To retrieve an arrow that sticks in a block, simply walk close to it."),
|
_doc_items_usagehelp = S("To use arrows as ammunition for a bow, just put them anywhere in your inventory, they will be used up automatically. To use arrows as ammunition for a dispenser, place them in the dispenser's inventory. To retrieve an arrow that sticks in a block, simply walk close to it."),
|
||||||
inventory_image = "mcl_bows_arrow_inv.png",
|
inventory_image = "mcl_bows_arrow_inv.png",
|
||||||
groups = { ammo=1, ammo_bow=1 },
|
groups = { ammo=1, ammo_bow=1, ammo_bow_regular=1 },
|
||||||
_on_dispense = function(itemstack, dispenserpos, droppos, dropnode, dropdir)
|
_on_dispense = function(itemstack, dispenserpos, droppos, dropnode, dropdir)
|
||||||
-- Shoot arrow
|
-- Shoot arrow
|
||||||
local shootpos = vector.add(dispenserpos, vector.multiply(dropdir, 0.51))
|
local shootpos = vector.add(dispenserpos, vector.multiply(dropdir, 0.51))
|
||||||
|
@ -83,6 +83,7 @@ local ARROW_ENTITY={
|
||||||
textures = {"mcl_bows:arrow_box"},
|
textures = {"mcl_bows:arrow_box"},
|
||||||
collisionbox = {-0.19, -0.125, -0.19, 0.19, 0.125, 0.19},
|
collisionbox = {-0.19, -0.125, -0.19, 0.19, 0.125, 0.19},
|
||||||
collide_with_objects = false,
|
collide_with_objects = false,
|
||||||
|
_fire_damage_resistant = true,
|
||||||
|
|
||||||
_lastpos={},
|
_lastpos={},
|
||||||
_startpos=nil,
|
_startpos=nil,
|
||||||
|
@ -105,6 +106,7 @@ local spawn_item = function(self, pos)
|
||||||
item:set_velocity({x=0, y=0, z=0})
|
item:set_velocity({x=0, y=0, z=0})
|
||||||
item:set_yaw(self.object:get_yaw())
|
item:set_yaw(self.object:get_yaw())
|
||||||
end
|
end
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -131,6 +133,8 @@ local damage_particles = function(pos, is_critical)
|
||||||
end
|
end
|
||||||
|
|
||||||
ARROW_ENTITY.on_step = function(self, dtime)
|
ARROW_ENTITY.on_step = function(self, dtime)
|
||||||
|
mcl_burning.tick(self.object, dtime)
|
||||||
|
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
local dpos = table.copy(pos) -- digital pos
|
local dpos = table.copy(pos) -- digital pos
|
||||||
dpos = vector.round(dpos)
|
dpos = vector.round(dpos)
|
||||||
|
@ -140,6 +144,7 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
||||||
self._stucktimer = self._stucktimer + dtime
|
self._stucktimer = self._stucktimer + dtime
|
||||||
self._stuckrechecktimer = self._stuckrechecktimer + dtime
|
self._stuckrechecktimer = self._stuckrechecktimer + dtime
|
||||||
if self._stucktimer > ARROW_TIMEOUT then
|
if self._stucktimer > ARROW_TIMEOUT then
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -161,7 +166,7 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
||||||
local objects = minetest.get_objects_inside_radius(pos, 1)
|
local objects = minetest.get_objects_inside_radius(pos, 1)
|
||||||
for _,obj in ipairs(objects) do
|
for _,obj in ipairs(objects) do
|
||||||
if obj:is_player() then
|
if obj:is_player() then
|
||||||
if not minetest.is_creative_enabled(obj:get_player_name()) then
|
if self._collectable and not minetest.is_creative_enabled(obj:get_player_name()) then
|
||||||
if obj:get_inventory():room_for_item("main", "mcl_bows:arrow") then
|
if obj:get_inventory():room_for_item("main", "mcl_bows:arrow") then
|
||||||
obj:get_inventory():add_item("main", "mcl_bows:arrow")
|
obj:get_inventory():add_item("main", "mcl_bows:arrow")
|
||||||
minetest.sound_play("item_drop_pickup", {
|
minetest.sound_play("item_drop_pickup", {
|
||||||
|
@ -171,6 +176,7 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
||||||
}, true)
|
}, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -232,6 +238,7 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
||||||
local def = minetest.registered_nodes[nn]
|
local def = minetest.registered_nodes[nn]
|
||||||
if (not def) or def.walkable then
|
if (not def) or def.walkable then
|
||||||
-- There's a node in the way. Delete arrow without damage
|
-- There's a node in the way. Delete arrow without damage
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -244,6 +251,9 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
||||||
armor.last_damage_types[obj:get_player_name()] = "projectile"
|
armor.last_damage_types[obj:get_player_name()] = "projectile"
|
||||||
end
|
end
|
||||||
damage_particles(self.object:get_pos(), self._is_critical)
|
damage_particles(self.object:get_pos(), self._is_critical)
|
||||||
|
if mcl_burning.is_burning(self.object) then
|
||||||
|
mcl_burning.set_on_fire(obj, 4)
|
||||||
|
end
|
||||||
obj:punch(self.object, 1.0, {
|
obj:punch(self.object, 1.0, {
|
||||||
full_punch_interval=1.0,
|
full_punch_interval=1.0,
|
||||||
damage_groups={fleshy=self._damage},
|
damage_groups={fleshy=self._damage},
|
||||||
|
@ -271,6 +281,7 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
||||||
end
|
end
|
||||||
minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true)
|
minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true)
|
||||||
end
|
end
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -403,6 +414,7 @@ ARROW_ENTITY.on_activate = function(self, staticdata, dtime_s)
|
||||||
-- If yes, delete it.
|
-- If yes, delete it.
|
||||||
self._stucktimer = minetest.get_gametime() - data.stuckstarttime
|
self._stucktimer = minetest.get_gametime() - data.stuckstarttime
|
||||||
if self._stucktimer > ARROW_TIMEOUT then
|
if self._stucktimer > ARROW_TIMEOUT then
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,7 +33,7 @@ local bow_load = {}
|
||||||
-- Another player table, this one stores the wield index of the bow being charged
|
-- Another player table, this one stores the wield index of the bow being charged
|
||||||
local bow_index = {}
|
local bow_index = {}
|
||||||
|
|
||||||
mcl_bows.shoot_arrow = function(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, bow_stack)
|
mcl_bows.shoot_arrow = function(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, bow_stack, collectable)
|
||||||
local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, arrow_item.."_entity")
|
local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, arrow_item.."_entity")
|
||||||
if power == nil then
|
if power == nil then
|
||||||
power = BOW_MAX_SPEED --19
|
power = BOW_MAX_SPEED --19
|
||||||
|
@ -50,6 +50,9 @@ mcl_bows.shoot_arrow = function(arrow_item, pos, dir, yaw, shooter, power, damag
|
||||||
if enchantments.punch then
|
if enchantments.punch then
|
||||||
knockback = enchantments.punch * 3
|
knockback = enchantments.punch * 3
|
||||||
end
|
end
|
||||||
|
if enchantments.flame then
|
||||||
|
mcl_burning.set_on_fire(obj, math.huge)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
obj:set_velocity({x=dir.x*power, y=dir.y*power, z=dir.z*power})
|
obj:set_velocity({x=dir.x*power, y=dir.y*power, z=dir.z*power})
|
||||||
obj:set_acceleration({x=0, y=-GRAVITY, z=0})
|
obj:set_acceleration({x=0, y=-GRAVITY, z=0})
|
||||||
|
@ -60,6 +63,7 @@ mcl_bows.shoot_arrow = function(arrow_item, pos, dir, yaw, shooter, power, damag
|
||||||
le._is_critical = is_critical
|
le._is_critical = is_critical
|
||||||
le._startpos = pos
|
le._startpos = pos
|
||||||
le._knockback = knockback
|
le._knockback = knockback
|
||||||
|
le._collectable = collectable
|
||||||
minetest.sound_play("mcl_bows_bow_shoot", {pos=pos, max_hear_distance=16}, true)
|
minetest.sound_play("mcl_bows_bow_shoot", {pos=pos, max_hear_distance=16}, true)
|
||||||
if shooter ~= nil and shooter:is_player() then
|
if shooter ~= nil and shooter:is_player() then
|
||||||
if obj:get_luaentity().player == "" then
|
if obj:get_luaentity().player == "" then
|
||||||
|
@ -88,6 +92,7 @@ local player_shoot_arrow = function(itemstack, player, power, damage, is_critica
|
||||||
local arrow_stack, arrow_stack_id = get_arrow(player)
|
local arrow_stack, arrow_stack_id = get_arrow(player)
|
||||||
local arrow_itemstring
|
local arrow_itemstring
|
||||||
local has_infinity_enchantment = mcl_enchanting.has_enchantment(player:get_wielded_item(), "infinity")
|
local has_infinity_enchantment = mcl_enchanting.has_enchantment(player:get_wielded_item(), "infinity")
|
||||||
|
local infinity_used = false
|
||||||
|
|
||||||
if minetest.is_creative_enabled(player:get_player_name()) then
|
if minetest.is_creative_enabled(player:get_player_name()) then
|
||||||
if arrow_stack then
|
if arrow_stack then
|
||||||
|
@ -100,7 +105,9 @@ local player_shoot_arrow = function(itemstack, player, power, damage, is_critica
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
arrow_itemstring = arrow_stack:get_name()
|
arrow_itemstring = arrow_stack:get_name()
|
||||||
if not has_infinity_enchantment then
|
if has_infinity_enchantment and minetest.get_item_group(arrow_itemstring, "ammo_bow_regular") > 0 then
|
||||||
|
infinity_used = true
|
||||||
|
else
|
||||||
arrow_stack:take_item()
|
arrow_stack:take_item()
|
||||||
end
|
end
|
||||||
local inv = player:get_inventory()
|
local inv = player:get_inventory()
|
||||||
|
@ -113,7 +120,7 @@ local player_shoot_arrow = function(itemstack, player, power, damage, is_critica
|
||||||
local dir = player:get_look_dir()
|
local dir = player:get_look_dir()
|
||||||
local yaw = player:get_look_horizontal()
|
local yaw = player:get_look_horizontal()
|
||||||
|
|
||||||
mcl_bows.shoot_arrow(arrow_itemstring, {x=playerpos.x,y=playerpos.y+1.5,z=playerpos.z}, dir, yaw, player, power, damage, is_critical, player:get_wielded_item())
|
mcl_bows.shoot_arrow(arrow_itemstring, {x=playerpos.x,y=playerpos.y+1.5,z=playerpos.z}, dir, yaw, player, power, damage, is_critical, player:get_wielded_item(), not infinity_used)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -131,7 +138,26 @@ S("The speed and damage of the arrow increases the longer you charge. The regula
|
||||||
range = 4,
|
range = 4,
|
||||||
-- Trick to disable digging as well
|
-- Trick to disable digging as well
|
||||||
on_use = function() return end,
|
on_use = function() return end,
|
||||||
|
on_place = function(itemstack, player, pointed_thing)
|
||||||
|
if pointed_thing and pointed_thing.type == "node" then
|
||||||
|
-- Call on_rightclick if the pointed node defines it
|
||||||
|
local node = minetest.get_node(pointed_thing.under)
|
||||||
|
if player and not player:get_player_control().sneak then
|
||||||
|
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||||
|
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, player, itemstack) or itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
itemstack:get_meta():set_string("active", "true")
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
|
on_secondary_use = function(itemstack)
|
||||||
|
itemstack:get_meta():set_string("active", "true")
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
groups = {weapon=1,weapon_ranged=1,bow=1,enchantability=1},
|
groups = {weapon=1,weapon_ranged=1,bow=1,enchantability=1},
|
||||||
|
_mcl_uses = 385,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- Iterates through player inventory and resets all the bows in "charging" state back to their original stage
|
-- Iterates through player inventory and resets all the bows in "charging" state back to their original stage
|
||||||
|
@ -139,11 +165,15 @@ local reset_bows = function(player)
|
||||||
local inv = player:get_inventory()
|
local inv = player:get_inventory()
|
||||||
local list = inv:get_list("main")
|
local list = inv:get_list("main")
|
||||||
for place, stack in pairs(list) do
|
for place, stack in pairs(list) do
|
||||||
if stack:get_name()=="mcl_bows:bow_0" or stack:get_name()=="mcl_bows:bow_1" or stack:get_name()=="mcl_bows:bow_2" then
|
if stack:get_name() == "mcl_bows:bow" or stack:get_name() == "mcl_bows:bow_enchanted" then
|
||||||
|
stack:get_meta():set_string("active", "")
|
||||||
|
elseif stack:get_name()=="mcl_bows:bow_0" or stack:get_name()=="mcl_bows:bow_1" or stack:get_name()=="mcl_bows:bow_2" then
|
||||||
stack:set_name("mcl_bows:bow")
|
stack:set_name("mcl_bows:bow")
|
||||||
|
stack:get_meta():set_string("active", "")
|
||||||
list[place] = stack
|
list[place] = stack
|
||||||
elseif stack:get_name()=="mcl_bows:bow_0_enchanted" or stack:get_name()=="mcl_bows:bow_1_enchanted" or stack:get_name()=="mcl_bows:bow_2_enchanted" then
|
elseif stack:get_name()=="mcl_bows:bow_0_enchanted" or stack:get_name()=="mcl_bows:bow_1_enchanted" or stack:get_name()=="mcl_bows:bow_2_enchanted" then
|
||||||
stack:set_name("mcl_bows:bow_enchanted")
|
stack:set_name("mcl_bows:bow_enchanted")
|
||||||
|
stack:get_meta():set_string("active", "")
|
||||||
list[place] = stack
|
list[place] = stack
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -176,6 +206,7 @@ for level=0, 2 do
|
||||||
on_use = function() return end,
|
on_use = function() return end,
|
||||||
on_drop = function(itemstack, dropper, pos)
|
on_drop = function(itemstack, dropper, pos)
|
||||||
reset_bow_state(dropper)
|
reset_bow_state(dropper)
|
||||||
|
itemstack:get_meta():set_string("active", "")
|
||||||
if mcl_enchanting.is_enchanted(itemstack:get_name()) then
|
if mcl_enchanting.is_enchanted(itemstack:get_name()) then
|
||||||
itemstack:set_name("mcl_bows:bow_enchanted")
|
itemstack:set_name("mcl_bows:bow_enchanted")
|
||||||
else
|
else
|
||||||
|
@ -189,6 +220,7 @@ for level=0, 2 do
|
||||||
on_place = function(itemstack)
|
on_place = function(itemstack)
|
||||||
return itemstack
|
return itemstack
|
||||||
end,
|
end,
|
||||||
|
_mcl_uses = 385,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -268,7 +300,7 @@ controls.register_on_hold(function(player, key, time)
|
||||||
end
|
end
|
||||||
local inv = minetest.get_inventory({type="player", name=name})
|
local inv = minetest.get_inventory({type="player", name=name})
|
||||||
local wielditem = player:get_wielded_item()
|
local wielditem = player:get_wielded_item()
|
||||||
if bow_load[name] == nil and (wielditem:get_name()=="mcl_bows:bow" or wielditem:get_name()=="mcl_bows:bow_enchanted") and (creative or get_arrow(player)) then
|
if bow_load[name] == nil and (wielditem:get_name()=="mcl_bows:bow" or wielditem:get_name()=="mcl_bows:bow_enchanted") and wielditem:get_meta():get("active") and (creative or get_arrow(player)) then
|
||||||
local enchanted = mcl_enchanting.is_enchanted(wielditem:get_name())
|
local enchanted = mcl_enchanting.is_enchanted(wielditem:get_name())
|
||||||
if enchanted then
|
if enchanted then
|
||||||
wielditem:set_name("mcl_bows:bow_0_enchanted")
|
wielditem:set_name("mcl_bows:bow_0_enchanted")
|
||||||
|
|
|
@ -82,7 +82,7 @@ local register_filled_cauldron = function(water_level, description, river_water)
|
||||||
drawtype = "nodebox",
|
drawtype = "nodebox",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
groups = {pickaxey=1, not_in_creative_inventory=1, cauldron=(1+water_level), comparator_signal=water_level},
|
groups = {pickaxey=1, not_in_creative_inventory=1, cauldron=(1+water_level), cauldron_filled=water_level, comparator_signal=water_level},
|
||||||
node_box = cauldron_nodeboxes[water_level],
|
node_box = cauldron_nodeboxes[water_level],
|
||||||
collision_box = cauldron_nodeboxes[0],
|
collision_box = cauldron_nodeboxes[0],
|
||||||
selection_box = { type = "regular" },
|
selection_box = { type = "regular" },
|
||||||
|
@ -122,3 +122,20 @@ minetest.register_craft({
|
||||||
{ "mcl_core:iron_ingot", "mcl_core:iron_ingot", "mcl_core:iron_ingot" },
|
{ "mcl_core:iron_ingot", "mcl_core:iron_ingot", "mcl_core:iron_ingot" },
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
minetest.register_abm({
|
||||||
|
label = "cauldrons",
|
||||||
|
nodenames = {"group:cauldron_filled"},
|
||||||
|
interval = 0.5,
|
||||||
|
chance = 1,
|
||||||
|
action = function(pos, node)
|
||||||
|
for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 0.4)) do
|
||||||
|
if mcl_burning.is_burning(obj) then
|
||||||
|
mcl_burning.extinguish(obj)
|
||||||
|
local new_group = minetest.get_item_group(node.name, "cauldron_filled") - 1
|
||||||
|
minetest.swap_node(pos, {name = "mcl_cauldrons:cauldron" .. (new_group == 0 and "" or "_" .. new_group)})
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
|
@ -1,10 +1,162 @@
|
||||||
local S = minetest.get_translator("mcl_chests")
|
local S = minetest.get_translator("mcl_chests")
|
||||||
local mod_doc = minetest.get_modpath("doc")
|
local mod_doc = minetest.get_modpath("doc")
|
||||||
|
|
||||||
|
-- Chest Entity
|
||||||
|
local animate_chests = (minetest.settings:get_bool("animated_chests") ~= false)
|
||||||
|
local entity_animations = {
|
||||||
|
shulker = {
|
||||||
|
speed = 50,
|
||||||
|
open = {x = 45, y = 95},
|
||||||
|
close = {x = 95, y = 145},
|
||||||
|
},
|
||||||
|
chest = {
|
||||||
|
speed = 25,
|
||||||
|
open = {x = 0, y = 10},
|
||||||
|
open_partly = {x = 0, y = 7},
|
||||||
|
close = {x = 10, y = 20},
|
||||||
|
close_partly = {x = 13, y = 20},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
minetest.register_entity("mcl_chests:chest", {
|
||||||
|
initial_properties = {
|
||||||
|
visual = "mesh",
|
||||||
|
visual_size = {x = 3, y = 3},
|
||||||
|
pointable = false,
|
||||||
|
physical = false,
|
||||||
|
static_save = false,
|
||||||
|
},
|
||||||
|
|
||||||
|
set_animation = function(self, animname)
|
||||||
|
local anim_table = entity_animations[self.animation_type]
|
||||||
|
local anim = anim_table[animname]
|
||||||
|
if not anim then return end
|
||||||
|
self.object:set_animation(anim, anim_table.speed, 0, false)
|
||||||
|
end,
|
||||||
|
|
||||||
|
open = function(self, playername, partly)
|
||||||
|
self.players[playername] = true
|
||||||
|
if not self.is_open then
|
||||||
|
self:set_animation(partly and "open_partly" or "open")
|
||||||
|
minetest.sound_play(self.sound_prefix .. "_open", {
|
||||||
|
pos = self.node_pos,
|
||||||
|
})
|
||||||
|
self.is_open = true
|
||||||
|
self.opened_partly = partly
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
close = function(self, playername)
|
||||||
|
local playerlist = self.players
|
||||||
|
playerlist[playername] = nil
|
||||||
|
if self.is_open then
|
||||||
|
for _ in pairs(playerlist) do
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self:set_animation(self.opened_partly and "close_partly" or "close")
|
||||||
|
minetest.sound_play(self.sound_prefix .. "_close", {
|
||||||
|
pos = self.node_pos,
|
||||||
|
})
|
||||||
|
self.is_open = false
|
||||||
|
self.opened_partly = false
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
initialize = function(self, node_pos, node_name, textures, dir, double, sound_prefix, mesh_prefix, animation_type)
|
||||||
|
self.node_pos = node_pos
|
||||||
|
self.node_name = node_name
|
||||||
|
self.sound_prefix = sound_prefix
|
||||||
|
self.animation_type = animation_type
|
||||||
|
local obj = self.object
|
||||||
|
obj:set_properties({
|
||||||
|
textures = textures,
|
||||||
|
mesh = mesh_prefix .. (double and "_double" or "") .. ".b3d",
|
||||||
|
})
|
||||||
|
self:set_yaw(dir)
|
||||||
|
end,
|
||||||
|
|
||||||
|
reinitialize = function(self, node_name)
|
||||||
|
self.node_name = node_name
|
||||||
|
end,
|
||||||
|
|
||||||
|
set_yaw = function(self, dir)
|
||||||
|
self.object:set_yaw(minetest.dir_to_yaw(dir))
|
||||||
|
end,
|
||||||
|
|
||||||
|
check = function(self)
|
||||||
|
local node_pos, node_name = self.node_pos, self.node_name
|
||||||
|
if not node_pos or not node_name then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local node = minetest.get_node(node_pos)
|
||||||
|
if node.name ~= node_name then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_activate = function(self)
|
||||||
|
self.object:set_armor_groups({immortal = 1})
|
||||||
|
self.players = {}
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_step = function(self, dtime)
|
||||||
|
if not self:check() then
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
local function get_entity_pos(pos, dir, double)
|
||||||
|
pos = vector.new(pos)
|
||||||
|
pos.y = pos.y - 0.49
|
||||||
|
if double then
|
||||||
|
local add, mul, vec, cross = vector.add, vector.multiply, vector.new, vector.cross
|
||||||
|
pos = add(pos, mul(cross(dir, vec(0, 1, 0)), -0.5))
|
||||||
|
end
|
||||||
|
return pos
|
||||||
|
end
|
||||||
|
|
||||||
|
local function find_entity(pos)
|
||||||
|
for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 0)) do
|
||||||
|
local luaentity = obj:get_luaentity()
|
||||||
|
if luaentity and luaentity.name == "mcl_chests:chest" then
|
||||||
|
return luaentity
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function get_entity_info(pos, param2, double, dir, entity_pos)
|
||||||
|
dir = dir or minetest.facedir_to_dir(param2)
|
||||||
|
return dir, get_entity_pos(pos, dir, double)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, animation_type, dir, entity_pos)
|
||||||
|
dir, entity_pos = get_entity_info(pos, param2, double, dir, entity_pos)
|
||||||
|
local obj = minetest.add_entity(entity_pos, "mcl_chests:chest")
|
||||||
|
local luaentity = obj:get_luaentity()
|
||||||
|
luaentity:initialize(pos, node_name, textures, dir, double, sound_prefix, mesh_prefix, animation_type)
|
||||||
|
return luaentity
|
||||||
|
end
|
||||||
|
|
||||||
|
local function find_or_create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, animation_type, dir, entity_pos)
|
||||||
|
dir, entity_pos = get_entity_info(pos, param2, double, dir, entity_pos)
|
||||||
|
return find_entity(entity_pos) or create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, animation_type, dir, entity_pos)
|
||||||
|
end
|
||||||
|
|
||||||
local no_rotate, simple_rotate
|
local no_rotate, simple_rotate
|
||||||
if minetest.get_modpath("screwdriver") then
|
if minetest.get_modpath("screwdriver") then
|
||||||
no_rotate = screwdriver.disallow
|
no_rotate = screwdriver.disallow
|
||||||
simple_rotate = screwdriver.rotate_simple
|
simple_rotate = function(pos, node, user, mode, new_param2)
|
||||||
|
if screwdriver.rotate_simple(pos, node, user, mode, new_param2) ~= false then
|
||||||
|
local nodename = node.name
|
||||||
|
local nodedef = minetest.registered_nodes[nodename]
|
||||||
|
local dir = minetest.facedir_to_dir(new_param2)
|
||||||
|
find_or_create_entity(pos, nodename, nodedef._chest_entity_textures, new_param2, false, nodedef._chest_entity_sound, nodedef._chest_entity_mesh, nodedef._chest_entity_animation_type, dir):set_yaw(dir)
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[ List of open chests.
|
--[[ List of open chests.
|
||||||
|
@ -13,9 +165,23 @@ Value:
|
||||||
If player is using a chest: { pos = <chest node position> }
|
If player is using a chest: { pos = <chest node position> }
|
||||||
Otherwise: nil ]]
|
Otherwise: nil ]]
|
||||||
local open_chests = {}
|
local open_chests = {}
|
||||||
|
|
||||||
|
local function back_is_blocked(pos, dir)
|
||||||
|
pos = vector.add(pos, dir)
|
||||||
|
local def = minetest.registered_nodes[minetest.get_node(pos).name]
|
||||||
|
pos.y = pos.y + 1
|
||||||
|
local def2 = minetest.registered_nodes[minetest.get_node(pos).name]
|
||||||
|
return not def or def.groups.opaque == 1 or not def2 or def2.groups.opaque == 1
|
||||||
|
end
|
||||||
-- To be called if a player opened a chest
|
-- To be called if a player opened a chest
|
||||||
local player_chest_open = function(player, pos)
|
local player_chest_open = function(player, pos, node_name, textures, param2, double, sound, mesh, shulker)
|
||||||
open_chests[player:get_player_name()] = { pos = pos }
|
local name = player:get_player_name()
|
||||||
|
open_chests[name] = {pos = pos, node_name = node_name, textures = textures, param2 = param2, double = double, sound = sound, mesh = mesh, shulker = shulker}
|
||||||
|
if animate_chests then
|
||||||
|
local dir = minetest.facedir_to_dir(param2)
|
||||||
|
local blocked = not shulker and (back_is_blocked(pos, dir) or double and back_is_blocked(mcl_util.get_double_container_neighbor_pos(pos, param2, node_name:sub(-4)), dir))
|
||||||
|
find_or_create_entity(pos, node_name, textures, param2, double, sound, mesh, shulker and "shulker" or "chest", dir):open(name, blocked)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Simple protection checking functions
|
-- Simple protection checking functions
|
||||||
|
@ -44,11 +210,13 @@ local trapped_chest_mesecons_rules = mesecon.rules.pplate
|
||||||
local chest_update_after_close = function(pos)
|
local chest_update_after_close = function(pos)
|
||||||
local node = minetest.get_node(pos)
|
local node = minetest.get_node(pos)
|
||||||
|
|
||||||
if node.name == "mcl_chests:trapped_chest_on" then
|
if node.name == "mcl_chests:trapped_chest_on_small" then
|
||||||
minetest.swap_node(pos, {name="mcl_chests:trapped_chest", param2 = node.param2})
|
minetest.swap_node(pos, {name="mcl_chests:trapped_chest_small", param2 = node.param2})
|
||||||
|
find_or_create_entity(pos, "mcl_chests:trapped_chest_small", {"mcl_chests_trapped.png"}, node.param2, false, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_small")
|
||||||
mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
|
mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
|
||||||
elseif node.name == "mcl_chests:trapped_chest_on_left" then
|
elseif node.name == "mcl_chests:trapped_chest_on_left" then
|
||||||
minetest.swap_node(pos, {name="mcl_chests:trapped_chest_left", param2 = node.param2})
|
minetest.swap_node(pos, {name="mcl_chests:trapped_chest_left", param2 = node.param2})
|
||||||
|
find_or_create_entity(pos, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_left")
|
||||||
mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
|
mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
|
||||||
|
|
||||||
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left")
|
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left")
|
||||||
|
@ -60,6 +228,7 @@ local chest_update_after_close = function(pos)
|
||||||
|
|
||||||
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
|
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
|
||||||
minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_left", param2 = node.param2})
|
minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_left", param2 = node.param2})
|
||||||
|
find_or_create_entity(pos_other, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_left")
|
||||||
mesecon.receptor_off(pos_other, trapped_chest_mesecons_rules)
|
mesecon.receptor_off(pos_other, trapped_chest_mesecons_rules)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -67,11 +236,14 @@ end
|
||||||
-- To be called if a player closed a chest
|
-- To be called if a player closed a chest
|
||||||
local player_chest_close = function(player)
|
local player_chest_close = function(player)
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
if open_chests[name] == nil then
|
local open_chest = open_chests[name]
|
||||||
|
if open_chest == nil then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local pos = open_chests[name].pos
|
if animate_chests then
|
||||||
chest_update_after_close(pos)
|
find_or_create_entity(open_chest.pos, open_chest.node_name, open_chest.textures, open_chest.param2, open_chest.double, open_chest.sound, open_chest.mesh, open_chest.shulker and "shulker" or "chest"):close(name)
|
||||||
|
end
|
||||||
|
chest_update_after_close(open_chest.pos)
|
||||||
|
|
||||||
open_chests[name] = nil
|
open_chests[name] = nil
|
||||||
end
|
end
|
||||||
|
@ -146,18 +318,82 @@ local on_chest_blast = function(pos)
|
||||||
minetest.remove_node(pos)
|
minetest.remove_node(pos)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function limit_put_list(stack, list)
|
||||||
|
for _, other in ipairs(list) do
|
||||||
|
stack = other:add_item(stack)
|
||||||
|
if stack:is_empty() then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return stack
|
||||||
|
end
|
||||||
|
|
||||||
|
local function limit_put(stack, inv1, inv2)
|
||||||
|
local leftover = ItemStack(stack)
|
||||||
|
leftover = limit_put_list(leftover, inv1:get_list("main"))
|
||||||
|
leftover = limit_put_list(leftover, inv2:get_list("main"))
|
||||||
|
return stack:get_count() - leftover:get_count()
|
||||||
|
end
|
||||||
|
|
||||||
|
local small_name = "mcl_chests:"..basename.."_small"
|
||||||
|
local small_textures = tiles_table.small
|
||||||
|
local left_name = "mcl_chests:"..basename.."_left"
|
||||||
|
local left_textures = tiles_table.double
|
||||||
|
|
||||||
minetest.register_node("mcl_chests:"..basename, {
|
minetest.register_node("mcl_chests:"..basename, {
|
||||||
description = desc,
|
description = desc,
|
||||||
_tt_help = tt_help,
|
_tt_help = tt_help,
|
||||||
_doc_items_longdesc = longdesc,
|
_doc_items_longdesc = longdesc,
|
||||||
_doc_items_usagehelp = usagehelp,
|
_doc_items_usagehelp = usagehelp,
|
||||||
_doc_items_hidden = hidden,
|
_doc_items_hidden = hidden,
|
||||||
tiles = tiles_table.small,
|
drawtype = "mesh",
|
||||||
|
mesh = "mcl_chests_chest.obj",
|
||||||
|
tiles = small_textures,
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "facedir",
|
||||||
|
stack_max = 64,
|
||||||
|
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||||
|
groups = {deco_block=1},
|
||||||
|
on_construct = function(pos, node)
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
node.name = small_name
|
||||||
|
minetest.set_node(pos, node)
|
||||||
|
end,
|
||||||
|
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||||
|
minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name"))
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
local function close_forms(canonical_basename, pos)
|
||||||
|
local players = minetest.get_connected_players()
|
||||||
|
for p=1, #players do
|
||||||
|
if vector.distance(players[p]:get_pos(), pos) <= 30 then
|
||||||
|
minetest.close_formspec(players[p]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_node(small_name, {
|
||||||
|
description = desc,
|
||||||
|
_tt_help = tt_help,
|
||||||
|
_doc_items_longdesc = longdesc,
|
||||||
|
_doc_items_usagehelp = usagehelp,
|
||||||
|
_doc_items_hidden = hidden,
|
||||||
|
drawtype = "nodebox",
|
||||||
|
node_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = {-0.4375, -0.5, -0.4375, 0.4375, 0.375, 0.4375},
|
||||||
|
},
|
||||||
|
tiles = {"mcl_chests_blank.png"},
|
||||||
|
_chest_entity_textures = small_textures,
|
||||||
|
_chest_entity_sound = "default_chest",
|
||||||
|
_chest_entity_mesh = "mcl_chests_chest",
|
||||||
|
_chest_entity_animation_type = "chest",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
stack_max = 64,
|
stack_max = 64,
|
||||||
drop = drop,
|
drop = drop,
|
||||||
groups = {handy=1,axey=1, container=2, deco_block=1, material_wood=1,flammable=-1},
|
groups = {handy=1,axey=1, container=2, deco_block=1, material_wood=1,flammable=-1,chest_entity=1, not_in_creative_inventory=1},
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||||
on_construct = function(pos)
|
on_construct = function(pos)
|
||||||
|
@ -185,16 +421,19 @@ minetest.register_node("mcl_chests:"..basename, {
|
||||||
-- BEGIN OF LISTRING WORKAROUND
|
-- BEGIN OF LISTRING WORKAROUND
|
||||||
inv:set_size("input", 1)
|
inv:set_size("input", 1)
|
||||||
-- END OF LISTRING WORKAROUND
|
-- END OF LISTRING WORKAROUND
|
||||||
if minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "right")).name == "mcl_chests:"..canonical_basename then
|
if minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "right")).name == "mcl_chests:"..canonical_basename.."_small" then
|
||||||
minetest.swap_node(pos, {name="mcl_chests:"..canonical_basename.."_right",param2=param2})
|
minetest.swap_node(pos, {name="mcl_chests:"..canonical_basename.."_right",param2=param2})
|
||||||
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right")
|
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right")
|
||||||
minetest.swap_node(p, { name = "mcl_chests:"..canonical_basename.."_left", param2 = param2 })
|
minetest.swap_node(p, { name = "mcl_chests:"..canonical_basename.."_left", param2 = param2 })
|
||||||
elseif minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "left")).name == "mcl_chests:"..canonical_basename then
|
create_entity(p, "mcl_chests:"..canonical_basename.."_left", left_textures, param2, true, "default_chest", "mcl_chests_chest", "chest")
|
||||||
|
elseif minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "left")).name == "mcl_chests:"..canonical_basename.."_small" then
|
||||||
minetest.swap_node(pos, {name="mcl_chests:"..canonical_basename.."_left",param2=param2})
|
minetest.swap_node(pos, {name="mcl_chests:"..canonical_basename.."_left",param2=param2})
|
||||||
|
create_entity(pos, "mcl_chests:"..canonical_basename.."_left", left_textures, param2, true, "default_chest", "mcl_chests_chest", "chest")
|
||||||
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "left")
|
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "left")
|
||||||
minetest.swap_node(p, { name = "mcl_chests:"..canonical_basename.."_right", param2 = param2 })
|
minetest.swap_node(p, { name = "mcl_chests:"..canonical_basename.."_right", param2 = param2 })
|
||||||
else
|
else
|
||||||
minetest.swap_node(pos, { name = "mcl_chests:"..canonical_basename, param2 = param2 })
|
minetest.swap_node(pos, { name = "mcl_chests:"..canonical_basename.."_small", param2 = param2 })
|
||||||
|
create_entity(pos, small_name, small_textures, param2, false, "default_chest", "mcl_chests_chest", "chest")
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||||
|
@ -253,23 +492,31 @@ minetest.register_node("mcl_chests:"..basename, {
|
||||||
if on_rightclick_addendum then
|
if on_rightclick_addendum then
|
||||||
on_rightclick_addendum(pos, node, clicker)
|
on_rightclick_addendum(pos, node, clicker)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
player_chest_open(clicker, pos, small_name, small_textures, node.param2, false, "default_chest", "mcl_chests_chest")
|
||||||
end,
|
end,
|
||||||
|
|
||||||
on_destruct = function(pos)
|
on_destruct = function(pos)
|
||||||
local players = minetest.get_connected_players()
|
close_forms(canonical_basename, pos)
|
||||||
for p=1, #players do
|
|
||||||
minetest.close_formspec(players[p]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z)
|
|
||||||
end
|
|
||||||
end,
|
end,
|
||||||
mesecons = mesecons,
|
mesecons = mesecons,
|
||||||
on_rotate = simple_rotate,
|
on_rotate = simple_rotate,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_node("mcl_chests:"..basename.."_left", {
|
minetest.register_node(left_name, {
|
||||||
tiles = tiles_table.left,
|
drawtype = "nodebox",
|
||||||
|
node_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = {-0.4375, -0.5, -0.4375, 0.5, 0.375, 0.4375},
|
||||||
|
},
|
||||||
|
tiles = {"mcl_chests_blank.png"},
|
||||||
|
_chest_entity_textures = left_textures,
|
||||||
|
_chest_entity_sound = "default_chest",
|
||||||
|
_chest_entity_mesh = "mcl_chests_chest",
|
||||||
|
_chest_entity_animation_type = "chest",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
groups = {handy=1,axey=1, container=5,not_in_creative_inventory=1, material_wood=1,flammable=-1},
|
groups = {handy=1,axey=1, container=5,not_in_creative_inventory=1, material_wood=1,flammable=-1,chest_entity=1,double_chest=1},
|
||||||
drop = drop,
|
drop = drop,
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||||
|
@ -278,33 +525,31 @@ minetest.register_node("mcl_chests:"..basename.."_left", {
|
||||||
local param2 = n.param2
|
local param2 = n.param2
|
||||||
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "left")
|
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "left")
|
||||||
if not p or minetest.get_node(p).name ~= "mcl_chests:"..canonical_basename.."_right" then
|
if not p or minetest.get_node(p).name ~= "mcl_chests:"..canonical_basename.."_right" then
|
||||||
n.name = "mcl_chests:"..canonical_basename
|
n.name = "mcl_chests:"..canonical_basename.."_small"
|
||||||
minetest.swap_node(pos, n)
|
minetest.swap_node(pos, n)
|
||||||
end
|
end
|
||||||
|
create_entity(pos, left_name, left_textures, param2, true, "default_chest", "mcl_chests_chest", "chest")
|
||||||
end,
|
end,
|
||||||
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||||
minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name"))
|
minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name"))
|
||||||
end,
|
end,
|
||||||
on_destruct = function(pos)
|
on_destruct = function(pos)
|
||||||
local n = minetest.get_node(pos)
|
local n = minetest.get_node(pos)
|
||||||
if n.name == "mcl_chests:"..basename then
|
if n.name == small_name then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local players = minetest.get_connected_players()
|
close_forms(canonical_basename, pos)
|
||||||
for p=1, #players do
|
|
||||||
minetest.close_formspec(players[p]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z)
|
|
||||||
end
|
|
||||||
|
|
||||||
local param2 = n.param2
|
local param2 = n.param2
|
||||||
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "left")
|
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "left")
|
||||||
if not p or minetest.get_node(p).name ~= "mcl_chests:"..basename.."_right" then
|
if not p or minetest.get_node(p).name ~= "mcl_chests:"..basename.."_right" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
for pl=1, #players do
|
close_forms(canonical_basename, p)
|
||||||
minetest.close_formspec(players[pl]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..p.x.."_"..p.y.."_"..p.z)
|
|
||||||
end
|
minetest.swap_node(p, { name = small_name, param2 = param2 })
|
||||||
minetest.swap_node(p, { name = "mcl_chests:"..basename, param2 = param2 })
|
create_entity(p, small_name, small_textures, param2, false, "default_chest", "mcl_chests_chest", "chest")
|
||||||
end,
|
end,
|
||||||
after_dig_node = drop_items_chest,
|
after_dig_node = drop_items_chest,
|
||||||
on_blast = on_chest_blast,
|
on_blast = on_chest_blast,
|
||||||
|
@ -318,17 +563,19 @@ minetest.register_node("mcl_chests:"..basename.."_left", {
|
||||||
-- BEGIN OF LISTRING WORKAROUND
|
-- BEGIN OF LISTRING WORKAROUND
|
||||||
elseif listname == "input" then
|
elseif listname == "input" then
|
||||||
local inv = minetest.get_inventory({type="node", pos=pos})
|
local inv = minetest.get_inventory({type="node", pos=pos})
|
||||||
if inv:room_for_item("main", stack) then
|
local other_pos = mcl_util.get_double_container_neighbor_pos(pos, minetest.get_node(pos).param2, "left")
|
||||||
|
local other_inv = minetest.get_inventory({type="node", pos=other_pos})
|
||||||
|
return limit_put(stack, inv, other_inv)
|
||||||
|
--[[if inv:room_for_item("main", stack) then
|
||||||
return -1
|
return -1
|
||||||
else
|
else
|
||||||
local other_pos = mcl_util.get_double_container_neighbor_pos(pos, minetest.get_node(pos).param2, "left")
|
|
||||||
local other_inv = minetest.get_inventory({type="node", pos=other_pos})
|
|
||||||
if other_inv:room_for_item("main", stack) then
|
if other_inv:room_for_item("main", stack) then
|
||||||
return -1
|
return -1
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
end
|
end]]--
|
||||||
-- END OF LISTRING WORKAROUND
|
-- END OF LISTRING WORKAROUND
|
||||||
else
|
else
|
||||||
return stack:get_count()
|
return stack:get_count()
|
||||||
|
@ -347,6 +594,8 @@ minetest.register_node("mcl_chests:"..basename.."_left", {
|
||||||
local other_pos = mcl_util.get_double_container_neighbor_pos(pos, minetest.get_node(pos).param2, "left")
|
local other_pos = mcl_util.get_double_container_neighbor_pos(pos, minetest.get_node(pos).param2, "left")
|
||||||
local other_inv = minetest.get_inventory({type="node", pos=other_pos})
|
local other_inv = minetest.get_inventory({type="node", pos=other_pos})
|
||||||
|
|
||||||
|
inv:set_stack("input", 1, nil)
|
||||||
|
|
||||||
double_chest_add_item(inv, other_inv, "main", stack)
|
double_chest_add_item(inv, other_inv, "main", stack)
|
||||||
end
|
end
|
||||||
-- END OF LISTRING WORKAROUND
|
-- END OF LISTRING WORKAROUND
|
||||||
|
@ -399,16 +648,23 @@ minetest.register_node("mcl_chests:"..basename.."_left", {
|
||||||
if on_rightclick_addendum_left then
|
if on_rightclick_addendum_left then
|
||||||
on_rightclick_addendum_left(pos, node, clicker)
|
on_rightclick_addendum_left(pos, node, clicker)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
player_chest_open(clicker, pos, left_name, left_textures, node.param2, true, "default_chest", "mcl_chests_chest")
|
||||||
end,
|
end,
|
||||||
mesecons = mesecons,
|
mesecons = mesecons,
|
||||||
on_rotate = no_rotate,
|
on_rotate = no_rotate,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_node("mcl_chests:"..basename.."_right", {
|
minetest.register_node("mcl_chests:"..basename.."_right", {
|
||||||
tiles = tiles_table.right,
|
drawtype = "nodebox",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
groups = {handy=1,axey=1, container=6,not_in_creative_inventory=1, material_wood=1,flammable=-1},
|
node_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = {-0.5, -0.5, -0.4375, 0.4375, 0.375, 0.4375},
|
||||||
|
},
|
||||||
|
tiles = {"mcl_chests_blank.png"},
|
||||||
|
groups = {handy=1,axey=1, container=6,not_in_creative_inventory=1, material_wood=1,flammable=-1,double_chest=2},
|
||||||
drop = drop,
|
drop = drop,
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||||
|
@ -417,7 +673,7 @@ minetest.register_node("mcl_chests:"..basename.."_right", {
|
||||||
local param2 = n.param2
|
local param2 = n.param2
|
||||||
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right")
|
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right")
|
||||||
if not p or minetest.get_node(p).name ~= "mcl_chests:"..canonical_basename.."_left" then
|
if not p or minetest.get_node(p).name ~= "mcl_chests:"..canonical_basename.."_left" then
|
||||||
n.name = "mcl_chests:"..canonical_basename
|
n.name = "mcl_chests:"..canonical_basename.."_small"
|
||||||
minetest.swap_node(pos, n)
|
minetest.swap_node(pos, n)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
@ -426,24 +682,21 @@ minetest.register_node("mcl_chests:"..basename.."_right", {
|
||||||
end,
|
end,
|
||||||
on_destruct = function(pos)
|
on_destruct = function(pos)
|
||||||
local n = minetest.get_node(pos)
|
local n = minetest.get_node(pos)
|
||||||
if n.name == "mcl_chests:"..basename then
|
if n.name == small_name then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local players = minetest.get_connected_players()
|
close_forms(canonical_basename, pos)
|
||||||
for p=1, #players do
|
|
||||||
minetest.close_formspec(players[p]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z)
|
|
||||||
end
|
|
||||||
|
|
||||||
local param2 = n.param2
|
local param2 = n.param2
|
||||||
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right")
|
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right")
|
||||||
if not p or minetest.get_node(p).name ~= "mcl_chests:"..basename.."_left" then
|
if not p or minetest.get_node(p).name ~= "mcl_chests:"..basename.."_left" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
for pl=1, #players do
|
close_forms(canonical_basename, p)
|
||||||
minetest.close_formspec(players[pl]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..p.x.."_"..p.y.."_"..p.z)
|
|
||||||
end
|
minetest.swap_node(p, { name = small_name, param2 = param2 })
|
||||||
minetest.swap_node(p, { name = "mcl_chests:"..basename, param2 = param2 })
|
create_entity(p, small_name, small_textures, param2, false, "default_chest", "mcl_chests_chest", "chest")
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
end,
|
end,
|
||||||
after_dig_node = drop_items_chest,
|
after_dig_node = drop_items_chest,
|
||||||
|
@ -459,16 +712,17 @@ minetest.register_node("mcl_chests:"..basename.."_right", {
|
||||||
elseif listname == "input" then
|
elseif listname == "input" then
|
||||||
local other_pos = mcl_util.get_double_container_neighbor_pos(pos, minetest.get_node(pos).param2, "right")
|
local other_pos = mcl_util.get_double_container_neighbor_pos(pos, minetest.get_node(pos).param2, "right")
|
||||||
local other_inv = minetest.get_inventory({type="node", pos=other_pos})
|
local other_inv = minetest.get_inventory({type="node", pos=other_pos})
|
||||||
if other_inv:room_for_item("main", stack) then
|
local inv = minetest.get_inventory({type="node", pos=pos})
|
||||||
|
--[[if other_inv:room_for_item("main", stack) then
|
||||||
return -1
|
return -1
|
||||||
else
|
else
|
||||||
local inv = minetest.get_inventory({type="node", pos=pos})
|
|
||||||
if inv:room_for_item("main", stack) then
|
if inv:room_for_item("main", stack) then
|
||||||
return -1
|
return -1
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
end
|
end--]]
|
||||||
|
return limit_put(stack, other_inv, inv)
|
||||||
-- END OF LISTRING WORKAROUND
|
-- END OF LISTRING WORKAROUND
|
||||||
else
|
else
|
||||||
return stack:get_count()
|
return stack:get_count()
|
||||||
|
@ -487,6 +741,8 @@ minetest.register_node("mcl_chests:"..basename.."_right", {
|
||||||
local other_inv = minetest.get_inventory({type="node", pos=other_pos})
|
local other_inv = minetest.get_inventory({type="node", pos=other_pos})
|
||||||
local inv = minetest.get_inventory({type="node", pos=pos})
|
local inv = minetest.get_inventory({type="node", pos=pos})
|
||||||
|
|
||||||
|
inv:set_stack("input", 1, nil)
|
||||||
|
|
||||||
double_chest_add_item(other_inv, inv, "main", stack)
|
double_chest_add_item(other_inv, inv, "main", stack)
|
||||||
end
|
end
|
||||||
-- END OF LISTRING WORKAROUND
|
-- END OF LISTRING WORKAROUND
|
||||||
|
@ -540,14 +796,16 @@ minetest.register_node("mcl_chests:"..basename.."_right", {
|
||||||
if on_rightclick_addendum_right then
|
if on_rightclick_addendum_right then
|
||||||
on_rightclick_addendum_right(pos, node, clicker)
|
on_rightclick_addendum_right(pos, node, clicker)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
player_chest_open(clicker, pos_other, left_name, left_textures, node.param2, true, "default_chest", "mcl_chests_chest")
|
||||||
end,
|
end,
|
||||||
mesecons = mesecons,
|
mesecons = mesecons,
|
||||||
on_rotate = no_rotate,
|
on_rotate = no_rotate,
|
||||||
})
|
})
|
||||||
|
|
||||||
if mod_doc then
|
if mod_doc then
|
||||||
doc.add_entry_alias("nodes", "mcl_chests:"..basename, "nodes", "mcl_chests:"..basename.."_left")
|
doc.add_entry_alias("nodes", small_name, "nodes", "mcl_chests:"..basename.."_left")
|
||||||
doc.add_entry_alias("nodes", "mcl_chests:"..basename, "nodes", "mcl_chests:"..basename.."_right")
|
doc.add_entry_alias("nodes", small_name, "nodes", "mcl_chests:"..basename.."_right")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- END OF register_chest FUNCTION BODY
|
-- END OF register_chest FUNCTION BODY
|
||||||
|
@ -561,29 +819,33 @@ register_chest("chest",
|
||||||
chestusage,
|
chestusage,
|
||||||
S("27 inventory slots") .. "\n" .. S("Can be combined to a large chest"),
|
S("27 inventory slots") .. "\n" .. S("Can be combined to a large chest"),
|
||||||
{
|
{
|
||||||
small = {"default_chest_top.png", "mcl_chests_chest_bottom.png",
|
small = {"mcl_chests_normal.png"},
|
||||||
|
double = {"mcl_chests_normal_double.png"},
|
||||||
|
inv = {"default_chest_top.png", "mcl_chests_chest_bottom.png",
|
||||||
"mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
|
"mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
|
||||||
"mcl_chests_chest_back.png", "default_chest_front.png"},
|
"mcl_chests_chest_back.png", "default_chest_front.png"},
|
||||||
left = {"default_chest_top_big.png", "default_chest_top_big.png",
|
--[[left = {"default_chest_top_big.png", "default_chest_top_big.png",
|
||||||
"mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
|
"mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
|
||||||
"default_chest_side_big.png^[transformFX", "default_chest_front_big.png"},
|
"default_chest_side_big.png^[transformFX", "default_chest_front_big.png"},
|
||||||
right = {"default_chest_top_big.png^[transformFX", "default_chest_top_big.png^[transformFX",
|
right = {"default_chest_top_big.png^[transformFX", "default_chest_top_big.png^[transformFX",
|
||||||
"mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
|
"mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
|
||||||
"default_chest_side_big.png", "default_chest_front_big.png^[transformFX"},
|
"default_chest_side_big.png", "default_chest_front_big.png^[transformFX"},]]--
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
local traptiles = {
|
local traptiles = {
|
||||||
small = {"mcl_chests_chest_trapped_top.png", "mcl_chests_chest_trapped_bottom.png",
|
small = {"mcl_chests_trapped.png"},
|
||||||
|
double = {"mcl_chests_trapped_double.png"},
|
||||||
|
inv = {"mcl_chests_chest_trapped_top.png", "mcl_chests_chest_trapped_bottom.png",
|
||||||
"mcl_chests_chest_trapped_right.png", "mcl_chests_chest_trapped_left.png",
|
"mcl_chests_chest_trapped_right.png", "mcl_chests_chest_trapped_left.png",
|
||||||
"mcl_chests_chest_trapped_back.png", "mcl_chests_chest_trapped_front.png"},
|
"mcl_chests_chest_trapped_back.png", "mcl_chests_chest_trapped_front.png"},
|
||||||
left = {"mcl_chests_chest_trapped_top_big.png", "mcl_chests_chest_trapped_top_big.png",
|
--[[left = {"mcl_chests_chest_trapped_top_big.png", "mcl_chests_chest_trapped_top_big.png",
|
||||||
"mcl_chests_chest_trapped_right.png", "mcl_chests_chest_trapped_left.png",
|
"mcl_chests_chest_trapped_right.png", "mcl_chests_chest_trapped_left.png",
|
||||||
"mcl_chests_chest_trapped_side_big.png^[transformFX", "mcl_chests_chest_trapped_front_big.png"},
|
"mcl_chests_chest_trapped_side_big.png^[transformFX", "mcl_chests_chest_trapped_front_big.png"},
|
||||||
right = {"mcl_chests_chest_trapped_top_big.png^[transformFX", "mcl_chests_chest_trapped_top_big.png^[transformFX",
|
right = {"mcl_chests_chest_trapped_top_big.png^[transformFX", "mcl_chests_chest_trapped_top_big.png^[transformFX",
|
||||||
"mcl_chests_chest_trapped_right.png", "mcl_chests_chest_trapped_left.png",
|
"mcl_chests_chest_trapped_right.png", "mcl_chests_chest_trapped_left.png",
|
||||||
"mcl_chests_chest_trapped_side_big.png", "mcl_chests_chest_trapped_front_big.png^[transformFX"},
|
"mcl_chests_chest_trapped_side_big.png", "mcl_chests_chest_trapped_front_big.png^[transformFX"},]]--
|
||||||
}
|
}
|
||||||
|
|
||||||
register_chest("trapped_chest",
|
register_chest("trapped_chest",
|
||||||
|
@ -598,22 +860,21 @@ register_chest("trapped_chest",
|
||||||
rules = trapped_chest_mesecons_rules,
|
rules = trapped_chest_mesecons_rules,
|
||||||
}},
|
}},
|
||||||
function(pos, node, clicker)
|
function(pos, node, clicker)
|
||||||
minetest.swap_node(pos, {name="mcl_chests:trapped_chest_on", param2 = node.param2})
|
minetest.swap_node(pos, {name="mcl_chests:trapped_chest_on_small", param2 = node.param2})
|
||||||
|
find_or_create_entity(pos, "mcl_chests:trapped_chest_on_small", {"mcl_chests_trapped.png"}, node.param2, false, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_on_small")
|
||||||
mesecon.receptor_on(pos, trapped_chest_mesecons_rules)
|
mesecon.receptor_on(pos, trapped_chest_mesecons_rules)
|
||||||
player_chest_open(clicker, pos)
|
|
||||||
end,
|
end,
|
||||||
function(pos, node, clicker)
|
function(pos, node, clicker)
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
meta:set_int("players", 1)
|
meta:set_int("players", 1)
|
||||||
|
|
||||||
minetest.swap_node(pos, {name="mcl_chests:trapped_chest_on_left", param2 = node.param2})
|
minetest.swap_node(pos, {name="mcl_chests:trapped_chest_on_left", param2 = node.param2})
|
||||||
|
find_or_create_entity(pos, "mcl_chests:trapped_chest_on_left", {"mcl_chests_trapped_double.png"}, node.param2, true, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_on_left")
|
||||||
mesecon.receptor_on(pos, trapped_chest_mesecons_rules)
|
mesecon.receptor_on(pos, trapped_chest_mesecons_rules)
|
||||||
|
|
||||||
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left")
|
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left")
|
||||||
minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_on_right", param2 = node.param2})
|
minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_on_right", param2 = node.param2})
|
||||||
mesecon.receptor_on(pos_other, trapped_chest_mesecons_rules)
|
mesecon.receptor_on(pos_other, trapped_chest_mesecons_rules)
|
||||||
|
|
||||||
player_chest_open(clicker, pos)
|
|
||||||
end,
|
end,
|
||||||
function(pos, node, clicker)
|
function(pos, node, clicker)
|
||||||
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
|
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
|
||||||
|
@ -622,9 +883,8 @@ register_chest("trapped_chest",
|
||||||
mesecon.receptor_on(pos, trapped_chest_mesecons_rules)
|
mesecon.receptor_on(pos, trapped_chest_mesecons_rules)
|
||||||
|
|
||||||
minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_on_left", param2 = node.param2})
|
minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_on_left", param2 = node.param2})
|
||||||
|
find_or_create_entity(pos_other, "mcl_chests:trapped_chest_on_left", {"mcl_chests_trapped_double.png"}, node.param2, true, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_on_left")
|
||||||
mesecon.receptor_on(pos_other, trapped_chest_mesecons_rules)
|
mesecon.receptor_on(pos_other, trapped_chest_mesecons_rules)
|
||||||
|
|
||||||
player_chest_open(clicker, pos)
|
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -634,15 +894,7 @@ register_chest("trapped_chest_on",
|
||||||
state = mesecon.state.on,
|
state = mesecon.state.on,
|
||||||
rules = trapped_chest_mesecons_rules,
|
rules = trapped_chest_mesecons_rules,
|
||||||
}},
|
}},
|
||||||
function(pos, node, clicker)
|
nil, nil, nil,
|
||||||
player_chest_open(clicker, pos)
|
|
||||||
end,
|
|
||||||
function(pos, node, clicker)
|
|
||||||
player_chest_open(clicker, pos)
|
|
||||||
end,
|
|
||||||
function(pos, node, clicker)
|
|
||||||
player_chest_open(clicker, pos)
|
|
||||||
end,
|
|
||||||
"trapped_chest",
|
"trapped_chest",
|
||||||
"trapped_chest"
|
"trapped_chest"
|
||||||
)
|
)
|
||||||
|
@ -650,13 +902,15 @@ register_chest("trapped_chest_on",
|
||||||
local function close_if_trapped_chest(pos, player)
|
local function close_if_trapped_chest(pos, player)
|
||||||
local node = minetest.get_node(pos)
|
local node = minetest.get_node(pos)
|
||||||
|
|
||||||
if node.name == "mcl_chests:trapped_chest_on" then
|
if node.name == "mcl_chests:trapped_chest_on_small" then
|
||||||
minetest.swap_node(pos, {name="mcl_chests:trapped_chest", param2 = node.param2})
|
minetest.swap_node(pos, {name="mcl_chests:trapped_chest_small", param2 = node.param2})
|
||||||
|
find_or_create_entity(pos, "mcl_chests:trapped_chest_small", {"mcl_chests_trapped.png"}, node.param2, false, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_small")
|
||||||
mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
|
mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
|
||||||
|
|
||||||
player_chest_close(player)
|
player_chest_close(player)
|
||||||
elseif node.name == "mcl_chests:trapped_chest_on_left" then
|
elseif node.name == "mcl_chests:trapped_chest_on_left" then
|
||||||
minetest.swap_node(pos, {name="mcl_chests:trapped_chest_left", param2 = node.param2})
|
minetest.swap_node(pos, {name="mcl_chests:trapped_chest_left", param2 = node.param2})
|
||||||
|
find_or_create_entity(pos, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_left")
|
||||||
mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
|
mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
|
||||||
|
|
||||||
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left")
|
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left")
|
||||||
|
@ -670,15 +924,16 @@ local function close_if_trapped_chest(pos, player)
|
||||||
|
|
||||||
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
|
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
|
||||||
minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_left", param2 = node.param2})
|
minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_left", param2 = node.param2})
|
||||||
|
find_or_create_entity(pos_other, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_left")
|
||||||
mesecon.receptor_off(pos_other, trapped_chest_mesecons_rules)
|
mesecon.receptor_off(pos_other, trapped_chest_mesecons_rules)
|
||||||
|
|
||||||
player_chest_close(player)
|
player_chest_close(player)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Disable trapped chest when it has been closed
|
-- Disable chest when it has been closed
|
||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
if formname:find("mcl_chests:trapped_chest_") == 1 then
|
if formname:find("mcl_chests:") == 1 then
|
||||||
if fields.quit then
|
if fields.quit then
|
||||||
player_chest_close(player)
|
player_chest_close(player)
|
||||||
end
|
end
|
||||||
|
@ -710,6 +965,26 @@ minetest.register_craft({
|
||||||
burntime = 15
|
burntime = 15
|
||||||
})
|
})
|
||||||
|
|
||||||
|
minetest.register_node("mcl_chests:ender_chest", {
|
||||||
|
description = S("Ender Chest"),
|
||||||
|
_tt_help = S("27 interdimensional inventory slots") .. "\n" .. S("Put items inside, retrieve them from any ender chest"),
|
||||||
|
_doc_items_longdesc = S("Ender chests grant you access to a single personal interdimensional inventory with 27 slots. This inventory is the same no matter from which ender chest you access it from. If you put one item into one ender chest, you will find it in all other ender chests. Each player will only see their own items, but not the items of other players."),
|
||||||
|
_doc_items_usagehelp = S("Rightclick the ender chest to access your personal interdimensional inventory."),
|
||||||
|
drawtype = "mesh",
|
||||||
|
mesh = "mcl_chests_chest.obj",
|
||||||
|
tiles = {"mcl_chests_ender.png"},
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "facedir",
|
||||||
|
stack_max = 64,
|
||||||
|
groups = {deco_block=1},
|
||||||
|
sounds = mcl_sounds.node_sound_stone_defaults(),
|
||||||
|
on_construct = function(pos, node)
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
node.name = "mcl_chests:ender_chest_small"
|
||||||
|
minetest.set_node(pos, node)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
local formspec_ender_chest = "size[9,8.75]"..
|
local formspec_ender_chest = "size[9,8.75]"..
|
||||||
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Ender Chest"))).."]"..
|
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Ender Chest"))).."]"..
|
||||||
"list[current_player;enderchest;0,0.5;9,3;]"..
|
"list[current_player;enderchest;0,0.5;9,3;]"..
|
||||||
|
@ -723,17 +998,27 @@ local formspec_ender_chest = "size[9,8.75]"..
|
||||||
"listring[current_player;main]"
|
"listring[current_player;main]"
|
||||||
|
|
||||||
|
|
||||||
minetest.register_node("mcl_chests:ender_chest", {
|
minetest.register_node("mcl_chests:ender_chest_small", {
|
||||||
description = S("Ender Chest"),
|
description = S("Ender Chest"),
|
||||||
_tt_help = S("27 interdimensional inventory slots") .. "\n" .. S("Put items inside, retrieve them from any ender chest"),
|
_tt_help = S("27 interdimensional inventory slots") .. "\n" .. S("Put items inside, retrieve them from any ender chest"),
|
||||||
_doc_items_longdesc = S("Ender chests grant you access to a single personal interdimensional inventory with 27 slots. This inventory is the same no matter from which ender chest you access it from. If you put one item into one ender chest, you will find it in all other ender chests. Each player will only see their own items, but not the items of other players."),
|
_doc_items_longdesc = S("Ender chests grant you access to a single personal interdimensional inventory with 27 slots. This inventory is the same no matter from which ender chest you access it from. If you put one item into one ender chest, you will find it in all other ender chests. Each player will only see their own items, but not the items of other players."),
|
||||||
_doc_items_usagehelp = S("Rightclick the ender chest to access your personal interdimensional inventory."),
|
_doc_items_usagehelp = S("Rightclick the ender chest to access your personal interdimensional inventory."),
|
||||||
tiles = {"mcl_chests_ender_chest_top.png", "mcl_chests_ender_chest_bottom.png",
|
drawtype = "nodebox",
|
||||||
|
node_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = {-0.4375, -0.5, -0.4375, 0.5, 0.375, 0.4375},
|
||||||
|
},
|
||||||
|
_chest_entity_textures = {"mcl_chests_ender.png"},
|
||||||
|
_chest_entity_sound = "mcl_chests_enderchest",
|
||||||
|
_chest_entity_mesh = "mcl_chests_chest",
|
||||||
|
_chest_entity_animation_type = "chest",
|
||||||
|
tiles = {"mcl_chests_blank.png"},
|
||||||
|
--[[{"mcl_chests_ender_chest_top.png", "mcl_chests_ender_chest_bottom.png",
|
||||||
"mcl_chests_ender_chest_right.png", "mcl_chests_ender_chest_left.png",
|
"mcl_chests_ender_chest_right.png", "mcl_chests_ender_chest_left.png",
|
||||||
"mcl_chests_ender_chest_back.png", "mcl_chests_ender_chest_front.png"},
|
"mcl_chests_ender_chest_back.png", "mcl_chests_ender_chest_front.png"},]]--
|
||||||
-- Note: The “container” group is missing here because the ender chest does not
|
-- Note: The “container” group is missing here because the ender chest does not
|
||||||
-- have an inventory on its own
|
-- have an inventory on its own
|
||||||
groups = {pickaxey=1, deco_block=1, material_stone=1},
|
groups = {pickaxey=1, deco_block=1, material_stone=1, chest_entity=1, not_in_creative_inventory=1},
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
light_source = 7,
|
light_source = 7,
|
||||||
|
@ -743,23 +1028,22 @@ minetest.register_node("mcl_chests:ender_chest", {
|
||||||
on_construct = function(pos)
|
on_construct = function(pos)
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
meta:set_string("formspec", formspec_ender_chest)
|
meta:set_string("formspec", formspec_ender_chest)
|
||||||
|
create_entity(pos, "mcl_chests:ender_chest_small", {"mcl_chests_ender.png"}, minetest.get_node(pos).param2, false, "mcl_chests_enderchest", "mcl_chests_chest", "chest")
|
||||||
|
end,
|
||||||
|
on_rightclick = function(pos, node, clicker)
|
||||||
|
player_chest_open(clicker, pos, "mcl_chests:ender_chest_small", {"mcl_chests_ender.png"}, node.param2, false, "mcl_chests_enderchest", "mcl_chests_chest")
|
||||||
|
end,
|
||||||
|
on_receive_fields = function(pos, formname, fields, sender)
|
||||||
|
if fields.quit then
|
||||||
|
player_chest_close(sender)
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
_mcl_blast_resistance = 3000,
|
_mcl_blast_resistance = 3000,
|
||||||
_mcl_hardness = 22.5,
|
_mcl_hardness = 22.5,
|
||||||
_mcl_silk_touch_drop = true,
|
_mcl_silk_touch_drop = {"mcl_chests:ender_chest"},
|
||||||
on_rotate = simple_rotate,
|
on_rotate = simple_rotate,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_lbm({
|
|
||||||
label = "Update ender chest + shulker box formspecs (0.51.0)",
|
|
||||||
name = "mcl_chests:update_formspecs_0_51_0",
|
|
||||||
nodenames = { "mcl_chests:ender_chest", "group:shulker_box" },
|
|
||||||
action = function(pos, node)
|
|
||||||
minetest.registered_nodes[node.name].on_construct(pos)
|
|
||||||
minetest.log("action", "[mcl_chests] Node formspec updated at "..minetest.pos_to_string(pos))
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_on_joinplayer(function(player)
|
minetest.register_on_joinplayer(function(player)
|
||||||
local inv = player:get_inventory()
|
local inv = player:get_inventory()
|
||||||
inv:set_size("enderchest", 9*3)
|
inv:set_size("enderchest", 9*3)
|
||||||
|
@ -852,6 +1136,8 @@ for color, desc in pairs(boxtypes) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local small_name = "mcl_chests:"..color.."_shulker_box_small"
|
||||||
|
|
||||||
minetest.register_node("mcl_chests:"..color.."_shulker_box", {
|
minetest.register_node("mcl_chests:"..color.."_shulker_box", {
|
||||||
description = desc,
|
description = desc,
|
||||||
_tt_help = S("27 inventory slots") .. "\n" .. S("Can be carried around with its contents"),
|
_tt_help = S("27 inventory slots") .. "\n" .. S("Can be carried around with its contents"),
|
||||||
|
@ -859,43 +1145,26 @@ for color, desc in pairs(boxtypes) do
|
||||||
_doc_items_entry_name = entry_name,
|
_doc_items_entry_name = entry_name,
|
||||||
_doc_items_longdesc = longdesc,
|
_doc_items_longdesc = longdesc,
|
||||||
_doc_items_usagehelp = usagehelp,
|
_doc_items_usagehelp = usagehelp,
|
||||||
tiles = {
|
tiles = {mob_texture},
|
||||||
"mcl_chests_"..color.."_shulker_box_top.png", -- top
|
drawtype = "mesh",
|
||||||
|
mesh = "mcl_chests_shulker.obj",
|
||||||
|
--[["mcl_chests_"..color.."_shulker_box_top.png", -- top
|
||||||
"[combine:16x16:-32,-28="..mob_texture, -- bottom
|
"[combine:16x16:-32,-28="..mob_texture, -- bottom
|
||||||
"[combine:16x16:0,-36="..mob_texture..":0,-16="..mob_texture, -- side
|
"[combine:16x16:0,-36="..mob_texture..":0,-16="..mob_texture, -- side
|
||||||
"[combine:16x16:-32,-36="..mob_texture..":-32,-16="..mob_texture, -- side
|
"[combine:16x16:-32,-36="..mob_texture..":-32,-16="..mob_texture, -- side
|
||||||
"[combine:16x16:-16,-36="..mob_texture..":-16,-16="..mob_texture, -- side
|
"[combine:16x16:-16,-36="..mob_texture..":-16,-16="..mob_texture, -- side
|
||||||
"[combine:16x16:-48,-36="..mob_texture..":-48,-16="..mob_texture, -- side
|
"[combine:16x16:-48,-36="..mob_texture..":-48,-16="..mob_texture, -- side]]--
|
||||||
},
|
groups = {handy=1,pickaxey=1, container=3, deco_block=1, dig_by_piston=1, shulker_box=1, old_shulker_box_node=1},
|
||||||
groups = {handy=1,pickaxey=1, container=3, deco_block=1, dig_by_piston=1, shulker_box=1},
|
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
sounds = mcl_sounds.node_sound_stone_defaults(),
|
sounds = mcl_sounds.node_sound_stone_defaults(),
|
||||||
stack_max = 1,
|
stack_max = 1,
|
||||||
drop = "",
|
drop = "",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
-- TODO: Make shulker boxes rotatable
|
|
||||||
-- This doesn't work, it just destroys the inventory:
|
|
||||||
-- on_place = minetest.rotate_node,
|
|
||||||
on_construct = function(pos)
|
on_construct = function(pos)
|
||||||
local meta = minetest.get_meta(pos)
|
local node = minetest.get_node(pos)
|
||||||
meta:set_string("formspec", formspec_shulker_box(nil))
|
node.name = small_name
|
||||||
local inv = meta:get_inventory()
|
minetest.set_node(pos, node)
|
||||||
inv:set_size("main", 9*3)
|
|
||||||
end,
|
|
||||||
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
|
|
||||||
-- Place shulker box as node
|
|
||||||
if minetest.registered_nodes[dropnode.name].buildable_to then
|
|
||||||
minetest.set_node(droppos, {name = stack:get_name(), param2 = minetest.dir_to_facedir(dropdir)})
|
|
||||||
local ninv = minetest.get_inventory({type="node", pos=droppos})
|
|
||||||
local imetadata = stack:get_metadata()
|
|
||||||
local iinv_main = minetest.deserialize(imetadata)
|
|
||||||
ninv:set_list("main", iinv_main)
|
|
||||||
ninv:set_size("main", 9*3)
|
|
||||||
set_shulkerbox_meta(minetest.get_meta(droppos), stack:get_meta())
|
|
||||||
stack:take_item()
|
|
||||||
end
|
|
||||||
return stack
|
|
||||||
end,
|
end,
|
||||||
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||||
local nmeta = minetest.get_meta(pos)
|
local nmeta = minetest.get_meta(pos)
|
||||||
|
@ -916,6 +1185,79 @@ for color, desc in pairs(boxtypes) do
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
|
||||||
|
-- Place shulker box as node
|
||||||
|
if minetest.registered_nodes[dropnode.name].buildable_to then
|
||||||
|
minetest.set_node(droppos, {name = small_name, param2 = minetest.dir_to_facedir(dropdir)})
|
||||||
|
local ninv = minetest.get_inventory({type="node", pos=droppos})
|
||||||
|
local imetadata = stack:get_metadata()
|
||||||
|
local iinv_main = minetest.deserialize(imetadata)
|
||||||
|
ninv:set_list("main", iinv_main)
|
||||||
|
ninv:set_size("main", 9*3)
|
||||||
|
set_shulkerbox_meta(minetest.get_meta(droppos), stack:get_meta())
|
||||||
|
stack:take_item()
|
||||||
|
end
|
||||||
|
return stack
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_node(small_name, {
|
||||||
|
description = desc,
|
||||||
|
_tt_help = S("27 inventory slots") .. "\n" .. S("Can be carried around with its contents"),
|
||||||
|
_doc_items_create_entry = create_entry,
|
||||||
|
_doc_items_entry_name = entry_name,
|
||||||
|
_doc_items_longdesc = longdesc,
|
||||||
|
_doc_items_usagehelp = usagehelp,
|
||||||
|
drawtype = "nodebox",
|
||||||
|
tiles = {"mcl_chests_blank.png"},
|
||||||
|
_chest_entity_textures = {mob_texture},
|
||||||
|
_chest_entity_sound = "mcl_chests_shulker",
|
||||||
|
_chest_entity_mesh = "mcl_chests_shulker",
|
||||||
|
_chest_entity_animation_type = "shulker",
|
||||||
|
groups = {handy=1,pickaxey=1, container=3, deco_block=1, dig_by_piston=1, shulker_box=1, chest_entity=1, not_in_creative_inventory=1},
|
||||||
|
is_ground_content = false,
|
||||||
|
sounds = mcl_sounds.node_sound_stone_defaults(),
|
||||||
|
stack_max = 1,
|
||||||
|
drop = "",
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "facedir",
|
||||||
|
-- TODO: Make shulker boxes rotatable
|
||||||
|
-- This doesn't work, it just destroys the inventory:
|
||||||
|
-- on_place = minetest.rotate_node,
|
||||||
|
on_construct = function(pos)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
meta:set_string("formspec", formspec_shulker_box(nil))
|
||||||
|
local inv = meta:get_inventory()
|
||||||
|
inv:set_size("main", 9*3)
|
||||||
|
create_entity(pos, small_name, {mob_texture}, minetest.get_node(pos).param2, false, "mcl_chests_shulker", "mcl_chests_shulker", "shulker")
|
||||||
|
end,
|
||||||
|
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||||
|
local nmeta = minetest.get_meta(pos)
|
||||||
|
local imetadata = itemstack:get_metadata()
|
||||||
|
local iinv_main = minetest.deserialize(imetadata)
|
||||||
|
local ninv = nmeta:get_inventory()
|
||||||
|
ninv:set_list("main", iinv_main)
|
||||||
|
ninv:set_size("main", 9*3)
|
||||||
|
set_shulkerbox_meta(nmeta, itemstack:get_meta())
|
||||||
|
|
||||||
|
if minetest.is_creative_enabled(placer:get_player_name()) then
|
||||||
|
if not ninv:is_empty("main") then
|
||||||
|
return nil
|
||||||
|
else
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
on_rightclick = function(pos, node, clicker)
|
||||||
|
player_chest_open(clicker, pos, small_name, {mob_texture}, node.param2, false, "mcl_chests_shulker", "mcl_chests_shulker", true)
|
||||||
|
end,
|
||||||
|
on_receive_fields = function(pos, formname, fields, sender)
|
||||||
|
if fields.quit then
|
||||||
|
player_chest_close(sender)
|
||||||
|
end
|
||||||
|
end,
|
||||||
on_destruct = function(pos)
|
on_destruct = function(pos)
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
local inv = meta:get_inventory()
|
local inv = meta:get_inventory()
|
||||||
|
@ -961,6 +1303,7 @@ for color, desc in pairs(boxtypes) do
|
||||||
|
|
||||||
if mod_doc and not is_canonical then
|
if mod_doc and not is_canonical then
|
||||||
doc.add_entry_alias("nodes", "mcl_chests:"..canonical_shulker_color.."_shulker_box", "nodes", "mcl_chests:"..color.."_shulker_box")
|
doc.add_entry_alias("nodes", "mcl_chests:"..canonical_shulker_color.."_shulker_box", "nodes", "mcl_chests:"..color.."_shulker_box")
|
||||||
|
doc.add_entry_alias("nodes", "mcl_chests:"..canonical_shulker_color.."_shulker_box_small", "nodes", "mcl_chests:"..color.."_shulker_box_small")
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
|
@ -1001,6 +1344,40 @@ minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
local function select_and_spawn_entity(pos, node)
|
||||||
|
local node_name = node.name
|
||||||
|
local node_def = minetest.registered_nodes[node_name]
|
||||||
|
local double_chest = minetest.get_item_group(node_name, "double_chest") > 0
|
||||||
|
create_entity(pos, node_name, node_def._chest_entity_textures, node.param2, double_chest, node_def._chest_entity_sound, node_def._chest_entity_mesh, node_def._chest_entity_animation_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_lbm({
|
||||||
|
label = "Spawn Chest entities",
|
||||||
|
name = "mcl_chests:spawn_chest_entities",
|
||||||
|
nodenames = {"group:chest_entity"},
|
||||||
|
run_at_every_load = true,
|
||||||
|
action = select_and_spawn_entity,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_lbm({
|
||||||
|
label = "Replace old chest nodes",
|
||||||
|
name = "mcl_chests:replace_old",
|
||||||
|
nodenames = {"mcl_chests:chest", "mcl_chests:trapped_chest", "mcl_chests:trapped_chest_on", "mcl_chests:ender_chest", "group:old_shulker_box_node"},
|
||||||
|
run_at_every_load = true,
|
||||||
|
action = function(pos, node)
|
||||||
|
local node_name = node.name
|
||||||
|
node.name = node_name .. "_small"
|
||||||
|
minetest.swap_node(pos, node)
|
||||||
|
select_and_spawn_entity(pos, node)
|
||||||
|
if node_name == "mcl_chests:trapped_chest_on" then
|
||||||
|
minetest.log("action", "[mcl_chests] Disabled active trapped chest on load: " ..minetest.pos_to_string(pos))
|
||||||
|
chest_update_after_close(pos)
|
||||||
|
elseif node_name == "mcl_chests:ender_chest" then
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
meta:set_string("formspec", formspec_ender_chest)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
minetest.register_lbm({
|
minetest.register_lbm({
|
||||||
-- Disable active/open trapped chests when loaded because nobody could
|
-- Disable active/open trapped chests when loaded because nobody could
|
||||||
|
@ -1008,7 +1385,7 @@ minetest.register_lbm({
|
||||||
-- Fixes redstone weirdness.
|
-- Fixes redstone weirdness.
|
||||||
label = "Disable active trapped chests",
|
label = "Disable active trapped chests",
|
||||||
name = "mcl_chests:reset_trapped_chests",
|
name = "mcl_chests:reset_trapped_chests",
|
||||||
nodenames = { "mcl_chests:trapped_chest_on", "mcl_chests:trapped_chest_on_left", "mcl_chests:trapped_chest_on_right" },
|
nodenames = { "mcl_chests:trapped_chest_on_small", "mcl_chests:trapped_chest_on_left", "mcl_chests:trapped_chest_on_right" },
|
||||||
run_at_every_load = true,
|
run_at_every_load = true,
|
||||||
action = function(pos, node)
|
action = function(pos, node)
|
||||||
minetest.log("action", "[mcl_chests] Disabled active trapped chest on load: " ..minetest.pos_to_string(pos))
|
minetest.log("action", "[mcl_chests] Disabled active trapped chest on load: " ..minetest.pos_to_string(pos))
|
||||||
|
@ -1016,17 +1393,6 @@ minetest.register_lbm({
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- Legacy
|
|
||||||
minetest.register_lbm({
|
|
||||||
label = "Update ender chest formspecs (0.60.0)",
|
|
||||||
name = "mcl_chests:update_ender_chest_formspecs_0_60_0",
|
|
||||||
nodenames = { "mcl_chests:ender_chest" },
|
|
||||||
run_at_every_load = false,
|
|
||||||
action = function(pos, node)
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
meta:set_string("formspec", formspec_ender_chest)
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
minetest.register_lbm({
|
minetest.register_lbm({
|
||||||
label = "Update shulker box formspecs (0.60.0)",
|
label = "Update shulker box formspecs (0.60.0)",
|
||||||
name = "mcl_chests:update_shulker_box_formspecs_0_60_0",
|
name = "mcl_chests:update_shulker_box_formspecs_0_60_0",
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
# Blender v2.76 (sub 0) OBJ File: 'chest.small.facedir.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib chest.small.facedir.mtl
|
||||||
|
o chest_upper_upper
|
||||||
|
v 0.062513 -0.063134 -0.500468
|
||||||
|
v 0.062513 0.186920 -0.500468
|
||||||
|
v 0.062514 -0.063134 -0.437955
|
||||||
|
v 0.062514 0.186920 -0.437955
|
||||||
|
v -0.062514 -0.063134 -0.500468
|
||||||
|
v -0.062514 0.186920 -0.500468
|
||||||
|
v -0.062514 -0.063134 -0.437955
|
||||||
|
v -0.062514 0.186920 -0.437955
|
||||||
|
v 0.437907 0.061263 -0.438085
|
||||||
|
v 0.437907 0.373830 -0.438085
|
||||||
|
v 0.437907 0.061263 0.437729
|
||||||
|
v 0.437907 0.373830 0.437729
|
||||||
|
v -0.437907 0.061263 -0.438085
|
||||||
|
v -0.437907 0.373830 -0.438085
|
||||||
|
v -0.437907 0.061263 0.437729
|
||||||
|
v -0.437907 0.373830 0.437729
|
||||||
|
v 0.437595 -0.500754 -0.437772
|
||||||
|
v 0.437595 0.124381 -0.437772
|
||||||
|
v 0.437595 -0.500754 0.437417
|
||||||
|
v 0.437595 0.124381 0.437417
|
||||||
|
v -0.437595 -0.500754 -0.437772
|
||||||
|
v -0.437595 0.124381 -0.437772
|
||||||
|
v -0.437595 -0.500754 0.437417
|
||||||
|
v -0.437595 0.124381 0.437417
|
||||||
|
vt 0.015625 0.921875
|
||||||
|
vt 0.015625 0.984375
|
||||||
|
vt 0.000000 0.984375
|
||||||
|
vt 0.000000 0.921875
|
||||||
|
vt 0.093750 0.921875
|
||||||
|
vt 0.093750 0.984375
|
||||||
|
vt 0.062500 0.984375
|
||||||
|
vt 0.062500 0.921875
|
||||||
|
vt 0.046875 0.984375
|
||||||
|
vt 0.046875 0.921875
|
||||||
|
vt 0.078125 0.984375
|
||||||
|
vt 0.078125 1.000000
|
||||||
|
vt 0.046875 1.000000
|
||||||
|
vt 0.015625 1.000000
|
||||||
|
vt 0.218750 0.703125
|
||||||
|
vt 0.218750 0.781250
|
||||||
|
vt 0.000000 0.781250
|
||||||
|
vt 0.000000 0.703125
|
||||||
|
vt 0.875000 0.703125
|
||||||
|
vt 0.875000 0.781250
|
||||||
|
vt 0.656250 0.781250
|
||||||
|
vt 0.656250 0.703125
|
||||||
|
vt 0.437500 0.781250
|
||||||
|
vt 0.437500 0.703125
|
||||||
|
vt 0.656250 1.000000
|
||||||
|
vt 0.437500 1.000000
|
||||||
|
vt 0.218750 1.000000
|
||||||
|
vt 0.218750 0.328125
|
||||||
|
vt 0.218750 0.484375
|
||||||
|
vt -0.000000 0.484375
|
||||||
|
vt -0.000000 0.328125
|
||||||
|
vt 0.875000 0.328125
|
||||||
|
vt 0.875000 0.484375
|
||||||
|
vt 0.656250 0.484375
|
||||||
|
vt 0.656250 0.328125
|
||||||
|
vt 0.437500 0.484375
|
||||||
|
vt 0.437500 0.328125
|
||||||
|
vn 1.000000 0.000000 -0.000000
|
||||||
|
vn 0.000000 0.000000 1.000000
|
||||||
|
vn -1.000000 0.000000 0.000000
|
||||||
|
vn 0.000000 0.000000 -1.000000
|
||||||
|
vn 0.000000 -1.000000 0.000000
|
||||||
|
vn 0.000000 1.000000 0.000000
|
||||||
|
usemtl None
|
||||||
|
s off
|
||||||
|
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||||
|
f 3/5/2 4/6/2 8/7/2 7/8/2
|
||||||
|
f 7/8/3 8/7/3 6/9/3 5/10/3
|
||||||
|
f 5/10/4 6/9/4 2/2/4 1/1/4
|
||||||
|
f 3/9/5 7/11/5 5/12/5 1/13/5
|
||||||
|
f 8/13/6 4/14/6 2/2/6 6/9/6
|
||||||
|
f 9/15/1 10/16/1 12/17/1 11/18/1
|
||||||
|
f 11/19/2 12/20/2 16/21/2 15/22/2
|
||||||
|
f 15/22/3 16/21/3 14/23/3 13/24/3
|
||||||
|
f 13/24/4 14/23/4 10/16/4 9/15/4
|
||||||
|
f 11/25/5 15/26/5 13/23/5 9/21/5
|
||||||
|
f 16/26/6 12/27/6 10/16/6 14/23/6
|
||||||
|
f 17/28/1 18/29/1 20/30/1 19/31/1
|
||||||
|
f 19/32/2 20/33/2 24/34/2 23/35/2
|
||||||
|
f 23/35/3 24/34/3 22/36/3 21/37/3
|
||||||
|
f 21/37/4 22/36/4 18/29/4 17/28/4
|
||||||
|
f 19/22/5 23/24/5 21/36/5 17/34/5
|
||||||
|
f 24/24/6 20/15/6 18/29/6 22/36/6
|
|
@ -0,0 +1,159 @@
|
||||||
|
# Blender v2.79 (sub 0) OBJ File: 'shulkerbox2.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib shulkerbox2.mtl
|
||||||
|
o low1_Cube.006
|
||||||
|
v -0.500000 -0.500001 0.500000
|
||||||
|
v -0.500000 0.062499 0.500000
|
||||||
|
v -0.500000 -0.500001 -0.500000
|
||||||
|
v -0.500000 0.062499 -0.500000
|
||||||
|
v 0.500000 -0.500001 0.500000
|
||||||
|
v 0.500000 0.062499 0.500000
|
||||||
|
v 0.500000 -0.500001 -0.500000
|
||||||
|
v 0.500000 0.062499 -0.500000
|
||||||
|
vt 0.250000 0.187500
|
||||||
|
vt -0.000000 0.187500
|
||||||
|
vt -0.000000 0.312500
|
||||||
|
vt 0.250000 0.312500
|
||||||
|
vt 1.000000 0.187500
|
||||||
|
vt 0.750000 0.187500
|
||||||
|
vt 0.750000 0.312500
|
||||||
|
vt 1.000000 0.312500
|
||||||
|
vt 0.500000 0.187500
|
||||||
|
vt 0.500000 0.312500
|
||||||
|
vt 0.750000 0.562500
|
||||||
|
vt 0.750000 0.312500
|
||||||
|
vt 0.500000 0.312500
|
||||||
|
vt 0.500000 0.562500
|
||||||
|
vt 0.500000 0.562500
|
||||||
|
vt 0.250000 0.562500
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
usemtl None
|
||||||
|
s off
|
||||||
|
f 1/1/1 3/2/1 4/3/1 2/4/1
|
||||||
|
f 3/5/2 7/6/2 8/7/2 4/8/2
|
||||||
|
f 7/6/3 5/9/3 6/10/3 8/7/3
|
||||||
|
f 5/9/4 1/1/4 2/4/4 6/10/4
|
||||||
|
f 3/11/5 1/12/5 5/13/5 7/14/5
|
||||||
|
f 8/15/6 6/10/6 2/4/6 4/16/6
|
||||||
|
o top1_Cube.005
|
||||||
|
v -0.500313 -0.220552 0.500313
|
||||||
|
v -0.500313 0.530073 0.500313
|
||||||
|
v -0.500313 -0.220552 -0.500313
|
||||||
|
v -0.500313 0.530073 -0.500313
|
||||||
|
v 0.500313 -0.220552 0.500313
|
||||||
|
v 0.500313 0.530073 0.500313
|
||||||
|
v 0.500313 -0.220552 -0.500313
|
||||||
|
v 0.500313 0.530073 -0.500313
|
||||||
|
vt 0.250000 0.562500
|
||||||
|
vt -0.000000 0.562500
|
||||||
|
vt -0.000000 0.750000
|
||||||
|
vt 0.250000 0.750000
|
||||||
|
vt 1.000000 0.562500
|
||||||
|
vt 0.750000 0.562500
|
||||||
|
vt 0.750000 0.750000
|
||||||
|
vt 1.000000 0.750000
|
||||||
|
vt 0.500000 0.562500
|
||||||
|
vt 0.500000 0.750000
|
||||||
|
vt 0.750000 1.000000
|
||||||
|
vt 0.750000 0.750000
|
||||||
|
vt 0.500000 0.750000
|
||||||
|
vt 0.500000 1.000000
|
||||||
|
vt 0.500000 1.000000
|
||||||
|
vt 0.250000 1.000000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
usemtl None
|
||||||
|
s off
|
||||||
|
f 9/17/7 11/18/7 12/19/7 10/20/7
|
||||||
|
f 11/21/8 15/22/8 16/23/8 12/24/8
|
||||||
|
f 15/22/9 13/25/9 14/26/9 16/23/9
|
||||||
|
f 13/25/10 9/17/10 10/20/10 14/26/10
|
||||||
|
f 11/27/11 9/28/11 13/29/11 15/30/11
|
||||||
|
f 16/31/12 14/26/12 10/20/12 12/32/12
|
||||||
|
o top2_Cube.002
|
||||||
|
v -0.500247 -0.220392 0.500247
|
||||||
|
v -0.500247 0.530234 0.500247
|
||||||
|
v -0.500247 -0.220392 -0.500378
|
||||||
|
v -0.500247 0.530234 -0.500378
|
||||||
|
v 0.500378 -0.220392 0.500247
|
||||||
|
v 0.500378 0.530234 0.500247
|
||||||
|
v 0.500378 -0.220392 -0.500378
|
||||||
|
v 0.500378 0.530234 -0.500378
|
||||||
|
vt 0.250000 0.562500
|
||||||
|
vt 0.250000 0.750000
|
||||||
|
vt -0.000000 0.750000
|
||||||
|
vt -0.000000 0.562500
|
||||||
|
vt 1.000000 0.562500
|
||||||
|
vt 1.000000 0.750000
|
||||||
|
vt 0.750000 0.750000
|
||||||
|
vt 0.750000 0.562500
|
||||||
|
vt 0.500000 0.750000
|
||||||
|
vt 0.500000 0.562500
|
||||||
|
vt 0.750000 1.000000
|
||||||
|
vt 0.500000 1.000000
|
||||||
|
vt 0.500000 0.750000
|
||||||
|
vt 0.750000 0.750000
|
||||||
|
vt 0.500000 1.000000
|
||||||
|
vt 0.250000 1.000000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl None
|
||||||
|
s off
|
||||||
|
f 17/33/13 18/34/13 20/35/13 19/36/13
|
||||||
|
f 19/37/14 20/38/14 24/39/14 23/40/14
|
||||||
|
f 23/40/15 24/39/15 22/41/15 21/42/15
|
||||||
|
f 21/42/16 22/41/16 18/34/16 17/33/16
|
||||||
|
f 19/43/17 23/44/17 21/45/17 17/46/17
|
||||||
|
f 24/47/18 20/48/18 18/34/18 22/41/18
|
||||||
|
o low2_Cube.001
|
||||||
|
v -0.499935 -0.499936 0.499935
|
||||||
|
v -0.499935 0.062565 0.499935
|
||||||
|
v -0.499935 -0.499936 -0.500066
|
||||||
|
v -0.499935 0.062565 -0.500066
|
||||||
|
v 0.500066 -0.499936 0.499935
|
||||||
|
v 0.500066 0.062565 0.499935
|
||||||
|
v 0.500066 -0.499936 -0.500066
|
||||||
|
v 0.500066 0.062565 -0.500066
|
||||||
|
vt 0.250000 0.187500
|
||||||
|
vt 0.250000 0.312500
|
||||||
|
vt -0.000000 0.312500
|
||||||
|
vt -0.000000 0.187500
|
||||||
|
vt 1.000000 0.187500
|
||||||
|
vt 1.000000 0.312500
|
||||||
|
vt 0.750000 0.312500
|
||||||
|
vt 0.750000 0.187500
|
||||||
|
vt 0.500000 0.312500
|
||||||
|
vt 0.500000 0.187500
|
||||||
|
vt 0.750000 0.562500
|
||||||
|
vt 0.500000 0.562500
|
||||||
|
vt 0.500000 0.312500
|
||||||
|
vt 0.750000 0.312500
|
||||||
|
vt 0.500000 0.562500
|
||||||
|
vt 0.250000 0.562500
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl None
|
||||||
|
s off
|
||||||
|
f 25/49/19 26/50/19 28/51/19 27/52/19
|
||||||
|
f 27/53/20 28/54/20 32/55/20 31/56/20
|
||||||
|
f 31/56/21 32/55/21 30/57/21 29/58/21
|
||||||
|
f 29/58/22 30/57/22 26/50/22 25/49/22
|
||||||
|
f 27/59/23 31/60/23 29/61/23 25/62/23
|
||||||
|
f 32/63/24 28/64/24 26/50/24 30/57/24
|
|
@ -0,0 +1,2 @@
|
||||||
|
default_chest_open and default_chest_close - Taken from minetest_game https://github.com/minetest/minetest_game
|
||||||
|
mcl_chests_enderchest_open and mcl_chests_enderchest_close - https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/resource-packs/1245112-snowsong-the-epic-sound-pack-sound-resource-pack
|
After Width: | Height: | Size: 570 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 2.0 KiB |
|
@ -97,7 +97,7 @@ for _, row in ipairs(block.dyes) do
|
||||||
_doc_items_create_entry = create_entry,
|
_doc_items_create_entry = create_entry,
|
||||||
_doc_items_entry_name = ename_cp,
|
_doc_items_entry_name = ename_cp,
|
||||||
tiles = {"mcl_colorblocks_concrete_powder_"..name..".png"},
|
tiles = {"mcl_colorblocks_concrete_powder_"..name..".png"},
|
||||||
groups = {handy=1,shovely=1, concrete_powder=1,building_block=1,falling_node=1, material_sand=1},
|
groups = {handy=1,shovely=1, concrete_powder=1,building_block=1,falling_node=1, material_sand=1, float=1},
|
||||||
stack_max = 64,
|
stack_max = 64,
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
sounds = mcl_sounds.node_sound_sand_defaults(),
|
sounds = mcl_sounds.node_sound_sand_defaults(),
|
||||||
|
@ -208,11 +208,20 @@ minetest.register_abm({
|
||||||
neighbors = {"group:water"},
|
neighbors = {"group:water"},
|
||||||
action = function(pos, node)
|
action = function(pos, node)
|
||||||
local harden_to = minetest.registered_nodes[node.name]._mcl_colorblocks_harden_to
|
local harden_to = minetest.registered_nodes[node.name]._mcl_colorblocks_harden_to
|
||||||
-- It should be impossible for harden_to to be nil, but a Minetest bug might call
|
-- It should be impossible for harden_to to be nil, but a Minetest bug might call
|
||||||
-- the ABM on the new concrete node, which isn't part of this ABM!
|
-- the ABM on the new concrete node, which isn't part of this ABM!
|
||||||
if harden_to then
|
if harden_to then
|
||||||
node.name = harden_to
|
node.name = harden_to
|
||||||
minetest.set_node(pos, node)
|
--Fix "float" group not lowering concrete into the water by 1.
|
||||||
end
|
local water_pos = { x = pos.x, y = pos.y-1, z = pos.z }
|
||||||
|
local water_node = minetest.get_node(water_pos)
|
||||||
|
if minetest.get_item_group(water_node.name, "water") == 0 then
|
||||||
|
minetest.set_node(pos, node)
|
||||||
|
else
|
||||||
|
minetest.set_node(water_pos,node)
|
||||||
|
minetest.set_node(pos, {name = "air"})
|
||||||
|
minetest.check_for_falling(pos) -- Update C. Powder that stacked above so they fall down after setting air.
|
||||||
|
end
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,4 +2,3 @@ mcl_core
|
||||||
mcl_worlds
|
mcl_worlds
|
||||||
mesecons
|
mesecons
|
||||||
doc?
|
doc?
|
||||||
mcl_enchanting
|
|
||||||
|
|
|
@ -57,9 +57,6 @@ minetest.register_globalstep(function(dtime)
|
||||||
if minetest.get_item_group(stack:get_name(), "compass") ~= 0 and
|
if minetest.get_item_group(stack:get_name(), "compass") ~= 0 and
|
||||||
minetest.get_item_group(stack:get_name(), "compass")-1 ~= compass_image then
|
minetest.get_item_group(stack:get_name(), "compass")-1 ~= compass_image then
|
||||||
local itemname = "mcl_compass:"..compass_image
|
local itemname = "mcl_compass:"..compass_image
|
||||||
if mcl_enchanting.is_enchanted(stack:get_name()) then
|
|
||||||
itemname = itemname .. "_enchanted"
|
|
||||||
end
|
|
||||||
stack:set_name(itemname)
|
stack:set_name(itemname)
|
||||||
player:get_inventory():set_stack("main", j, stack)
|
player:get_inventory():set_stack("main", j, stack)
|
||||||
end
|
end
|
||||||
|
@ -98,7 +95,7 @@ for i,img in ipairs(images) do
|
||||||
inventory_image = img,
|
inventory_image = img,
|
||||||
wield_image = img,
|
wield_image = img,
|
||||||
stack_max = 64,
|
stack_max = 64,
|
||||||
groups = {not_in_creative_inventory=inv, compass=i, tool=1, disable_repair=1, enchantability=1 }
|
groups = {not_in_creative_inventory=inv, compass=i, tool=1, disable_repair=1 }
|
||||||
})
|
})
|
||||||
|
|
||||||
-- Help aliases. Makes sure the lookup tool works correctly
|
-- Help aliases. Makes sure the lookup tool works correctly
|
||||||
|
|