Compare commits

..

4 Commits

Author SHA1 Message Date
epCode b90ff44f73 fix enderman walk velocity 2022-10-16 17:48:29 -07:00
epCode 3557f02b8f decrease damage animspeed 2022-10-16 17:41:45 -07:00
epCode c3425a69b1 allow player animations hit by mobs 2022-10-16 17:23:28 -07:00
epCode b7eda10054 add better pvp knockback 2022-10-16 17:16:38 -07:00
1029 changed files with 9517 additions and 28208 deletions

View File

@ -1,12 +0,0 @@
root = true
[*]
end_of_line = lf
[*.lua]
charset = utf8
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true
keep_one_space_between_table_and_bracket = false
spaces_around_operators = true

View File

@ -1,36 +0,0 @@
---
name: "Bug report"
about: "File a bug report"
labels:
- unconfirmed
- bug
---
<!--
Thanks for taking the time to fill out this bug report!
Please follow our contributing guidelines first:
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CONTRIBUTING.md#rules-about-both-bugs-and-feature-requests
By submitting this issue, you agree to follow our Code of Conduct:
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CODE_OF_CONDUCT.md
-->
<!--
What version of MineClone2 are you using? We do not provide support for outdated versions of MineClone2.
Current latest version is listed here, at the top:
https://git.minetest.land/MineClone2/MineClone2/tags
-->
MineClone2 version:
### What happened?
Report about the bug! Please send large log snippets as an attachement file.
### What should happen:
Tell us what should happen!
### Steps to reproduce
Tell us how we can reproduce the bug!

View File

@ -1,26 +0,0 @@
---
name: "Feature request"
about: "File a feature request not in Minecraft"
labels:
- "non-Minecraft feature"
- "needs discussion"
---
<!--
Got a new non-Minecraft feature request? Explain to us why we should consider your idea.
Please follow our contributing guidelines first:
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CONTRIBUTING.md#rules-about-both-bugs-and-feature-requests
By submitting this issue, you agree to follow our Code of Conduct:
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CODE_OF_CONDUCT.md
-->
### Feature
Tell us about your requested feature not in Minecraft!
### Why
Tell us why should we implement it!

View File

@ -1,25 +0,0 @@
---
name: "Missing Feature request"
about: "File a missing feature request in Minecraft but not in MineClone2"
labels:
- "missing feature"
---
<!--
Thanks for taking the time to fill out this missing feature request!
Please follow our contributing guidelines first:
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CONTRIBUTING.md#rules-about-both-bugs-and-feature-requests
By submitting this issue, you agree to follow our Code of Conduct:
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CODE_OF_CONDUCT.md
-->
### Current feature in Minecraft
Tell us about the feature currently in Minecraft! What is it like on Minecraft?
### Current feature in MineClone2
Tell us about the feature currently in MineClone2! What is different?

View File

@ -1,20 +0,0 @@
---
name: "Pull request"
about: "Submit a pull request"
labels:
---
<!--
Please follow our contributing guidelines first:
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CONTRIBUTING.md#how-you-can-help-as-a-programmer
By submitting this pull request, you agree to follow our Code of Conduct:
https://git.minetest.land/MineClone2/MineClone2/src/branch/master/CODE_OF_CONDUCT.md
-->
Tell us about your pull request! Reference related issues, if necessary
### Testing
Tell us how to test your changes!

2
.gitignore vendored
View File

@ -3,5 +3,3 @@
*.blend1 *.blend1
*.blend2 *.blend2
*.blend3 *.blend3
/.idea/
*.xcf

View File

@ -60,7 +60,7 @@ representative at an online or offline event.
Instances of abusive, harassing, or otherwise unacceptable behavior may be Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at reported to the community leaders responsible for enforcement at
ancientmariner_dev@proton.me. eliasfleckenstein@web.de.
All complaints will be reviewed and investigated promptly and fairly. All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the All community leaders are obligated to respect the privacy and security of the

View File

@ -8,13 +8,12 @@
## Maintainers ## Maintainers
* AncientMariner
* Nicu * Nicu
* cora
## Previous Maintainers ## Previous Maintainers
* Fleckenstein * Fleckenstein
* jordan4ibanez * jordan4ibanez
* cora
## Developers ## Developers
* bzoss * bzoss
@ -34,9 +33,6 @@
* RandomLegoBrick * RandomLegoBrick
* SumianVoice * SumianVoice
* MrRar * MrRar
* talamh
* Faerraven / Michieal
* FossFanatic
## Contributors ## Contributors
* Laurent Rocher * Laurent Rocher
@ -70,6 +66,7 @@
* Benjamin Schötz * Benjamin Schötz
* Doloment * Doloment
* Sydney Gems * Sydney Gems
* talamh
* Emily2255 * Emily2255
* Emojigit * Emojigit
* FinishedFragment * FinishedFragment
@ -88,17 +85,6 @@
* opfromthestart * opfromthestart
* snowyu * snowyu
* FaceDeer * FaceDeer
* Faerraven / Michieal
* FossFanatic
* Herbert West
* GuyLiner
* 3raven
* anarquimico
* TheOnlyJoeEnderman
* Ranko Saotome
* Gregor Parzefall
* Wbjitscool
* b3nderman
## MineClone5 ## MineClone5
* kay27 * kay27
@ -109,7 +95,7 @@
* chmodsayshello * chmodsayshello
* 3raven * 3raven
* PrairieWind * PrairieWind
* Gustavo6046 / wallabra * Gustavo1
* CableGuy67 * CableGuy67
* MrRar * MrRar
@ -150,13 +136,11 @@
* jordan4ibanez * jordan4ibanez
* paramat * paramat
* cora * cora
* Faerraven / Michieal
## 3D Models ## 3D Models
* 22i * 22i
* tobyplowy * tobyplowy
* epCode * epCode
* Faerraven / Michieal
## Textures ## Textures
* XSSheep * XSSheep
@ -170,8 +154,6 @@
* MysticTempest * MysticTempest
* RandomLegoBrick * RandomLegoBrick
* cora * cora
* Faerraven / Michieal
* Nicu
## Translations ## Translations
* Wuzzy * Wuzzy
@ -185,12 +167,9 @@
* Emojigit * Emojigit
* snowyu * snowyu
* 3raven * 3raven
* SakuraRiu
## Funders ## Funders
* 40W * 40W
* bauknecht
* Cora
## Special thanks ## Special thanks
* celeron55 for creating Minetest * celeron55 for creating Minetest
@ -198,4 +177,3 @@
* wsor for working tirelessly in the shadows for the good of all of us, particularly helping with solving contentDB and copyright issues. * wsor for working tirelessly in the shadows for the good of all of us, particularly helping with solving contentDB and copyright issues.
* The workaholics who spent way too much time writing for the Minecraft Wiki. It's an invaluable resource for creating this game * The workaholics who spent way too much time writing for the Minecraft Wiki. It's an invaluable resource for creating this game
* Notch and Jeb for being the major forces behind Minecraft * Notch and Jeb for being the major forces behind Minecraft
* Dark Reaven Music (https://soundcloud.com/dark-reaven-music) for the main menu theme (Calmed Cube), which is licensed under https://creativecommons.org/licenses/by-sa/3.0/

View File

@ -74,8 +74,6 @@ Please read <http://minecraft.gamepedia.com/Breaking> to learn how digging times
* `coral_species=X`: Specifies the species of a coral; equal X means equal species * `coral_species=X`: Specifies the species of a coral; equal X means equal species
* `set_on_fire=X`: Sets any (not fire-resistant) mob or player on fire for X seconds when touching * `set_on_fire=X`: Sets any (not fire-resistant) mob or player on fire for X seconds when touching
* `compostability=X`: Item can be used on a composter block; X (1-100) is the % chance of adding a level of compost * `compostability=X`: Item can be used on a composter block; X (1-100) is the % chance of adding a level of compost
* `leaves=X`: Node will spotaneously decay if no tree trunk nodes remain within 6 blocks distance.
* `leaves_orphan`: See above, these nodes are in the process of decayed.
#### Footnotes #### Footnotes

View File

@ -1,21 +0,0 @@
Survive, farm, build, explore, play with friends, and do much more. Inspired by a well known block game, pushing beyond.
How to play:
#### Download Minetest
- Navigate to https://www.minetest.net/ to download the client.
- Once installed, open and select the "Content" tab
#### Install MineClone2 from ContentDB
- Click "Browse Online Content" and filter by Games (select "Games" from the dropdown box)
- Find "MineClone2" (should be first on the list or on the first page)
- Click the [+] button next to MineClone2 and wait for download to finish
- Click "Back to Main Menu"
#### Create new world and play
- Click "Start Game" tab
- At the bottom click the MineClone2 icon (the 2 dirt with grass blocks)
- Click "New", give your world a name
- You can leave seed blank or put in a word of your choice
- Select your new world
- Click "Play Game" and enjoy!

View File

@ -2,6 +2,8 @@
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils. An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
Developed by many people. Not developed or endorsed by Mojang AB. Developed by many people. Not developed or endorsed by Mojang AB.
Version: 0.80 (in development)
### Gameplay ### Gameplay
You start in a randomly-generated world made entirely of cubes. You can explore You start in a randomly-generated world made entirely of cubes. You can explore
the world and dig and build almost every block in the world to create new the world and dig and build almost every block in the world to create new
@ -156,7 +158,7 @@ The following features are incomplete:
* Some monsters and animals * Some monsters and animals
* Redstone-related things * Redstone-related things
* Some special minecarts (hopper and chest minecarts work) * Special minecarts
* A couple of non-trivial blocks and items * A couple of non-trivial blocks and items
Bonus features (not found in Minecraft): Bonus features (not found in Minecraft):

View File

@ -1,22 +0,0 @@
#File to document release steps with a view to evolving into a script
#Update CREDITS.md
#Update version in game.conf
lua tools/generate_ingame_credits.lua
git add CREDITS.md
git add mods/HUD/mcl_credits/people.lua
git add game.conf
#git add RELEASE.md
git commit -m "Pre-release update credits and set version 0.82.0"
git tag 0.82.0
git push origin 0.82.0
#Update version in game.conf to -SNAPSHOT
git commit -m "Post-release set version 0.82.0-SNAPSHOT"

View File

@ -1,4 +1,2 @@
title = MineClone 2 title = MineClone 2
description = A survival sandbox game. Survive, gather, hunt, build, explore, and do much more. description = A survival sandbox game. Survive, gather, hunt, build, explore, and do much more.
disallowed_mapgens = v6
version=0.82.0-SNAPSHOT

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 990 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 865 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 916 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 606 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 76 KiB

BIN
menu/overlay.1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
menu/overlay.2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

BIN
menu/overlay.3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

BIN
menu/overlay.4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

BIN
menu/overlay.5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

BIN
menu/overlay.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

View File

@ -204,7 +204,7 @@ end
-- Checks if the given node would drop its useful drop if dug by a given tool. -- Checks if the given node would drop its useful drop if dug by a given tool.
-- Returns true if it will yield its useful drop, false otherwise. -- Returns true if it will yield its useful drop, false otherwise.
function mcl_autogroup.can_harvest(nodename, toolname, player) function mcl_autogroup.can_harvest(nodename, toolname)
local ndef = minetest.registered_nodes[nodename] local ndef = minetest.registered_nodes[nodename]
if not ndef then if not ndef then
@ -228,9 +228,7 @@ function mcl_autogroup.can_harvest(nodename, toolname, player)
end end
-- Check if it can be dug by hand -- Check if it can be dug by hand
if not player or not player:is_player() then return false end local tdef = minetest.registered_tools[""]
local name = player:get_inventory():get_stack("hand", 1):get_name()
local tdef = minetest.registered_items[name]
if tdef then if tdef then
for g, gdef in pairs(tdef._mcl_diggroups) do for g, gdef in pairs(tdef._mcl_diggroups) do
if ndef.groups[g] then if ndef.groups[g] then
@ -262,7 +260,7 @@ local function get_tool_capabilities(tdef)
-- If the damage group and punch interval from hand is not included, -- If the damage group and punch interval from hand is not included,
-- then the user will not be able to attack with the tool. -- then the user will not be able to attack with the tool.
local hand_toolcaps = mcl_meshhand.survival_hand_tool_caps local hand_toolcaps = minetest.registered_tools[""].tool_capabilities
return { return {
full_punch_interval = hand_toolcaps.full_punch_interval, full_punch_interval = hand_toolcaps.full_punch_interval,
damage_groups = hand_toolcaps.damage_groups damage_groups = hand_toolcaps.damage_groups
@ -282,7 +280,7 @@ end
-- would have to add _mcl_autogroup as a dependency which would break the mod -- would have to add _mcl_autogroup as a dependency which would break the mod
-- loading order. -- loading order.
function mcl_autogroup.get_groupcaps(toolname, efficiency) function mcl_autogroup.get_groupcaps(toolname, efficiency)
local tdef = minetest.registered_items[toolname] local tdef = minetest.registered_tools[toolname]
local groupcaps = table.copy(get_tool_capabilities(tdef).groupcaps or {}) local groupcaps = table.copy(get_tool_capabilities(tdef).groupcaps or {})
add_groupcaps(toolname, groupcaps, tdef._mcl_diggroups, efficiency) add_groupcaps(toolname, groupcaps, tdef._mcl_diggroups, efficiency)
return groupcaps return groupcaps
@ -352,7 +350,7 @@ local function overwrite()
end end
end end
for tname, tdef in pairs(minetest.registered_items) do for tname, tdef in pairs(minetest.registered_tools) do
-- Assign groupcaps for digging the registered digging groups -- Assign groupcaps for digging the registered digging groups
-- depending on the _mcl_diggroups in the tool definition -- depending on the _mcl_diggroups in the tool definition
if tdef._mcl_diggroups then if tdef._mcl_diggroups then
@ -362,12 +360,6 @@ local function overwrite()
minetest.override_item(tname, { minetest.override_item(tname, {
tool_capabilities = toolcaps tool_capabilities = toolcaps
}) })
else
-- This is needed to deal damage when punching mobs
-- with random items in hand in survival mode
minetest.override_item(tname, {
tool_capabilities = mcl_meshhand.survival_hand_tool_caps
})
end end
end end
end end

View File

@ -5,8 +5,6 @@
-- Nodes in group "supported_node" can be placed on any node that does not -- Nodes in group "supported_node" can be placed on any node that does not
-- have the "airlike" drawtype. Carpets are an example of this type. -- have the "airlike" drawtype. Carpets are an example of this type.
local pairs = pairs
local math = math
local vector = vector local vector = vector
local facedir_to_dir = minetest.facedir_to_dir local facedir_to_dir = minetest.facedir_to_dir
@ -24,17 +22,15 @@ local add_item = minetest.add_item
-- We need this to do the exact same dropping node handling in our override -- We need this to do the exact same dropping node handling in our override
-- minetest.check_single_for_falling() function as in the builtin function. -- minetest.check_single_for_falling() function as in the builtin function.
-- --
---@param p Vector
local function drop_attached_node(p) local function drop_attached_node(p)
local n = get_node(p) local n = get_node(p)
local drops = get_node_drops(n, "") local drops = get_node_drops(n, "")
local def = registered_nodes[n.name] local def = registered_nodes[n.name]
if def and def.preserve_metadata then if def and def.preserve_metadata then
local oldmeta = get_meta(p):to_table().fields local oldmeta = get_meta(p):to_table().fields
-- Copy pos and node because the callback can modify them. -- Copy pos and node because the callback can modify them.
local pos_copy = vector.copy(p) local pos_copy = vector.new(p)
local node_copy = { name = n.name, param1 = n.param1, param2 = n.param2 } local node_copy = {name=n.name, param1=n.param1, param2=n.param2}
local drop_stacks = {} local drop_stacks = {}
for k, v in pairs(drops) do for k, v in pairs(drops) do
drop_stacks[k] = ItemStack(v) drop_stacks[k] = ItemStack(v)
@ -42,18 +38,16 @@ local function drop_attached_node(p)
drops = drop_stacks drops = drop_stacks
def.preserve_metadata(pos_copy, node_copy, oldmeta, drops) def.preserve_metadata(pos_copy, node_copy, oldmeta, drops)
end end
if def and def.sounds and def.sounds.fall then if def and def.sounds and def.sounds.fall then
minetest.sound_play(def.sounds.fall, { pos = p }, true) core.sound_play(def.sounds.fall, {pos = p}, true)
end end
remove_node(p) remove_node(p)
for _, item in pairs(drops) do for _, item in pairs(drops) do
local pos = vector.offset(p, local pos = {
math.random() / 2 - 0.25, x = p.x + math.random()/2 - 0.25,
math.random() / 2 - 0.25, y = p.y + math.random()/2 - 0.25,
math.random() / 2 - 0.25 z = p.z + math.random()/2 - 0.25,
) }
add_item(pos, item) add_item(pos, item)
end end
end end
@ -96,3 +90,4 @@ function minetest.check_single_for_falling(pos)
return false return false
end end

View File

@ -1,11 +1,10 @@
# mcl_autogroup # mcl_autogroup
This mod emulate digging times from mc. This mod emulate digging times from mc.
## mcl_autogroup.can_harvest(nodename, toolname, player) ## mcl_autogroup.can_harvest(nodename, toolname)
Return true if <nodename> can be dig with <toolname> by <player>. Return true if <nodename> can be dig with <toolname>.
* nodename: string, valid nodename * nodename: string, valid nodename
* toolname: (optional) string, valid toolname * toolname: (optional) string, valid toolname
* player: (optinal) ObjectRef, valid player
## mcl_autogroup.get_groupcaps(toolname, efficiency) ## mcl_autogroup.get_groupcaps(toolname, efficiency)
This function is used to calculate diggroups for tools. This function is used to calculate diggroups for tools.

View File

@ -12,7 +12,6 @@ mcl_damage = {
drown = {bypasses_armor = true}, drown = {bypasses_armor = true},
starve = {bypasses_armor = true, bypasses_magic = true}, starve = {bypasses_armor = true, bypasses_magic = true},
cactus = {}, cactus = {},
sweet_berry = {},
fall = {bypasses_armor = true}, fall = {bypasses_armor = true},
fly_into_wall = {bypasses_armor = true}, -- unused fly_into_wall = {bypasses_armor = true}, -- unused
out_of_world = {bypasses_armor = true, bypasses_magic = true, bypasses_invulnerability = true, bypasses_totem = true}, out_of_world = {bypasses_armor = true, bypasses_magic = true, bypasses_invulnerability = true, bypasses_totem = true},
@ -155,6 +154,7 @@ end, true)
minetest.register_on_player_hpchange(function(player, hp_change, mt_reason) minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
if not damage_enabled then return 0 end if not damage_enabled then return 0 end
if player:get_hp() > 0 then if player:get_hp() > 0 then
mt_reason.approved = true
if hp_change < 0 then if hp_change < 0 then
mcl_damage.run_damage_callbacks(player, -hp_change, mcl_damage.from_mt(mt_reason)) mcl_damage.run_damage_callbacks(player, -hp_change, mcl_damage.from_mt(mt_reason))
end end
@ -162,7 +162,9 @@ minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
end, false) end, false)
minetest.register_on_dieplayer(function(player, mt_reason) minetest.register_on_dieplayer(function(player, mt_reason)
mcl_damage.run_death_callbacks(player, mcl_damage.from_mt(mt_reason)) if mt_reason.approved then
mcl_damage.run_death_callbacks(player, mcl_damage.from_mt(mt_reason))
end
minetest.log("action","Player "..player:get_player_name().." died at "..minetest.pos_to_string(vector.round(player:get_pos()))) minetest.log("action","Player "..player:get_player_name().." died at "..minetest.pos_to_string(vector.round(player:get_pos())))
end) end)

View File

@ -1,27 +0,0 @@
## mcl_events
### Registering Events
`mlc_events.register_event("name",def)`
#### Event Definition
{
stage = 0,
max_stage = 1,
percent = 100,
bars = {},
completed = false,
cond_start = function() end,
--return table of paramtables e.g. { { player = playername, pos = position, ... } }, custom parameters will be passed to the event object/table
on_step = function(event) end,
--this function is run every game step when the event is active
on_start = function(event) end,
-- this function is run when the event starts
on_stage_begin = function(event) end,
-- this function runs when a new stage of the event starts
cond_progress = function(event) end, --return false or next stage id
--this function checks if the event should progress to the next (or any other) stage
cond_complete = function(event) end,
--return true if event finished successfully
}
### Debugging
* /event_start <event> -- starts the given event at the current player coordinates

View File

@ -1,155 +0,0 @@
mcl_events = {}
mcl_events.registered_events = {}
local disabled_events = minetest.settings:get("mcl_disabled_events")
if disabled_events then disabled_events = disabled_events:split(",")
else disabled_events = {} end
local DBG = minetest.settings:get_bool("mcl_logging_event_api",false)
local active_events = {}
local event_tpl = {
stage = 0,
max_stage = 1,
percent = 100,
bars = {},
completed = false,
cond_start = function(event) end, --return table of positions
on_step = function(event) end,
on_start = function(event) end,
on_stage_begin = function(event) end,
cond_progress = function(event) end, --return next stage
cond_complete = function(event) end, --return success
}
local function mcl_log(m,l)
if DBG then
if not l then l = "action" end
minetest.log(l,"[mcl_events] "..m)
end
end
function mcl_events.register_event(name,def)
if table.indexof(disabled_events,name) ~= -1 then return end
mcl_events.registered_events[name] = def
mcl_events.registered_events[name].name = name
end
local function addbars(self)
if not self.enable_bossbar then return end
for _,player in pairs(minetest.get_connected_players()) do
if vector.distance(self.pos,player:get_pos()) < 64 then
local bar = mcl_bossbars.add_bar(player, {color = "red", text = self.readable_name .. ": Wave "..self.stage.." / "..self.max_stage, percentage = self.percent }, true,1)
table.insert(self.bars,bar)
end
end
end
local function start_event(p,e)
mcl_log("[mcl_events] Event started: "..e.readable_name.." at "..minetest.pos_to_string(vector.round(p.pos)))
local idx = #active_events + 1
active_events[idx] = table.copy(e)
setmetatable(active_events[idx],{__index = event_tpl})
for k,v in pairs(p) do active_events[idx][k] = v end
active_events[idx].stage = 0
active_events[idx].percent = 100
active_events[idx].bars = {}
active_events[idx].time_start = os.time()
if active_events[idx].on_start then
active_events[idx]:on_start(p.pos)
end
addbars(active_events[idx])
end
local function finish_event(self,idx)
mcl_log("[mcl_events] Finished: "..self.readable_name.." at "..minetest.pos_to_string(vector.round(self.pos)))
if self.on_complete then self:on_complete() end
for _,b in pairs(self.bars) do
mcl_bossbars.remove_bar(b)
end
table.remove(active_events,idx)
end
local etime = 0
function check_events(dtime)
--process active events
for idx,ae in pairs(active_events) do
if ae.cond_complete and ae:cond_complete() then
ae.finished = true
finish_event(ae,idx)
elseif not ae.cond_complete and ae.max_stage and ae.max_stage <= ae.stage then
ae.finished = true
finish_event(ae,idx)
elseif not ae.finished and ae.cond_progress then
local p = ae:cond_progress()
if p == true then
ae.stage = ae.stage + 1
if ae:on_stage_begin() == true then
mcl_log("[mcl_events] Event "..ae.readable_name.." at "..minetest.pos_to_string(vector.round(ae.pos)).." failed at stage_begin of stage "..ae.stage )
active_events[idx] = nil
end
elseif tonumber(p) then
ae.stage = tonumber(p) or ae.stage + 1
ae:on_stage_begin()
end
elseif not ae.finished and ae.on_step then
ae:on_step(dtime)
end
addbars(ae)
end
-- check if a new event should be started
etime = etime - dtime
if etime > 0 then return end
etime = 10
for _,e in pairs(mcl_events.registered_events) do
local pp = e.cond_start()
if pp then
--minetest.log("It's gonna start the raid maybe")
for _,p in pairs(pp) do
local start = true
if e.exclusive_to_area then
for _,ae in pairs(active_events) do
if e.name == ae.name and vector.distance(p.pos,ae.pos) < e.exclusive_to_area then start = false end
end
end
if start then
--minetest.log("It's gonna start the raid definitely")
start_event(p,e)
elseif DBG then
mcl_log("[mcl_events] Event "..e.readable_name.." already active at "..minetest.pos_to_string(vector.round(p.pos)))
end
end
else
--minetest.log("Do not start this raid")
end
end
for idx,ae in pairs(active_events) do
local player_near = false
for _,pl in pairs(minetest.get_connected_players()) do
if ae.pos and vector.distance(pl:get_pos(),ae.pos) < 64 then player_near = true end
end
if ae.pos and not player_near then
mcl_log("[mcl_events] Event "..ae.readable_name.." at "..minetest.pos_to_string(vector.round(ae.pos)).." aborted - no players near." )
active_events[idx] = nil
end
end
end
minetest.register_globalstep(check_events)
mcl_info.register_debug_field("Active Events",{
level = 4,
func = function(pl,pos)
return tostring(#active_events)
end
})
minetest.register_chatcommand("event_start",{
privs = {debug = true},
description = "Debug command to start events",
func = function(pname,param)
local p = minetest.get_player_by_name(pname)
local evdef = mcl_events.registered_events[param]
if not evdef then return false,"Event "..param.." doesn't exist.'" end
start_event({pos=p:get_pos(),player=pname,factor=1},evdef)
return true,"Started event "..param
end,
})

View File

@ -1,3 +0,0 @@
name = mcl_events
author = cora
depends = mcl_mobs,mcl_bossbars, mcl_info

View File

@ -130,10 +130,10 @@ local function add_particles(pos, radius)
time = 0.125, time = 0.125,
minpos = pos, minpos = pos,
maxpos = pos, maxpos = pos,
minvel = vector.new(-radius, -radius, -radius), minvel = {x = -radius, y = -radius, z = -radius},
maxvel = vector.new(radius, radius, radius), maxvel = {x = radius, y = radius, z = radius},
minacc = vector.zero(), minacc = vector.new(),
maxacc = vector.zero(), maxacc = vector.new(),
minexptime = 0.5, minexptime = 0.5,
maxexptime = 1.0, maxexptime = 1.0,
minsize = radius * 0.5, minsize = radius * 0.5,
@ -207,7 +207,7 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
local npos_z = math.floor(rpos_z + 0.5) local npos_z = math.floor(rpos_z + 0.5)
local npos = { x = npos_x, y = npos_y, z = npos_z } local npos = { x = npos_x, y = npos_y, z = npos_z }
local idx = (npos_z - emin_z) * zstride + (npos_y - emin_y) * ystride + local idx = (npos_z - emin_z) * zstride + (npos_y - emin_y) * ystride +
npos_x - emin_x + 1 npos_x - emin_x + 1
local cid = data[idx] local cid = data[idx]
local br = node_blastres[cid] or INDESTRUCT_BLASTRES local br = node_blastres[cid] or INDESTRUCT_BLASTRES
@ -288,7 +288,7 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
rdir_y = rdir_y / rdir_len rdir_y = rdir_y / rdir_len
rdir_z = rdir_z / rdir_len rdir_z = rdir_z / rdir_len
for i = 0, rdir_len / STEP_LENGTH do for i=0, rdir_len / STEP_LENGTH do
rpos_x = rpos_x + rdir_x * STEP_LENGTH rpos_x = rpos_x + rdir_x * STEP_LENGTH
rpos_y = rpos_y + rdir_y * STEP_LENGTH rpos_y = rpos_y + rdir_y * STEP_LENGTH
rpos_z = rpos_z + rdir_z * STEP_LENGTH rpos_z = rpos_z + rdir_z * STEP_LENGTH
@ -296,7 +296,7 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
local npos_y = math.floor(rpos_y + 0.5) local npos_y = math.floor(rpos_y + 0.5)
local npos_z = math.floor(rpos_z + 0.5) local npos_z = math.floor(rpos_z + 0.5)
local idx = (npos_z - emin_z) * zstride + (npos_y - emin_y) * ystride + local idx = (npos_z - emin_z) * zstride + (npos_y - emin_y) * ystride +
npos_x - emin_x + 1 npos_x - emin_x + 1
local cid = data[idx] local cid = data[idx]
@ -333,17 +333,16 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
end end
if sleep_formspec_doesnt_close_mt53 then if sleep_formspec_doesnt_close_mt53 then
minetest.after(0.3, minetest.after(0.3, function() -- 0.2 is minimum delay for closing old formspec and open died formspec -- TODO: REMOVE THIS IN THE FUTURE
function() -- 0.2 is minimum delay for closing old formspec and open died formspec -- TODO: REMOVE THIS IN THE FUTURE if not obj:is_player() then
if not obj:is_player() then return
return end
end mcl_util.deal_damage(obj, damage, {type = "explosion", direct = direct, source = source})
mcl_util.deal_damage(obj, damage, { type = "explosion", direct = direct, source = source })
obj:add_velocity(vector.multiply(punch_dir, impact * 20)) obj:add_velocity(vector.multiply(punch_dir, impact * 20))
end) end)
else else
mcl_util.deal_damage(obj, damage, { type = "explosion", direct = direct, source = source }) mcl_util.deal_damage(obj, damage, {type = "explosion", direct = direct, source = source})
if obj:is_player() or ent.tnt_knockback then if obj:is_player() or ent.tnt_knockback then
obj:add_velocity(vector.multiply(punch_dir, impact * 20)) obj:add_velocity(vector.multiply(punch_dir, impact * 20))
@ -389,24 +388,23 @@ local function trace_explode(pos, strength, raydirs, radius, info, direct, sourc
-- We use bulk_set_node instead of LVM because we want to have on_destruct and -- We use bulk_set_node instead of LVM because we want to have on_destruct and
-- on_construct being called -- on_construct being called
if #airs > 0 then if #airs > 0 then
bulk_set_node(airs, { name = "air" }) bulk_set_node(airs, {name="air"})
end end
if #fires > 0 then if #fires > 0 then
bulk_set_node(fires, { name = "mcl_fire:fire" }) bulk_set_node(fires, {name="mcl_fire:fire"})
end end
-- Update falling nodes -- Update falling nodes
for a = 1, #airs do for a=1, #airs do
local p = airs[a] local p = airs[a]
check_for_falling(vector.offset(p, 0, 1, 0)) check_for_falling({x=p.x, y=p.y+1, z=p.z})
end end
for f = 1, #fires do for f=1, #fires do
local p = fires[f] local p = fires[f]
check_for_falling(vector.offset(p, 0, 1, 0)) check_for_falling({x=p.x, y=p.y+1, z=p.z})
end end
-- Log explosion -- Log explosion
minetest.log("action", "Explosion at " .. pos_to_string(pos) .. " with strength " .. strength .. " and radius " .. minetest.log("action", "Explosion at "..pos_to_string(pos).." with strength "..strength.." and radius "..radius)
radius)
end end
-- Create an explosion with strength at pos. -- Create an explosion with strength at pos.
@ -430,11 +428,6 @@ end
-- griefing - If true, the explosion will destroy nodes (default: true) -- griefing - If true, the explosion will destroy nodes (default: true)
-- grief_protected - If true, the explosion will also destroy nodes which have -- grief_protected - If true, the explosion will also destroy nodes which have
-- been protected (default: false) -- been protected (default: false)
---@param pos Vector
---@param strength number
---@param info {drop_chance: number, max_blast_resistance: number, sound: boolean, particles: boolean, fire: boolean, griefing: boolean, grief_protected: boolean}
---@param direct? ObjectRef
---@param source? ObjectRef
function mcl_explosions.explode(pos, strength, info, direct, source) function mcl_explosions.explode(pos, strength, info, direct, source)
if info == nil then if info == nil then
info = {} info = {}

View File

@ -1,2 +0,0 @@
# textdomain:mcl_explosions
@1 was caught in an explosion.=@1は爆発に巻き込まれた。

View File

@ -3,26 +3,26 @@ mcl_vars = {}
mcl_vars.redstone_tick = 0.1 mcl_vars.redstone_tick = 0.1
-- GUI / inventory menu settings --- GUI / inventory menu settings
mcl_vars.gui_slots = "listcolors[#9990;#FFF7;#FFF0;#000;#FFF]" mcl_vars.gui_slots = "listcolors[#9990;#FFF7;#FFF0;#000;#FFF]"
-- nonbg is added as formspec prepend in mcl_formspec_prepend -- nonbg is added as formspec prepend in mcl_formspec_prepend
mcl_vars.gui_nonbg = table.concat({ mcl_vars.gui_nonbg = mcl_vars.gui_slots ..
mcl_vars.gui_slots, "style_type[image_button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]"..
"style_type[image_button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]", "style_type[button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]"..
"style_type[button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2]", "style_type[field;textcolor=#323232]"..
"style_type[field;textcolor=#323232]", "style_type[label;textcolor=#323232]"..
"style_type[label;textcolor=#323232]", "style_type[textarea;textcolor=#323232]"..
"style_type[textarea;textcolor=#323232]", "style_type[checkbox;textcolor=#323232]"
"style_type[checkbox;textcolor=#323232]",
})
-- Background stuff must be manually added by mods (no formspec prepend) -- Background stuff must be manually added by mods (no formspec prepend)
mcl_vars.gui_bg_color = "bgcolor[#00000000]" mcl_vars.gui_bg_color = "bgcolor[#00000000]"
mcl_vars.gui_bg_img = "background9[1,1;1,1;mcl_base_textures_background9.png;true;7]" mcl_vars.gui_bg_img = "background9[1,1;1,1;mcl_base_textures_background9.png;true;7]"
-- Legacy
mcl_vars.inventory_header = ""
-- Tool wield size -- Tool wield size
mcl_vars.tool_wield_scale = vector.new(1.8, 1.8, 1) mcl_vars.tool_wield_scale = { x = 1.8, y = 1.8, z = 1 }
-- Mapgen variables -- Mapgen variables
local mg_name = minetest.get_mapgen_setting("mg_name") local mg_name = minetest.get_mapgen_setting("mg_name")
@ -35,69 +35,55 @@ mcl_vars.chunksize = math.max(1, tonumber(minetest.get_mapgen_setting("chunksize
mcl_vars.MAP_BLOCKSIZE = math.max(1, minetest.MAP_BLOCKSIZE or 16) mcl_vars.MAP_BLOCKSIZE = math.max(1, minetest.MAP_BLOCKSIZE or 16)
mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000) mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, minetest.MAX_MAP_GENERATION_LIMIT or 31000) mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, minetest.MAX_MAP_GENERATION_LIMIT or 31000)
local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2) local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2)
mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
mcl_vars.chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE mcl_vars.chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE
local central_chunk_min_pos = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE local central_chunk_min_pos = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
local central_chunk_max_pos = central_chunk_min_pos + mcl_vars.chunk_size_in_nodes - 1 local central_chunk_max_pos = central_chunk_min_pos + mcl_vars.chunk_size_in_nodes - 1
local ccfmin = central_chunk_min_pos - mcl_vars.MAP_BLOCKSIZE -- Fullminp/fullmaxp of central chunk, in nodes local ccfmin = central_chunk_min_pos - mcl_vars.MAP_BLOCKSIZE -- Fullminp/fullmaxp of central chunk, in nodes
local ccfmax = central_chunk_max_pos + mcl_vars.MAP_BLOCKSIZE local ccfmax = central_chunk_max_pos + mcl_vars.MAP_BLOCKSIZE
local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) / local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) / mcl_vars.MAP_BLOCKSIZE)
mcl_vars.MAP_BLOCKSIZE)
local mapgen_limit_min = -mapgen_limit_b * mcl_vars.MAP_BLOCKSIZE local mapgen_limit_min = -mapgen_limit_b * mcl_vars.MAP_BLOCKSIZE
local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_vars.MAP_BLOCKSIZE - 1 local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_vars.MAP_BLOCKSIZE - 1
local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / mcl_vars.chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / mcl_vars.chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk
local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / mcl_vars.chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits. local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / mcl_vars.chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits.
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * mcl_vars.chunk_size_in_nodes mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * mcl_vars.chunk_size_in_nodes
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * mcl_vars.chunk_size_in_nodes mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * mcl_vars.chunk_size_in_nodes
---@param x integer
---@return integer
local function coordinate_to_block(x) local function coordinate_to_block(x)
return math.floor(x / mcl_vars.MAP_BLOCKSIZE) return math.floor(x / mcl_vars.MAP_BLOCKSIZE)
end end
---@param x integer
---@return integer
local function coordinate_to_chunk(x) local function coordinate_to_chunk(x)
return math.floor((coordinate_to_block(x) - central_chunk_offset) / mcl_vars.chunksize) return math.floor((coordinate_to_block(x) - central_chunk_offset) / mcl_vars.chunksize)
end end
---@param pos Vector
---@return Vector
function mcl_vars.pos_to_block(pos) function mcl_vars.pos_to_block(pos)
return vector.new( return {
coordinate_to_block(pos.x), x = coordinate_to_block(pos.x),
coordinate_to_block(pos.y), y = coordinate_to_block(pos.y),
coordinate_to_block(pos.z) z = coordinate_to_block(pos.z)
) }
end end
---@param pos Vector
---@return Vector
function mcl_vars.pos_to_chunk(pos) function mcl_vars.pos_to_chunk(pos)
return vector.new( return {
coordinate_to_chunk(pos.x), x = coordinate_to_chunk(pos.x),
coordinate_to_chunk(pos.y), y = coordinate_to_chunk(pos.y),
coordinate_to_chunk(pos.z) z = coordinate_to_chunk(pos.z)
) }
end end
local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / mcl_vars.chunk_size_in_nodes) local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / mcl_vars.chunk_size_in_nodes)
local k_positive_z = k_positive * 2 local k_positive_z = k_positive * 2
local k_positive_y = k_positive_z * k_positive_z local k_positive_y = k_positive_z * k_positive_z
---@param pos Vector
---@return integer
function mcl_vars.get_chunk_number(pos) -- unsigned int function mcl_vars.get_chunk_number(pos) -- unsigned int
local c = mcl_vars.pos_to_chunk(pos) local c = mcl_vars.pos_to_chunk(pos)
return (c.y + k_positive) * k_positive_y + return
(c.y + k_positive) * k_positive_y +
(c.z + k_positive) * k_positive_z + (c.z + k_positive) * k_positive_z +
c.x + k_positive c.x + k_positive
end end
if not superflat and not singlenode then if not superflat and not singlenode then
@ -131,8 +117,11 @@ elseif singlenode then
mcl_vars.mg_bedrock_is_rough = false mcl_vars.mg_bedrock_is_rough = false
else else
-- Classic superflat -- Classic superflat
local ground = tonumber(minetest.get_mapgen_setting("mgflat_ground_level")) or 8 local ground = minetest.get_mapgen_setting("mgflat_ground_level")
ground = tonumber(ground)
if not ground then
ground = 8
end
mcl_vars.mg_overworld_min = ground - 3 mcl_vars.mg_overworld_min = ground - 3
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit 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_min = mcl_vars.mg_overworld_min
@ -149,7 +138,6 @@ mcl_vars.mg_nether_min = -29067 -- Carefully chosen to be at a mapchunk border
mcl_vars.mg_nether_max = mcl_vars.mg_nether_min + 128 mcl_vars.mg_nether_max = mcl_vars.mg_nether_min + 128
mcl_vars.mg_bedrock_nether_bottom_min = mcl_vars.mg_nether_min mcl_vars.mg_bedrock_nether_bottom_min = mcl_vars.mg_nether_min
mcl_vars.mg_bedrock_nether_top_max = mcl_vars.mg_nether_max mcl_vars.mg_bedrock_nether_top_max = mcl_vars.mg_nether_max
mcl_vars.mg_nether_deco_max = mcl_vars.mg_nether_max -11 -- this is so ceiling decorations don't spill into other biomes as bedrock generation calls minetest.generate_decorations to put netherrack under the bedrock
if not superflat then if not superflat then
mcl_vars.mg_bedrock_nether_bottom_max = mcl_vars.mg_bedrock_nether_bottom_min + 4 mcl_vars.mg_bedrock_nether_bottom_max = mcl_vars.mg_bedrock_nether_bottom_min + 4
mcl_vars.mg_bedrock_nether_top_min = mcl_vars.mg_bedrock_nether_top_max - 4 mcl_vars.mg_bedrock_nether_top_min = mcl_vars.mg_bedrock_nether_top_max - 4
@ -192,16 +180,14 @@ minetest.craftitemdef_default.stack_max = 64
math.randomseed(os.time()) math.randomseed(os.time())
local chunks = {} -- intervals of chunks generated local chunks = {} -- intervals of chunks generated
---@param pos Vector
function mcl_vars.add_chunk(pos) function mcl_vars.add_chunk(pos)
local n = mcl_vars.get_chunk_number(pos) -- unsigned int local n = mcl_vars.get_chunk_number(pos) -- unsigned int
local prev local prev
for i, d in pairs(chunks) do for i, d in pairs(chunks) do
if n <= d[2] then -- we've found it if n <= d[2] then -- we've found it
if (n == d[2]) or (n >= d[1]) then return end -- already here if (n == d[2]) or (n >= d[1]) then return end -- already here
if n == d[1] - 1 then -- right before: if n == d[1]-1 then -- right before:
if prev and (prev[2] == n - 1) then if prev and (prev[2] == n-1) then
prev[2] = d[2] prev[2] = d[2]
table.remove(chunks, i) table.remove(chunks, i)
return return
@ -209,20 +195,17 @@ function mcl_vars.add_chunk(pos)
d[1] = n d[1] = n
return return
end end
if prev and (prev[2] == n - 1) then --join to previous if prev and (prev[2] == n-1) then --join to previous
prev[2] = n prev[2] = n
return return
end end
table.insert(chunks, i, { n, n }) -- insert new interval before i table.insert(chunks, i, {n, n}) -- insert new interval before i
return return
end end
prev = d prev = d
end end
chunks[#chunks + 1] = { n, n } chunks[#chunks+1] = {n, n}
end end
---@param pos Vector
---@return boolean
function mcl_vars.is_generated(pos) function mcl_vars.is_generated(pos)
local n = mcl_vars.get_chunk_number(pos) -- unsigned int local n = mcl_vars.get_chunk_number(pos) -- unsigned int
for i, d in pairs(chunks) do for i, d in pairs(chunks) do
@ -233,46 +216,47 @@ function mcl_vars.is_generated(pos)
return false return false
end end
---"Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does. -- "Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does.
---@param pos Vector Position, if it's wrong, `{name="error"}` node will return. -- p: Position, if it's wrong, {name="error"} node will return.
---@param force? boolean Optional (default: `false`), Do the maximum to still read the node within us_timeout. -- force: optional (default: false) - Do the maximum to still read the node within us_timeout.
---@param us_timeout? number Optional (default: `244 = 0.000244 s = 1/80/80/80`), set it at least to `3000000` to let mapgen to finish its job -- us_timeout: optional (default: 244 = 0.000244 s = 1/80/80/80), set it at least to 3000000 to let mapgen to finish its job.
---@return node # Node definition, eg. `{name="air"}`. Unfortunately still can return `{name="ignore"}`. --
---@nodiscard -- returns node definition, eg. {name="air"}. Unfortunately still can return {name="ignore"}.
function mcl_vars.get_node(pos, force, us_timeout) function mcl_vars.get_node(p, force, us_timeout)
-- check initial circumstances -- check initial circumstances
if not pos or not pos.x or not pos.y or not pos.z then return { name = "error" } end if not p or not p.x or not p.y or not p.z then return {name="error"} end
-- try common way -- try common way
local node = minetest.get_node(pos) local node = minetest.get_node(p)
if node.name ~= "ignore" then if node.name ~= "ignore" then
return node return node
end end
-- copy vector to get sure it won't changed by other threads -- copy table to get sure it won't changed by other threads
local pos_copy = vector.copy(pos) local pos = {x=p.x,y=p.y,z=p.z}
-- try LVM -- try LVM
minetest.get_voxel_manip():read_from_map(pos_copy, pos_copy) minetest.get_voxel_manip():read_from_map(pos, pos)
node = minetest.get_node(pos_copy) node = minetest.get_node(pos)
if node.name ~= "ignore" or not force then if node.name ~= "ignore" or not force then
return node return node
end end
-- all ways failed - need to emerge (or forceload if generated) -- all ways failed - need to emerge (or forceload if generated)
if mcl_vars.is_generated(pos_copy) then local us_timeout = us_timeout or 244
if mcl_vars.is_generated(pos) then
minetest.chat_send_all("IMPOSSIBLE! Please report this to MCL2 issue tracker!") minetest.chat_send_all("IMPOSSIBLE! Please report this to MCL2 issue tracker!")
minetest.forceload_block(pos_copy) minetest.forceload_block(pos)
else else
minetest.emerge_area(pos_copy, pos_copy) minetest.emerge_area(pos, pos)
end end
local t = minetest.get_us_time() local t = minetest.get_us_time()
node = minetest.get_node(pos_copy) node = minetest.get_node(pos)
while (not node or node.name == "ignore") and (minetest.get_us_time() - t < (us_timeout or 244)) do while (not node or node.name == "ignore") and (minetest.get_us_time() - t < us_timeout) do
node = minetest.get_node(pos_copy) node = minetest.get_node(pos)
end end
return node return node

View File

@ -11,22 +11,42 @@ Creative Commons Attribution 3.0 Unported (CC BY-SA 3.0)
http://creativecommons.org/licenses/by/3.0/ http://creativecommons.org/licenses/by/3.0/
Glass breaking sounds (CC BY 3.0): Glass breaking sounds (CC BY 3.0):
1: http://www.freesound.org/people/cmusounddesign/sounds/71947/ 1: http://www.freesound.org/people/cmusounddesign/sounds/71947/
2: http://www.freesound.org/people/Tomlija/sounds/97669/ 2: http://www.freesound.org/people/Tomlija/sounds/97669/
3: http://www.freesound.org/people/lsprice/sounds/88808/ 3: http://www.freesound.org/people/lsprice/sounds/88808/
default_tool_breaks.ogg by EdgardEdition (CC BY 3.0), http://www.freesound.org/people/EdgardEdition default_tool_breaks.ogg by EdgardEdition (CC BY 3.0), http://www.freesound.org/people/EdgardEdition
Mito551 (sounds) (CC BY-SA 3.0): Mito551 (sounds) (CC BY-SA 3.0):
default_dig_crumbly.ogg default_dig_choppy.ogg
default_dig_cracky.ogg
default_dig_crumbly.1.ogg
default_dig_crumbly.2.ogg
default_dig_oddly_breakable_by_hand.ogg default_dig_oddly_breakable_by_hand.ogg
default_dug_node.*.ogg default_dug_node.1.ogg
default_grass_footstep.*.ogg default_dug_node.2.ogg
default_gravel_footstep.*.ogg default_grass_footstep.1.ogg
default_place_node.*.ogg default_grass_footstep.2.ogg
default_place_node_hard.*.ogg default_grass_footstep.3.ogg
default_wood_footstep.*.ogg default_gravel_footstep.1.ogg
default_dirt_footstep.*.ogg default_gravel_footstep.2.ogg
default_gravel_footstep.3.ogg
default_gravel_footstep.4.ogg
default_grass_footstep.1.ogg
default_place_node.1.ogg
default_place_node.2.ogg
default_place_node.3.ogg
default_place_node_hard.1.ogg
default_place_node_hard.2.ogg
default_hard_footstep.1.ogg
default_hard_footstep.2.ogg
default_hard_footstep.3.ogg
default_sand_footstep.1.ogg
default_sand_footstep.2.ogg
default_wood_footstep.1.ogg
default_wood_footstep.2.ogg
default_dirt_footstep.1.ogg
default_dirt_footstep.2.ogg
default_glass_footstep.ogg default_glass_footstep.ogg
Metal sounds: Metal sounds:
@ -34,64 +54,35 @@ Metal sounds:
- https://www.freesound.org/people/yadronoff/sounds/320397/ - https://www.freesound.org/people/yadronoff/sounds/320397/
default_dug_metal.*.ogg - Iwan Gabovitch - qubodup - CC0 default_dug_metal.*.ogg - Iwan Gabovitch - qubodup - CC0
- http://opengameart.org/users/qubodup - http://opengameart.org/users/qubodup
default_metal_footstep.*.ogg - (CC0 1.0) - CC0 1.0 default_metal_footstep.*.ogg - Ottomaani138 - CC0
- https://freesound.org/people/mypantsfelldown/sounds/398937/ - https://www.freesound.org/people/Ottomaani138/sounds/232692/
default_place_node_metal.*.ogg - Ogrebane - CC0 default_place_node_metal.*.ogg - Ogrebane - CC0
- http://opengameart.org/content/wood-and-metal-sound-effects-volume-2 - http://opengameart.org/content/wood-and-metal-sound-effects-volume-2
AGFX (CC BY 3.0): AGFX (CC BY 3.0)
https://www.freesound.org/people/AGFX/packs/1253/ https://www.freesound.org/people/AGFX/packs/1253/
default_water_footstep.*.ogg default_water_footstep.1.ogg
default_water_footstep.2.ogg
default_water_footstep.3.ogg
(default_water_footstep.4.ogg is silent)
blukotek (CC0 1.0): blukotek (CC0 1.0)
https://www.freesound.org/people/blukotek/sounds/251660/ https://www.freesound.org/people/blukotek/sounds/251660/
default_dig_snappy.ogg default_dig_snappy.ogg
sonictechtonic (CC BY 3.0): sonictechtonic (CC BY 3.0)
https://www.freesound.org/people/sonictechtonic/sounds/241872/ https://www.freesound.org/people/sonictechtonic/sounds/241872/
player_damage.ogg player_damage.ogg
Sheyvan (CC0 1.0): Voxelands project <http://www.voxelands.com/> (CC BY-SA 3.0)
https://freesound.org/people/Sheyvan/sounds/476113/
default_dig_choppy.*.ogg
lolamadeus (CC0 1.0):
https://freesound.org/people/lolamadeus/sounds/179341/
default_gravel_dig.*.ogg
default_gravel_dug.*.ogg
Benboncan (CC BY 3.0):
https://freesound.org/people/Benboncan/sounds/71823/
default_dig_cracky.*.ogg
Erdie (CC BY 3.0):
https://freesound.org/people/Erdie/sounds/41579/
default_hard_footstep.*.ogg
worthahep88 (CC0 1.0):
https://freesound.org/people/worthahep88/sounds/319224/
default_sand_footstep.*.ogg
dheming (CC BY 3.0):
https://freesound.org/people/dheming/sounds/268023/
default_ice_dig.*.ogg
InspectorJ (CC BY 3.0):
https://freesound.org/people/InspectorJ/sounds/416967/
default_ice_footstep.*.ogg
Angel_Perez_Grandi (CC BY 3.0):
https://freesound.org/people/Angel_Perez_Grandi/sounds/49190/
default_ice_dug.ogg
Voxelands project <http://www.voxelands.com/> (CC BY-SA 3.0):
mcl_sounds_place_node_water.ogg mcl_sounds_place_node_water.ogg
mcl_sounds_dug_water.ogg mcl_sounds_dug_water.ogg
(Note: Artists from the Voxelands project include: sdzen, darkrose, sapier, (Note: Artists from the Voxelands project include: sdzen, darkrose, sapier,
Tom Peter, Telaron, juskiddink) Tom Peter, Telaron, juskiddink)
Michel Baradari <https://opengameart.org/content/lava-splash> (CC BY 3.0): Michel Baradari <https://opengameart.org/content/lava-splash> (CC BY 3.0)
default_place_node_lava.ogg default_place_node_lava.ogg
Adam_N (CC0 1.0): Adam_N (CC0 1.0):
@ -99,7 +90,7 @@ Adam_N (CC0 1.0):
Source: <https://www.freesound.org/people/Adam_N/sounds/346692/> Source: <https://www.freesound.org/people/Adam_N/sounds/346692/>
Alecia Shepherd (CC BY-SA 4.0): Alecia Shepherd (CC BY-SA 4.0):
mcl_sounds_cloth.*.ogg mcl_sounds_cloth.ogg
Source: SnowSong sound and music pack <https://opengameart.org/content/snowsong-sound-and-music-pack> Source: SnowSong sound and music pack <https://opengameart.org/content/snowsong-sound-and-music-pack>
Unknown authors (WTFPL): Unknown authors (WTFPL):

View File

@ -11,7 +11,7 @@ function mcl_sounds.node_sound_defaults(table)
table.dug = table.dug or table.dug = table.dug or
{name="default_dug_node", gain=0.25} {name="default_dug_node", gain=0.25}
table.dig = table.dig or table.dig = table.dig or
{name="default_dig_oddly_breakable_by_hand", gain=0.5} {name="default_dig_oddly_breakable_by_hand", gain=1.0}
table.place = table.place or table.place = table.place or
{name="default_place_node_hard", gain=1.0} {name="default_place_node_hard", gain=1.0}
return table return table
@ -20,11 +20,11 @@ end
function mcl_sounds.node_sound_stone_defaults(table) function mcl_sounds.node_sound_stone_defaults(table)
table = table or {} table = table or {}
table.footstep = table.footstep or table.footstep = table.footstep or
{name="default_hard_footstep", gain=0.2} {name="default_hard_footstep", gain=0.5}
table.dug = table.dug or table.dug = table.dug or
{name="default_hard_footstep", gain=1.0} {name="default_hard_footstep", gain=1.0}
table.dig = table.dig or table.dig = table.dig or
{name="default_dig_cracky", gain=0.5} {name="default_dig_cracky", gain=1.0}
mcl_sounds.node_sound_defaults(table) mcl_sounds.node_sound_defaults(table)
return table return table
end end
@ -32,13 +32,13 @@ end
function mcl_sounds.node_sound_metal_defaults(table) function mcl_sounds.node_sound_metal_defaults(table)
table = table or {} table = table or {}
table.footstep = table.footstep or table.footstep = table.footstep or
{name="default_metal_footstep", gain=0.2} {name="default_metal_footstep", gain=0.5}
table.dug = table.dug or table.dug = table.dug or
{name="default_dug_metal", gain=0.5} {name="default_dug_metal", gain=1.0}
table.dig = table.dig or table.dig = table.dig or
{name="default_dig_metal", gain=0.5} {name="default_dig_metal", gain=1.0}
table.place = table.place or table.place = table.place or
{name="default_place_node_metal", gain=0.5} {name="default_place_node_metal", gain=1.0}
mcl_sounds.node_sound_defaults(table) mcl_sounds.node_sound_defaults(table)
return table return table
end end
@ -46,11 +46,11 @@ end
function mcl_sounds.node_sound_dirt_defaults(table) function mcl_sounds.node_sound_dirt_defaults(table)
table = table or {} table = table or {}
table.footstep = table.footstep or table.footstep = table.footstep or
{name="default_dirt_footstep", gain=0.25}
table.dug = table.dug or
{name="default_dirt_footstep", gain=1.0} {name="default_dirt_footstep", gain=1.0}
table.dug = table.dug or
{name="default_dirt_footstep", gain=1.5}
table.dig = table.dig or table.dig = table.dig or
{name="default_dig_crumbly", gain=0.4} {name="default_dig_crumbly", gain=1.0}
table.place = table.place or table.place = table.place or
{name="default_place_node", gain=1.0} {name="default_place_node", gain=1.0}
mcl_sounds.node_sound_defaults(table) mcl_sounds.node_sound_defaults(table)
@ -60,25 +60,11 @@ end
function mcl_sounds.node_sound_sand_defaults(table) function mcl_sounds.node_sound_sand_defaults(table)
table = table or {} table = table or {}
table.footstep = table.footstep or table.footstep = table.footstep or
{name="default_sand_footstep", gain=0.05} {name="default_sand_footstep", gain=0.5}
table.dug = table.dug or table.dug = table.dug or
{name="default_sand_footstep", gain=0.15} {name="default_sand_footstep", gain=1.0}
table.dig = table.dig or table.dig = table.dig or
{name="default_dig_crumbly", gain=0.4} {name="default_dig_crumbly", gain=1.0}
table.place = table.place or
{name="default_place_node", gain=1.0}
mcl_sounds.node_sound_defaults(table)
return table
end
function mcl_sounds.node_sound_gravel_defaults(table)
table = table or {}
table.footstep = table.footstep or
{name="default_gravel_footstep", gain=0.25}
table.dug = table.dug or
{name="default_gravel_dug", gain=1.0}
table.dig = table.dig or
{name="default_gravel_dig", gain=0.35}
table.place = table.place or table.place = table.place or
{name="default_place_node", gain=1.0} {name="default_place_node", gain=1.0}
mcl_sounds.node_sound_defaults(table) mcl_sounds.node_sound_defaults(table)
@ -92,33 +78,21 @@ function mcl_sounds.node_sound_snow_defaults(table)
table.dug = table.dug or table.dug = table.dug or
{name="pedology_snow_soft_footstep", gain=1.0} {name="pedology_snow_soft_footstep", gain=1.0}
table.dig = table.dig or table.dig = table.dig or
{name="pedology_snow_soft_footstep", gain=1.0} {name="default_dig_crumbly", gain=1.0}
table.place = table.place or table.place = table.place or
{name="default_place_node", gain=1.0} {name="default_place_node", gain=1.0}
mcl_sounds.node_sound_defaults(table) mcl_sounds.node_sound_defaults(table)
return table return table
end end
function mcl_sounds.node_sound_ice_defaults(table)
table = table or {}
table.footstep = table.footstep or
{name="default_ice_footstep", gain=0.15}
table.dug = table.dug or
{name="default_ice_dug", gain=0.5}
table.dig = table.dig or
{name="default_ice_dig", gain=0.5}
mcl_sounds.node_sound_defaults(table)
return table
end
function mcl_sounds.node_sound_wood_defaults(table) function mcl_sounds.node_sound_wood_defaults(table)
table = table or {} table = table or {}
table.footstep = table.footstep or table.footstep = table.footstep or
{name="default_wood_footstep", gain=0.15} {name="default_wood_footstep", gain=0.5}
table.dug = table.dug or table.dug = table.dug or
{name="default_wood_footstep", gain=1.0} {name="default_wood_footstep", gain=1.0}
table.dig = table.dig or table.dig = table.dig or
{name="default_dig_choppy", gain=0.4} {name="default_dig_choppy", gain=1.0}
mcl_sounds.node_sound_defaults(table) mcl_sounds.node_sound_defaults(table)
return table return table
end end
@ -154,11 +128,11 @@ end
function mcl_sounds.node_sound_glass_defaults(table) function mcl_sounds.node_sound_glass_defaults(table)
table = table or {} table = table or {}
table.footstep = table.footstep or table.footstep = table.footstep or
{name="default_glass_footstep", gain=0.3} {name="default_glass_footstep", gain=0.5}
table.dug = table.dug or table.dug = table.dug or
{name="default_break_glass", gain=1.0} {name="default_break_glass", gain=1.0}
table.dig = table.dig or table.dig = table.dig or
{name="default_dig_cracky", gain=0.5} {name="default_dig_cracky", gain=1.0}
mcl_sounds.node_sound_defaults(table) mcl_sounds.node_sound_defaults(table)
return table return table
end end

Binary file not shown.

Binary file not shown.

View File

@ -2,8 +2,8 @@ mcl_util = {}
-- Updates all values in t using values from to*. -- Updates all values in t using values from to*.
function table.update(t, ...) function table.update(t, ...)
for _, to in ipairs {...} do for _, to in ipairs{...} do
for k, v in pairs(to) do for k,v in pairs(to) do
t[k] = v t[k] = v
end end
end end
@ -12,8 +12,8 @@ end
-- Updates nil values in t using values from to*. -- Updates nil values in t using values from to*.
function table.update_nil(t, ...) function table.update_nil(t, ...)
for _, to in ipairs {...} do for _, to in ipairs{...} do
for k, v in pairs(to) do for k,v in pairs(to) do
if t[k] == nil then if t[k] == nil then
t[k] = v t[k] = v
end end
@ -22,20 +22,7 @@ function table.update_nil(t, ...)
return t return t
end end
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_default", false)
local LOG_MODULE = "[MCL2]"
function mcl_util.mcl_log(message, module, bypass_default_logger)
local selected_module = LOG_MODULE
if module then
selected_module = module
end
if (bypass_default_logger or LOGGING_ON) and message then
minetest.log(selected_module .. " " .. message)
end
end
function mcl_util.file_exists(name) function mcl_util.file_exists(name)
if type(name) ~= "string" then return end
local f = io.open(name) local f = io.open(name)
if not f then if not f then
return false return false
@ -68,7 +55,7 @@ function mcl_util.rotate_axis_and_place(itemstack, placer, pointed_thing, infini
local undef = minetest.registered_nodes[unode.name] local undef = minetest.registered_nodes[unode.name]
if undef and undef.on_rightclick then if undef and undef.on_rightclick then
undef.on_rightclick(pointed_thing.under, unode, placer, undef.on_rightclick(pointed_thing.under, unode, placer,
itemstack, pointed_thing) itemstack, pointed_thing)
return return
end end
local fdir = minetest.dir_to_facedir(placer:get_look_dir()) local fdir = minetest.dir_to_facedir(placer:get_look_dir())
@ -150,23 +137,23 @@ end
function mcl_util.get_double_container_neighbor_pos(pos, param2, side) function mcl_util.get_double_container_neighbor_pos(pos, param2, side)
if side == "right" then if side == "right" then
if param2 == 0 then if param2 == 0 then
return {x = pos.x - 1, y = pos.y, z = pos.z} return {x=pos.x-1, y=pos.y, z=pos.z}
elseif param2 == 1 then elseif param2 == 1 then
return {x = pos.x, y = pos.y, z = pos.z + 1} return {x=pos.x, y=pos.y, z=pos.z+1}
elseif param2 == 2 then elseif param2 == 2 then
return {x = pos.x + 1, y = pos.y, z = pos.z} return {x=pos.x+1, y=pos.y, z=pos.z}
elseif param2 == 3 then elseif param2 == 3 then
return {x = pos.x, y = pos.y, z = pos.z - 1} return {x=pos.x, y=pos.y, z=pos.z-1}
end end
else else
if param2 == 0 then if param2 == 0 then
return {x = pos.x + 1, y = pos.y, z = pos.z} return {x=pos.x+1, y=pos.y, z=pos.z}
elseif param2 == 1 then elseif param2 == 1 then
return {x = pos.x, y = pos.y, z = pos.z - 1} return {x=pos.x, y=pos.y, z=pos.z-1}
elseif param2 == 2 then elseif param2 == 2 then
return {x = pos.x - 1, y = pos.y, z = pos.z} return {x=pos.x-1, y=pos.y, z=pos.z}
elseif param2 == 3 then elseif param2 == 3 then
return {x = pos.x, y = pos.y, z = pos.z + 1} return {x=pos.x, y=pos.y, z=pos.z+1}
end end
end end
end end
@ -184,7 +171,7 @@ end
function mcl_util.get_eligible_transfer_item_slot(src_inventory, src_list, dst_inventory, dst_list, condition) function mcl_util.get_eligible_transfer_item_slot(src_inventory, src_list, dst_inventory, dst_list, condition)
local size = src_inventory:get_size(src_list) local size = src_inventory:get_size(src_list)
local stack local stack
for i = 1, size do for i=1, size do
stack = src_inventory:get_stack(src_list, i) stack = src_inventory:get_stack(src_list, i)
if not stack:is_empty() and (condition == nil or condition(stack, src_inventory, src_list, dst_inventory, dst_list)) then if not stack:is_empty() and (condition == nil or condition(stack, src_inventory, src_list, dst_inventory, dst_list)) then
return i return i
@ -287,10 +274,10 @@ function mcl_util.move_item_container(source_pos, destination_pos, source_list,
-- Main inventory for most container types -- Main inventory for most container types
if sctype == 2 or sctype == 3 or sctype == 5 or sctype == 6 or sctype == 7 then if sctype == 2 or sctype == 3 or sctype == 5 or sctype == 6 or sctype == 7 then
source_list = "main" source_list = "main"
-- Furnace: output -- Furnace: output
elseif sctype == 4 then elseif sctype == 4 then
source_list = "dst" source_list = "dst"
-- Unknown source container type. Bail out -- Unknown source container type. Bail out
else else
return false return false
end end
@ -343,7 +330,7 @@ function mcl_util.move_item_container(source_pos, destination_pos, source_list,
-- Main inventory for most container types -- Main inventory for most container types
if dctype == 2 or dctype == 3 or dctype == 5 or dctype == 6 or dctype == 7 then if dctype == 2 or dctype == 3 or dctype == 5 or dctype == 6 or dctype == 7 then
destination_list = "main" destination_list = "main"
-- Furnace source slot -- Furnace source slot
elseif dctype == 4 then elseif dctype == 4 then
destination_list = "src" destination_list = "src"
end end
@ -408,7 +395,7 @@ end
-- Returns true if item (itemstring or ItemStack) can be used as a furnace fuel. -- Returns true if item (itemstring or ItemStack) can be used as a furnace fuel.
-- Returns false otherwise -- Returns false otherwise
function mcl_util.is_fuel(item) function mcl_util.is_fuel(item)
return minetest.get_craft_result({method = "fuel", width = 1, items = {item}}).time ~= 0 return minetest.get_craft_result({method="fuel", width=1, items={item}}).time ~= 0
end end
-- Returns a on_place function for plants -- Returns a on_place function for plants
@ -455,7 +442,7 @@ function mcl_util.generate_on_place_plant_function(condition)
if success then if success then
if idef.sounds and idef.sounds.place then if idef.sounds and idef.sounds.place then
minetest.sound_play(idef.sounds.place, {pos = pointed_thing.above, gain = 1}, true) minetest.sound_play(idef.sounds.place, {pos=pointed_thing.above, gain=1}, true)
end end
end end
itemstack = new_itemstack itemstack = new_itemstack
@ -612,12 +599,10 @@ function mcl_util.get_object_name(object)
end end
function mcl_util.replace_mob(obj, mob) function mcl_util.replace_mob(obj, mob)
if not obj then return end
local rot = obj:get_yaw() local rot = obj:get_yaw()
local pos = obj:get_pos() local pos = obj:get_pos()
obj:remove() obj:remove()
obj = minetest.add_entity(pos, mob) obj = minetest.add_entity(pos, mob)
if not obj then return end
obj:set_yaw(rot) obj:set_yaw(rot)
return obj return obj
end end
@ -642,372 +627,87 @@ end
local function roundN(n, d) local function roundN(n, d)
if type(n) ~= "number" then return n end if type(n) ~= "number" then return n end
local m = 10 ^ d local m = 10^d
return math.floor(n * m + 0.5) / m return math.floor(n * m + 0.5) / m
end end
local function close_enough(a, b) local function close_enough(a,b)
local rt = true local rt=true
if type(a) == "table" and type(b) == "table" then if type(a) == "table" and type(b) == "table" then
for k, v in pairs(a) do for k,v in pairs(a) do
if roundN(v, 2) ~= roundN(b[k], 2) then if roundN(v,2) ~= roundN(b[k],2) then
rt = false rt=false
break break
end end
end end
else else
rt = roundN(a, 2) == roundN(b, 2) rt = roundN(a,2) == roundN(b,2)
end end
return rt return rt
end end
local function props_changed(props, oldprops) local function props_changed(props,oldprops)
local changed = false local changed=false
local p = {} local p={}
for k, v in pairs(props) do for k,v in pairs(props) do
if not close_enough(v, oldprops[k]) then if not close_enough(v,oldprops[k]) then
p[k] = v p[k]=v
changed = true changed=true
end end
end end
return changed, p return changed,p
end end
--tests for roundN --tests for roundN
local test_round1 = 15 local test_round1=15
local test_round2 = 15.00199999999 local test_round2=15.00199999999
local test_round3 = 15.00111111 local test_round3=15.00111111
local test_round4 = 15.00999999 local test_round4=15.00999999
assert(roundN(test_round1, 2) == roundN(test_round1, 2)) assert(roundN(test_round1,2)==roundN(test_round1,2))
assert(roundN(test_round1, 2) == roundN(test_round2, 2)) assert(roundN(test_round1,2)==roundN(test_round2,2))
assert(roundN(test_round1, 2) == roundN(test_round3, 2)) assert(roundN(test_round1,2)==roundN(test_round3,2))
assert(roundN(test_round1, 2) ~= roundN(test_round4, 2)) assert(roundN(test_round1,2)~=roundN(test_round4,2))
-- tests for close_enough -- tests for close_enough
local test_cb = {-0.35, 0, -0.35, 0.35, 0.8, 0.35} --collisionboxes local test_cb = {-0.35,0,-0.35,0.35,0.8,0.35} --collisionboxes
local test_cb_close = {-0.351213, 0, -0.35, 0.35, 0.8, 0.351212} local test_cb_close = {-0.351213,0,-0.35,0.35,0.8,0.351212}
local test_cb_diff = {-0.35, 0, -1.35, 0.35, 0.8, 0.35} local test_cb_diff = {-0.35,0,-1.35,0.35,0.8,0.35}
local test_eh = 1.65 --eye height local test_eh = 1.65 --eye height
local test_eh_close = 1.65123123 local test_eh_close = 1.65123123
local test_eh_diff = 1.35 local test_eh_diff = 1.35
local test_nt = {r = 225, b = 225, a = 225, g = 225} --nametag local test_nt = { r = 225, b = 225, a = 225, g = 225 } --nametag
local test_nt_diff = {r = 225, b = 225, a = 0, g = 225} local test_nt_diff = { r = 225, b = 225, a = 0, g = 225 }
assert(close_enough(test_cb, test_cb_close)) assert(close_enough(test_cb,test_cb_close))
assert(not close_enough(test_cb, test_cb_diff)) assert(not close_enough(test_cb,test_cb_diff))
assert(close_enough(test_eh, test_eh_close)) assert(close_enough(test_eh,test_eh_close))
assert(not close_enough(test_eh, test_eh_diff)) assert(not close_enough(test_eh,test_eh_diff))
assert(not close_enough(test_nt, test_nt_diff)) --no floats involved here assert(not close_enough(test_nt,test_nt_diff)) --no floats involved here
--tests for properties_changed --tests for properties_changed
local test_properties_set1 = {collisionbox = {-0.35, 0, -0.35, 0.35, 0.8, 0.35}, eye_height = 0.65, local test_properties_set1={collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 0.65, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}
nametag_color = {r = 225, b = 225, a = 225, g = 225}} local test_properties_set2={collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 1.35, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}
local test_properties_set2 = {collisionbox = {-0.35, 0, -0.35, 0.35, 0.8, 0.35}, eye_height = 1.35,
nametag_color = {r = 225, b = 225, a = 225, g = 225}}
local test_p1, _ = props_changed(test_properties_set1, test_properties_set1) local test_p1,_=props_changed(test_properties_set1,test_properties_set1)
local test_p2, _ = props_changed(test_properties_set1, test_properties_set2) local test_p2,_=props_changed(test_properties_set1,test_properties_set2)
assert(not test_p1) assert(not test_p1)
assert(test_p2) assert(test_p2)
function mcl_util.set_properties(obj, props) function mcl_util.set_properties(obj,props)
local changed, p = props_changed(props, obj:get_properties()) local changed,p=props_changed(props,obj:get_properties())
if changed then if changed then
obj:set_properties(p) obj:set_properties(p)
end end
end end
function mcl_util.set_bone_position(obj, bone, pos, rot) function mcl_util.set_bone_position(obj,b,p,r) --bone,position,rotation
local current_pos, current_rot = obj:get_bone_position(bone) local oldp,oldr=obj:get_bone_position(b)
local pos_equal = not pos or vector.equals(vector.round(current_pos), vector.round(pos)) if vector.equals(vector.round(oldp),vector.round(p)) and vector.equals(vector.round(oldr),vector.round(r)) then
local rot_equal = not rot or vector.equals(vector.round(current_rot), vector.round(rot)) return
if not pos_equal or not rot_equal then
obj:set_bone_position(bone, pos or current_pos, rot or current_rot)
end end
end obj:set_bone_position(b,p,r)
---Return a function to use in `on_place`.
---
---Allow to bypass the `buildable_to` node field in a `on_place` callback.
---
---You have to make sure that the nodes you return true for have `buildable_to = true`.
---@param func fun(node_name: string): boolean Return `true` if node must not replace the buildable_to node which have `node_name`
---@return fun(itemstack: ItemStack, placer: ObjectRef, pointed_thing: pointed_thing, param2: integer): ItemStack?
function mcl_util.bypass_buildable_to(func)
--------------------------
-- MINETEST CODE: UTILS --
--------------------------
local function copy_pointed_thing(pointed_thing)
return {
type = pointed_thing.type,
above = pointed_thing.above and vector.copy(pointed_thing.above),
under = pointed_thing.under and vector.copy(pointed_thing.under),
ref = pointed_thing.ref,
}
end
local function user_name(user)
return user and user:get_player_name() or ""
end
-- Returns a logging function. For empty names, does not log.
local function make_log(name)
return name ~= "" and minetest.log or function() end
end
local function check_attached_node(p, n, group_rating)
local def = core.registered_nodes[n.name]
local d = vector.zero()
if group_rating == 3 then
-- always attach to floor
d.y = -1
elseif group_rating == 4 then
-- always attach to ceiling
d.y = 1
elseif group_rating == 2 then
-- attach to facedir or 4dir direction
if (def.paramtype2 == "facedir" or
def.paramtype2 == "colorfacedir") then
-- Attach to whatever facedir is "mounted to".
-- For facedir, this is where tile no. 5 point at.
-- The fallback vector here is in case 'facedir to dir' is nil due
-- to voxelmanip placing a wallmounted node without resetting a
-- pre-existing param2 value that is out-of-range for facedir.
-- The fallback vector corresponds to param2 = 0.
d = core.facedir_to_dir(n.param2) or vector.new(0, 0, 1)
elseif (def.paramtype2 == "4dir" or
def.paramtype2 == "color4dir") then
-- Similar to facedir handling
d = core.fourdir_to_dir(n.param2) or vector.new(0, 0, 1)
end
elseif def.paramtype2 == "wallmounted" or
def.paramtype2 == "colorwallmounted" then
-- Attach to whatever this node is "mounted to".
-- This where tile no. 2 points at.
-- The fallback vector here is used for the same reason as
-- for facedir nodes.
d = core.wallmounted_to_dir(n.param2) or vector.new(0, 1, 0)
else
d.y = -1
end
local p2 = vector.add(p, d)
local nn = core.get_node(p2).name
local def2 = core.registered_nodes[nn]
if def2 and not def2.walkable then
return false
end
return true
end
return function(itemstack, placer, pointed_thing, param2)
-------------------
-- MINETEST CODE --
-------------------
local def = itemstack:get_definition()
if def.type ~= "node" or pointed_thing.type ~= "node" then
return itemstack
end
local under = pointed_thing.under
local oldnode_under = minetest.get_node_or_nil(under)
local above = pointed_thing.above
local oldnode_above = minetest.get_node_or_nil(above)
local playername = user_name(placer)
local log = make_log(playername)
if not oldnode_under or not oldnode_above then
log("info", playername .. " tried to place"
.. " node in unloaded position " .. minetest.pos_to_string(above))
return itemstack
end
local olddef_under = minetest.registered_nodes[oldnode_under.name]
olddef_under = olddef_under or minetest.nodedef_default
local olddef_above = minetest.registered_nodes[oldnode_above.name]
olddef_above = olddef_above or minetest.nodedef_default
if not olddef_above.buildable_to and not olddef_under.buildable_to then
log("info", playername .. " tried to place"
.. " node in invalid position " .. minetest.pos_to_string(above)
.. ", replacing " .. oldnode_above.name)
return itemstack
end
---------------------
-- CUSTOMIZED CODE --
---------------------
-- Place above pointed node
local place_to = vector.copy(above)
-- If node under is buildable_to, check for callback result and place into it instead
if olddef_under.buildable_to and not func(oldnode_under.name) then
log("info", "node under is buildable to")
place_to = vector.copy(under)
end
-------------------
-- MINETEST CODE --
-------------------
if minetest.is_protected(place_to, playername) then
log("action", playername
.. " tried to place " .. def.name
.. " at protected position "
.. minetest.pos_to_string(place_to))
minetest.record_protection_violation(place_to, playername)
return itemstack
end
local oldnode = minetest.get_node(place_to)
local newnode = {name = def.name, param1 = 0, param2 = param2 or 0}
-- Calculate direction for wall mounted stuff like torches and signs
if def.place_param2 ~= nil then
newnode.param2 = def.place_param2
elseif (def.paramtype2 == "wallmounted" or
def.paramtype2 == "colorwallmounted") and not param2 then
local dir = vector.subtract(under, above)
newnode.param2 = minetest.dir_to_wallmounted(dir)
-- Calculate the direction for furnaces and chests and stuff
elseif (def.paramtype2 == "facedir" or
def.paramtype2 == "colorfacedir" or
def.paramtype2 == "4dir" or
def.paramtype2 == "color4dir") and not param2 then
local placer_pos = placer and placer:get_pos()
if placer_pos then
local dir = vector.subtract(above, placer_pos)
newnode.param2 = minetest.dir_to_facedir(dir)
log("info", "facedir: " .. newnode.param2)
end
end
local metatable = itemstack:get_meta():to_table().fields
-- Transfer color information
if metatable.palette_index and not def.place_param2 then
local color_divisor = nil
if def.paramtype2 == "color" then
color_divisor = 1
elseif def.paramtype2 == "colorwallmounted" then
color_divisor = 8
elseif def.paramtype2 == "colorfacedir" then
color_divisor = 32
elseif def.paramtype2 == "color4dir" then
color_divisor = 4
elseif def.paramtype2 == "colordegrotate" then
color_divisor = 32
end
if color_divisor then
local color = math.floor(metatable.palette_index / color_divisor)
local other = newnode.param2 % color_divisor
newnode.param2 = color * color_divisor + other
end
end
-- Check if the node is attached and if it can be placed there
local an = minetest.get_item_group(def.name, "attached_node")
if an ~= 0 and
not check_attached_node(place_to, newnode, an) then
log("action", "attached node " .. def.name ..
" cannot be placed at " .. minetest.pos_to_string(place_to))
return itemstack
end
log("action", playername .. " places node "
.. def.name .. " at " .. minetest.pos_to_string(place_to))
-- Add node and update
minetest.add_node(place_to, newnode)
-- Play sound if it was done by a player
if playername ~= "" and def.sounds and def.sounds.place then
minetest.sound_play(def.sounds.place, {
pos = place_to,
exclude_player = playername,
}, true)
end
local take_item = true
-- Run callback
if def.after_place_node then
-- Deepcopy place_to and pointed_thing because callback can modify it
local place_to_copy = vector.copy(place_to)
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
if def.after_place_node(place_to_copy, placer, itemstack,
pointed_thing_copy) then
take_item = false
end
end
-- Run script hook
for _, callback in ipairs(minetest.registered_on_placenodes) do
-- Deepcopy pos, node and pointed_thing because callback can modify them
local place_to_copy = vector.copy(place_to)
local newnode_copy = {name = newnode.name, param1 = newnode.param1, param2 = newnode.param2}
local oldnode_copy = {name = oldnode.name, param1 = oldnode.param1, param2 = oldnode.param2}
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
if callback(place_to_copy, newnode_copy, placer, oldnode_copy, itemstack, pointed_thing_copy) then
take_item = false
end
end
if take_item then
itemstack:take_item()
end
return itemstack
end
end
--[[Check for a protection violation in a given area.
--
-- Applies is_protected() to a 3D lattice of points in the defined volume. The points are spaced
-- evenly throughout the volume and have a spacing similar to, but no larger than, "interval".
--
-- @param pos1 A position table of the area volume's first edge.
-- @param pos2 A position table of the area volume's second edge.
-- @param player The player performing the action.
-- @param interval Optional. Max spacing between checked points at the volume.
-- Default: Same as minetest.is_area_protected.
--
-- @return true on protection violation detection. false otherwise.
--
-- @notes *All corners and edges of the defined volume are checked.
]]
function mcl_util.check_area_protection(pos1, pos2, player, interval)
local name = player and player:get_player_name() or ""
local protected_pos = minetest.is_area_protected(pos1, pos2, name, interval)
if protected_pos then
minetest.record_protection_violation(protected_pos, name)
return true
end
return false
end
--[[Check for a protection violation on a single position.
--
-- @param position A position table to check for protection violation.
-- @param player The player performing the action.
--
-- @return true on protection violation detection. false otherwise.
]]
function mcl_util.check_position_protection(position, player)
local name = player and player:get_player_name() or ""
if minetest.is_protected(position, name) then
minetest.record_protection_violation(position, name)
return true
end
return false
end end

View File

@ -56,7 +56,7 @@ end
local function set_attach(boat) local function set_attach(boat)
boat._driver:set_attach(boat.object, "", boat._driver:set_attach(boat.object, "",
{x = 0, y = 1.5, z = 1}, {x = 0, y = 0, z = 0}) {x = 0, y = 0.42, z = -1}, {x = 0, y = 0, z = 0})
end end
local function set_double_attach(boat) local function set_double_attach(boat)
@ -67,7 +67,7 @@ local function set_double_attach(boat)
end end
local function set_choat_attach(boat) local function set_choat_attach(boat)
boat._driver:set_attach(boat.object, "", boat._driver:set_attach(boat.object, "",
{x = 0, y = 1.5, z = 1}, {x = 0, y = 0, z = 0}) {x = 0, y = 0.42, z = 1.8}, {x = 0, y = 0, z = 0})
end end
local function attach_object(self, obj) local function attach_object(self, obj)
@ -109,7 +109,6 @@ local function attach_object(self, obj)
end end
local function detach_object(obj, change_pos) local function detach_object(obj, change_pos)
if not obj or not obj:get_pos() then return end
obj:set_detach() obj:set_detach()
obj:set_properties({visual_size = get_visual_size(obj)}) obj:set_properties({visual_size = get_visual_size(obj)})
if obj:is_player() then if obj:is_player() then
@ -136,7 +135,7 @@ local boat = {
selectionbox = {-0.7, -0.15, -0.7, 0.7, 0.55, 0.7}, selectionbox = {-0.7, -0.15, -0.7, 0.7, 0.55, 0.7},
visual = "mesh", visual = "mesh",
mesh = "mcl_boats_boat.b3d", mesh = "mcl_boats_boat.b3d",
textures = { "mcl_boats_texture_oak_boat.png", "blank.png" }, textures = {"mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png"},
visual_size = boat_visual_size, visual_size = boat_visual_size,
hp_max = boat_max_hp, hp_max = boat_max_hp,
damage_texture_modifier = "^[colorize:white:0", damage_texture_modifier = "^[colorize:white:0",
@ -147,7 +146,7 @@ local boat = {
_last_v = 0, -- Temporary speed variable _last_v = 0, -- Temporary speed variable
_removed = false, -- If true, boat entity is considered removed (e.g. after punch) and should be ignored _removed = false, -- If true, boat entity is considered removed (e.g. after punch) and should be ignored
_itemstring = "mcl_boats:boat", -- Itemstring of the boat item (implies boat type) _itemstring = "mcl_boats:boat", -- Itemstring of the boat item (implies boat type)
_animation = 0, -- 0: not animated; 1: paddling forwards; -1: paddling backwards _animation = 0, -- 0: not animated; 1: paddling forwards; -1: paddling forwards
_regen_timer = 0, _regen_timer = 0,
_damage_anim = 0, _damage_anim = 0,
} }
@ -170,14 +169,8 @@ function boat.on_activate(self, staticdata, dtime_s)
self._last_v = self._v self._last_v = self._v
self._itemstring = data.itemstring self._itemstring = data.itemstring
-- Update the texutes for existing old boat entity instances. while #data.textures < 5 do
-- Maybe remove this in the future. table.insert(data.textures, data.textures[1])
if #data.textures ~= 2 then
local has_chest = self._itemstring:find("chest")
data.textures = {
data.textures[1]:gsub("_chest", ""),
has_chest and "mcl_chests_normal.png" or "blank.png"
}
end end
self.object:set_properties({textures = data.textures}) self.object:set_properties({textures = data.textures})
@ -429,7 +422,8 @@ end
minetest.register_entity("mcl_boats:boat", boat) minetest.register_entity("mcl_boats:boat", boat)
local cboat = table.copy(boat) local cboat = table.copy(boat)
cboat.textures = { "mcl_boats_texture_oak_chest_boat.png", "mcl_chests_normal.png" } cboat.mesh = "mcl_boats_boat_with_chest.b3d"
cboat.textures = {"mcl_boats_texture_oak_chest_boat.png", "mcl_boats_texture_oak_chest_boat.png", "mcl_boats_texture_oak_chest_boat.png", "mcl_boats_texture_oak_chest_boat.png", "mcl_boats_texture_oak_chest_boat.png"}
cboat._itemstring = "mcl_boats:chest_boat" cboat._itemstring = "mcl_boats:chest_boat"
cboat.collisionbox = {-0.5, -0.15, -0.5, 0.5, 0.75, 0.5} cboat.collisionbox = {-0.5, -0.15, -0.5, 0.5, 0.75, 0.5}
cboat.selectionbox = {-0.7, -0.15, -0.7, 0.7, 0.75, 0.7} cboat.selectionbox = {-0.7, -0.15, -0.7, 0.7, 0.75, 0.7}
@ -439,7 +433,11 @@ mcl_entity_invs.register_inv("mcl_boats:chest_boat","Boat",27)
local boat_ids = { "boat", "boat_spruce", "boat_birch", "boat_jungle", "boat_acacia", "boat_dark_oak", "boat_obsidian", "boat_mangrove", "chest_boat", "chest_boat_spruce", "chest_boat_birch", "chest_boat_jungle", "chest_boat_acacia", "chest_boat_dark_oak", "chest_boat_mangrove" } local boat_ids = { "boat", "boat_spruce", "boat_birch", "boat_jungle", "boat_acacia", "boat_dark_oak", "boat_obsidian", "boat_mangrove", "chest_boat", "chest_boat_spruce", "chest_boat_birch", "chest_boat_jungle", "chest_boat_acacia", "chest_boat_dark_oak", "chest_boat_mangrove" }
local names = { S("Oak Boat"), S("Spruce Boat"), S("Birch Boat"), S("Jungle Boat"), S("Acacia Boat"), S("Dark Oak Boat"), S("Obsidian Boat"), S("Mangrove Boat"), S("Oak Chest Boat"), S("Spruce Chest Boat"), S("Birch Chest Boat"), S("Jungle Chest Boat"), S("Acacia Chest Boat"), S("Dark Oak Chest Boat"), S("Mangrove Chest Boat") } local names = { S("Oak Boat"), S("Spruce Boat"), S("Birch Boat"), S("Jungle Boat"), S("Acacia Boat"), S("Dark Oak Boat"), S("Obsidian Boat"), S("Mangrove Boat"), S("Oak Chest Boat"), S("Spruce Chest Boat"), S("Birch Chest Boat"), S("Jungle Chest Boat"), S("Acacia Chest Boat"), S("Dark Oak Chest Boat"), S("Mangrove Chest Boat") }
local craftstuffs = { "mcl_core:wood", "mcl_core:sprucewood", "mcl_core:birchwood", "mcl_core:junglewood", "mcl_core:acaciawood", "mcl_core:darkwood", "mcl_core:obsidian", "mcl_mangrove:mangrove_wood" } local craftstuffs = {}
if minetest.get_modpath("mcl_core") then
craftstuffs = { "mcl_core:wood", "mcl_core:sprucewood", "mcl_core:birchwood", "mcl_core:junglewood", "mcl_core:acaciawood", "mcl_core:darkwood", "mcl_core:obsidian", "mcl_mangrove:mangrove_wood" }
end
local images = { "oak", "spruce", "birch", "jungle", "acacia", "dark_oak", "obsidian", "mangrove", "oak_chest", "spruce_chest", "birch_chest", "jungle_chest", "acacia_chest", "dark_oak_chest", "mangrove_chest" }
for b=1, #boat_ids do for b=1, #boat_ids do
local itemstring = "mcl_boats:"..boat_ids[b] local itemstring = "mcl_boats:"..boat_ids[b]
@ -455,21 +453,6 @@ for b=1, #boat_ids do
end end
tt_help = S("Water vehicle") tt_help = S("Water vehicle")
local inventory_image
local texture
local id = boat_ids[b]
if id:find("chest") then
if id == "chest_boat" then id = "oak" end
local id = id:gsub("chest_boat_", "")
inventory_image = "mcl_boats_" .. id .. "_chest_boat.png"
texture = "mcl_boats_texture_" .. id .. "_boat.png"
else
if id == "boat" then id = "oak" end
local id = id:gsub("boat_", "")
inventory_image = "mcl_boats_" .. id .. "_boat.png"
texture = "mcl_boats_texture_" .. id .. "_boat.png"
end
minetest.register_craftitem(itemstring, { minetest.register_craftitem(itemstring, {
description = names[b], description = names[b],
_tt_help = tt_help, _tt_help = tt_help,
@ -477,7 +460,7 @@ for b=1, #boat_ids do
_doc_items_entry_name = helpname, _doc_items_entry_name = helpname,
_doc_items_longdesc = longdesc, _doc_items_longdesc = longdesc,
_doc_items_usagehelp = usagehelp, _doc_items_usagehelp = usagehelp,
inventory_image = inventory_image, inventory_image = "mcl_boats_"..images[b].."_boat.png",
liquids_pointable = true, liquids_pointable = true,
groups = { boat = 1, transport = 1}, groups = { boat = 1, transport = 1},
stack_max = 1, stack_max = 1,
@ -505,14 +488,13 @@ for b=1, #boat_ids do
pos = vector.add(pos, vector.multiply(dir, boat_y_offset_ground)) pos = vector.add(pos, vector.multiply(dir, boat_y_offset_ground))
end end
local boat_ent = "mcl_boats:boat" local boat_ent = "mcl_boats:boat"
local chest_tex = "blank.png"
if itemstring:find("chest") then if itemstring:find("chest") then
boat_ent = "mcl_boats:chest_boat" boat_ent = "mcl_boats:chest_boat"
chest_tex = "mcl_chests_normal.png"
end end
local boat = minetest.add_entity(pos, boat_ent) local boat = minetest.add_entity(pos, boat_ent)
local texture = "mcl_boats_texture_"..images[b].."_boat.png"
boat:get_luaentity()._itemstring = itemstring boat:get_luaentity()._itemstring = itemstring
boat:set_properties({ textures = { texture, chest_tex } }) boat:set_properties({textures = { texture, texture, texture, texture, texture }})
boat:set_yaw(placer:get_look_horizontal()) boat:set_yaw(placer:get_look_horizontal())
if not minetest.is_creative_enabled(placer:get_player_name()) then if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item() itemstack:take_item()

View File

@ -1,13 +0,0 @@
# textdomain: mcl_boats
Acacia Boat=アカシアのボート
Birch Boat=シラカバのボート
Boat=ボート
Boats are used to travel on the surface of water.=ボートは、水面を移動するために使われます。
Dark Oak Boat=ダークオークのボート
Jungle Boat=ジャングルのボート
Oak Boat=オークのボート
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Use [Sneak] to leave the boat, punch the boat to make it drop as an item.=水源を右クリックすると、ボートが配置されます。ボートを右クリックすると、乗り込みます。[左][右]で舵取り、[前]で加速、[後]で減速または後退します。[スニーク]でボートから離れ、ボートをパンチするとアイテムとしてドロップします。
Spruce Boat=トウヒのボート
Water vehicle=水上用の乗物
Sneak to dismount=スニークで降りる
Obsidian Boat=黒曜石のボート

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,36 +0,0 @@
# mcl_dripping
Dripping Mod by kddekadenz, modified for MineClone 2 by Wuzzy, NO11 and AFCM
## Manual
- drops are generated rarely under solid nodes
- they will stay some time at the generated block and than they fall down
- when they collide with the ground, a sound is played and they are destroyed
Water and Lava have builtin drops registered.
## License
code & sounds: CC0
## API
```lua
mcl_dripping.register_drop({
-- The group the liquid's nodes belong to
liquid = "water",
-- The texture used (particles will take a random 2x2 area of it)
texture = "default_water_source_animated.png",
-- Define particle glow, ranges from `0` to `minetest.LIGHT_MAX`
light = 1,
-- The nodes (or node group) the particles will spawn under
nodes = { "group:opaque", "group:leaves" },
-- The sound that will be played then the particle detaches from the roof, see SimpleSoundSpec in lua_api.txt
sound = "drippingwater_drip",
-- The interval for the ABM to run
interval = 60,
-- The chance of the ABM
chance = 10,
})
```

View File

@ -3,99 +3,53 @@
-- License of code, textures & sounds: CC0 -- License of code, textures & sounds: CC0
local math = math local math = math
local function make_drop(pos,liquid,sound,interval)
mcl_dripping = {}
---@param pos Vector
---@param liquid string
---@param sound SimpleSoundSpec
---@param interval integer
---@param texture string
local function make_drop(pos, liquid, sound, interval, texture)
local pt = { local pt = {
velocity = vector.zero(), velocity = vector.new(0,0,0),
collision_removal = false, collision_removal = false,
} }
local t = math.random() + math.random(1, interval) local t = math.random() + math.random(1, interval)
minetest.after(t,function()
minetest.after(t, function()
local x, z = math.random(-45, 45) / 100, math.random(-45, 45) / 100 local x, z = math.random(-45, 45) / 100, math.random(-45, 45) / 100
pt.pos = vector.offset(pos,x,-0.52,z)
pt.pos = vector.offset(pos, x, -0.52, z) pt.acceleration = vector.new(0,0,0)
pt.acceleration = vector.zero()
pt.collisiondetection = false pt.collisiondetection = false
pt.expirationtime = t pt.expirationtime = t
pt.texture = "[combine:2x2:" .. pt.texture="[combine:2x2:" .. -math.random(1, 16) .. "," .. -math.random(1, 16) .. "=default_" .. liquid .. "_source_animated.png"
-math.random(1, 16) .. "," .. -math.random(1, 16) .. "=" .. texture
minetest.add_particle(pt) minetest.add_particle(pt)
minetest.after(t,function()
minetest.after(t, function() pt.acceleration = vector.new(0,-5,0)
pt.acceleration = vector.new(0, -5, 0)
pt.collisiondetection = true pt.collisiondetection = true
pt.expirationtime = math.random() + math.random(1, interval / 2) pt.expirationtime = math.random() + math.random(1, interval/2)
minetest.add_particle(pt) minetest.add_particle(pt)
minetest.sound_play({name = "drippingwater_" .. sound .. "drip"}, {pos = pos, gain = 0.5, max_hear_distance = 8}, true)
minetest.sound_play(sound, { pos = pos, gain = 0.5, max_hear_distance = 8 },
true)
end) end)
end) end)
end end
---@class mcl_dripping_drop_definition local function register_drop(liquid, glow, sound, nodes, interval, chance)
---@field liquid string The group the liquid's nodes belong to
---@field texture string The texture used (particles will take a random 2x2 area of it)
---@field light integer Define particle glow, ranges from `0` to `minetest.LIGHT_MAX`
---@field nodes string[] The nodes (or node group) the particles will spawn under
---@field interval integer The interval for the ABM to run
---@field chance integer The chance of the ABM
---@field sound SimpleSoundSpec The sound that will be played then the particle detaches from the roof
---@param def mcl_dripping_drop_definition
function mcl_dripping.register_drop(def)
minetest.register_abm({ minetest.register_abm({
label = "Create drops", label = "Create drops",
nodenames = def.nodes, nodenames = nodes,
neighbors = { "group:" .. def.liquid }, neighbors = {"group:" .. liquid},
interval = def.interval, interval = interval,
chance = def.chance, chance = chance,
action = function(pos) action = function(pos)
local below = minetest.get_node(vector.offset(pos,0,-1,0)).name local r = math.ceil(interval / 20)
if below ~= "air" then return end local nn=minetest.find_nodes_in_area(vector.offset(pos,-r,0,-r),vector.offset(pos,r,0,r),nodes)
local r = math.ceil(def.interval / 20)
local nn = minetest.find_nodes_in_area(vector.offset(pos, -r, 0, -r), vector.offset(pos, r, 0, r), def.nodes)
--start a bunch of particle cycles to be able to get away --start a bunch of particle cycles to be able to get away
--with longer abm cycles --with longer abm cycles
table.shuffle(nn) table.shuffle(nn)
for i = 1, math.random(#nn) do for i=1,math.random(#nn) do
if minetest.get_item_group(minetest.get_node(vector.offset(nn[i], 0, 1, 0)).name, def.liquid) ~= 0 then if minetest.get_item_group(minetest.get_node(vector.offset(nn[i], 0, 1, 0)).name, liquid) ~= 0
make_drop(nn[i], def.liquid, def.sound, def.interval, def.texture) and minetest.get_node(vector.offset(nn[i], 0, -1, 0)).name == "air" then
make_drop(nn[i],liquid,sound,interval)
end end
end end
end, end,
}) })
end end
mcl_dripping.register_drop({ register_drop("water", 1, "", {"group:opaque", "group:leaves"},60,10)
liquid = "water", register_drop("lava", math.max(7, minetest.registered_nodes["mcl_core:lava_source"].light_source - 3), "lava", {"group:opaque"},60,10)
texture = "default_water_source_animated.png",
light = 1,
nodes = { "group:opaque", "group:leaves" },
sound = "drippingwater_drip",
interval = 60.3,
chance = 10,
})
mcl_dripping.register_drop({
liquid = "lava",
texture = "default_lava_source_animated.png",
light = math.max(7, minetest.registered_nodes["mcl_core:lava_source"].light_source - 3),
nodes = { "group:opaque" },
sound = "drippingwater_lavadrip",
interval = 110.1,
chance = 10,
})

View File

@ -0,0 +1,29 @@
Dripping Mod
by kddekadenz
modified for MineClone 2 by Wuzzy and NO11
Installing instructions:
1. Copy the mcl_dripping mod folder into games/gamemode/mods
2. Start game and enjoy :)
Manual:
-> drops are generated rarely under solid nodes
-> they will stay some time at the generated block and than they fall down
-> when they collide with the ground, a sound is played and they are destroyed
License:
code & sounds: CC0
Changelog:
16.04.2012 - first release
28.04.2012 - drops are now 3D; added lava drops; fixed generating of drops (not at edges now)

View File

@ -2,10 +2,6 @@ mcl_entity_invs = {}
local open_invs = {} local open_invs = {}
local function mcl_log (message)
mcl_util.mcl_log (message, "[Entity Invs]")
end
local function check_distance(inv,player,count) local function check_distance(inv,player,count)
for _,o in pairs(minetest.get_objects_inside_radius(player:get_pos(),5)) do for _,o in pairs(minetest.get_objects_inside_radius(player:get_pos(),5)) do
local l = o:get_luaentity() local l = o:get_luaentity()
@ -26,25 +22,20 @@ local inv_callbacks = {
end, end,
} }
function mcl_entity_invs.load_inv(ent,size) local function load_inv(ent,size)
mcl_log("load_inv")
if not ent._inv_id then return end if not ent._inv_id then return end
mcl_log("load_inv 2")
local inv = minetest.get_inventory({type="detached", name=ent._inv_id}) local inv = minetest.get_inventory({type="detached", name=ent._inv_id})
if not inv then if not inv then
mcl_log("load_inv 3")
inv = minetest.create_detached_inventory(ent._inv_id, inv_callbacks) inv = minetest.create_detached_inventory(ent._inv_id, inv_callbacks)
inv:set_size("main", size) inv:set_size("main", size)
if ent._items then if ent._items then
inv:set_list("main",ent._items) inv:set_list("main",ent._items)
end end
else
mcl_log("load_inv 4")
end end
return inv return inv
end end
function mcl_entity_invs.save_inv(ent) local function save_inv(ent)
if ent._inv then if ent._inv then
ent._items = {} ent._items = {}
for i,it in ipairs(ent._inv:get_list("main")) do for i,it in ipairs(ent._inv:get_list("main")) do
@ -55,60 +46,32 @@ function mcl_entity_invs.save_inv(ent)
end end
end end
local function load_default_formspec (ent, text)
text = text or ""
local invent_size = ent._inv_size
local div_by_two = invent_size % 2 == 0
local div_by_three = invent_size % 3 == 0
--mcl_log("Div by 3: ".. tostring(div_by_three))
--mcl_log("Div by 2: ".. tostring(div_by_two))
--mcl_log("invent_size: ".. tostring(invent_size))
local rows = 3
if invent_size > 18 or (div_by_three == true and invent_size > 8) then
--mcl_log("Div by 3")
rows = 3
elseif (div_by_two == true and invent_size > 3) or invent_size > 9 then
--mcl_log("Div by 2")
rows = 2
else
--mcl_log("Not div by 2 or 3")
rows = 1
end
--local rows = 3
local cols = (math.ceil(ent._inv_size/rows))
local spacing = (9 - cols) / 2
local formspec = "size[9,8.75]"
.. "label[0,0;" .. minetest.formspec_escape(
minetest.colorize("#313131", ent._inv_title .. " ".. text)) .. "]"
.. "list[detached:"..ent._inv_id..";main;"..spacing..",0.5;"..cols..","..rows..";]"
.. mcl_formspec.get_itemslot_bg(spacing,0.5,cols,rows)
.. "label[0,4.0;" .. minetest.formspec_escape(
minetest.colorize("#313131", "Inventory")) .. "]"
.. "list[current_player;main;0,4.5;9,3;9]"
.. mcl_formspec.get_itemslot_bg(0,4.5,9,3)
.. "list[current_player;main;0,7.74;9,1;]"
.. mcl_formspec.get_itemslot_bg(0,7.74,9,1)
.. "listring[detached:"..ent._inv_id..";main]"
.. "listring[current_player;main]"
return formspec
end
function mcl_entity_invs.show_inv_form(ent,player,text) function mcl_entity_invs.show_inv_form(ent,player,text)
if not ent._inv_id then return end if not ent._inv_id then return end
if not open_invs[ent] then if not open_invs[ent] then
open_invs[ent] = 0 open_invs[ent] = 0
end end
ent._inv = mcl_entity_invs.load_inv(ent,ent._inv_size) text = text or ""
ent._inv = load_inv(ent,ent._inv_size)
open_invs[ent] = open_invs[ent] + 1 open_invs[ent] = open_invs[ent] + 1
local playername = player:get_player_name() local playername = player:get_player_name()
local rows = 3
minetest.show_formspec(playername, ent._inv_id, load_default_formspec (ent, text)) local cols = (math.ceil(ent._inv_size/rows))
local spacing = (9 - cols) / 2
local formspec = "size[9,8.75]"
.. "label[0,0;" .. minetest.formspec_escape(
minetest.colorize("#313131", ent._inv_title .. " ".. text)) .. "]"
.. "list[detached:"..ent._inv_id..";main;"..spacing..",0.5;"..cols..","..rows..";]"
.. mcl_formspec.get_itemslot_bg(spacing,0.5,cols,rows)
.. "label[0,4.0;" .. minetest.formspec_escape(
minetest.colorize("#313131", "Inventory")) .. "]"
.. "list[current_player;main;0,4.5;9,3;9]"
.. mcl_formspec.get_itemslot_bg(0,4.5,9,3)
.. "list[current_player;main;0,7.74;9,1;]"
.. mcl_formspec.get_itemslot_bg(0,7.74,9,1)
.. "listring[detached:"..ent._inv_id..";main]"
.. "listring[current_player;main]"
minetest.show_formspec(playername,ent._inv_id,formspec)
end end
local function drop_inv(ent) local function drop_inv(ent)
@ -122,9 +85,9 @@ local function drop_inv(ent)
end end
local function on_remove(self,killer,oldf) local function on_remove(self,killer,oldf)
mcl_entity_invs.save_inv(self) save_inv(self)
drop_inv(self) drop_inv(self)
if oldf then return oldf(self,killer) end if oldf then return oldf(self,killer) end
end end
minetest.register_on_player_receive_fields(function(player, formname, fields) minetest.register_on_player_receive_fields(function(player, formname, fields)
@ -132,7 +95,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == k._inv_id then if formname == k._inv_id then
open_invs[k] = open_invs[k] - 1 open_invs[k] = open_invs[k] - 1
if open_invs[k] < 1 then if open_invs[k] < 1 then
mcl_entity_invs.save_inv(k) save_inv(k)
open_invs[k] = nil open_invs[k] = nil
end end
end end
@ -188,7 +151,7 @@ function mcl_entity_invs.register_inv(entity_name,show_name,size,no_on_righclick
local old_ode = minetest.registered_entities[entity_name].on_deactivate local old_ode = minetest.registered_entities[entity_name].on_deactivate
minetest.registered_entities[entity_name].on_deactivate = function(self,removal) minetest.registered_entities[entity_name].on_deactivate = function(self,removal)
mcl_entity_invs.save_inv(self) save_inv(self)
if removal then if removal then
on_remove(self) on_remove(self)
end end

View File

@ -25,10 +25,4 @@ http://minetest.net/
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO. 0. You just DO WHAT THE FUCK YOU WANT TO.
---------
Alterations and contributions are released under GNU GPLv3 after 11/11/2022 and for contributors:
AncientMariner/ancientmarinerdev

View File

@ -6,25 +6,22 @@ local pool = {}
local tick = false local tick = false
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_item_entities", false)
local function mcl_log(message)
if LOGGING_ON then
mcl_util.mcl_log(message, "[Item Entities]", true)
end
end
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
pool[player:get_player_name()] = 0 local name
name = player:get_player_name()
pool[name] = 0
end) end)
minetest.register_on_leaveplayer(function(player) minetest.register_on_leaveplayer(function(player)
pool[player:get_player_name()] = nil local name
name = player:get_player_name()
pool[name] = nil
end) end)
local has_awards = minetest.get_modpath("awards") local has_awards = minetest.get_modpath("awards")
mcl_item_entity = {} local mcl_item_entity = {}
--basic settings --basic settings
local item_drop_settings = {} --settings table local item_drop_settings = {} --settings table
@ -39,29 +36,22 @@ item_drop_settings.random_item_velocity = true --this sets random item velocity
item_drop_settings.drop_single_item = false --if true, the drop control drops 1 item instead of the entire stack, and sneak+drop drops the stack item_drop_settings.drop_single_item = false --if true, the drop control drops 1 item instead of the entire stack, and sneak+drop drops the stack
-- drop_single_item is disabled by default because it is annoying to throw away items from the intentory screen -- drop_single_item is disabled by default because it is annoying to throw away items from the intentory screen
item_drop_settings.magnet_time = 0.75 -- how many seconds an item follows the player before giving up item_drop_settings.magnet_time = 0.75 -- how many seconds an item follows the player before giving up
local function get_gravity() local function get_gravity()
return tonumber(minetest.settings:get("movement_gravity")) or 9.81 return tonumber(minetest.settings:get("movement_gravity")) or 9.81
end end
mcl_item_entity.registered_pickup_achievement = {} local registered_pickup_achievement = {}
---Register an achievement that will be unlocked on pickup. --TODO: remove limitation of 1 award per itemname
---
---TODO: remove limitation of 1 award per itemname
---@param itemname string
---@param award string
function mcl_item_entity.register_pickup_achievement(itemname, award) function mcl_item_entity.register_pickup_achievement(itemname, award)
if not has_awards then if not has_awards then
minetest.log("warning", minetest.log("warning", "[mcl_item_entity] Trying to register pickup achievement ["..award.."] for ["..itemname.."] while awards missing")
"[mcl_item_entity] Trying to register pickup achievement [" .. award .. "] for [" .. elseif registered_pickup_achievement[itemname] then
itemname .. "] while awards missing") minetest.log("error", "[mcl_item_entity] Trying to register already existing pickup achievement ["..award.."] for ["..itemname.."]")
elseif mcl_item_entity.registered_pickup_achievement[itemname] then
minetest.log("error",
"[mcl_item_entity] Trying to register already existing pickup achievement [" .. award .. "] for [" .. itemname .. "]")
else else
mcl_item_entity.registered_pickup_achievement[itemname] = award registered_pickup_achievement[itemname] = award
end end
end end
@ -74,13 +64,11 @@ mcl_item_entity.register_pickup_achievement("mcl_nether:ancient_debris", "mcl:hi
mcl_item_entity.register_pickup_achievement("mcl_end:dragon_egg", "mcl:PickUpDragonEgg") mcl_item_entity.register_pickup_achievement("mcl_end:dragon_egg", "mcl:PickUpDragonEgg")
mcl_item_entity.register_pickup_achievement("mcl_armor:elytra", "mcl:skysTheLimit") mcl_item_entity.register_pickup_achievement("mcl_armor:elytra", "mcl:skysTheLimit")
---@param object ObjectRef
---@param player ObjectRef
local function check_pickup_achievements(object, player) local function check_pickup_achievements(object, player)
if has_awards then if has_awards then
local itemname = ItemStack(object:get_luaentity().itemstring):get_name() local itemname = ItemStack(object:get_luaentity().itemstring):get_name()
local playername = player:get_player_name() local playername = player:get_player_name()
for name, award in pairs(mcl_item_entity.registered_pickup_achievement) do for name,award in pairs(registered_pickup_achievement) do
if itemname == name or minetest.get_item_group(itemname, name) ~= 0 then if itemname == name or minetest.get_item_group(itemname, name) ~= 0 then
awards.unlock(playername, award) awards.unlock(playername, award)
end end
@ -88,23 +76,16 @@ local function check_pickup_achievements(object, player)
end end
end end
---@param object ObjectRef
---@param luaentity Luaentity
---@param ignore_check? boolean
local function enable_physics(object, luaentity, ignore_check) local function enable_physics(object, luaentity, ignore_check)
if luaentity.physical_state == false or ignore_check == true then if luaentity.physical_state == false or ignore_check == true then
luaentity.physical_state = true luaentity.physical_state = true
object:set_properties({ object:set_properties({
physical = true physical = true
}) })
object:set_acceleration(vector.new(0, -get_gravity(), 0)) object:set_acceleration({x=0,y=-get_gravity(),z=0})
end end
end end
---@param object ObjectRef
---@param luaentity Luaentity
---@param ignore_check? boolean
---@param reset_movement? boolean
local function disable_physics(object, luaentity, ignore_check, reset_movement) local function disable_physics(object, luaentity, ignore_check, reset_movement)
if luaentity.physical_state == true or ignore_check == true then if luaentity.physical_state == true or ignore_check == true then
luaentity.physical_state = false luaentity.physical_state = false
@ -112,16 +93,17 @@ local function disable_physics(object, luaentity, ignore_check, reset_movement)
physical = false physical = false
}) })
if reset_movement ~= false then if reset_movement ~= false then
object:set_velocity(vector.zero()) object:set_velocity({x=0,y=0,z=0})
object:set_acceleration(vector.zero()) object:set_acceleration({x=0,y=0,z=0})
end end
end end
end end
minetest.register_globalstep(function(_)
minetest.register_globalstep(function(dtime)
tick = not tick tick = not tick
for _, player in pairs(minetest.get_connected_players()) do for _,player in pairs(minetest.get_connected_players()) do
if player:get_hp() > 0 or not minetest.settings:get_bool("enable_damage") then if player:get_hp() > 0 or not minetest.settings:get_bool("enable_damage") then
local name = player:get_player_name() local name = player:get_player_name()
@ -133,7 +115,7 @@ minetest.register_globalstep(function(_)
pos = pos, pos = pos,
gain = 0.3, gain = 0.3,
max_hear_distance = 16, max_hear_distance = 16,
pitch = math.random(70, 110) / 100 pitch = math.random(70,110)/100
}) })
if pool[name] > 6 then if pool[name] > 6 then
pool[name] = 6 pool[name] = 6
@ -143,18 +125,15 @@ minetest.register_globalstep(function(_)
end end
local inv = player:get_inventory() local inv = player:get_inventory()
local checkpos = vector.offset(pos, 0, item_drop_settings.player_collect_height, 0) local checkpos = {x=pos.x,y=pos.y + item_drop_settings.player_collect_height,z=pos.z}
--magnet and collection --magnet and collection
for _, object in pairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do for _,object in pairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do
if not object:is_player() and vector.distance(checkpos, object:get_pos()) < item_drop_settings.radius_magnet and 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() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer
and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
if object:get_luaentity()._magnet_timer >= 0 and 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
object:get_luaentity()._magnet_timer < item_drop_settings.magnet_time and inv and
inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
-- Collection -- Collection
if not object:get_luaentity()._removed then if not object:get_luaentity()._removed then
@ -169,8 +148,8 @@ minetest.register_globalstep(function(_)
object:get_luaentity().target = checkpos object:get_luaentity().target = checkpos
object:get_luaentity()._removed = true object:get_luaentity()._removed = true
object:set_velocity(vector.zero()) object:set_velocity({x=0,y=0,z=0})
object:set_acceleration(vector.zero()) object:set_acceleration({x=0,y=0,z=0})
object:move_to(checkpos) object:move_to(checkpos)
@ -190,6 +169,7 @@ minetest.register_globalstep(function(_)
local entity = object:get_luaentity() local entity = object:get_luaentity()
entity.collector = player:get_player_name() entity.collector = player:get_player_name()
entity.collected = true entity.collected = true
end end
end end
@ -204,11 +184,6 @@ end)
local tmp_id = 0 local tmp_id = 0
---@param drop string|drop_definition
---@param toolname string
---@param param2 integer
---@param paramtype2 paramtype2
---@return string[]
local function get_drops(drop, toolname, param2, paramtype2) local function get_drops(drop, toolname, param2, paramtype2)
tmp_id = tmp_id + 1 tmp_id = tmp_id + 1
local tmp_node_name = "mcl_item_entity:" .. tmp_id local tmp_node_name = "mcl_item_entity:" .. tmp_id
@ -217,7 +192,7 @@ local function get_drops(drop, toolname, param2, paramtype2)
drop = drop, drop = drop,
paramtype2 = paramtype2 paramtype2 = paramtype2
} }
local drops = minetest.get_node_drops({ name = tmp_node_name, param2 = param2 }, toolname) local drops = minetest.get_node_drops({name = tmp_node_name, param2 = param2}, toolname)
minetest.registered_nodes[tmp_node_name] = nil minetest.registered_nodes[tmp_node_name] = nil
return drops return drops
end end
@ -252,17 +227,10 @@ function minetest.handle_node_drops(pos, drops, digger)
-- NOTE: This function override allows digger to be nil. -- NOTE: This function override allows digger to be nil.
-- This means there is no digger. This is a special case which allows this function to be called -- This means there is no digger. This is a special case which allows this function to be called
-- by hand. Creative Mode is intentionally ignored in this case. -- by hand. Creative Mode is intentionally ignored in this case.
if digger and digger:is_player() and minetest.is_creative_enabled(digger:get_player_name()) then
local inv = digger:get_inventory() if (digger and digger:is_player() and minetest.is_creative_enabled(digger:get_player_name())) or doTileDrops == false then
if inv then
for _, item in ipairs(drops) do
if not inv:contains_item("main", item, true) then
inv:add_item("main", item)
end
end
end
return return
elseif not doTileDrops then return end end
-- Check if node will yield its useful drop by the digger's tool -- Check if node will yield its useful drop by the digger's tool
local dug_node = minetest.get_node(pos) local dug_node = minetest.get_node(pos)
@ -270,9 +238,9 @@ function minetest.handle_node_drops(pos, drops, digger)
local tool local tool
if digger then if digger then
tool = digger:get_wielded_item() tool = digger:get_wielded_item()
tooldef = minetest.registered_items[tool:get_name()] tooldef = minetest.registered_tools[tool:get_name()]
if not mcl_autogroup.can_harvest(dug_node.name, tool:get_name(), digger) then if not mcl_autogroup.can_harvest(dug_node.name, tool:get_name()) then
return return
end end
end end
@ -287,7 +255,7 @@ function minetest.handle_node_drops(pos, drops, digger)
* table: Drop every itemstring in this table when dug by shears _mcl_silk_touch_drop * table: Drop every itemstring in this table when dug by shears _mcl_silk_touch_drop
]] ]]
local enchantments = tool and mcl_enchanting.get_enchantments(tool) local enchantments = tool and mcl_enchanting.get_enchantments(tool, "silk_touch")
local silk_touch_drop = false local silk_touch_drop = false
local nodedef = minetest.registered_nodes[dug_node.name] local nodedef = minetest.registered_nodes[dug_node.name]
@ -316,8 +284,7 @@ function minetest.handle_node_drops(pos, drops, digger)
local max_count = fortune_drop.max_count + fortune_level * (fortune_drop.factor or 1) local max_count = fortune_drop.max_count + fortune_level * (fortune_drop.factor or 1)
local chance = fortune_drop.chance or fortune_drop.get_chance and fortune_drop.get_chance(fortune_level) local chance = fortune_drop.chance or fortune_drop.get_chance and fortune_drop.get_chance(fortune_level)
if not chance or math.random() < chance then if not chance or math.random() < chance then
drops = discrete_uniform_distribution(fortune_drop.multiply and drops or fortune_drop.items, min_count, max_count, drops = discrete_uniform_distribution(fortune_drop.multiply and drops or fortune_drop.items, min_count, max_count, fortune_drop.cap)
fortune_drop.cap)
elseif fortune_drop.override then elseif fortune_drop.override then
drops = {} drops = {}
end end
@ -329,13 +296,13 @@ function minetest.handle_node_drops(pos, drops, digger)
end end
if digger and mcl_experience.throw_xp and not silk_touch_drop then if digger and mcl_experience.throw_xp and not silk_touch_drop then
local experience_amount = minetest.get_item_group(dug_node.name, "xp") local experience_amount = minetest.get_item_group(dug_node.name,"xp")
if experience_amount > 0 then if experience_amount > 0 then
mcl_experience.throw_xp(pos, experience_amount) mcl_experience.throw_xp(pos, experience_amount)
end end
end end
for _, item in ipairs(drops) do for _,item in ipairs(drops) do
local count local count
if type(item) == "string" then if type(item) == "string" then
count = ItemStack(item):get_count() count = ItemStack(item):get_count()
@ -344,7 +311,7 @@ function minetest.handle_node_drops(pos, drops, digger)
end end
local drop_item = ItemStack(item) local drop_item = ItemStack(item)
drop_item:set_count(1) drop_item:set_count(1)
for i = 1, count do for i=1,count do
local dpos = table.copy(pos) local dpos = table.copy(pos)
-- Apply offset for plantlike_rooted nodes because of their special shape -- Apply offset for plantlike_rooted nodes because of their special shape
if nodedef and nodedef.drawtype == "plantlike_rooted" and nodedef.walkable then if nodedef and nodedef.drawtype == "plantlike_rooted" and nodedef.walkable then
@ -371,7 +338,7 @@ end
function minetest.item_drop(itemstack, dropper, pos) function minetest.item_drop(itemstack, dropper, pos)
if dropper and dropper:is_player() then if dropper and dropper:is_player() then
local v = dropper:get_look_dir() local v = dropper:get_look_dir()
local p = vector.offset(pos, 0, 1.2, 0) local p = {x=pos.x, y=pos.y+1.2, z=pos.z}
local cs = itemstack:get_count() local cs = itemstack:get_count()
if dropper:get_player_control().sneak then if dropper:get_player_control().sneak then
cs = 1 cs = 1
@ -379,9 +346,9 @@ function minetest.item_drop(itemstack, dropper, pos)
local item = itemstack:take_item(cs) local item = itemstack:take_item(cs)
local obj = minetest.add_item(p, item) local obj = minetest.add_item(p, item)
if obj then if obj then
v.x = v.x * 4 v.x = v.x*4
v.y = v.y * 4 + 2 v.y = v.y*4 + 2
v.z = v.z * 4 v.z = v.z*4
obj:set_velocity(v) obj:set_velocity(v)
-- Force collection delay -- Force collection delay
obj:get_luaentity()._insta_collect = false obj:get_luaentity()._insta_collect = false
@ -399,137 +366,27 @@ end
local function cxcz(o, cw, one, zero) local function cxcz(o, cw, one, zero)
if cw < 0 then if cw < 0 then
table.insert(o, { [one] = 1, y = 0, [zero] = 0 }) table.insert(o, { [one]=1, y=0, [zero]=0 })
table.insert(o, { [one] = -1, y = 0, [zero] = 0 }) table.insert(o, { [one]=-1, y=0, [zero]=0 })
else else
table.insert(o, { [one] = -1, y = 0, [zero] = 0 }) table.insert(o, { [one]=-1, y=0, [zero]=0 })
table.insert(o, { [one] = 1, y = 0, [zero] = 0 }) table.insert(o, { [one]=1, y=0, [zero]=0 })
end end
return o return o
end end
local function hopper_take_item(self, pos)
--mcl_log("self.itemstring: ".. self.itemstring)
--mcl_log("self.itemstring: ".. minetest.pos_to_string(pos))
local objs = minetest.get_objects_inside_radius(pos, 2)
if objs and self.itemstring then
--mcl_log("there is an itemstring. Number of objs: ".. #objs)
for k, v in pairs(objs) do
local ent = v:get_luaentity()
-- Don't forget actual hoppers
if ent and ent.name == "mcl_minecarts:hopper_minecart" then
local taken_items = false
mcl_log("ent.name: " .. tostring(ent.name))
mcl_log("ent pos: " .. tostring(ent.object:get_pos()))
local inv = mcl_entity_invs.load_inv(ent, 5)
if not inv then
mcl_log("No inv")
return false
end
local current_itemstack = ItemStack(self.itemstring)
mcl_log("inv. size: " .. ent._inv_size)
if inv:room_for_item("main", current_itemstack) then
mcl_log("Room")
inv:add_item("main", current_itemstack)
self.object:get_luaentity().itemstring = ""
self.object:remove()
taken_items = true
else
mcl_log("no Room")
end
if not taken_items then
local items_remaining = current_itemstack:get_count()
-- This will take part of a floating item stack if no slot can hold the full amount
for i = 1, ent._inv_size, 1 do
local stack = inv:get_stack("main", i)
mcl_log("i: " .. tostring(i))
mcl_log("Items remaining: " .. items_remaining)
mcl_log("Name: " .. tostring(stack:get_name()))
if current_itemstack:get_name() == stack:get_name() then
mcl_log("We have a match. Name: " .. tostring(stack:get_name()))
local room_for = stack:get_stack_max() - stack:get_count()
mcl_log("Room for: " .. tostring(room_for))
if room_for == 0 then
-- Do nothing
mcl_log("No room")
elseif room_for < items_remaining then
mcl_log("We have more items remaining than space")
items_remaining = items_remaining - room_for
stack:set_count(stack:get_stack_max())
inv:set_stack("main", i, stack)
taken_items = true
else
local new_stack_size = stack:get_count() + items_remaining
stack:set_count(new_stack_size)
mcl_log("We have more than enough space. Now holds: " .. new_stack_size)
inv:set_stack("main", i, stack)
items_remaining = 0
self.object:get_luaentity().itemstring = ""
self.object:remove()
taken_items = true
break
end
mcl_log("Count: " .. tostring(stack:get_count()))
mcl_log("stack max: " .. tostring(stack:get_stack_max()))
--mcl_log("Is it empty: " .. stack:to_string())
end
if i == ent._inv_size and taken_items then
mcl_log("We are on last item and still have items left. Set final stack size: " .. items_remaining)
current_itemstack:set_count(items_remaining)
--mcl_log("Itemstack2: " .. current_itemstack:to_string())
self.itemstring = current_itemstack:to_string()
end
end
end
--Add in, and delete
if taken_items then
mcl_log("Saving")
mcl_entity_invs.save_inv(ent)
return taken_items
else
mcl_log("No need to save")
end
end
end
end
return false
end
minetest.register_entity(":__builtin:item", { minetest.register_entity(":__builtin:item", {
initial_properties = { initial_properties = {
hp_max = 1, hp_max = 1,
physical = true, physical = true,
collide_with_objects = false, collide_with_objects = false,
collisionbox = { -0.3, -0.3, -0.3, 0.3, 0.3, 0.3 }, collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
pointable = false, pointable = false,
visual = "wielditem", visual = "wielditem",
visual_size = { x = 0.4, y = 0.4 }, visual_size = {x = 0.4, y = 0.4},
textures = { "" }, textures = {""},
spritediv = { x = 1, y = 1 }, spritediv = {x = 1, y = 1},
initial_sprite_basepos = { x = 0, y = 0 }, initial_sprite_basepos = {x = 0, y = 0},
is_visible = false, is_visible = false,
infotext = "", infotext = "",
}, },
@ -567,11 +424,11 @@ minetest.register_entity(":__builtin:item", {
if vel and vel.x == 0 and vel.z == 0 and self.random_velocity > 0 then if vel and vel.x == 0 and vel.z == 0 and self.random_velocity > 0 then
local v = self.random_velocity local v = self.random_velocity
local x = math.random(5, 10) / 10 * v local x = math.random(5, 10) / 10 * v
if math.random(0, 10) < 5 then x = -x end if math.random(0,10) < 5 then x = -x end
local z = math.random(5, 10) / 10 * v local z = math.random(5, 10) / 10 * v
if math.random(0, 10) < 5 then z = -z end if math.random(0,10) < 5 then z = -z end
local y = math.random(2, 4) local y = math.random(2,4)
self.object:set_velocity(vector.new(x, y, z)) self.object:set_velocity({x=x, y=y, z=z})
end end
self.random_velocity = 0 self.random_velocity = 0
end, end,
@ -599,7 +456,7 @@ minetest.register_entity(":__builtin:item", {
local max_count = stack:get_stack_max() local max_count = stack:get_stack_max()
if count > max_count then if count > max_count then
count = max_count count = max_count
self.itemstring = stack:get_name() .. " " .. max_count self.itemstring = stack:get_name().." "..max_count
end end
local itemtable = stack:to_table() local itemtable = stack:to_table()
local itemname = nil local itemname = nil
@ -620,9 +477,9 @@ minetest.register_entity(":__builtin:item", {
local prop = { local prop = {
is_visible = true, is_visible = true,
visual = "wielditem", visual = "wielditem",
textures = { itemname }, textures = {itemname},
visual_size = { x = s, y = s }, visual_size = {x = s, y = s},
collisionbox = { -c, -c, -c, c, c, c }, collisionbox = {-c, -c, -c, c, c, c},
automatic_rotate = math.pi * 0.5, automatic_rotate = math.pi * 0.5,
infotext = description, infotext = description,
glow = glow, glow = glow,
@ -718,9 +575,9 @@ minetest.register_entity(":__builtin:item", {
self._forcestart = nil self._forcestart = nil
self._forcetimer = 0 self._forcetimer = 0
self.object:set_armor_groups({ immortal = 1 }) self.object:set_armor_groups({immortal = 1})
-- self.object:set_velocity(vector.new(0, 2, 0)) -- self.object:set_velocity({x = 0, y = 2, z = 0})
self.object:set_acceleration(vector.new(0, -get_gravity(), 0)) self.object:set_acceleration({x = 0, y = -get_gravity(), z = 0})
self:set_item(self.itemstring) self:set_item(self.itemstring)
end, end,
@ -733,9 +590,9 @@ minetest.register_entity(":__builtin:item", {
local stack = ItemStack(entity.itemstring) local stack = ItemStack(entity.itemstring)
local name = stack:get_name() local name = stack:get_name()
if own_stack:get_name() ~= name or if own_stack:get_name() ~= name or
own_stack:get_meta() ~= stack:get_meta() or own_stack:get_meta() ~= stack:get_meta() or
own_stack:get_wear() ~= stack:get_wear() or own_stack:get_wear() ~= stack:get_wear() or
own_stack:get_free_space() == 0 then own_stack:get_free_space() == 0 then
-- Can not merge different or full stack -- Can not merge different or full stack
return false return false
end end
@ -768,8 +625,8 @@ minetest.register_entity(":__builtin:item", {
self.object:set_properties({ self.object:set_properties({
physical = false physical = false
}) })
self.object:set_velocity(vector.zero()) self.object:set_velocity({x=0,y=0,z=0})
self.object:set_acceleration(vector.zero()) self.object:set_acceleration({x=0,y=0,z=0})
return return
end end
self.age = self.age + dtime self.age = self.age + dtime
@ -784,22 +641,15 @@ minetest.register_entity(":__builtin:item", {
-- Delete corrupted item entities. The itemstring MUST be non-empty on its first step, -- Delete corrupted item entities. The itemstring MUST be non-empty on its first step,
-- otherwise there might have some data corruption. -- otherwise there might have some data corruption.
if self.itemstring == "" then if self.itemstring == "" then
minetest.log("warning", minetest.log("warning", "Item entity with empty itemstring found at "..minetest.pos_to_string(self.object:get_pos()).. "! Deleting it now.")
"Item entity with empty itemstring found at " .. minetest.pos_to_string(self.object:get_pos()) ..
"! Deleting it now.")
self._removed = true self._removed = true
self.object:remove() self.object:remove()
return return
end end
local p = self.object:get_pos() local p = self.object:get_pos()
-- If hopper has taken item, it has gone, and no operations should be conducted on this item local node = minetest.get_node_or_nil(p)
if hopper_take_item(self, p) then local in_unloaded = (node == nil)
return
end
local node = minetest.get_node(p)
local in_unloaded = node.name == "ignore"
if in_unloaded then if in_unloaded then
-- Don't infinetly fall into unloaded map -- Don't infinetly fall into unloaded map
@ -809,27 +659,27 @@ minetest.register_entity(":__builtin:item", {
if self.is_clock then if self.is_clock then
self.object:set_properties({ self.object:set_properties({
textures = { "mcl_clock:clock_" .. (mcl_worlds.clock_works(p) and mcl_clock.old_time or mcl_clock.random_frame) } textures = {"mcl_clock:clock_" .. (mcl_worlds.clock_works(p) and mcl_clock.old_time or mcl_clock.random_frame)}
}) })
end end
local nn = node.name local nn = node.name
local is_in_water = (minetest.get_item_group(nn, "liquid") ~= 0) local is_in_water = (minetest.get_item_group(nn, "liquid") ~= 0)
local nn_above = minetest.get_node(vector.offset(p, 0, 0.1, 0)).name local nn_above = minetest.get_node({x=p.x, y=p.y+0.1, z=p.z}).name
-- make sure it's more or less stationary and is at water level -- make sure it's more or less stationary and is at water level
local sleep_threshold = 0.3 local sleep_threshold = 0.3
local is_floating = false local is_floating = false
local is_stationary = math.abs(self.object:get_velocity().x) < sleep_threshold local is_stationary = math.abs(self.object:get_velocity().x) < sleep_threshold
and math.abs(self.object:get_velocity().y) < sleep_threshold and math.abs(self.object:get_velocity().y) < sleep_threshold
and math.abs(self.object:get_velocity().z) < sleep_threshold and math.abs(self.object:get_velocity().z) < sleep_threshold
if is_in_water and is_stationary then if is_in_water and is_stationary then
is_floating = (is_in_water is_floating = (is_in_water
and (minetest.get_item_group(nn_above, "liquid") == 0)) and (minetest.get_item_group(nn_above, "liquid") == 0))
end end
if is_floating and self.physical_state == true then if is_floating and self.physical_state == true then
self.object:set_velocity(vector.zero()) self.object:set_velocity({x = 0, y = 0, z = 0})
self.object:set_acceleration(vector.zero()) self.object:set_acceleration({x = 0, y = 0, z = 0})
disable_physics(self.object, self) disable_physics(self.object, self)
end end
-- If no collector was found for a long enough time, declare the magnet as disabled -- If no collector was found for a long enough time, declare the magnet as disabled
@ -849,7 +699,7 @@ minetest.register_entity(":__builtin:item", {
--Wait 2 seconds to allow mob drops to be cooked, & picked up instead of instantly destroyed. --Wait 2 seconds to allow mob drops to be cooked, & picked up instead of instantly destroyed.
if self.age > 2 and minetest.get_item_group(self.itemstring, "fire_immune") == 0 then if self.age > 2 and minetest.get_item_group(self.itemstring, "fire_immune") == 0 then
if dg ~= 2 then if dg ~= 2 then
minetest.sound_play("builtin_item_lava", { pos = self.object:get_pos(), gain = 0.5 }) minetest.sound_play("builtin_item_lava", {pos = self.object:get_pos(), gain = 0.5})
end end
self._removed = true self._removed = true
self.object:remove() self.object:remove()
@ -889,7 +739,7 @@ minetest.register_entity(":__builtin:item", {
end end
-- Check which one of the 4 sides is free -- Check which one of the 4 sides is free
for o = 1, #order do for o=1, #order do
local nn = minetest.get_node(vector.add(p, order[o])).name local nn = minetest.get_node(vector.add(p, order[o])).name
local def = minetest.registered_nodes[nn] local def = minetest.registered_nodes[nn]
if def and def.walkable == false and nn ~= "ignore" then if def and def.walkable == false and nn ~= "ignore" then
@ -899,7 +749,7 @@ minetest.register_entity(":__builtin:item", {
end end
-- If none of the 4 sides is free, shoot upwards -- If none of the 4 sides is free, shoot upwards
if shootdir == nil then if shootdir == nil then
shootdir = vector.new(0, 1, 0) shootdir = { x=0, y=1, z=0 }
local nn = minetest.get_node(vector.add(p, shootdir)).name local nn = minetest.get_node(vector.add(p, shootdir)).name
if nn == "ignore" then if nn == "ignore" then
-- Do not push into ignore -- Do not push into ignore
@ -909,7 +759,7 @@ minetest.register_entity(":__builtin:item", {
-- Set new item moving speed accordingly -- Set new item moving speed accordingly
local newv = vector.multiply(shootdir, 3) local newv = vector.multiply(shootdir, 3)
self.object:set_acceleration(vector.zero()) self.object:set_acceleration({x = 0, y = 0, z = 0})
self.object:set_velocity(newv) self.object:set_velocity(newv)
disable_physics(self.object, self, false, false) disable_physics(self.object, self, false, false)
@ -931,10 +781,10 @@ minetest.register_entity(":__builtin:item", {
if self._forcetimer > 0 then if self._forcetimer > 0 then
local cbox = self.object:get_properties().collisionbox local cbox = self.object:get_properties().collisionbox
local ok = false local ok = false
if self._force.x > 0 and (p.x > (self._forcestart.x + 0.5 + (cbox[4] - cbox[1]) / 2)) then ok = true if self._force.x > 0 and (p.x > (self._forcestart.x + 0.5 + (cbox[4] - cbox[1])/2)) then ok = true
elseif self._force.x < 0 and (p.x < (self._forcestart.x + 0.5 - (cbox[4] - cbox[1]) / 2)) then ok = true elseif self._force.x < 0 and (p.x < (self._forcestart.x + 0.5 - (cbox[4] - cbox[1])/2)) then ok = true
elseif self._force.z > 0 and (p.z > (self._forcestart.z + 0.5 + (cbox[6] - cbox[3]) / 2)) then ok = true elseif self._force.z > 0 and (p.z > (self._forcestart.z + 0.5 + (cbox[6] - cbox[3])/2)) then ok = true
elseif self._force.z < 0 and (p.z < (self._forcestart.z + 0.5 - (cbox[6] - cbox[3]) / 2)) then ok = true end elseif self._force.z < 0 and (p.z < (self._forcestart.z + 0.5 - (cbox[6] - cbox[3])/2)) then ok = true end
-- Item was successfully forced out. No more pushing -- Item was successfully forced out. No more pushing
if ok then if ok then
self._forcetimer = -1 self._forcetimer = -1
@ -965,7 +815,7 @@ minetest.register_entity(":__builtin:item", {
-- Set new item moving speed into the direciton of the liquid -- Set new item moving speed into the direciton of the liquid
local newv = vector.multiply(vec, f) local newv = vector.multiply(vec, f)
-- Swap to acceleration instead of a static speed to better mimic MC mechanics. -- Swap to acceleration instead of a static speed to better mimic MC mechanics.
self.object:set_acceleration(vector.new(newv.x, -0.22, newv.z)) self.object:set_acceleration({x = newv.x, y = -0.22, z = newv.z})
self.physical_state = true self.physical_state = true
self._flowing = true self._flowing = true
@ -978,10 +828,9 @@ minetest.register_entity(":__builtin:item", {
local cur_vec = self.object:get_velocity() local cur_vec = self.object:get_velocity()
-- apply some acceleration in the opposite direction so it doesn't slide forever -- apply some acceleration in the opposite direction so it doesn't slide forever
local vec = { local vec = {
x = 0 - cur_vec.x * 0.9, x = 0 -cur_vec.x*0.9,
y = 3 - cur_vec.y * 0.9, y = 3 -cur_vec.y*0.9,
z = 0 - cur_vec.z * 0.9 z = 0 -cur_vec.z*0.9}
}
self.object:set_acceleration(vec) self.object:set_acceleration(vec)
-- slow down the item in water -- slow down the item in water
local vel = self.object:get_velocity() local vel = self.object:get_velocity()
@ -1005,20 +854,20 @@ minetest.register_entity(":__builtin:item", {
end end
-- If node is not registered or node is walkably solid and resting on nodebox -- If node is not registered or node is walkably solid and resting on nodebox
local nn = minetest.get_node(vector.offset(p, 0, -0.5, 0)).name local nn = minetest.get_node({x=p.x, y=p.y-0.5, z=p.z}).name
local def = minetest.registered_nodes[nn] local def = minetest.registered_nodes[nn]
local v = self.object:get_velocity() local v = self.object:get_velocity()
local is_on_floor = def and (def.walkable local is_on_floor = def and (def.walkable
and not def.groups.slippery and v.y == 0) and not def.groups.slippery and v.y == 0)
if not minetest.registered_nodes[nn] if not minetest.registered_nodes[nn]
or is_floating or is_on_floor then or is_floating or is_on_floor then
local own_stack = ItemStack(self.object:get_luaentity().itemstring) local own_stack = ItemStack(self.object:get_luaentity().itemstring)
-- Merge with close entities of the same item -- Merge with close entities of the same item
for _, object in pairs(minetest.get_objects_inside_radius(p, 0.8)) do for _, object in pairs(minetest.get_objects_inside_radius(p, 0.8)) do
local obj = object:get_luaentity() local obj = object:get_luaentity()
if obj and obj.name == "__builtin:item" if obj and obj.name == "__builtin:item"
and obj.physical_state == false then and obj.physical_state == false then
if self:try_merge_with(own_stack, object, obj) then if self:try_merge_with(own_stack, object, obj) then
return return
end end

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