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,
|
||||
***version 1.11***, ***PC edition***.
|
||||
|
||||
MineClone 2 is maintained by one person. Namely, Wuzzy. You can find me,
|
||||
Wuzzy, in the Minetest forums (forums.minetest.net), in IRC in the #minetest
|
||||
MineClone 2 is maintained by two persons. Namely, kay27 and EliasFleckenstein. You can find us
|
||||
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
|
||||
<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
|
||||
means they will become part of a free software.
|
||||
|
||||
## The suggested workflow
|
||||
I don't **dictate** your workflow, but in order to work with me in an efficient
|
||||
way, you can follow my suggestions.
|
||||
We don't **dictate** your workflow, but in order to work with us in an efficient
|
||||
way, you can follow these suggestions:
|
||||
|
||||
For small and medium changes:
|
||||
|
||||
* Fork the repository
|
||||
* Do your change in a new branch
|
||||
* 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. ;-)
|
||||
|
||||
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
|
||||
need to show your contributions align with the project goals. I still
|
||||
reserve the right to revert everything that I don't like.
|
||||
For bigger changes, I strongly recommend to use feature branches and
|
||||
need to show your contributions align with the project goals. We still
|
||||
reserve the right to revert everything that we don't like.
|
||||
For bigger changes, we strongly recommend to use feature branches and
|
||||
discuss with me first.
|
||||
|
||||
Contributors will be credited in `README.md`.
|
||||
|
||||
## Quality remarks
|
||||
Again: There is ***no*** guarantee I will accept anything from anybody.
|
||||
But I will gladly take in code from others when I feel it saves me work
|
||||
Again: There is ***no*** guarantee we will accept anything from anybody.
|
||||
But we will gladly take in code from others when we feel it saves us work
|
||||
in the long run.
|
||||
|
||||
### Inclusion criteria
|
||||
|
@ -79,9 +79,18 @@ Depending on what you add, the chances for inclusion vary:
|
|||
## Reporting bugs
|
||||
Report all bugs and missing Minecraft features here:
|
||||
|
||||
<https://git.minetest.land/Wuzzy/MineClone2/issues>
|
||||
<https://git.minetest.land/MineClone2/MineClone2/issues>
|
||||
|
||||
## Direct discussion
|
||||
We have an IRC channel! Join us on #mineclone2 in freenode.net.
|
||||
|
||||
<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_block=X`: Coral block (1 = alive, 2 = dead)
|
||||
* `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
|
||||
|
||||
|
@ -96,6 +97,8 @@ Please read <http://minecraft.gamepedia.com/Breaking> to learn how digging times
|
|||
* `carpet=1:` (Wool) carpet
|
||||
* `stick=1`: Stick
|
||||
* `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
|
||||
|
||||
|
@ -197,6 +200,7 @@ These groups are used mostly for informational purposes
|
|||
* `building_block=1`: Block is a building block
|
||||
* `deco_block=1`: Block is a decorational block
|
||||
|
||||
|
||||
## Fake item groups
|
||||
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.
|
||||
|
|
|
@ -20,7 +20,6 @@ For these features, no easy Lua workaround could be found.
|
|||
## 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
|
||||
- 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
|
||||
|
||||
## 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 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
|
||||
- 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
|
||||
- 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
|
||||
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
|
||||
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
|
||||
|
||||
* Sandbox-style gameplay, no goals (for now)
|
||||
* Sandbox-style gameplay, no goals
|
||||
* Survive: Fight against hostile monsters and hunger
|
||||
* 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
|
||||
* Collect flowers (and other dye sources) and colorize your world
|
||||
* 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:
|
||||
|
||||
* Tools, weapons
|
||||
* Armor (unbalanced)
|
||||
* Armor
|
||||
* Crafting system: 2×2 grid, crafting table (3×3 grid), furnace, including a crafting guide
|
||||
* Chests, large chests, ender chests, shulker boxes
|
||||
* Furnaces, hoppers
|
||||
|
@ -117,6 +118,8 @@ The following main features are available:
|
|||
* Redstone circuits (partially)
|
||||
* Minecarts (partial)
|
||||
* Status effects (partial)
|
||||
* Experience
|
||||
* Enchanting
|
||||
* Brewing, potions, tipped arrow (partial)
|
||||
* Boats
|
||||
* Fire
|
||||
|
@ -142,12 +145,9 @@ The following main features are available:
|
|||
The following features are incomplete:
|
||||
|
||||
* Generated structures (especially villages)
|
||||
* NPCs
|
||||
* Some monsters and animals
|
||||
* Redstone-related things
|
||||
* The End
|
||||
* Enchanting
|
||||
* Experience
|
||||
* Special minecarts
|
||||
* A couple of non-trivial blocks and items
|
||||
|
||||
|
@ -182,7 +182,7 @@ Technical differences from Minecraft:
|
|||
## Reporting bugs
|
||||
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
|
||||
|
||||
|
@ -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.
|
||||
|
||||
### 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
|
||||
* [ex-bart](https://github.com/ex-bart): Redstone comparators
|
||||
* [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
|
||||
* MysticTempest: Bugfixes
|
||||
* [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
|
||||
* 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
|
||||
|
||||
* davedevils for starting MineClone, the original version of this game
|
||||
* Wuzzy for starting and maintaining MineClone2 for several years
|
||||
* celeron55 for creating Minetest
|
||||
* 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
|
||||
|
@ -261,7 +263,6 @@ Various sources. See the respective mod directories for details.
|
|||
|
||||
## Info for programmers
|
||||
You find interesting and useful infos in `API.md`.
|
||||
This project is currently mostly a one-person project.
|
||||
|
||||
## Legal information
|
||||
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:
|
||||
|
||||
### 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.
|
||||
|
||||
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
|
||||
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()
|
||||
-- Store blast resistance values by content ids to improve performance.
|
||||
for name, def in pairs(minetest.registered_nodes) do
|
||||
|
@ -135,14 +139,21 @@ end
|
|||
-- strength - The strength of each ray
|
||||
-- raydirs - The directions for each ray
|
||||
-- radius - The maximum distance each ray will go
|
||||
-- drop_chance - The chance that destroyed nodes will drop their items
|
||||
-- fire - If true, 1/3 of destroyed nodes become fire
|
||||
-- info - Table containing information about explosion
|
||||
-- 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
|
||||
-- inlined to avoid function calls and unnecessary table creation. This was
|
||||
-- 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 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 destroy = {}
|
||||
|
||||
local drop_chance = info.drop_chance
|
||||
local fire = info.fire
|
||||
local max_blast_resistance = info.max_blast_resistance
|
||||
|
||||
-- Trace rays for environment destruction
|
||||
for i = 1, #raydirs do
|
||||
local rpos_x = pos.x
|
||||
local rpos_y = pos.y
|
||||
local rpos_z = pos.z
|
||||
local rdir_x = raydirs[i].x
|
||||
local rdir_y = raydirs[i].y
|
||||
local rdir_z = raydirs[i].z
|
||||
local rstr = (0.7 + math.random() * 0.6) * strength
|
||||
if info.griefing then
|
||||
for i = 1, #raydirs do
|
||||
local rpos_x = pos.x
|
||||
local rpos_y = pos.y
|
||||
local rpos_z = pos.z
|
||||
local rdir_x = raydirs[i].x
|
||||
local rdir_y = raydirs[i].y
|
||||
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
|
||||
local npos_x = math.floor(rpos_x + 0.5)
|
||||
local npos_y = math.floor(rpos_y + 0.5)
|
||||
local npos_z = math.floor(rpos_z + 0.5)
|
||||
local idx = (npos_z - emin_z) * zstride + (npos_y - emin_y) * ystride +
|
||||
npos_x - emin_x + 1
|
||||
for r = 0, math.ceil(radius * (1.0 / STEP_LENGTH)) do
|
||||
local npos_x = math.floor(rpos_x + 0.5)
|
||||
local npos_y = math.floor(rpos_y + 0.5)
|
||||
local npos_z = math.floor(rpos_z + 0.5)
|
||||
local idx = (npos_z - emin_z) * zstride + (npos_y - emin_y) * ystride +
|
||||
npos_x - emin_x + 1
|
||||
|
||||
local cid = data[idx]
|
||||
local br = node_blastres[cid]
|
||||
local hash = minetest.hash_node_position({x=npos_x, y=npos_y, z=npos_z})
|
||||
local cid = data[idx]
|
||||
local br = node_blastres[cid]
|
||||
if br < INDESTRUCT_BLASTRES and br > max_blast_resistance then
|
||||
br = max_blast_resistance
|
||||
end
|
||||
|
||||
rpos_x = rpos_x + STEP_LENGTH * rdir_x
|
||||
rpos_y = rpos_y + STEP_LENGTH * rdir_y
|
||||
rpos_z = rpos_z + STEP_LENGTH * rdir_z
|
||||
local hash = minetest.hash_node_position({x=npos_x, y=npos_y, z=npos_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
|
||||
break
|
||||
end
|
||||
rstr = rstr - 0.75 * STEP_LENGTH - (br + 0.3) * STEP_LENGTH
|
||||
|
||||
if cid ~= minetest.CONTENT_AIR and not minetest.is_protected({x = npos_x, y = npos_y, z = npos_z}, "") then
|
||||
destroy[hash] = idx
|
||||
if rstr <= 0 then
|
||||
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
|
||||
|
@ -284,8 +305,18 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
|||
impact = 0
|
||||
end
|
||||
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
|
||||
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
|
||||
mcl_death_messages.player_damage(obj, S("@1 was caught in an explosion.", name))
|
||||
end
|
||||
|
@ -293,17 +324,21 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
|||
armor.last_damage_types[name] = "explosion"
|
||||
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
|
||||
obj:add_player_velocity(vector.multiply(punch_dir, impact * 20))
|
||||
elseif ent.tnt_knockback then
|
||||
obj:add_velocity(vector.multiply(punch_dir, impact * 20))
|
||||
if sleep_formspec_doesnt_close_mt53 then
|
||||
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
|
||||
if not obj then return end
|
||||
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
|
||||
|
@ -313,14 +348,14 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
|||
|
||||
-- Remove destroyed blocks and drop items
|
||||
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 remove = true
|
||||
|
||||
if do_drop or on_blast ~= nil then
|
||||
local npos = minetest.get_position_from_hash(hash)
|
||||
if on_blast ~= nil then
|
||||
on_blast(npos, 1.0)
|
||||
on_blast(npos, 1.0, do_drop)
|
||||
remove = false
|
||||
else
|
||||
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
|
||||
minetest.log('action', 'Explosion at ' .. minetest.pos_to_string(pos) ..
|
||||
' with strength ' .. strength .. ' and radius ' .. radius)
|
||||
|
||||
end
|
||||
|
||||
-- Create an explosion with strength at pos.
|
||||
|
@ -371,16 +405,24 @@ end
|
|||
-- Parameters:
|
||||
-- pos - The position where the explosion originates from
|
||||
-- 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)
|
||||
--
|
||||
-- Values in info:
|
||||
-- drop_chance - If specified becomes the drop chance of all nodes in the
|
||||
-- explosion (defaults to 1.0 / strength)
|
||||
-- no_sound - If true then the explosion will not play a sound
|
||||
-- no_particle - If true then the explosion will not create particles
|
||||
-- explosion (default: 1.0 / strength)
|
||||
-- max_blast_resistance - If specified the explosion will treat all
|
||||
-- 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)
|
||||
-- griefing - If true, the explosion will destroy nodes (default: true)
|
||||
function mcl_explosions.explode(pos, strength, info, puncher)
|
||||
if info == nil then
|
||||
info = {}
|
||||
end
|
||||
|
||||
-- The maximum blast radius (in the air)
|
||||
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
|
||||
local shape = sphere_shapes[radius]
|
||||
|
||||
local creative_enabled = minetest.is_creative_enabled("")
|
||||
trace_explode(pos, strength, shape, radius, (info and info.drop_chance) or 1 / strength, info.fire == true, puncher, creative_enabled)
|
||||
-- Default values
|
||||
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)
|
||||
end
|
||||
if not (info and info.no_sound) then
|
||||
if info.sound then
|
||||
minetest.sound_play("tnt_explode", {
|
||||
pos = pos, gain = 1.0,
|
||||
max_hear_distance = strength * 16
|
||||
|
|
|
@ -25,6 +25,7 @@ mcl_vars.inventory_header = ""
|
|||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
local minecraft_height_limit = 256
|
||||
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
|
||||
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_max = central_chunk_max_pos + numcmax * chunk_size_in_nodes
|
||||
|
||||
if not superflat then
|
||||
if not superflat and not singlenode then
|
||||
-- Normal mode
|
||||
--[[ Realm stacking (h is for height)
|
||||
- Overworld (h>=256)
|
||||
|
@ -66,6 +67,14 @@ if not superflat then
|
|||
mcl_vars.mg_lava = 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
|
||||
-- Classic superflat
|
||||
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)
|
||||
math.randomseed(os.time())
|
||||
|
||||
|
|
|
@ -11,12 +11,15 @@ Parameters:
|
|||
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.
|
||||
{
|
||||
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
|
||||
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)
|
||||
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)
|
||||
weight = 5, -- Likelihood of this item being selected (see below). Optional (default: 1)
|
||||
},
|
||||
{ -- more tables like above, one table per item stack }
|
||||
}
|
||||
|
@ -56,24 +59,29 @@ function mcl_loot.get_loot(loot_definitions, pr)
|
|||
end
|
||||
if item then
|
||||
local itemstring = item.itemstring
|
||||
if item.amount_min and item.amount_max then
|
||||
itemstring = itemstring .. " " .. pr:next(item.amount_min, item.amount_max)
|
||||
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
|
||||
|
||||
if not item.amount_min and not item.amount_max then
|
||||
itemstring = itemstring .. " 1"
|
||||
local itemstack = item.itemstack
|
||||
if itemstring then
|
||||
if item.amount_min and item.amount_max then
|
||||
itemstring = itemstring .. " " .. pr:next(item.amount_min, item.amount_max)
|
||||
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
|
||||
table.insert(items, itemstring)
|
||||
else
|
||||
minetest.log("error", "[mcl_loot] INTERNAL ERROR! Failed to select random loot item!")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -395,4 +395,13 @@ function mcl_util.generate_on_place_plant_function(condition)
|
|||
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",
|
||||
textures = {"mcl_boats_texture_oak_boat.png"},
|
||||
visual_size = boat_visual_size,
|
||||
hp_max = 4,
|
||||
|
||||
_driver = nil, -- Attached driver (player) or nil if none
|
||||
_passenger = nil,
|
||||
_v = 0, -- Speed
|
||||
_last_v = 0, -- Temporary speed variable
|
||||
_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
|
||||
}
|
||||
|
||||
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)
|
||||
if not clicker or not clicker:is_player() then
|
||||
if self._passenger or not clicker or clicker:get_attach() then
|
||||
return
|
||||
end
|
||||
local name = clicker:get_player_name()
|
||||
if self._driver and clicker == self._driver then
|
||||
self._driver = nil
|
||||
--[[if attach and attach:get_luaentity() then
|
||||
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}})
|
||||
mcl_player.player_attached[name] = false
|
||||
mcl_player.player_set_animation(clicker, "stand" , 30)
|
||||
local pos = clicker:get_pos()
|
||||
pos = {x = pos.x, y = pos.y + 0.2, z = pos.z}
|
||||
clicker:set_pos(pos)
|
||||
elseif not self._driver then
|
||||
local attach = clicker:get_attach()
|
||||
if attach and attach:get_luaentity() then
|
||||
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--]]
|
||||
if self._driver then
|
||||
if self._driver:is_player() then
|
||||
self._passenger = clicker
|
||||
else
|
||||
-- for later use: transport mobs in boats
|
||||
self._passenger = self._driver
|
||||
self._driver = clicker
|
||||
end
|
||||
set_double_attach(self)
|
||||
else
|
||||
self._driver = clicker
|
||||
clicker:set_attach(self.object, "",
|
||||
{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())
|
||||
set_attach(self)
|
||||
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
|
||||
|
||||
|
||||
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)
|
||||
if type(data) == "table" then
|
||||
self._v = data.v
|
||||
self._last_v = self._v
|
||||
self._itemstring = data.itemstring
|
||||
self.object:set_properties({textures=data.textures})
|
||||
self.object:set_properties({textures = data.textures, damage_texture_modifier = ""})
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -120,32 +149,26 @@ function boat.get_staticdata(self)
|
|||
end
|
||||
|
||||
|
||||
function boat.on_punch(self, puncher)
|
||||
if not puncher or not puncher:is_player() or self._removed then
|
||||
return
|
||||
end
|
||||
if self._driver and puncher == self._driver then
|
||||
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
|
||||
function boat.on_death(self, killer)
|
||||
if killer and killer:is_player() and minetest.is_creative_enabled(killer:get_player_name()) then
|
||||
local inv = killer:get_inventory()
|
||||
if not inv:contains_item("main", self._itemstring) then
|
||||
inv:add_item("main", self._itemstring)
|
||||
end
|
||||
self.object:remove()
|
||||
else
|
||||
minetest.add_item(self.object:get_pos(), self._itemstring)
|
||||
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
|
||||
|
||||
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)
|
||||
local on_water = true
|
||||
local in_water = false
|
||||
|
@ -163,8 +186,43 @@ function boat.on_step(self, dtime)
|
|||
v_slowdown = 0.05
|
||||
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 had_passenger and not self._passenger then
|
||||
set_attach(self)
|
||||
end
|
||||
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()
|
||||
if ctrl.up then
|
||||
-- Forwards
|
||||
|
@ -191,13 +249,13 @@ function boat.on_step(self, dtime)
|
|||
self._animation = 0
|
||||
end
|
||||
end
|
||||
if ctrl.left then
|
||||
if ctrl and ctrl.left then
|
||||
if self._v < 0 then
|
||||
self.object:set_yaw(yaw - (1 + dtime) * 0.03 * v_factor)
|
||||
else
|
||||
self.object:set_yaw(yaw + (1 + dtime) * 0.03 * v_factor)
|
||||
end
|
||||
elseif ctrl.right then
|
||||
elseif ctrl and ctrl.right then
|
||||
if self._v < 0 then
|
||||
self.object:set_yaw(yaw + (1 + dtime) * 0.03 * v_factor)
|
||||
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
|
||||
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.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.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
|
||||
|
@ -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}
|
||||
|
||||
--magnet and collection
|
||||
for _,object in ipairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.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
|
||||
for _,object in ipairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do
|
||||
if not object:is_player() and vector.distance(checkpos, object:get_pos()) < item_drop_settings.radius_magnet and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
|
||||
object:get_luaentity()._magnet_timer = object:get_luaentity()._magnet_timer + dtime
|
||||
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
|
||||
|
@ -193,6 +194,12 @@ local check_can_drop = function(node_name, tool_capabilities)
|
|||
if toolgroupcaps[plus] then
|
||||
return true
|
||||
end
|
||||
for e=1,5 do
|
||||
local effplus = plus .. "_efficiency_" .. e
|
||||
if toolgroupcaps[effplus] then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for b=1, #basegroups do
|
||||
|
@ -204,6 +211,12 @@ local check_can_drop = function(node_name, tool_capabilities)
|
|||
if toolgroupcaps[plus] then
|
||||
return true
|
||||
end
|
||||
for e=1,5 do
|
||||
local effplus = plus .. "_efficiency_" .. e
|
||||
if toolgroupcaps[effplus] then
|
||||
return true
|
||||
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.
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
|
@ -319,7 +332,7 @@ function minetest.handle_node_drops(pos, drops, digger)
|
|||
end
|
||||
else
|
||||
-- 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)
|
||||
end
|
||||
end
|
||||
|
@ -632,12 +645,15 @@ minetest.register_entity(":__builtin:item", {
|
|||
local fg = minetest.get_item_group(nn, "fire")
|
||||
local dg = minetest.get_item_group(nn, "destroys_items")
|
||||
if (def and (lg ~= 0 or fg ~= 0 or dg == 1)) then
|
||||
if dg ~= 2 then
|
||||
minetest.sound_play("builtin_item_lava", {pos = self.object:get_pos(), gain = 0.5}, true)
|
||||
--Wait 2 seconds to allow mob drops to be cooked, & picked up instead of instantly destroyed.
|
||||
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
|
||||
self._removed = true
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
||||
-- Push item out when stuck inside solid opaque node
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
mobs = {}
|
||||
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 HORNY_TIME = 30
|
||||
|
@ -226,7 +226,7 @@ local collision = function(self)
|
|||
local z = 0
|
||||
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()
|
||||
or (object:get_luaentity()._cmi_is_mob == true and object ~= self.object) then
|
||||
|
@ -276,13 +276,16 @@ end
|
|||
local get_velocity = function(self)
|
||||
|
||||
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
|
||||
|
||||
|
||||
-- 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
|
||||
yaw = 0
|
||||
|
@ -291,6 +294,9 @@ local set_yaw = function(self, yaw, delay)
|
|||
delay = delay or 0
|
||||
|
||||
if delay == 0 then
|
||||
if self.shaking and dtime then
|
||||
yaw = yaw + (math.random() * 2 - 1) * 5 * dtime
|
||||
end
|
||||
self.object:set_yaw(yaw)
|
||||
return yaw
|
||||
end
|
||||
|
@ -302,8 +308,8 @@ local set_yaw = function(self, yaw, delay)
|
|||
end
|
||||
|
||||
-- global function to set mob yaw
|
||||
function mobs:yaw(self, yaw, delay)
|
||||
set_yaw(self, yaw, delay)
|
||||
function mobs:yaw(self, yaw, delay, dtime)
|
||||
set_yaw(self, yaw, delay, dtime)
|
||||
end
|
||||
|
||||
local add_texture_mod = function(self, mod)
|
||||
|
@ -390,7 +396,7 @@ local is_node_dangerous = function(self, nodename)
|
|||
return true
|
||||
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
|
||||
end
|
||||
return false
|
||||
|
@ -643,11 +649,13 @@ end
|
|||
|
||||
|
||||
-- drop items
|
||||
local item_drop = function(self, cooked)
|
||||
local item_drop = function(self, cooked, looting_level)
|
||||
|
||||
-- no drops if disabled by setting
|
||||
if not mobs_drop_items then return end
|
||||
|
||||
looting_level = looting_level or 0
|
||||
|
||||
-- no drops for child mobs (except monster)
|
||||
if (self.child and self.type ~= "monster") then
|
||||
return
|
||||
|
@ -659,11 +667,33 @@ local item_drop = function(self, cooked)
|
|||
self.drops = self.drops or {} -- nil check
|
||||
|
||||
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)
|
||||
item = self.drops[n].name
|
||||
local num = 0
|
||||
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
|
||||
if cooked then
|
||||
|
@ -752,15 +782,22 @@ local check_for_death = function(self, cause, cmi_cause)
|
|||
local function death_handle(self)
|
||||
-- dropped cooked item if mob died in fire or lava
|
||||
if cause == "lava" or cause == "fire" then
|
||||
item_drop(self, true)
|
||||
item_drop(self, true, 0)
|
||||
else
|
||||
item_drop(self, nil)
|
||||
end
|
||||
local wielditem = ItemStack()
|
||||
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(pos, math.random(self.xp_min, self.xp_max))
|
||||
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))
|
||||
end
|
||||
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
|
||||
|
||||
|
@ -768,7 +805,7 @@ local check_for_death = function(self, cause, cmi_cause)
|
|||
if self.on_die then
|
||||
|
||||
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
|
||||
death_handle(self)
|
||||
end
|
||||
|
@ -779,6 +816,7 @@ local check_for_death = function(self, cause, cmi_cause)
|
|||
|
||||
if on_die_exit == true then
|
||||
self.state = "die"
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove()
|
||||
return true
|
||||
end
|
||||
|
@ -841,6 +879,7 @@ local check_for_death = function(self, cause, cmi_cause)
|
|||
local dpos = self.object:get_pos()
|
||||
local cbox = self.collisionbox
|
||||
local yaw = self.object:get_rotation().y
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove()
|
||||
mobs.death_effect(dpos, yaw, cbox, not self.instant_death)
|
||||
end
|
||||
|
@ -989,6 +1028,7 @@ local do_env_damage = function(self)
|
|||
|
||||
-- remove mob if beyond map limits
|
||||
if not within_limits(pos, 0) then
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove()
|
||||
return true
|
||||
end
|
||||
|
@ -1017,8 +1057,11 @@ local do_env_damage = function(self)
|
|||
if mod_worlds then
|
||||
_, dim = mcl_worlds.y_to_layer(pos.y)
|
||||
end
|
||||
if self.sunlight_damage ~= 0 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.sunlight_damage ~= 0 or self.ignited_by_sunlight) and (minetest.get_node_light(pos) or 0) >= minetest.LIGHT_MAX and dim == "overworld" 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
|
||||
end
|
||||
end
|
||||
|
@ -1106,7 +1149,7 @@ local do_env_damage = function(self)
|
|||
end
|
||||
|
||||
-- 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
|
||||
|
||||
|
@ -1238,7 +1281,7 @@ local do_jump = function(self)
|
|||
}, "air")
|
||||
|
||||
-- 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
|
||||
end
|
||||
|
||||
|
@ -1269,7 +1312,7 @@ local do_jump = function(self)
|
|||
end
|
||||
self.object:set_acceleration({
|
||||
x = v.x * 2,
|
||||
y = 0,
|
||||
y = -10,
|
||||
z = v.z * 2,
|
||||
})
|
||||
end, self, v)
|
||||
|
@ -2059,6 +2102,7 @@ local follow_flop = function(self)
|
|||
or self.order == "follow")
|
||||
and not self.following
|
||||
and self.state ~= "attack"
|
||||
and self.order ~= "sit"
|
||||
and self.state ~= "runaway" then
|
||||
|
||||
local s = self.object:get_pos()
|
||||
|
@ -2079,6 +2123,7 @@ local follow_flop = function(self)
|
|||
if self.type == "npc"
|
||||
and self.order == "follow"
|
||||
and self.state ~= "attack"
|
||||
and self.order ~= "sit"
|
||||
and self.owner ~= "" then
|
||||
|
||||
-- npc stop following player if not owner
|
||||
|
@ -2211,7 +2256,6 @@ local dogswitch = function(self, dtime)
|
|||
return self.dogshoot_switch
|
||||
end
|
||||
|
||||
|
||||
-- execute current state (stand, walk, run, attacks)
|
||||
-- returns true if mob has died
|
||||
local do_states = function(self, dtime)
|
||||
|
@ -2364,6 +2408,8 @@ local do_states = function(self, dtime)
|
|||
set_velocity(self, 0)
|
||||
self.state = "stand"
|
||||
set_animation(self, "stand")
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
yaw = set_yaw(self, yaw + 0.78, 8)
|
||||
else
|
||||
|
||||
set_velocity(self, self.walk_velocity)
|
||||
|
@ -2390,6 +2436,8 @@ local do_states = function(self, dtime)
|
|||
set_velocity(self, 0)
|
||||
self.state = "stand"
|
||||
set_animation(self, "stand")
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
yaw = set_yaw(self, yaw + 0.78, 8)
|
||||
else
|
||||
set_velocity(self, self.run_velocity)
|
||||
set_animation(self, "run")
|
||||
|
@ -2434,7 +2482,7 @@ local do_states = function(self, dtime)
|
|||
|
||||
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 entity_damage_radius = self.explosion_damage_radius
|
||||
|
@ -2499,7 +2547,7 @@ local do_states = function(self, dtime)
|
|||
|
||||
if mod_explosions 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
|
||||
minetest.sound_play(self.sounds.explode, {
|
||||
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)
|
||||
end
|
||||
end
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove()
|
||||
|
||||
return true
|
||||
|
@ -2606,7 +2655,7 @@ local do_states = function(self, dtime)
|
|||
|
||||
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
|
||||
if dist > self.reach then
|
||||
|
@ -2622,6 +2671,8 @@ local do_states = function(self, dtime)
|
|||
|
||||
set_velocity(self, 0)
|
||||
set_animation(self, "stand")
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
yaw = set_yaw(self, yaw + 0.78, 8)
|
||||
else
|
||||
|
||||
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
|
||||
|
||||
yaw = set_yaw(self, yaw)
|
||||
yaw = set_yaw(self, yaw, 0, dtime)
|
||||
|
||||
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
|
||||
and self.timer > self.shoot_interval
|
||||
and not minetest.raycast(p, self.attack:get_pos(), false, false):next()
|
||||
and random(1, 100) <= 60 then
|
||||
|
||||
self.timer = 0
|
||||
|
@ -2723,10 +2778,6 @@ local do_states = function(self, dtime)
|
|||
-- play shoot attack sound
|
||||
mob_sound(self, "shoot_attack")
|
||||
|
||||
local p = self.object:get_pos()
|
||||
|
||||
p.y = p.y + (self.collisionbox[2] + self.collisionbox[5]) / 2
|
||||
|
||||
-- Shoot arrow
|
||||
if minetest.registered_entities[self.arrow] then
|
||||
|
||||
|
@ -2915,6 +2966,13 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
|||
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
|
||||
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
|
||||
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({
|
||||
x = dir.x * kb,
|
||||
y = dir.y * kb + up,
|
||||
|
@ -3121,7 +3191,8 @@ local mob_staticdata = function(self)
|
|||
and ((not self.nametag) or (self.nametag == ""))
|
||||
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()
|
||||
|
||||
return ""-- nil
|
||||
|
@ -3160,7 +3231,7 @@ local mob_activate = function(self, staticdata, def, dtime)
|
|||
-- remove monsters in peaceful mode
|
||||
if self.type == "monster"
|
||||
and minetest.settings:get_bool("only_peaceful_mobs", false) then
|
||||
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove()
|
||||
|
||||
return
|
||||
|
@ -3324,6 +3395,10 @@ end
|
|||
-- main mob function
|
||||
local mob_step = function(self, dtime)
|
||||
|
||||
if not self.fire_resistant then
|
||||
mcl_burning.tick(self.object, dtime)
|
||||
end
|
||||
|
||||
if use_cmi then
|
||||
cmi.notify_step(self.object, dtime)
|
||||
end
|
||||
|
@ -3385,6 +3460,9 @@ local mob_step = function(self, dtime)
|
|||
end
|
||||
|
||||
self.delay = self.delay - 1
|
||||
if self.shaking then
|
||||
yaw = yaw + (math.random() * 2 - 1) * 5 * dtime
|
||||
end
|
||||
self.object:set_yaw(yaw)
|
||||
end
|
||||
|
||||
|
@ -3516,39 +3594,27 @@ local mob_step = function(self, dtime)
|
|||
set_velocity(self, 0)
|
||||
self.state = "stand"
|
||||
set_animation(self, "stand")
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
yaw = set_yaw(self, yaw + 0.78, 8)
|
||||
end
|
||||
|
||||
-- Despawning: when lifetimer expires, remove mob
|
||||
if remove_far
|
||||
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
|
||||
if self.lifetimer <= 10 then
|
||||
|
||||
-- only despawn away from player
|
||||
local far_objs = minetest.get_objects_inside_radius(pos, 48)
|
||||
for n = 1, #far_objs do
|
||||
|
||||
if far_objs[n]:is_player() then
|
||||
|
||||
local close_objs = minetest.get_objects_inside_radius(pos, 16)
|
||||
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
|
||||
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))
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove()
|
||||
elseif self.lifetimer <= 10 then
|
||||
if math.random(10) < 4 then
|
||||
self.despawn_immediately = true
|
||||
else
|
||||
self.lifetimer = 20
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -3750,6 +3816,9 @@ minetest.register_entity(name, {
|
|||
suffocation_timer = 0,
|
||||
follow_velocity = def.follow_velocity or 2.4,
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
-- 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
|
||||
|
||||
|
@ -4106,7 +4175,7 @@ function mobs:register_arrow(name, def)
|
|||
if self.switch == 0
|
||||
or self.timer > 150
|
||||
or not within_limits(pos, 0) then
|
||||
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove();
|
||||
|
||||
return
|
||||
|
@ -4489,3 +4558,20 @@ function mobs:alias_mob(old_name, new_name)
|
|||
})
|
||||
|
||||
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)
|
||||
'xp_min' the minimum 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)
|
||||
-- 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
|
||||
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
|
||||
elseif minetest.get_item_group(node.name, "opaque") ~= 0 or minetest.registered_nodes[node.name].liquidtype ~= "none" then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Reject everything else
|
||||
return true
|
||||
end
|
||||
|
|
|
@ -41,7 +41,8 @@ mobs:register_mob("mobs_mc:blaze", {
|
|||
{name = mobs_mc.items.blaze_rod,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "common",},
|
||||
},
|
||||
animation = {
|
||||
stand_speed = 25,
|
||||
|
@ -73,6 +74,7 @@ mobs:register_mob("mobs_mc:blaze", {
|
|||
makes_footstep_sound = false,
|
||||
fear_height = 0,
|
||||
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)
|
||||
|
@ -89,6 +91,7 @@ mobs:register_arrow("mobs_mc:blaze_fireball", {
|
|||
if rawget(_G, "armor") and armor.last_damage_types then
|
||||
armor.last_damage_types[player:get_player_name()] = "fireball"
|
||||
end
|
||||
mcl_burning.set_on_fire(player, 5, 1, "blaze")
|
||||
player:punch(self.object, 1.0, {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy = 5},
|
||||
|
@ -96,6 +99,7 @@ mobs:register_arrow("mobs_mc:blaze_fireball", {
|
|||
end,
|
||||
|
||||
hit_mob = function(self, mob)
|
||||
mcl_burning.set_on_fire(mob, 5)
|
||||
mob:punch(self.object, 1.0, {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy = 5},
|
||||
|
|
|
@ -32,11 +32,13 @@ mobs:register_mob("mobs_mc:chicken", {
|
|||
{name = mobs_mc.items.chicken_raw,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "common",},
|
||||
{name = mobs_mc.items.feather,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,},
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
},
|
||||
fall_damage = 0,
|
||||
fall_speed = -2.25,
|
||||
|
|
|
@ -23,11 +23,13 @@ local cow_def = {
|
|||
{name = mobs_mc.items.beef_raw,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 3,},
|
||||
max = 3,
|
||||
looting = "common",},
|
||||
{name = mobs_mc.items.leather,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,},
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
},
|
||||
runaway = true,
|
||||
sounds = {
|
||||
|
|
|
@ -71,17 +71,21 @@ mobs:register_mob("mobs_mc:creeper", {
|
|||
if self._forced_explosion_countdown_timer ~= nil then
|
||||
self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime
|
||||
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()
|
||||
end
|
||||
end
|
||||
end,
|
||||
on_die = function(self, pos)
|
||||
-- Drop a random music disc
|
||||
-- TODO: Only do this if killed by skeleton
|
||||
if math.random(1, 200) == 1 then
|
||||
local r = math.random(1, #mobs_mc.items.music_discs)
|
||||
minetest.add_item({x=pos.x, y=pos.y+1, z=pos.z}, mobs_mc.items.music_discs[r])
|
||||
on_die = function(self, pos, cmi_cause)
|
||||
-- Drop a random music disc when killed by skeleton or stray
|
||||
if cmi_cause and cmi_cause.type == "punch" then
|
||||
local luaentity = cmi_cause.puncher and cmi_cause.puncher:get_luaentity()
|
||||
if luaentity and luaentity.name:find("arrow") then
|
||||
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,
|
||||
maxdrops = 2,
|
||||
|
@ -89,7 +93,8 @@ mobs:register_mob("mobs_mc:creeper", {
|
|||
{name = mobs_mc.items.gunpowder,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,},
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
|
||||
-- Head
|
||||
-- TODO: Only drop if killed by charged creeper
|
||||
|
|
|
@ -49,6 +49,8 @@ mobs:register_mob("mobs_mc:enderdragon", {
|
|||
arrow = "mobs_mc:dragon_fireball",
|
||||
shoot_interval = 0.5,
|
||||
shoot_offset = -1.0,
|
||||
xp_min = 12000,
|
||||
xp_max = 12000,
|
||||
animation = {
|
||||
fly_speed = 8, stand_speed = 8,
|
||||
stand_start = 0, stand_end = 20,
|
||||
|
@ -65,7 +67,8 @@ mobs:register_mob("mobs_mc:enderdragon", {
|
|||
--end
|
||||
end
|
||||
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))
|
||||
|
||||
-- How freqeuntly to take and place blocks, in seconds
|
||||
local take_frequency_min = 25
|
||||
local take_frequency_max = 90
|
||||
local place_frequency_min = 10
|
||||
local place_frequency_max = 30
|
||||
local take_frequency_min = 235
|
||||
local take_frequency_max = 245
|
||||
local place_frequency_min = 235
|
||||
local place_frequency_max = 245
|
||||
|
||||
-- Create the textures table for the enderman, depending on which kind of block
|
||||
-- the enderman holds (if any).
|
||||
|
@ -220,7 +220,8 @@ mobs:register_mob("mobs_mc:enderman", {
|
|||
{name = mobs_mc.items.ender_pearl,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "common"},
|
||||
},
|
||||
animation = select_enderman_animation("normal"),
|
||||
_taken_node = "",
|
||||
|
@ -273,10 +274,10 @@ mobs:register_mob("mobs_mc:enderman", {
|
|||
end
|
||||
-- AGRESSIVELY WARP/CHASE PLAYER BEHAVIOUR HERE.
|
||||
if self.state == "attack" then
|
||||
if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
self:teleport(nil)
|
||||
self.state = ""
|
||||
else
|
||||
--if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
--self:teleport(nil)
|
||||
--self.state = ""
|
||||
--else
|
||||
if self.attack then
|
||||
local target = self.attack
|
||||
local pos = target:get_pos()
|
||||
|
@ -286,7 +287,7 @@ mobs:register_mob("mobs_mc:enderman", {
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--end
|
||||
end
|
||||
-- ARROW / DAYTIME PEOPLE AVOIDANCE BEHAVIOUR HERE.
|
||||
-- Check for arrows and people nearby.
|
||||
|
@ -297,9 +298,9 @@ mobs:register_mob("mobs_mc:enderman", {
|
|||
if obj then
|
||||
if minetest.is_player(obj) then
|
||||
-- Warp from players during day.
|
||||
if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
self:teleport(nil)
|
||||
end
|
||||
--if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
-- self:teleport(nil)
|
||||
--end
|
||||
else
|
||||
local lua = obj:get_luaentity()
|
||||
if lua then
|
||||
|
@ -314,14 +315,14 @@ mobs:register_mob("mobs_mc:enderman", {
|
|||
local enderpos = self.object:get_pos()
|
||||
if self.provoked == "broke_contact" then
|
||||
self.provoked = "false"
|
||||
if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
self:teleport(nil)
|
||||
self.state = ""
|
||||
else
|
||||
--if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
-- self:teleport(nil)
|
||||
-- self.state = ""
|
||||
--else
|
||||
if self.attack ~= nil then
|
||||
self.state = 'attack'
|
||||
end
|
||||
end
|
||||
--end
|
||||
end
|
||||
-- Check to see if people are near by enough to look at us.
|
||||
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)
|
||||
-- damage from rain caused by itself so we don't want it to attack itself.
|
||||
if hitter ~= self.object and hitter ~= nil then
|
||||
if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
self:teleport(nil)
|
||||
else
|
||||
--if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
|
||||
-- self:teleport(nil)
|
||||
--else
|
||||
self:teleport(hitter)
|
||||
self.attack=hitter
|
||||
self.state="attack"
|
||||
end
|
||||
--end
|
||||
end
|
||||
end,
|
||||
armor = { fleshy = 100, water_vulnerable = 100 },
|
||||
|
|
|
@ -38,8 +38,8 @@ mobs:register_mob("mobs_mc:ghast", {
|
|||
walk_velocity = 1.6,
|
||||
run_velocity = 3.2,
|
||||
drops = {
|
||||
{name = mobs_mc.items.gunpowder, chance = 1, min = 0, max = 2,},
|
||||
{name = mobs_mc.items.ghast_tear, chance = 3,min = 0,max = 1,},
|
||||
{name = mobs_mc.items.gunpowder, chance = 1, min = 0, max = 2, looting = "common"},
|
||||
{name = mobs_mc.items.ghast_tear, chance = 10/6, min = 0, max = 1, looting = "common", looting_ignore_chance = true},
|
||||
},
|
||||
animation = {
|
||||
stand_speed = 50, walk_speed = 50, run_speed = 50,
|
||||
|
@ -62,6 +62,7 @@ mobs:register_mob("mobs_mc:ghast", {
|
|||
fly = true,
|
||||
makes_footstep_sound = false,
|
||||
instant_death = true,
|
||||
fire_resistant = true,
|
||||
})
|
||||
|
||||
|
||||
|
|
|
@ -46,7 +46,8 @@ mobs:register_mob("mobs_mc:guardian", {
|
|||
{name = mobs_mc.items.prismarine_shard,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 32,},
|
||||
max = 32,
|
||||
looting = "common",},
|
||||
-- TODO: Reduce of drops when ocean monument is ready.
|
||||
|
||||
-- The following drops are approximations
|
||||
|
@ -54,29 +55,39 @@ mobs:register_mob("mobs_mc:guardian", {
|
|||
{name = mobs_mc.items.fish_raw,
|
||||
chance = 4,
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "common",},
|
||||
{name = mobs_mc.items.prismarine_crystals,
|
||||
chance = 4,
|
||||
min = 1,
|
||||
max = 2,},
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
|
||||
-- Rare drop: fish
|
||||
{name = mobs_mc.items.fish_raw,
|
||||
chance = 160, -- 2.5% / 4
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.0025,},
|
||||
{name = mobs_mc.items.salmon_raw,
|
||||
chance = 160,
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.0025,},
|
||||
{name = mobs_mc.items.clownfish_raw,
|
||||
chance = 160,
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.0025,},
|
||||
{name = mobs_mc.items.pufferfish_raw,
|
||||
chance = 160,
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.0025,},
|
||||
},
|
||||
fly = true,
|
||||
makes_footstep_sound = false,
|
||||
|
|
|
@ -51,7 +51,8 @@ mobs:register_mob("mobs_mc:guardian_elder", {
|
|||
{name = mobs_mc.items.prismarine_shard,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 64,},
|
||||
max = 64,
|
||||
looting = "common",},
|
||||
|
||||
-- TODO: Only drop if killed by player
|
||||
{name = mobs_mc.items.wet_sponge,
|
||||
|
@ -64,29 +65,39 @@ mobs:register_mob("mobs_mc:guardian_elder", {
|
|||
{name = mobs_mc.items.fish_raw,
|
||||
chance = 4,
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "common",},
|
||||
{name = mobs_mc.items.prismarine_crystals,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 10,},
|
||||
max = 10,
|
||||
looting = "common",},
|
||||
|
||||
-- Rare drop: fish
|
||||
{name = mobs_mc.items.fish_raw,
|
||||
chance = 160, -- 2.5% / 4
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.01 / 4,},
|
||||
{name = mobs_mc.items.salmon_raw,
|
||||
chance = 160,
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.01 / 4,},
|
||||
{name = mobs_mc.items.clownfish_raw,
|
||||
chance = 160,
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.01 / 4,},
|
||||
{name = mobs_mc.items.pufferfish_raw,
|
||||
chance = 160,
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.01 / 4,},
|
||||
},
|
||||
fly = true,
|
||||
makes_footstep_sound = false,
|
||||
|
|
|
@ -127,7 +127,8 @@ local horse = {
|
|||
{name = mobs_mc.items.leather,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,},
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
},
|
||||
|
||||
do_custom = function(self, dtime)
|
||||
|
|
|
@ -54,7 +54,8 @@ mobs:register_mob("mobs_mc:llama", {
|
|||
{name = mobs_mc.items.leather,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,},
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
},
|
||||
fear_height = 4,
|
||||
sounds = {
|
||||
|
|
|
@ -37,7 +37,8 @@ mobs:register_mob("mobs_mc:parrot", {
|
|||
{name = mobs_mc.items.feather,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 2,},
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
},
|
||||
animation = {
|
||||
stand_speed = 50,
|
||||
|
|
|
@ -27,7 +27,8 @@ mobs:register_mob("mobs_mc:pig", {
|
|||
{name = mobs_mc.items.porkchop_raw,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 3,},
|
||||
max = 3,
|
||||
looting = "common",},
|
||||
},
|
||||
fear_height = 4,
|
||||
sounds = {
|
||||
|
|
|
@ -36,12 +36,14 @@ mobs:register_mob("mobs_mc:polar_bear", {
|
|||
{name = mobs_mc.items.fish_raw,
|
||||
chance = 2,
|
||||
min = 0,
|
||||
max = 2,},
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
-- 1/4 to drop raw salmon
|
||||
{name = mobs_mc.items.salmon_raw,
|
||||
chance = 4,
|
||||
min = 0,
|
||||
max = 2,},
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
|
||||
},
|
||||
floats = 1,
|
||||
|
|
|
@ -41,11 +41,9 @@ local rabbit = {
|
|||
runaway = true,
|
||||
jump = true,
|
||||
drops = {
|
||||
{name = mobs_mc.items.rabbit_raw, chance = 1, min = 0, max = 1},
|
||||
{name = mobs_mc.items.rabbit_hide, chance = 1, min = 0, max = 1},
|
||||
{name = mobs_mc.items.rabbit_foot, chance = 10, min = 0, max = 1},
|
||||
-- TODO: Drop rabbit's foot when it's useful
|
||||
--{name = mobs_mc.items.rabbit_foot, chance = 10, min = 1, 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, looting = "common",},
|
||||
{name = mobs_mc.items.rabbit_foot, chance = 10, min = 0, max = 1, looting = "rare", looting_factor = 0.03,},
|
||||
},
|
||||
fear_height = 4,
|
||||
animation = {
|
||||
|
|
|
@ -63,11 +63,13 @@ mobs:register_mob("mobs_mc:sheep", {
|
|||
{name = mobs_mc.items.mutton_raw,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 2,},
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
{name = colors["unicolor_white"][1],
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "common",},
|
||||
},
|
||||
fear_height = 4,
|
||||
sounds = {
|
||||
|
|
|
@ -35,9 +35,11 @@ mobs:register_mob("mobs_mc:shulker", {
|
|||
jump = false,
|
||||
drops = {
|
||||
{name = mobs_mc.items.shulker_shell,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 1,},
|
||||
chance = 2,
|
||||
min = 1,
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.0625},
|
||||
},
|
||||
animation = {
|
||||
stand_speed = 25, walk_speed = 25, run_speed = 50, punch_speed = 25,
|
||||
|
|
|
@ -46,15 +46,18 @@ local skeleton = {
|
|||
{name = mobs_mc.items.arrow,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,},
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
{name = mobs_mc.items.bow,
|
||||
chance = 11,
|
||||
chance = 100 / 8.5,
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",},
|
||||
{name = mobs_mc.items.bone,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,},
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
|
||||
-- Head
|
||||
-- TODO: Only drop if killed by charged creeper
|
||||
|
@ -78,7 +81,7 @@ local skeleton = {
|
|||
die_speed = 15,
|
||||
die_loop = false,
|
||||
},
|
||||
sunlight_damage = 1,
|
||||
ignited_by_sunlight = true,
|
||||
view_range = 16,
|
||||
fear_height = 4,
|
||||
attack_type = "dogshoot",
|
||||
|
@ -116,12 +119,21 @@ stray.textures = {
|
|||
-- TODO: different sound (w/ echo)
|
||||
-- TODO: stray's arrow inflicts slowness status
|
||||
table.insert(stray.drops, {
|
||||
-- Chance to drop additional arrow.
|
||||
-- TODO: Should be tipped arrow of slowness
|
||||
name = mobs_mc.items.arrow,
|
||||
name = "mcl_potions:slowness_arrow",
|
||||
chance = 2,
|
||||
min = 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)
|
||||
|
|
|
@ -45,17 +45,20 @@ mobs:register_mob("mobs_mc:witherskeleton", {
|
|||
{name = mobs_mc.items.coal,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "common",},
|
||||
{name = mobs_mc.items.bone,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,},
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
|
||||
-- Head
|
||||
{name = mobs_mc.items.head_wither_skeleton,
|
||||
chance = 40, -- 2.5% chance
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",},
|
||||
},
|
||||
animation = {
|
||||
stand_start = 0,
|
||||
|
@ -87,6 +90,7 @@ mobs:register_mob("mobs_mc:witherskeleton", {
|
|||
dogshoot_count_max =0.5,
|
||||
fear_height = 4,
|
||||
harmed_by_heal = true,
|
||||
fire_resistant = true,
|
||||
})
|
||||
|
||||
--spawn
|
||||
|
|
|
@ -108,7 +108,8 @@ local slime_big = {
|
|||
jump_height = 5.2,
|
||||
fear_height = 0,
|
||||
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)
|
||||
|
||||
|
@ -220,7 +221,8 @@ local magma_cube_big = {
|
|||
walk_chance = 0,
|
||||
fear_height = 0,
|
||||
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)
|
||||
|
||||
|
|
|
@ -49,8 +49,10 @@ local spider = {
|
|||
view_range = 16,
|
||||
floats = 1,
|
||||
drops = {
|
||||
{name = mobs_mc.items.string, chance = 1, min = 0, max = 2,},
|
||||
{name = mobs_mc.items.spider_eye, chance = 3, min = 1, max = 1,},
|
||||
{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, looting = "common", looting_chance_function = function(lvl)
|
||||
return 1 - 2 / (lvl + 3)
|
||||
end},
|
||||
},
|
||||
specific_attack = { "player", "mobs_mc:iron_golem" },
|
||||
fear_height = 4,
|
||||
|
|
|
@ -42,7 +42,8 @@ mobs:register_mob("mobs_mc:squid", {
|
|||
{name = mobs_mc.items.black_dye,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 3,},
|
||||
max = 3,
|
||||
looting = "common",},
|
||||
},
|
||||
visual_size = {x=3, y=3},
|
||||
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_mobitems:string", 15, 20 }, E1 },
|
||||
-- TODO: replace with enchanted fishing rod
|
||||
{ { "mcl_core:emerald", 3, 11 }, { "mcl_fishing:fishing_rod", 1, 1} },
|
||||
{ { "mcl_core:emerald", 3, 11 }, { "mcl_fishing:fishing_rod_enchanted", 1, 1} },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -154,23 +153,27 @@ local professions = {
|
|||
trades = {
|
||||
{
|
||||
{ { "mcl_core:paper", 24, 36 }, E1 },
|
||||
-- TODO: enchanted book
|
||||
{ { "mcl_books:book", 8, 10 }, E1 },
|
||||
{ { "mcl_core:emerald", 10, 12 }, { "mcl_compass:compass", 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_core:emerald", 10, 12 }, { "mcl_clock:clock", 1, 1 } },
|
||||
{ E1, { "mcl_core:glass", 3, 5 } },
|
||||
{ { "mcl_core:emerald", 5, 64 }, { "mcl_enchanting:book_enchanted", 1 ,1 }},
|
||||
},
|
||||
|
||||
{
|
||||
{ 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 } },
|
||||
|
@ -214,8 +217,7 @@ local professions = {
|
|||
|
||||
{
|
||||
{ { "mcl_core:diamond", 3, 4 }, E1 },
|
||||
-- TODO: enchant
|
||||
{ { "mcl_core:emerald", 16, 19 }, { "mcl_armor:chestplate_diamond", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 16, 19 }, { "mcl_armor:chestplate_diamond_enchanted", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
|
@ -236,8 +238,7 @@ local professions = {
|
|||
},
|
||||
|
||||
{
|
||||
-- TODO: enchant
|
||||
{ { "mcl_core:emerald", 7, 12 }, { "mcl_armor:chestplate_leather", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 7, 12 }, { "mcl_armor:chestplate_leather_enchanted", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
|
@ -272,16 +273,13 @@ local professions = {
|
|||
|
||||
{
|
||||
{ { "mcl_core:iron_ingot", 7, 9 }, E1 },
|
||||
-- TODO: enchant
|
||||
{ { "mcl_core:emerald", 9, 10 }, { "mcl_tools:sword_iron", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 9, 10 }, { "mcl_tools:sword_iron_enchanted", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_core:diamond", 3, 4 }, E1 },
|
||||
-- TODO: enchant
|
||||
{ { "mcl_core:emerald", 12, 15 }, { "mcl_tools:sword_diamond", 1, 1 } },
|
||||
-- TODO: enchant
|
||||
{ { "mcl_core:emerald", 9, 12 }, { "mcl_tools:axe_diamond", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 12, 15 }, { "mcl_tools:sword_diamond_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 9, 12 }, { "mcl_tools:axe_diamond_enchanted", 1, 1 } },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -291,20 +289,17 @@ local professions = {
|
|||
trades = {
|
||||
{
|
||||
{ { "mcl_core:coal_lump", 16, 24 }, E1 },
|
||||
-- TODO: enchant
|
||||
{ { "mcl_core:emerald", 5, 7 }, { "mcl_tools:shovel_iron", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 5, 7 }, { "mcl_tools:shovel_iron_enchanted", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_core:iron_ingot", 7, 9 }, E1 },
|
||||
-- TODO: enchant
|
||||
{ { "mcl_core:emerald", 9, 11 }, { "mcl_tools:pick_iron", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 9, 11 }, { "mcl_tools:pick_iron_enchanted", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_core:diamond", 3, 4 }, E1 },
|
||||
-- TODO: enchant
|
||||
{ { "mcl_core:emerald", 12, 15 }, { "mcl_tools:pick_diamond", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 12, 15 }, { "mcl_tools:pick_diamond_enchanted", 1, 1 } },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -328,7 +323,10 @@ local professions = {
|
|||
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 = {
|
||||
|
@ -408,6 +406,15 @@ local init_trades = function(self, inv)
|
|||
local offered_item = trade[2][1]
|
||||
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 }
|
||||
if trade[1][4] then
|
||||
local wanted2_item = trade[1][4]
|
||||
|
@ -417,7 +424,7 @@ local init_trades = function(self, inv)
|
|||
|
||||
table.insert(trades, {
|
||||
wanted = wanted,
|
||||
offered = offered_item .. " " .. offered_count,
|
||||
offered = offered_stack:to_table(),
|
||||
tier = tiernum, -- tier of this trade
|
||||
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
|
||||
|
@ -426,6 +433,7 @@ local init_trades = function(self, inv)
|
|||
end
|
||||
end
|
||||
self._trades = minetest.serialize(trades)
|
||||
minetest.deserialize(self._trades)
|
||||
end
|
||||
|
||||
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().."]"
|
||||
.."tooltip[2,1;0.8,0.8;"..F(wanted1:get_description()).."]"
|
||||
..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()).."]"
|
||||
.."list["..tradeinv..";input;2,2.5;2,1;]"
|
||||
.."list["..tradeinv..";output;5.76,2.55;1,1;]"
|
||||
|
@ -954,6 +962,7 @@ mobs:register_mob("mobs_mc:villager", {
|
|||
walk_velocity = 1.2,
|
||||
run_velocity = 2.4,
|
||||
drops = {},
|
||||
can_despawn = false,
|
||||
-- TODO: sounds
|
||||
animation = {
|
||||
stand_speed = 25,
|
||||
|
|
|
@ -55,7 +55,8 @@ mobs:register_mob("mobs_mc:evoker", {
|
|||
{name = mobs_mc.items.emerald,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "common",},
|
||||
{name = mobs_mc.items.totem,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
|
|
|
@ -41,11 +41,13 @@ mobs:register_mob("mobs_mc:vindicator", {
|
|||
{name = mobs_mc.items.emerald,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "common",},
|
||||
{name = mobs_mc.items.iron_axe,
|
||||
chance = 11,
|
||||
chance = 100 / 8.5,
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",},
|
||||
},
|
||||
-- TODO: sounds
|
||||
animation = {
|
||||
|
@ -66,7 +68,6 @@ mobs:register_mob("mobs_mc:vindicator", {
|
|||
},
|
||||
view_range = 16,
|
||||
fear_height = 4,
|
||||
|
||||
})
|
||||
|
||||
-- spawn eggs
|
||||
|
|
|
@ -5,12 +5,25 @@
|
|||
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
-- TODO: Turn villagers to 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", {
|
||||
type = "monster",
|
||||
|
@ -44,19 +57,26 @@ mobs:register_mob("mobs_mc:villager_zombie", {
|
|||
{name = mobs_mc.items.rotten_flesh,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,},
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
{name = mobs_mc.items.iron_ingot,
|
||||
chance = 120, -- 2.5% / 3
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.01 / 3,},
|
||||
{name = mobs_mc.items.carrot,
|
||||
chance = 120, -- 2.5% / 3
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.01 / 3,},
|
||||
{name = mobs_mc.items.potato,
|
||||
chance = 120, -- 2.5% / 3
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.01 / 3,},
|
||||
},
|
||||
sounds = {
|
||||
random = "mobs_mc_zombie_growl",
|
||||
|
@ -75,14 +95,60 @@ mobs:register_mob("mobs_mc:villager_zombie", {
|
|||
run_start = 0,
|
||||
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,
|
||||
fear_height = 4,
|
||||
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
|
||||
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,
|
||||
max_drops = 3,
|
||||
drops = {
|
||||
{name = mobs_mc.items.glass_bottle, chance = 8, min = 0, max = 2,},
|
||||
{name = mobs_mc.items.glowstone_dust, chance = 8, min = 0, max = 2,},
|
||||
{name = mobs_mc.items.gunpowder, chance = 8, min = 0, max = 2,},
|
||||
{name = mobs_mc.items.redstone, chance = 8, min = 0, max = 2,},
|
||||
{name = mobs_mc.items.spider_eye, chance = 8, min = 0, max = 2,},
|
||||
{name = mobs_mc.items.sugar, chance = 8, min = 0, max = 2,},
|
||||
{name = mobs_mc.items.stick, chance = 4, 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, looting = "common",},
|
||||
{name = mobs_mc.items.gunpowder, chance = 8, min = 0, max = 2, looting = "common",},
|
||||
{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, looting = "common",},
|
||||
{name = mobs_mc.items.sugar, chance = 8, min = 0, max = 2, looting = "common",},
|
||||
{name = mobs_mc.items.stick, chance = 4, min = 0, max = 2, looting = "common",},
|
||||
},
|
||||
-- TODO: sounds
|
||||
animation = {
|
||||
|
@ -68,7 +68,6 @@ mobs:register_mob("mobs_mc:witch", {
|
|||
},
|
||||
view_range = 16,
|
||||
fear_height = 4,
|
||||
|
||||
})
|
||||
|
||||
-- potion projectile (EXPERIMENTAL)
|
||||
|
|
|
@ -13,19 +13,26 @@ local drops_common = {
|
|||
{name = mobs_mc.items.rotten_flesh,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,},
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
{name = mobs_mc.items.iron_ingot,
|
||||
chance = 120, -- 2.5% / 3
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.01 / 3,},
|
||||
{name = mobs_mc.items.carrot,
|
||||
chance = 120, -- 2.5% / 3
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.01 / 3,},
|
||||
{name = mobs_mc.items.potato,
|
||||
chance = 120, -- 2.5% / 3
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare",
|
||||
looting_factor = 0.01 / 3,},
|
||||
}
|
||||
|
||||
local drops_zombie = table.copy(drops_common)
|
||||
|
@ -78,6 +85,7 @@ local zombie = {
|
|||
walk_start = 0, walk_end = 40,
|
||||
run_start = 0, run_end = 40,
|
||||
},
|
||||
ignited_by_sunlight = true,
|
||||
sunlight_damage = 2,
|
||||
view_range = 16,
|
||||
attack_type = "dogfight",
|
||||
|
@ -104,6 +112,7 @@ mobs:register_mob("mobs_mc:baby_zombie", baby_zombie)
|
|||
-- Desert variant of the zombie
|
||||
local husk = table.copy(zombie)
|
||||
husk.textures = {{"mobs_mc_husk.png"}}
|
||||
husk.ignited_by_sunlight = false
|
||||
husk.sunlight_damage = 0
|
||||
husk.drops = drops_common
|
||||
-- TODO: Husks avoid water
|
||||
|
|
|
@ -19,7 +19,6 @@ local pigman = {
|
|||
hp_max = 20,
|
||||
xp_min = 6,
|
||||
xp_max = 6,
|
||||
breath_max = -1,
|
||||
armor = {undead = 90, fleshy = 90},
|
||||
attack_type = "dogfight",
|
||||
group_attack = { "mobs_mc:pigman", "mobs_mc:baby_pigman" },
|
||||
|
@ -50,19 +49,23 @@ local pigman = {
|
|||
{name = mobs_mc.items.rotten_flesh,
|
||||
chance = 1,
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "common"},
|
||||
{name = mobs_mc.items.gold_nugget,
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "common"},
|
||||
{name = mobs_mc.items.gold_ingot,
|
||||
chance = 40, -- 2.5%
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare"},
|
||||
{name = mobs_mc.items.gold_sword,
|
||||
chance = 12, -- 8.333%, approximation to 8.5%
|
||||
chance = 100 / 8.5,
|
||||
min = 1,
|
||||
max = 1,},
|
||||
max = 1,
|
||||
looting = "rare"},
|
||||
},
|
||||
animation = {
|
||||
stand_speed = 25,
|
||||
|
@ -82,6 +85,7 @@ local pigman = {
|
|||
fear_height = 4,
|
||||
view_range = 16,
|
||||
harmed_by_heal = true,
|
||||
fire_damage_resistant = true,
|
||||
}
|
||||
|
||||
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 damage is disabled, we can't kill players.
|
||||
-- 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)
|
||||
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!"))
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
local modpath = minetest.get_modpath("mcl_weather");
|
||||
local modpath = minetest.get_modpath("mcl_weather")
|
||||
|
||||
mcl_weather = {}
|
||||
|
||||
-- If not located then embeded skycolor mod version will be loaded.
|
||||
if minetest.get_modpath("skycolor") == nil then
|
||||
dofile(modpath.."/skycolor.lua")
|
||||
dofile(modpath.."/skycolor.lua")
|
||||
end
|
||||
|
||||
dofile(modpath.."/weather_core.lua")
|
||||
|
@ -13,5 +13,5 @@ dofile(modpath.."/rain.lua")
|
|||
dofile(modpath.."/nether_dust.lua")
|
||||
|
||||
if minetest.get_modpath("lightning") ~= nil then
|
||||
dofile(modpath.."/thunder.lua")
|
||||
dofile(modpath.."/thunder.lua")
|
||||
end
|
||||
|
|
|
@ -24,11 +24,8 @@ end
|
|||
local timer = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
timer = timer + dtime
|
||||
if timer >= 0.7 then
|
||||
timer = 0
|
||||
else
|
||||
return
|
||||
end
|
||||
if timer < 0.7 then return end
|
||||
timer = 0
|
||||
|
||||
for _, player in ipairs(minetest.get_connected_players()) do
|
||||
if not mcl_worlds.has_dust(player:get_pos()) then
|
||||
|
|
|
@ -2,198 +2,198 @@ local PARTICLES_COUNT_RAIN = 30
|
|||
local PARTICLES_COUNT_THUNDER = 45
|
||||
|
||||
mcl_weather.rain = {
|
||||
-- max rain particles created at time
|
||||
particles_count = PARTICLES_COUNT_RAIN,
|
||||
-- max rain particles created at time
|
||||
particles_count = PARTICLES_COUNT_RAIN,
|
||||
|
||||
-- flag to turn on/off extinguish fire for rain
|
||||
extinguish_fire = true,
|
||||
-- flag to turn on/off extinguish fire for rain
|
||||
extinguish_fire = true,
|
||||
|
||||
-- flag useful when mixing weathers
|
||||
raining = false,
|
||||
-- flag useful when mixing weathers
|
||||
raining = false,
|
||||
|
||||
-- keeping last timeofday value (rounded).
|
||||
-- Defaulted to non-existing value for initial comparing.
|
||||
sky_last_update = -1,
|
||||
-- keeping last timeofday value (rounded).
|
||||
-- Defaulted to non-existing value for initial comparing.
|
||||
sky_last_update = -1,
|
||||
|
||||
init_done = false,
|
||||
init_done = false,
|
||||
}
|
||||
|
||||
mcl_weather.rain.sound_handler = function(player)
|
||||
return minetest.sound_play("weather_rain", {
|
||||
to_player = player:get_player_name(),
|
||||
loop = true,
|
||||
})
|
||||
return minetest.sound_play("weather_rain", {
|
||||
to_player = player:get_player_name(),
|
||||
loop = true,
|
||||
})
|
||||
end
|
||||
|
||||
-- set skybox based on time (uses skycolor api)
|
||||
mcl_weather.rain.set_sky_box = function()
|
||||
if mcl_weather.state == "rain" then
|
||||
mcl_weather.skycolor.add_layer(
|
||||
"weather-pack-rain-sky",
|
||||
{{r=0, g=0, b=0},
|
||||
{r=85, g=86, b=98},
|
||||
{r=135, g=135, b=151},
|
||||
{r=85, g=86, b=98},
|
||||
{r=0, g=0, b=0}})
|
||||
mcl_weather.skycolor.active = true
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
player:set_clouds({color="#5D5D5FE8"})
|
||||
end
|
||||
end
|
||||
if mcl_weather.state == "rain" then
|
||||
mcl_weather.skycolor.add_layer(
|
||||
"weather-pack-rain-sky",
|
||||
{{r=0, g=0, b=0},
|
||||
{r=85, g=86, b=98},
|
||||
{r=135, g=135, b=151},
|
||||
{r=85, g=86, b=98},
|
||||
{r=0, g=0, b=0}})
|
||||
mcl_weather.skycolor.active = true
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
player:set_clouds({color="#5D5D5FE8"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- creating manually parctiles instead of particles spawner because of easier to control
|
||||
-- spawn position.
|
||||
mcl_weather.rain.add_rain_particles = function(player)
|
||||
|
||||
mcl_weather.rain.last_rp_count = 0
|
||||
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)
|
||||
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
|
||||
minetest.add_particle({
|
||||
pos = {x=random_pos_x, y=random_pos_y, z=random_pos_z},
|
||||
velocity = {x=0, y=-10, z=0},
|
||||
acceleration = {x=0, y=-30, z=0},
|
||||
expirationtime = 1.0,
|
||||
size = math.random(0.5, 3),
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
vertical = true,
|
||||
texture = mcl_weather.rain.get_texture(),
|
||||
playername = player:get_player_name()
|
||||
})
|
||||
end
|
||||
end
|
||||
mcl_weather.rain.last_rp_count = 0
|
||||
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)
|
||||
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
|
||||
minetest.add_particle({
|
||||
pos = {x=random_pos_x, y=random_pos_y, z=random_pos_z},
|
||||
velocity = {x=0, y=-10, z=0},
|
||||
acceleration = {x=0, y=-30, z=0},
|
||||
expirationtime = 1.0,
|
||||
size = math.random(0.5, 3),
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
vertical = true,
|
||||
texture = mcl_weather.rain.get_texture(),
|
||||
playername = player:get_player_name()
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Simple random texture getter
|
||||
mcl_weather.rain.get_texture = function()
|
||||
local texture_name
|
||||
local random_number = math.random()
|
||||
if random_number > 0.33 then
|
||||
texture_name = "weather_pack_rain_raindrop_1.png"
|
||||
elseif random_number > 0.66 then
|
||||
texture_name = "weather_pack_rain_raindrop_2.png"
|
||||
else
|
||||
texture_name = "weather_pack_rain_raindrop_3.png"
|
||||
end
|
||||
return texture_name;
|
||||
local texture_name
|
||||
local random_number = math.random()
|
||||
if random_number > 0.33 then
|
||||
texture_name = "weather_pack_rain_raindrop_1.png"
|
||||
elseif random_number > 0.66 then
|
||||
texture_name = "weather_pack_rain_raindrop_2.png"
|
||||
else
|
||||
texture_name = "weather_pack_rain_raindrop_3.png"
|
||||
end
|
||||
return texture_name;
|
||||
end
|
||||
|
||||
-- register player for rain weather.
|
||||
-- basically needs for origin sky reference and rain sound controls.
|
||||
mcl_weather.rain.add_player = function(player)
|
||||
if mcl_weather.players[player:get_player_name()] == nil then
|
||||
local player_meta = {}
|
||||
player_meta.origin_sky = {player:get_sky()}
|
||||
mcl_weather.players[player:get_player_name()] = player_meta
|
||||
end
|
||||
if mcl_weather.players[player:get_player_name()] == nil then
|
||||
local player_meta = {}
|
||||
player_meta.origin_sky = {player:get_sky()}
|
||||
mcl_weather.players[player:get_player_name()] = player_meta
|
||||
end
|
||||
end
|
||||
|
||||
-- remove player from player list effected by rain.
|
||||
-- be sure to remove sound before removing player otherwise soundhandler reference will be lost.
|
||||
mcl_weather.rain.remove_player = function(player)
|
||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||
if player_meta ~= nil and player_meta.origin_sky ~= nil then
|
||||
player:set_clouds({color="#FFF0F0E5"})
|
||||
mcl_weather.players[player:get_player_name()] = nil
|
||||
end
|
||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||
if player_meta ~= nil and player_meta.origin_sky ~= nil then
|
||||
player:set_clouds({color="#FFF0F0E5"})
|
||||
mcl_weather.players[player:get_player_name()] = nil
|
||||
end
|
||||
end
|
||||
|
||||
mcl_worlds.register_on_dimension_change(function(player, dimension)
|
||||
if dimension ~= "overworld" and dimension ~= "void" then
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
mcl_weather.rain.remove_player(player)
|
||||
elseif dimension == "overworld" then
|
||||
mcl_weather.rain.update_sound(player)
|
||||
if mcl_weather.rain.raining then
|
||||
mcl_weather.rain.add_rain_particles(player)
|
||||
mcl_weather.rain.add_player(player)
|
||||
end
|
||||
end
|
||||
if dimension ~= "overworld" and dimension ~= "void" then
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
mcl_weather.rain.remove_player(player)
|
||||
elseif dimension == "overworld" then
|
||||
mcl_weather.rain.update_sound(player)
|
||||
if mcl_weather.rain.raining then
|
||||
mcl_weather.rain.add_rain_particles(player)
|
||||
mcl_weather.rain.add_player(player)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- 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
|
||||
-- when player stay on 'edge' where sound should play and stop depending from random raindrop appearance.
|
||||
mcl_weather.rain.update_sound = function(player)
|
||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||
if player_meta ~= nil then
|
||||
if player_meta.sound_updated ~= nil and player_meta.sound_updated + 5 > minetest.get_gametime() then
|
||||
return false
|
||||
end
|
||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||
if player_meta ~= nil then
|
||||
if player_meta.sound_updated ~= nil and player_meta.sound_updated + 5 > minetest.get_gametime() then
|
||||
return false
|
||||
end
|
||||
|
||||
if player_meta.sound_handler ~= nil then
|
||||
if mcl_weather.rain.last_rp_count == 0 then
|
||||
minetest.sound_fade(player_meta.sound_handler, -0.5, 0.0)
|
||||
player_meta.sound_handler = nil
|
||||
end
|
||||
elseif mcl_weather.rain.last_rp_count > 0 then
|
||||
player_meta.sound_handler = mcl_weather.rain.sound_handler(player)
|
||||
end
|
||||
if player_meta.sound_handler ~= nil then
|
||||
if mcl_weather.rain.last_rp_count == 0 then
|
||||
minetest.sound_fade(player_meta.sound_handler, -0.5, 0.0)
|
||||
player_meta.sound_handler = nil
|
||||
end
|
||||
elseif mcl_weather.rain.last_rp_count > 0 then
|
||||
player_meta.sound_handler = mcl_weather.rain.sound_handler(player)
|
||||
end
|
||||
|
||||
player_meta.sound_updated = minetest.get_gametime()
|
||||
end
|
||||
player_meta.sound_updated = minetest.get_gametime()
|
||||
end
|
||||
end
|
||||
|
||||
-- rain sound removed from player.
|
||||
mcl_weather.rain.remove_sound = function(player)
|
||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||
if player_meta ~= nil and player_meta.sound_handler ~= nil then
|
||||
minetest.sound_fade(player_meta.sound_handler, -0.5, 0.0)
|
||||
player_meta.sound_handler = nil
|
||||
player_meta.sound_updated = nil
|
||||
end
|
||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||
if player_meta ~= nil and player_meta.sound_handler ~= nil then
|
||||
minetest.sound_fade(player_meta.sound_handler, -0.5, 0.0)
|
||||
player_meta.sound_handler = nil
|
||||
player_meta.sound_updated = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- callback function for removing rain
|
||||
mcl_weather.rain.clear = function()
|
||||
mcl_weather.rain.raining = false
|
||||
mcl_weather.rain.sky_last_update = -1
|
||||
mcl_weather.rain.init_done = false
|
||||
mcl_weather.rain.set_particles_mode("rain")
|
||||
mcl_weather.skycolor.remove_layer("weather-pack-rain-sky")
|
||||
for _, player in ipairs(minetest.get_connected_players()) do
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
mcl_weather.rain.remove_player(player)
|
||||
end
|
||||
mcl_weather.rain.raining = false
|
||||
mcl_weather.rain.sky_last_update = -1
|
||||
mcl_weather.rain.init_done = false
|
||||
mcl_weather.rain.set_particles_mode("rain")
|
||||
mcl_weather.skycolor.remove_layer("weather-pack-rain-sky")
|
||||
for _, player in ipairs(minetest.get_connected_players()) do
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
mcl_weather.rain.remove_player(player)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
if mcl_weather.state ~= "rain" then
|
||||
return false
|
||||
end
|
||||
if mcl_weather.state ~= "rain" then
|
||||
return false
|
||||
end
|
||||
|
||||
mcl_weather.rain.make_weather()
|
||||
mcl_weather.rain.make_weather()
|
||||
end)
|
||||
|
||||
mcl_weather.rain.make_weather = function()
|
||||
if mcl_weather.rain.init_done == false then
|
||||
mcl_weather.rain.raining = true
|
||||
mcl_weather.rain.set_sky_box()
|
||||
mcl_weather.rain.set_particles_mode(mcl_weather.mode)
|
||||
mcl_weather.rain.init_done = true
|
||||
end
|
||||
if mcl_weather.rain.init_done == false then
|
||||
mcl_weather.rain.raining = true
|
||||
mcl_weather.rain.set_sky_box()
|
||||
mcl_weather.rain.set_particles_mode(mcl_weather.mode)
|
||||
mcl_weather.rain.init_done = true
|
||||
end
|
||||
|
||||
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
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
return false
|
||||
end
|
||||
mcl_weather.rain.add_player(player)
|
||||
mcl_weather.rain.add_rain_particles(player)
|
||||
mcl_weather.rain.update_sound(player)
|
||||
end
|
||||
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
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
return false
|
||||
end
|
||||
mcl_weather.rain.add_player(player)
|
||||
mcl_weather.rain.add_rain_particles(player)
|
||||
mcl_weather.rain.update_sound(player)
|
||||
end
|
||||
end
|
||||
|
||||
-- Switch the number of raindrops: "thunder" for many raindrops, otherwise for normal raindrops
|
||||
mcl_weather.rain.set_particles_mode = function(mode)
|
||||
if mode == "thunder" then
|
||||
mcl_weather.rain.particles_count = PARTICLES_COUNT_THUNDER
|
||||
else
|
||||
mcl_weather.rain.particles_count = PARTICLES_COUNT_RAIN
|
||||
end
|
||||
if mode == "thunder" then
|
||||
mcl_weather.rain.particles_count = PARTICLES_COUNT_THUNDER
|
||||
else
|
||||
mcl_weather.rain.particles_count = PARTICLES_COUNT_RAIN
|
||||
end
|
||||
end
|
||||
|
||||
if mcl_weather.allow_abm then
|
||||
|
@ -266,16 +266,16 @@ if mcl_weather.allow_abm then
|
|||
end
|
||||
|
||||
if mcl_weather.reg_weathers.rain == nil then
|
||||
mcl_weather.reg_weathers.rain = {
|
||||
clear = mcl_weather.rain.clear,
|
||||
light_factor = 0.6,
|
||||
-- 10min - 20min
|
||||
min_duration = 600,
|
||||
max_duration = 1200,
|
||||
transitions = {
|
||||
[65] = "none",
|
||||
[70] = "snow",
|
||||
[100] = "thunder",
|
||||
}
|
||||
}
|
||||
mcl_weather.reg_weathers.rain = {
|
||||
clear = mcl_weather.rain.clear,
|
||||
light_factor = 0.6,
|
||||
-- 10min - 20min
|
||||
min_duration = 600,
|
||||
max_duration = 1200,
|
||||
transitions = {
|
||||
[65] = "none",
|
||||
[70] = "snow",
|
||||
[100] = "thunder",
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -81,17 +81,16 @@ end)
|
|||
|
||||
-- register snow weather
|
||||
if mcl_weather.reg_weathers.snow == nil then
|
||||
mcl_weather.reg_weathers.snow = {
|
||||
clear = mcl_weather.snow.clear,
|
||||
light_factor = 0.6,
|
||||
-- 10min - 20min
|
||||
min_duration = 600,
|
||||
max_duration = 1200,
|
||||
transitions = {
|
||||
[65] = "none",
|
||||
[80] = "rain",
|
||||
[100] = "thunder",
|
||||
}
|
||||
}
|
||||
mcl_weather.reg_weathers.snow = {
|
||||
clear = mcl_weather.snow.clear,
|
||||
light_factor = 0.6,
|
||||
-- 10min - 20min
|
||||
min_duration = 600,
|
||||
max_duration = 1200,
|
||||
transitions = {
|
||||
[65] = "none",
|
||||
[80] = "rain",
|
||||
[100] = "thunder",
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ mcl_weather.state = "none"
|
|||
-- player list for saving player meta info
|
||||
mcl_weather.players = {}
|
||||
|
||||
-- default weather recalculation interval
|
||||
mcl_weather.check_interval = 300
|
||||
-- default weather check interval for global step
|
||||
mcl_weather.check_interval = 5
|
||||
|
||||
-- weather min duration
|
||||
mcl_weather.min_duration = 600
|
||||
|
@ -25,14 +25,14 @@ mcl_weather.reg_weathers = {}
|
|||
mcl_weather.allow_abm = true
|
||||
|
||||
mcl_weather.reg_weathers["none"] = {
|
||||
min_duration = mcl_weather.min_duration,
|
||||
max_duration = mcl_weather.max_duration,
|
||||
light_factor = nil,
|
||||
transitions = {
|
||||
[50] = "rain",
|
||||
[100] = "snow",
|
||||
},
|
||||
clear = function() end,
|
||||
min_duration = mcl_weather.min_duration,
|
||||
max_duration = mcl_weather.max_duration,
|
||||
light_factor = nil,
|
||||
transitions = {
|
||||
[50] = "rain",
|
||||
[100] = "snow",
|
||||
},
|
||||
clear = function() end,
|
||||
}
|
||||
|
||||
local storage = minetest.get_mod_storage()
|
||||
|
@ -45,211 +45,230 @@ end
|
|||
minetest.register_on_shutdown(save_weather)
|
||||
|
||||
mcl_weather.get_rand_end_time = function(min_duration, max_duration)
|
||||
local r
|
||||
if min_duration ~= nil and max_duration ~= nil then
|
||||
r = math.random(min_duration, max_duration);
|
||||
else
|
||||
r = math.random(mcl_weather.min_duration, mcl_weather.max_duration);
|
||||
end
|
||||
return minetest.get_gametime() + r
|
||||
local r
|
||||
if min_duration ~= nil and max_duration ~= nil then
|
||||
r = math.random(min_duration, max_duration)
|
||||
else
|
||||
r = math.random(mcl_weather.min_duration, mcl_weather.max_duration)
|
||||
end
|
||||
return minetest.get_gametime() + r
|
||||
end
|
||||
|
||||
mcl_weather.get_current_light_factor = function()
|
||||
if mcl_weather.state == "none" then
|
||||
return nil
|
||||
else
|
||||
return mcl_weather.reg_weathers[mcl_weather.state].light_factor
|
||||
end
|
||||
if mcl_weather.state == "none" then
|
||||
return nil
|
||||
else
|
||||
return mcl_weather.reg_weathers[mcl_weather.state].light_factor
|
||||
end
|
||||
end
|
||||
|
||||
-- Returns true if pos is outdoor.
|
||||
-- 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.
|
||||
mcl_weather.is_outdoor = function(pos)
|
||||
local cpos = {x=pos.x, y=pos.y+1, z=pos.z}
|
||||
local dim = mcl_worlds.pos_to_dimension(cpos)
|
||||
if minetest.get_node_light(cpos, 0.5) == 15 and dim == "overworld" then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
local cpos = {x=pos.x, y=pos.y+1, z=pos.z}
|
||||
local dim = mcl_worlds.pos_to_dimension(cpos)
|
||||
if minetest.get_node_light(cpos, 0.5) == 15 and dim == "overworld" then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- checks if player is undewater. This is needed in order to
|
||||
-- turn off weather particles generation.
|
||||
mcl_weather.is_underwater = function(player)
|
||||
local ppos = player:get_pos()
|
||||
local offset = player:get_eye_offset()
|
||||
local player_eye_pos = {x = ppos.x + offset.x,
|
||||
y = ppos.y + offset.y + 1.5,
|
||||
z = ppos.z + offset.z}
|
||||
local node_level = minetest.get_node_level(player_eye_pos)
|
||||
if node_level == 8 or node_level == 7 then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
local ppos = player:get_pos()
|
||||
local offset = player:get_eye_offset()
|
||||
local player_eye_pos = {x = ppos.x + offset.x,
|
||||
y = ppos.y + offset.y + 1.5,
|
||||
z = ppos.z + offset.z}
|
||||
local node_level = minetest.get_node_level(player_eye_pos)
|
||||
if node_level == 8 or node_level == 7 then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- 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.
|
||||
mcl_weather.get_random_pos_by_player_look_dir = function(player)
|
||||
local look_dir = player:get_look_dir()
|
||||
local player_pos = player:get_pos()
|
||||
local look_dir = player:get_look_dir()
|
||||
local player_pos = player:get_pos()
|
||||
|
||||
local random_pos_x = 0
|
||||
local random_pos_y = 0
|
||||
local random_pos_z = 0
|
||||
local random_pos_x = 0
|
||||
local random_pos_y = 0
|
||||
local random_pos_z = 0
|
||||
|
||||
if look_dir.x > 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_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5)
|
||||
else
|
||||
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)
|
||||
end
|
||||
else
|
||||
if look_dir.z > 0 then
|
||||
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)
|
||||
else
|
||||
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)
|
||||
end
|
||||
end
|
||||
if look_dir.x > 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_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5)
|
||||
else
|
||||
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)
|
||||
end
|
||||
else
|
||||
if look_dir.z > 0 then
|
||||
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)
|
||||
else
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
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
|
||||
end
|
||||
|
||||
local t, wci = 0, mcl_weather.check_interval
|
||||
minetest.register_globalstep(function(dtime)
|
||||
if mcl_weather.end_time == nil then
|
||||
mcl_weather.end_time = mcl_weather.get_rand_end_time()
|
||||
end
|
||||
-- recalculate weather
|
||||
if mcl_weather.end_time <= minetest.get_gametime() then
|
||||
local changeWeather = minetest.settings:get_bool("mcl_doWeatherCycle")
|
||||
if changeWeather == nil then
|
||||
changeWeather = true
|
||||
end
|
||||
if changeWeather then
|
||||
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
|
||||
t = t + dtime
|
||||
if t < wci then return end
|
||||
t = 0
|
||||
|
||||
if mcl_weather.end_time == nil then
|
||||
mcl_weather.end_time = mcl_weather.get_rand_end_time()
|
||||
end
|
||||
-- recalculate weather
|
||||
if mcl_weather.end_time <= minetest.get_gametime() then
|
||||
local changeWeather = minetest.settings:get_bool("mcl_doWeatherCycle")
|
||||
if changeWeather == nil then
|
||||
changeWeather = true
|
||||
end
|
||||
if changeWeather then
|
||||
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)
|
||||
|
||||
-- Sets random weather (which could be 'none' (no weather)).
|
||||
mcl_weather.set_random_weather = function(weather_name, weather_meta)
|
||||
if (weather_meta ~= nil) then
|
||||
local transitions = weather_meta.transitions
|
||||
local random_roll = math.random(0,100)
|
||||
local new_weather
|
||||
for v, weather in pairs(transitions) do
|
||||
if random_roll < v then
|
||||
new_weather = weather
|
||||
break
|
||||
end
|
||||
end
|
||||
if new_weather then
|
||||
mcl_weather.change_weather(new_weather)
|
||||
end
|
||||
end
|
||||
if weather_meta == nil then return end
|
||||
local transitions = weather_meta.transitions
|
||||
local random_roll = math.random(0,100)
|
||||
local new_weather
|
||||
for v, weather in pairs(transitions) do
|
||||
if random_roll < v then
|
||||
new_weather = weather
|
||||
break
|
||||
end
|
||||
end
|
||||
if new_weather then
|
||||
mcl_weather.change_weather(new_weather)
|
||||
end
|
||||
end
|
||||
|
||||
-- Change weather to new_weather.
|
||||
-- * explicit_end_time is OPTIONAL. If specified, explicitly set the
|
||||
-- gametime (minetest.get_gametime) in which the weather ends.
|
||||
mcl_weather.change_weather = function(new_weather, explicit_end_time)
|
||||
if (mcl_weather.reg_weathers ~= nil and mcl_weather.reg_weathers[new_weather] ~= nil) then
|
||||
if (mcl_weather.state ~= nil and mcl_weather.reg_weathers[mcl_weather.state] ~= nil) then
|
||||
mcl_weather.reg_weathers[mcl_weather.state].clear()
|
||||
end
|
||||
mcl_weather.state = 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
|
||||
-- * changer is OPTIONAL, for logging purposes.
|
||||
mcl_weather.change_weather = function(new_weather, explicit_end_time, changer_name)
|
||||
local changer_name = changer_name or debug.getinfo(2).name.."()"
|
||||
|
||||
if (mcl_weather.reg_weathers ~= nil and mcl_weather.reg_weathers[new_weather] ~= nil) then
|
||||
if (mcl_weather.state ~= nil and mcl_weather.reg_weathers[mcl_weather.state] ~= nil) then
|
||||
mcl_weather.reg_weathers[mcl_weather.state].clear()
|
||||
end
|
||||
|
||||
local old_weather = mcl_weather.state
|
||||
|
||||
mcl_weather.state = new_weather
|
||||
|
||||
if old_weather == "none" then
|
||||
old_weather = "clear"
|
||||
end
|
||||
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
|
||||
|
||||
mcl_weather.get_weather = function()
|
||||
return mcl_weather.state
|
||||
return mcl_weather.state
|
||||
end
|
||||
|
||||
minetest.register_privilege("weather_manager", {
|
||||
description = S("Gives ability to control weather"),
|
||||
give_to_singleplayer = false
|
||||
description = S("Gives ability to control weather"),
|
||||
give_to_singleplayer = false
|
||||
})
|
||||
|
||||
-- Weather command definition. Set
|
||||
minetest.register_chatcommand("weather", {
|
||||
params = "(clear | rain | snow | thunder) [<duration>]",
|
||||
description = S("Changes the weather to the specified parameter."),
|
||||
privs = {weather_manager = true},
|
||||
func = function(name, param)
|
||||
if (param == "") then
|
||||
return false, S("Error: No weather specified.")
|
||||
end
|
||||
local new_weather, end_time
|
||||
local parse1, parse2 = string.match(param, "(%w+) ?(%d*)")
|
||||
if parse1 then
|
||||
if parse1 == "clear" then
|
||||
new_weather = "none"
|
||||
else
|
||||
new_weather = parse1
|
||||
end
|
||||
else
|
||||
return false, S("Error: Invalid parameters.")
|
||||
end
|
||||
if parse2 then
|
||||
if type(tonumber(parse2)) == "number" then
|
||||
local duration = tonumber(parse2)
|
||||
if duration < 1 then
|
||||
return false, S("Error: Duration can't be less than 1 second.")
|
||||
end
|
||||
end_time = minetest.get_gametime() + duration
|
||||
end
|
||||
end
|
||||
params = "(clear | rain | snow | thunder) [<duration>]",
|
||||
description = S("Changes the weather to the specified parameter."),
|
||||
privs = {weather_manager = true},
|
||||
func = function(name, param)
|
||||
if (param == "") then
|
||||
return false, S("Error: No weather specified.")
|
||||
end
|
||||
local new_weather, end_time
|
||||
local parse1, parse2 = string.match(param, "(%w+) ?(%d*)")
|
||||
if parse1 then
|
||||
if parse1 == "clear" then
|
||||
new_weather = "none"
|
||||
else
|
||||
new_weather = parse1
|
||||
end
|
||||
else
|
||||
return false, S("Error: Invalid parameters.")
|
||||
end
|
||||
if parse2 then
|
||||
if type(tonumber(parse2)) == "number" then
|
||||
local duration = tonumber(parse2)
|
||||
if duration < 1 then
|
||||
return false, S("Error: Duration can't be less than 1 second.")
|
||||
end
|
||||
end_time = minetest.get_gametime() + duration
|
||||
end
|
||||
end
|
||||
|
||||
local success = mcl_weather.change_weather(new_weather, end_time)
|
||||
if success then
|
||||
return true
|
||||
else
|
||||
return false, S("Error: Invalid weather specified. Use “clear”, “rain”, “snow” or “thunder”.")
|
||||
end
|
||||
end
|
||||
local success = mcl_weather.change_weather(new_weather, end_time, name)
|
||||
if success then
|
||||
return true
|
||||
else
|
||||
return false, S("Error: Invalid weather specified. Use “clear”, “rain”, “snow” or “thunder”.")
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("toggledownfall", {
|
||||
params = "",
|
||||
description = S("Toggles between clear weather and weather with downfall (randomly rain, thunderstorm or snow)"),
|
||||
privs = {weather_manager = true},
|
||||
func = function(name, param)
|
||||
-- Currently rain/thunder/snow: Set weather to clear
|
||||
if mcl_weather.state ~= "none" then
|
||||
return mcl_weather.change_weather("none")
|
||||
params = "",
|
||||
description = S("Toggles between clear weather and weather with downfall (randomly rain, thunderstorm or snow)"),
|
||||
privs = {weather_manager = true},
|
||||
func = function(name, param)
|
||||
-- Currently rain/thunder/snow: Set weather to clear
|
||||
if mcl_weather.state ~= "none" then
|
||||
return mcl_weather.change_weather("none", nil, name)
|
||||
|
||||
-- Currently clear: Set weather randomly to rain/thunder/snow
|
||||
else
|
||||
local new = { "rain", "thunder", "snow" }
|
||||
local r = math.random(1, #new)
|
||||
return mcl_weather.change_weather(new[r])
|
||||
end
|
||||
end
|
||||
-- Currently clear: Set weather randomly to rain/thunder/snow
|
||||
else
|
||||
local new = { "rain", "thunder", "snow" }
|
||||
local r = math.random(1, #new)
|
||||
return mcl_weather.change_weather(new[r], nil, name)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- 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.
|
||||
local weather_allow_abm = minetest.settings:get_bool("weather_allow_abm")
|
||||
if weather_allow_abm ~= nil and weather_allow_abm == false then
|
||||
mcl_weather.allow_abm = false
|
||||
mcl_weather.allow_abm = false
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -1109,7 +1109,13 @@ if progressive_mode then
|
|||
local name = player:get_player_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
|
||||
|
||||
M.register_on_leaveplayer(function(player)
|
||||
|
|
|
@ -77,6 +77,8 @@ hud_manager.add_hud = function(player,hud_name,def)
|
|||
size = def.size,
|
||||
offset = def.offset,
|
||||
z_index = def.z_index,
|
||||
alignment = def.alignment,
|
||||
scale = def.scale,
|
||||
})
|
||||
-- create new 3d array here
|
||||
-- depends.txt is not needed
|
||||
|
@ -148,7 +150,7 @@ function mcl_experience.set_player_xp_level(player,level)
|
|||
return
|
||||
end
|
||||
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)})
|
||||
-- we may don't update the bar
|
||||
end
|
||||
|
@ -164,21 +166,21 @@ minetest.register_on_joinplayer(function(player)
|
|||
|
||||
hud_manager.add_hud(player,"experience_bar",
|
||||
{
|
||||
hud_elem_type = "statbar", position = {x=0.5, y=1},
|
||||
name = "experience bar",
|
||||
text = "experience_bar.png",
|
||||
text2 = "experience_bar_background.png",
|
||||
number = temp_pool.bar, item = 36,
|
||||
direction = 0,
|
||||
offset = {x = (-8 * 28) - 29, y = -(48 + 24 + 16)},
|
||||
size = { x=28, y=28 }, z_index = 11,
|
||||
hud_elem_type = "image",
|
||||
name = "experience bar",
|
||||
text = "experience_bar_background.png^[lowpart:" .. math.floor(temp_pool.bar / 36 * 100) .. ":experience_bar.png^[transformR270",
|
||||
position = {x=0.5, y=1},
|
||||
offset = {x = (-9 * 28) - 3, y = -(48 + 24 + 16 - 5)},
|
||||
scale = {x = 2.8, y = 3.0},
|
||||
alignment = { x = 1, y = 1 },
|
||||
z_index = 11,
|
||||
})
|
||||
|
||||
hud_manager.add_hud(player,"xp_level",
|
||||
{
|
||||
hud_elem_type = "text", position = {x=0.5, y=1},
|
||||
name = "xp_level", text = tostring(temp_pool.level),
|
||||
number = 0xFFFFFF,
|
||||
number = 0x80FF20,
|
||||
offset = {x = 0, y = -(48 + 24 + 24)},
|
||||
z_index = 12,
|
||||
})
|
||||
|
@ -247,7 +249,7 @@ function mcl_experience.add_experience(player, experience)
|
|||
end
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
end)
|
||||
|
@ -304,14 +306,14 @@ local function xp_step(self, dtime)
|
|||
return
|
||||
end
|
||||
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.disable_physics(self)
|
||||
--get the variables
|
||||
pos = self.object: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
|
||||
|
||||
|
@ -330,8 +332,79 @@ local function xp_step(self, dtime)
|
|||
goal = velocity
|
||||
acceleration = vector.new(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
|
||||
self.object:add_velocity(vector.add(acceleration,player_velocity))
|
||||
elseif distance < 0.4 then
|
||||
mcl_experience.add_experience(collector, self._xp)
|
||||
elseif distance < 0.8 then
|
||||
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()
|
||||
end
|
||||
return
|
||||
|
@ -534,3 +607,47 @@ function mcl_experience.throw_experience(pos, amount)
|
|||
j = j + 1
|
||||
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>]
|
||||
Gives a player some XP=Даёт игроку XP
|
||||
Error: Too many parameters!=Ошибка: слишком много параметров!
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# textdomain: mcl_experience
|
||||
[[<player>] <xp>]=[[<joueur>] <xp>]
|
||||
Gives a player some XP=Donne de l'XP à un joueur
|
||||
Error: Too many parameters!=Erreur: Trop de paramètres!
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# textdomain: mcl_experience
|
||||
[[<player>] <xp>]=
|
||||
Gives a player some XP=
|
||||
Error: Too many parameters!=
|
||||
Error: Incorrect value of XP=
|
||||
Error: Player not found=
|
||||
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] = {}
|
||||
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
|
||||
loaded after _mcl_autogroup for this to work, because it required certain
|
||||
groups to be set. ]]
|
||||
|
@ -82,11 +94,33 @@ do
|
|||
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
|
||||
table.sort(to_sort)
|
||||
replace_enchanted_books(to_sort)
|
||||
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 playername = player:get_player_name()
|
||||
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
|
||||
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
|
||||
local name = string.lower(def.name)
|
||||
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
|
||||
if filter_item(string.lower(def.name), def.description, lang, filter) then
|
||||
table.insert(creative_list, name)
|
||||
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)
|
||||
replace_enchanted_books(creative_list)
|
||||
|
||||
inv:set_size("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)
|
||||
if not digger or not digger:is_player() then
|
||||
return
|
||||
for _,item in ipairs(drops) do
|
||||
minetest.add_item(pos, item)
|
||||
end
|
||||
end
|
||||
local inv = digger:get_inventory()
|
||||
if inv then
|
||||
|
|
|
@ -141,7 +141,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||
return_fields(player,"craft")
|
||||
return_fields(player,"enchanting_lapis")
|
||||
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
|
||||
set_inventory(player)
|
||||
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)
|
||||
minetest.after(mcl_vars.redstone_tick, function(pos)
|
||||
node = minetest.get_node(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
if not node then
|
||||
return
|
||||
end
|
||||
|
@ -284,6 +284,7 @@ if realtime then
|
|||
mcl_observers.set_node = minetest.set_node
|
||||
mcl_observers.swap_node = minetest.swap_node
|
||||
mcl_observers.remove_node = minetest.remove_node
|
||||
mcl_observers.bulk_set_node = minetest.bulk_set_node
|
||||
|
||||
minetest.add_node=function(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})
|
||||
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:
|
||||
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 #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
|
||||
-- the vectors must be absolute positions
|
||||
|
@ -195,10 +195,9 @@ function mesecon.mvps_set_owner(pos, placer)
|
|||
end
|
||||
end
|
||||
|
||||
local function are_protected(positions, player_name)
|
||||
local name = player_name
|
||||
for _, pos in pairs(positions) do
|
||||
if is_protected(pos, name) then
|
||||
local function are_protected(nodes, player_name)
|
||||
for _, node in pairs(nodes) do
|
||||
if minetest.is_protected(node.pos, player_name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
|
|
@ -97,7 +97,7 @@ local piston_on = function (pos, node)
|
|||
local meta = minetest.get_meta(pos)
|
||||
local success, stack, oldstack = mesecon.mvps_push(np, dir, PISTON_MAXIMUM_PUSH, meta:get_string("owner"), pos)
|
||||
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})
|
||||
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
|
||||
|
@ -115,7 +115,7 @@ end
|
|||
|
||||
local piston_off = function (pos, node)
|
||||
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)
|
||||
if not pistonspec.sticky then
|
||||
return
|
||||
|
|
|
@ -554,7 +554,7 @@ minetest.register_on_player_hpchange(function(player, hp_change, reason)
|
|||
epf = epf + blast_protection_level * 2
|
||||
end
|
||||
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
|
||||
epf = epf + fire_protection_level * 2
|
||||
end
|
||||
|
|
|
@ -223,7 +223,7 @@ minetest.register_node("mcl_armor_stand:armor_stand", {
|
|||
after_destruct = function(pos)
|
||||
update_entity(pos)
|
||||
end,
|
||||
on_blast = function(pos)
|
||||
on_blast = function(pos, _, do_drop)
|
||||
local object = get_stand_object(pos)
|
||||
if object then
|
||||
object:remove()
|
||||
|
@ -231,6 +231,10 @@ minetest.register_node("mcl_armor_stand:armor_stand", {
|
|||
minetest.after(1, function(pos)
|
||||
update_entity(pos)
|
||||
end, pos)
|
||||
minetest.remove_node(pos)
|
||||
if do_drop then
|
||||
minetest.add_item(pos, "mcl_armor_stand:armor_stand")
|
||||
end
|
||||
end,
|
||||
on_rotate = function(pos, node, user, mode)
|
||||
if mode == screwdriver.ROTATE_FACE then
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
local S = minetest.get_translator("mcl_beds")
|
||||
|
||||
local reverse = true
|
||||
|
||||
local function destruct_bed(pos, is_top)
|
||||
local node = minetest.get_node(pos)
|
||||
local other
|
||||
local function destruct_bed(pos, oldnode)
|
||||
local node = oldnode or minetest.get_node(pos)
|
||||
if not node then return end
|
||||
local dir = minetest.facedir_to_dir(node.param2)
|
||||
if is_top then
|
||||
other = vector.subtract(pos, dir)
|
||||
else
|
||||
other = vector.add(pos, dir)
|
||||
end
|
||||
|
||||
if reverse then
|
||||
reverse = not reverse
|
||||
minetest.remove_node(other)
|
||||
minetest.check_for_falling(other)
|
||||
else
|
||||
reverse = not reverse
|
||||
local pos2, node2
|
||||
if string.sub(node.name, -4) == "_top" then
|
||||
pos2 = vector.subtract(pos, dir)
|
||||
node2 = minetest.get_node(pos2)
|
||||
if node2 and string.sub(node2.name, -7) == "_bottom" then
|
||||
minetest.remove_node(pos2)
|
||||
end
|
||||
minetest.check_for_falling(pos)
|
||||
elseif string.sub(node.name, -7) == "_bottom" then
|
||||
minetest.add_item(pos, node.name)
|
||||
pos2 = vector.add(pos, dir)
|
||||
node2 = minetest.get_node(pos2)
|
||||
if node2 and string.sub(node2.name, -4) == "_top" then
|
||||
minetest.remove_node(pos2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -86,6 +87,7 @@ function mcl_beds.register_bed(name, def)
|
|||
node_box = node_box_bottom,
|
||||
selection_box = selection_box_bottom,
|
||||
collision_box = collision_box_bottom,
|
||||
drop = "",
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
local under = pointed_thing.under
|
||||
|
||||
|
@ -139,10 +141,9 @@ function mcl_beds.register_bed(name, def)
|
|||
return itemstack
|
||||
end,
|
||||
|
||||
on_destruct = function(pos)
|
||||
destruct_bed(pos, false)
|
||||
kick_player_after_destruct(pos)
|
||||
end,
|
||||
after_destruct = destruct_bed,
|
||||
|
||||
on_destruct = kick_player_after_destruct,
|
||||
|
||||
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
||||
mcl_beds.on_rightclick(pos, clicker, false)
|
||||
|
@ -205,7 +206,7 @@ function mcl_beds.register_bed(name, def)
|
|||
_mcl_hardness = 0.2,
|
||||
_mcl_blast_resistance = 1,
|
||||
sounds = def.sounds or default_sounds,
|
||||
drop = name .. "_bottom",
|
||||
drop = "",
|
||||
node_box = node_box_top,
|
||||
selection_box = selection_box_top,
|
||||
collision_box = collision_box_top,
|
||||
|
@ -214,10 +215,7 @@ function mcl_beds.register_bed(name, def)
|
|||
return itemstack
|
||||
end,
|
||||
on_rotate = false,
|
||||
on_destruct = function(pos)
|
||||
destruct_bed(pos, true)
|
||||
kick_player_after_destruct(pos)
|
||||
end,
|
||||
after_destruct = destruct_bed,
|
||||
})
|
||||
|
||||
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_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
|
||||
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
|
||||
return false, S("You can't sleep, the bed's too far away!")
|
||||
end
|
||||
|
||||
for _, other_pos in pairs(mcl_beds.bed_pos) do
|
||||
if vector.distance(bed_pos, other_pos) < 0.1 then
|
||||
minetest.chat_send_player(name, S("This bed is already occupied!"))
|
||||
return false
|
||||
return false, S("This bed is already occupied!")
|
||||
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
|
||||
-- sometimes reports incorrect Y speed. A velocity threshold
|
||||
-- of 0.125 still seems good enough.
|
||||
if vector.length(player:get_player_velocity()) > 0.125 then
|
||||
minetest.chat_send_player(name, S("You have to stop moving before going to bed!"))
|
||||
return false
|
||||
if vector.length(player:get_velocity() or player:get_player_velocity()) > 0.125 then
|
||||
return false, S("You have to stop moving before going to bed!")
|
||||
end
|
||||
|
||||
-- No sleeping if monsters nearby.
|
||||
|
@ -109,9 +111,8 @@ local function lay_down(player, pos, bed_pos, state, skip)
|
|||
-- 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 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
|
||||
return false
|
||||
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 def2 = minetest.registered_nodes[n2.name]
|
||||
if def1.walkable or def2.walkable then
|
||||
minetest.chat_send_player(name, S("You can't sleep, the bed is obstructed!"))
|
||||
return false
|
||||
return false, S("You can't sleep, the bed is obstructed!")
|
||||
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
|
||||
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)
|
||||
return false, S("It's too dangerous to sleep here!")
|
||||
end
|
||||
|
||||
-- Check day of time and weather
|
||||
local tod = minetest.get_timeofday() * 24000
|
||||
-- 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 spawn_changed then
|
||||
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!"))
|
||||
return false, S("You can only sleep at night or during a thunderstorm.")
|
||||
end
|
||||
|
||||
mcl_beds.player[name] = 1
|
||||
|
@ -329,13 +314,17 @@ function mcl_beds.on_rightclick(pos, player, is_top)
|
|||
|
||||
-- move to bed
|
||||
if not mcl_beds.player[name] then
|
||||
local success, message
|
||||
if is_top then
|
||||
lay_down(player, ppos, pos)
|
||||
success, message = lay_down(player, ppos, pos)
|
||||
else
|
||||
local node = minetest.get_node(pos)
|
||||
local dir = minetest.facedir_to_dir(node.param2)
|
||||
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
|
||||
else
|
||||
lay_down(player, nil, nil, false)
|
||||
|
@ -362,15 +351,15 @@ minetest.register_on_joinplayer(function(player)
|
|||
-- Make player awake on joining server
|
||||
meta:set_string("mcl_beds:sleeping", "false")
|
||||
end
|
||||
|
||||
playerphysics.remove_physics_factor(player, "speed", "mcl_beds:sleeping")
|
||||
playerphysics.remove_physics_factor(player, "jump", "mcl_beds:sleeping")
|
||||
update_formspecs(false)
|
||||
end)
|
||||
|
||||
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 name = player:get_player_name()
|
||||
for n, player in ipairs(players) do
|
||||
if player:get_player_name() == name then
|
||||
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."),
|
||||
_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",
|
||||
groups = { ammo=1, ammo_bow=1 },
|
||||
groups = { ammo=1, ammo_bow=1, ammo_bow_regular=1 },
|
||||
_on_dispense = function(itemstack, dispenserpos, droppos, dropnode, dropdir)
|
||||
-- Shoot arrow
|
||||
local shootpos = vector.add(dispenserpos, vector.multiply(dropdir, 0.51))
|
||||
|
@ -83,6 +83,7 @@ local ARROW_ENTITY={
|
|||
textures = {"mcl_bows:arrow_box"},
|
||||
collisionbox = {-0.19, -0.125, -0.19, 0.19, 0.125, 0.19},
|
||||
collide_with_objects = false,
|
||||
_fire_damage_resistant = true,
|
||||
|
||||
_lastpos={},
|
||||
_startpos=nil,
|
||||
|
@ -105,6 +106,7 @@ local spawn_item = function(self, pos)
|
|||
item:set_velocity({x=0, y=0, z=0})
|
||||
item:set_yaw(self.object:get_yaw())
|
||||
end
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove()
|
||||
end
|
||||
|
||||
|
@ -131,6 +133,8 @@ local damage_particles = function(pos, is_critical)
|
|||
end
|
||||
|
||||
ARROW_ENTITY.on_step = function(self, dtime)
|
||||
mcl_burning.tick(self.object, dtime)
|
||||
|
||||
local pos = self.object:get_pos()
|
||||
local dpos = table.copy(pos) -- digital pos
|
||||
dpos = vector.round(dpos)
|
||||
|
@ -140,6 +144,7 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
|||
self._stucktimer = self._stucktimer + dtime
|
||||
self._stuckrechecktimer = self._stuckrechecktimer + dtime
|
||||
if self._stucktimer > ARROW_TIMEOUT then
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
@ -161,7 +166,7 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
|||
local objects = minetest.get_objects_inside_radius(pos, 1)
|
||||
for _,obj in ipairs(objects) do
|
||||
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
|
||||
obj:get_inventory():add_item("main", "mcl_bows:arrow")
|
||||
minetest.sound_play("item_drop_pickup", {
|
||||
|
@ -171,6 +176,7 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
|||
}, true)
|
||||
end
|
||||
end
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
@ -232,6 +238,7 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
|||
local def = minetest.registered_nodes[nn]
|
||||
if (not def) or def.walkable then
|
||||
-- There's a node in the way. Delete arrow without damage
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
@ -244,6 +251,9 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
|||
armor.last_damage_types[obj:get_player_name()] = "projectile"
|
||||
end
|
||||
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, {
|
||||
full_punch_interval=1.0,
|
||||
damage_groups={fleshy=self._damage},
|
||||
|
@ -271,6 +281,7 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
|||
end
|
||||
minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true)
|
||||
end
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
@ -403,6 +414,7 @@ ARROW_ENTITY.on_activate = function(self, staticdata, dtime_s)
|
|||
-- If yes, delete it.
|
||||
self._stucktimer = minetest.get_gametime() - data.stuckstarttime
|
||||
if self._stucktimer > ARROW_TIMEOUT then
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
|
|
@ -33,7 +33,7 @@ local bow_load = {}
|
|||
-- Another player table, this one stores the wield index of the bow being charged
|
||||
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")
|
||||
if power == nil then
|
||||
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
|
||||
knockback = enchantments.punch * 3
|
||||
end
|
||||
if enchantments.flame then
|
||||
mcl_burning.set_on_fire(obj, math.huge)
|
||||
end
|
||||
end
|
||||
obj:set_velocity({x=dir.x*power, y=dir.y*power, z=dir.z*power})
|
||||
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._startpos = pos
|
||||
le._knockback = knockback
|
||||
le._collectable = collectable
|
||||
minetest.sound_play("mcl_bows_bow_shoot", {pos=pos, max_hear_distance=16}, true)
|
||||
if shooter ~= nil and shooter:is_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_itemstring
|
||||
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 arrow_stack then
|
||||
|
@ -100,7 +105,9 @@ local player_shoot_arrow = function(itemstack, player, power, damage, is_critica
|
|||
return false
|
||||
end
|
||||
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()
|
||||
end
|
||||
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 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
|
||||
end
|
||||
|
||||
|
@ -131,7 +138,26 @@ S("The speed and damage of the arrow increases the longer you charge. The regula
|
|||
range = 4,
|
||||
-- Trick to disable digging as well
|
||||
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},
|
||||
_mcl_uses = 385,
|
||||
})
|
||||
|
||||
-- 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 list = inv:get_list("main")
|
||||
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:get_meta():set_string("active", "")
|
||||
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
|
||||
stack:set_name("mcl_bows:bow_enchanted")
|
||||
stack:get_meta():set_string("active", "")
|
||||
list[place] = stack
|
||||
end
|
||||
end
|
||||
|
@ -176,6 +206,7 @@ for level=0, 2 do
|
|||
on_use = function() return end,
|
||||
on_drop = function(itemstack, dropper, pos)
|
||||
reset_bow_state(dropper)
|
||||
itemstack:get_meta():set_string("active", "")
|
||||
if mcl_enchanting.is_enchanted(itemstack:get_name()) then
|
||||
itemstack:set_name("mcl_bows:bow_enchanted")
|
||||
else
|
||||
|
@ -189,6 +220,7 @@ for level=0, 2 do
|
|||
on_place = function(itemstack)
|
||||
return itemstack
|
||||
end,
|
||||
_mcl_uses = 385,
|
||||
})
|
||||
end
|
||||
|
||||
|
@ -268,7 +300,7 @@ controls.register_on_hold(function(player, key, time)
|
|||
end
|
||||
local inv = minetest.get_inventory({type="player", name=name})
|
||||
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())
|
||||
if enchanted then
|
||||
wielditem:set_name("mcl_bows:bow_0_enchanted")
|
||||
|
|
|
@ -82,7 +82,7 @@ local register_filled_cauldron = function(water_level, description, river_water)
|
|||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
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],
|
||||
collision_box = cauldron_nodeboxes[0],
|
||||
selection_box = { type = "regular" },
|
||||
|
@ -122,3 +122,20 @@ minetest.register_craft({
|
|||
{ "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 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
|
||||
if minetest.get_modpath("screwdriver") then
|
||||
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
|
||||
|
||||
--[[ List of open chests.
|
||||
|
@ -13,9 +165,23 @@ Value:
|
|||
If player is using a chest: { pos = <chest node position> }
|
||||
Otherwise: nil ]]
|
||||
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
|
||||
local player_chest_open = function(player, pos)
|
||||
open_chests[player:get_player_name()] = { pos = pos }
|
||||
local player_chest_open = function(player, pos, node_name, textures, param2, double, sound, mesh, shulker)
|
||||
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
|
||||
|
||||
-- Simple protection checking functions
|
||||
|
@ -44,11 +210,13 @@ local trapped_chest_mesecons_rules = mesecon.rules.pplate
|
|||
local chest_update_after_close = function(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
|
||||
if node.name == "mcl_chests:trapped_chest_on" then
|
||||
minetest.swap_node(pos, {name="mcl_chests:trapped_chest", param2 = node.param2})
|
||||
if node.name == "mcl_chests:trapped_chest_on_small" then
|
||||
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)
|
||||
elseif node.name == "mcl_chests:trapped_chest_on_left" then
|
||||
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)
|
||||
|
||||
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")
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
@ -67,11 +236,14 @@ end
|
|||
-- To be called if a player closed a chest
|
||||
local player_chest_close = function(player)
|
||||
local name = player:get_player_name()
|
||||
if open_chests[name] == nil then
|
||||
local open_chest = open_chests[name]
|
||||
if open_chest == nil then
|
||||
return
|
||||
end
|
||||
local pos = open_chests[name].pos
|
||||
chest_update_after_close(pos)
|
||||
if animate_chests then
|
||||
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
|
||||
end
|
||||
|
@ -146,18 +318,82 @@ local on_chest_blast = function(pos)
|
|||
minetest.remove_node(pos)
|
||||
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, {
|
||||
description = desc,
|
||||
_tt_help = tt_help,
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usagehelp,
|
||||
_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",
|
||||
paramtype2 = "facedir",
|
||||
stack_max = 64,
|
||||
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,
|
||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||
on_construct = function(pos)
|
||||
|
@ -185,16 +421,19 @@ minetest.register_node("mcl_chests:"..basename, {
|
|||
-- BEGIN OF LISTRING WORKAROUND
|
||||
inv:set_size("input", 1)
|
||||
-- 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})
|
||||
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right")
|
||||
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})
|
||||
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")
|
||||
minetest.swap_node(p, { name = "mcl_chests:"..canonical_basename.."_right", param2 = param2 })
|
||||
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,
|
||||
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||
|
@ -253,23 +492,31 @@ minetest.register_node("mcl_chests:"..basename, {
|
|||
if on_rightclick_addendum then
|
||||
on_rightclick_addendum(pos, node, clicker)
|
||||
end
|
||||
|
||||
player_chest_open(clicker, pos, small_name, small_textures, node.param2, false, "default_chest", "mcl_chests_chest")
|
||||
end,
|
||||
|
||||
on_destruct = function(pos)
|
||||
local players = minetest.get_connected_players()
|
||||
for p=1, #players do
|
||||
minetest.close_formspec(players[p]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z)
|
||||
end
|
||||
close_forms(canonical_basename, pos)
|
||||
end,
|
||||
mesecons = mesecons,
|
||||
on_rotate = simple_rotate,
|
||||
})
|
||||
|
||||
minetest.register_node("mcl_chests:"..basename.."_left", {
|
||||
tiles = tiles_table.left,
|
||||
minetest.register_node(left_name, {
|
||||
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",
|
||||
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,
|
||||
is_ground_content = false,
|
||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||
|
@ -278,33 +525,31 @@ minetest.register_node("mcl_chests:"..basename.."_left", {
|
|||
local param2 = n.param2
|
||||
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
|
||||
n.name = "mcl_chests:"..canonical_basename
|
||||
n.name = "mcl_chests:"..canonical_basename.."_small"
|
||||
minetest.swap_node(pos, n)
|
||||
end
|
||||
create_entity(pos, left_name, left_textures, param2, true, "default_chest", "mcl_chests_chest", "chest")
|
||||
end,
|
||||
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||
minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name"))
|
||||
end,
|
||||
on_destruct = function(pos)
|
||||
local n = minetest.get_node(pos)
|
||||
if n.name == "mcl_chests:"..basename then
|
||||
if n.name == small_name then
|
||||
return
|
||||
end
|
||||
|
||||
local players = minetest.get_connected_players()
|
||||
for p=1, #players do
|
||||
minetest.close_formspec(players[p]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z)
|
||||
end
|
||||
close_forms(canonical_basename, pos)
|
||||
|
||||
local param2 = n.param2
|
||||
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
|
||||
return
|
||||
end
|
||||
for pl=1, #players do
|
||||
minetest.close_formspec(players[pl]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..p.x.."_"..p.y.."_"..p.z)
|
||||
end
|
||||
minetest.swap_node(p, { name = "mcl_chests:"..basename, param2 = param2 })
|
||||
close_forms(canonical_basename, p)
|
||||
|
||||
minetest.swap_node(p, { name = small_name, param2 = param2 })
|
||||
create_entity(p, small_name, small_textures, param2, false, "default_chest", "mcl_chests_chest", "chest")
|
||||
end,
|
||||
after_dig_node = drop_items_chest,
|
||||
on_blast = on_chest_blast,
|
||||
|
@ -318,17 +563,19 @@ minetest.register_node("mcl_chests:"..basename.."_left", {
|
|||
-- BEGIN OF LISTRING WORKAROUND
|
||||
elseif listname == "input" then
|
||||
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
|
||||
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
|
||||
return -1
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
end]]--
|
||||
-- END OF LISTRING WORKAROUND
|
||||
else
|
||||
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_inv = minetest.get_inventory({type="node", pos=other_pos})
|
||||
|
||||
inv:set_stack("input", 1, nil)
|
||||
|
||||
double_chest_add_item(inv, other_inv, "main", stack)
|
||||
end
|
||||
-- END OF LISTRING WORKAROUND
|
||||
|
@ -399,16 +648,23 @@ minetest.register_node("mcl_chests:"..basename.."_left", {
|
|||
if on_rightclick_addendum_left then
|
||||
on_rightclick_addendum_left(pos, node, clicker)
|
||||
end
|
||||
|
||||
player_chest_open(clicker, pos, left_name, left_textures, node.param2, true, "default_chest", "mcl_chests_chest")
|
||||
end,
|
||||
mesecons = mesecons,
|
||||
on_rotate = no_rotate,
|
||||
})
|
||||
|
||||
minetest.register_node("mcl_chests:"..basename.."_right", {
|
||||
tiles = tiles_table.right,
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
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,
|
||||
is_ground_content = false,
|
||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||
|
@ -417,7 +673,7 @@ minetest.register_node("mcl_chests:"..basename.."_right", {
|
|||
local param2 = n.param2
|
||||
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
|
||||
n.name = "mcl_chests:"..canonical_basename
|
||||
n.name = "mcl_chests:"..canonical_basename.."_small"
|
||||
minetest.swap_node(pos, n)
|
||||
end
|
||||
end,
|
||||
|
@ -426,24 +682,21 @@ minetest.register_node("mcl_chests:"..basename.."_right", {
|
|||
end,
|
||||
on_destruct = function(pos)
|
||||
local n = minetest.get_node(pos)
|
||||
if n.name == "mcl_chests:"..basename then
|
||||
if n.name == small_name then
|
||||
return
|
||||
end
|
||||
|
||||
local players = minetest.get_connected_players()
|
||||
for p=1, #players do
|
||||
minetest.close_formspec(players[p]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z)
|
||||
end
|
||||
close_forms(canonical_basename, pos)
|
||||
|
||||
local param2 = n.param2
|
||||
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
|
||||
return
|
||||
end
|
||||
for pl=1, #players do
|
||||
minetest.close_formspec(players[pl]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..p.x.."_"..p.y.."_"..p.z)
|
||||
end
|
||||
minetest.swap_node(p, { name = "mcl_chests:"..basename, param2 = param2 })
|
||||
close_forms(canonical_basename, p)
|
||||
|
||||
minetest.swap_node(p, { name = small_name, param2 = param2 })
|
||||
create_entity(p, small_name, small_textures, param2, false, "default_chest", "mcl_chests_chest", "chest")
|
||||
local meta = minetest.get_meta(pos)
|
||||
end,
|
||||
after_dig_node = drop_items_chest,
|
||||
|
@ -459,16 +712,17 @@ minetest.register_node("mcl_chests:"..basename.."_right", {
|
|||
elseif listname == "input" then
|
||||
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})
|
||||
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
|
||||
else
|
||||
local inv = minetest.get_inventory({type="node", pos=pos})
|
||||
if inv:room_for_item("main", stack) then
|
||||
return -1
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
end--]]
|
||||
return limit_put(stack, other_inv, inv)
|
||||
-- END OF LISTRING WORKAROUND
|
||||
else
|
||||
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 inv = minetest.get_inventory({type="node", pos=pos})
|
||||
|
||||
inv:set_stack("input", 1, nil)
|
||||
|
||||
double_chest_add_item(other_inv, inv, "main", stack)
|
||||
end
|
||||
-- END OF LISTRING WORKAROUND
|
||||
|
@ -540,14 +796,16 @@ minetest.register_node("mcl_chests:"..basename.."_right", {
|
|||
if on_rightclick_addendum_right then
|
||||
on_rightclick_addendum_right(pos, node, clicker)
|
||||
end
|
||||
|
||||
player_chest_open(clicker, pos_other, left_name, left_textures, node.param2, true, "default_chest", "mcl_chests_chest")
|
||||
end,
|
||||
mesecons = mesecons,
|
||||
on_rotate = no_rotate,
|
||||
})
|
||||
|
||||
if mod_doc then
|
||||
doc.add_entry_alias("nodes", "mcl_chests:"..basename, "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.."_left")
|
||||
doc.add_entry_alias("nodes", small_name, "nodes", "mcl_chests:"..basename.."_right")
|
||||
end
|
||||
|
||||
-- END OF register_chest FUNCTION BODY
|
||||
|
@ -561,29 +819,33 @@ register_chest("chest",
|
|||
chestusage,
|
||||
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_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",
|
||||
"default_chest_side_big.png^[transformFX", "default_chest_front_big.png"},
|
||||
right = {"default_chest_top_big.png^[transformFX", "default_chest_top_big.png^[transformFX",
|
||||
"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
|
||||
)
|
||||
|
||||
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_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_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",
|
||||
"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",
|
||||
|
@ -598,22 +860,21 @@ register_chest("trapped_chest",
|
|||
rules = trapped_chest_mesecons_rules,
|
||||
}},
|
||||
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)
|
||||
player_chest_open(clicker, pos)
|
||||
end,
|
||||
function(pos, node, clicker)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_int("players", 1)
|
||||
|
||||
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)
|
||||
|
||||
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})
|
||||
mesecon.receptor_on(pos_other, trapped_chest_mesecons_rules)
|
||||
|
||||
player_chest_open(clicker, pos)
|
||||
end,
|
||||
function(pos, node, clicker)
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
player_chest_open(clicker, pos)
|
||||
end
|
||||
)
|
||||
|
||||
|
@ -634,15 +894,7 @@ register_chest("trapped_chest_on",
|
|||
state = mesecon.state.on,
|
||||
rules = trapped_chest_mesecons_rules,
|
||||
}},
|
||||
function(pos, node, clicker)
|
||||
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,
|
||||
nil, nil, nil,
|
||||
"trapped_chest",
|
||||
"trapped_chest"
|
||||
)
|
||||
|
@ -650,13 +902,15 @@ register_chest("trapped_chest_on",
|
|||
local function close_if_trapped_chest(pos, player)
|
||||
local node = minetest.get_node(pos)
|
||||
|
||||
if node.name == "mcl_chests:trapped_chest_on" then
|
||||
minetest.swap_node(pos, {name="mcl_chests:trapped_chest", param2 = node.param2})
|
||||
if node.name == "mcl_chests:trapped_chest_on_small" then
|
||||
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)
|
||||
|
||||
player_chest_close(player)
|
||||
elseif node.name == "mcl_chests:trapped_chest_on_left" then
|
||||
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)
|
||||
|
||||
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")
|
||||
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)
|
||||
|
||||
player_chest_close(player)
|
||||
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)
|
||||
if formname:find("mcl_chests:trapped_chest_") == 1 then
|
||||
if formname:find("mcl_chests:") == 1 then
|
||||
if fields.quit then
|
||||
player_chest_close(player)
|
||||
end
|
||||
|
@ -710,6 +965,26 @@ minetest.register_craft({
|
|||
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]"..
|
||||
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Ender Chest"))).."]"..
|
||||
"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]"
|
||||
|
||||
|
||||
minetest.register_node("mcl_chests:ender_chest", {
|
||||
minetest.register_node("mcl_chests:ender_chest_small", {
|
||||
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."),
|
||||
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_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
|
||||
-- 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,
|
||||
paramtype = "light",
|
||||
light_source = 7,
|
||||
|
@ -743,23 +1028,22 @@ minetest.register_node("mcl_chests:ender_chest", {
|
|||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
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,
|
||||
_mcl_blast_resistance = 3000,
|
||||
_mcl_hardness = 22.5,
|
||||
_mcl_silk_touch_drop = true,
|
||||
_mcl_silk_touch_drop = {"mcl_chests:ender_chest"},
|
||||
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)
|
||||
local inv = player:get_inventory()
|
||||
inv:set_size("enderchest", 9*3)
|
||||
|
@ -852,6 +1136,8 @@ for color, desc in pairs(boxtypes) do
|
|||
end
|
||||
end
|
||||
|
||||
local small_name = "mcl_chests:"..color.."_shulker_box_small"
|
||||
|
||||
minetest.register_node("mcl_chests:"..color.."_shulker_box", {
|
||||
description = desc,
|
||||
_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_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usagehelp,
|
||||
tiles = {
|
||||
"mcl_chests_"..color.."_shulker_box_top.png", -- top
|
||||
tiles = {mob_texture},
|
||||
drawtype = "mesh",
|
||||
mesh = "mcl_chests_shulker.obj",
|
||||
--[["mcl_chests_"..color.."_shulker_box_top.png", -- top
|
||||
"[combine:16x16:-32,-28="..mob_texture, -- bottom
|
||||
"[combine:16x16:0,-36="..mob_texture..":0,-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:-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},
|
||||
"[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},
|
||||
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)
|
||||
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
|
||||
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)
|
||||
local nmeta = minetest.get_meta(pos)
|
||||
|
@ -916,6 +1185,79 @@ for color, desc in pairs(boxtypes) do
|
|||
return nil
|
||||
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)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
|
@ -961,6 +1303,7 @@ for color, desc in pairs(boxtypes) do
|
|||
|
||||
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_small", "nodes", "mcl_chests:"..color.."_shulker_box_small")
|
||||
end
|
||||
|
||||
minetest.register_craft({
|
||||
|
@ -1001,6 +1344,40 @@ minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv
|
|||
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({
|
||||
-- Disable active/open trapped chests when loaded because nobody could
|
||||
|
@ -1008,7 +1385,7 @@ minetest.register_lbm({
|
|||
-- Fixes redstone weirdness.
|
||||
label = "Disable active 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,
|
||||
action = function(pos, node)
|
||||
minetest.log("action", "[mcl_chests] Disabled active trapped chest on load: " ..minetest.pos_to_string(pos))
|
||||
|
@ -1016,17 +1393,6 @@ minetest.register_lbm({
|
|||
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({
|
||||
label = "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_entry_name = ename_cp,
|
||||
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,
|
||||
is_ground_content = false,
|
||||
sounds = mcl_sounds.node_sound_sand_defaults(),
|
||||
|
@ -208,11 +208,20 @@ minetest.register_abm({
|
|||
neighbors = {"group:water"},
|
||||
action = function(pos, node)
|
||||
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
|
||||
-- the ABM on the new concrete node, which isn't part of this ABM!
|
||||
if harden_to then
|
||||
node.name = harden_to
|
||||
minetest.set_node(pos, node)
|
||||
end
|
||||
-- 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!
|
||||
if harden_to then
|
||||
node.name = harden_to
|
||||
--Fix "float" group not lowering concrete into the water by 1.
|
||||
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,
|
||||
})
|
||||
|
|
|
@ -2,4 +2,3 @@ mcl_core
|
|||
mcl_worlds
|
||||
mesecons
|
||||
doc?
|
||||
mcl_enchanting
|
||||
|
|
|
@ -57,9 +57,6 @@ minetest.register_globalstep(function(dtime)
|
|||
if minetest.get_item_group(stack:get_name(), "compass") ~= 0 and
|
||||
minetest.get_item_group(stack:get_name(), "compass")-1 ~= compass_image then
|
||||
local itemname = "mcl_compass:"..compass_image
|
||||
if mcl_enchanting.is_enchanted(stack:get_name()) then
|
||||
itemname = itemname .. "_enchanted"
|
||||
end
|
||||
stack:set_name(itemname)
|
||||
player:get_inventory():set_stack("main", j, stack)
|
||||
end
|
||||
|
@ -98,7 +95,7 @@ for i,img in ipairs(images) do
|
|||
inventory_image = img,
|
||||
wield_image = img,
|
||||
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
|
||||
|
|