Compare commits

..

3 Commits

498 changed files with 2884 additions and 11035 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!

1
.gitignore vendored
View File

@ -4,4 +4,3 @@
*.blend2 *.blend2
*.blend3 *.blend3
/.idea/ /.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
@ -35,8 +34,8 @@
* SumianVoice * SumianVoice
* MrRar * MrRar
* talamh * talamh
* Faerraven / Michieal * Faerraven
* FossFanatic * AncientMariner
## Contributors ## Contributors
* Laurent Rocher * Laurent Rocher
@ -96,9 +95,6 @@
* anarquimico * anarquimico
* TheOnlyJoeEnderman * TheOnlyJoeEnderman
* Ranko Saotome * Ranko Saotome
* Gregor Parzefall
* Wbjitscool
* b3nderman
## MineClone5 ## MineClone5
* kay27 * kay27
@ -150,13 +146,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
@ -171,7 +165,6 @@
* RandomLegoBrick * RandomLegoBrick
* cora * cora
* Faerraven / Michieal * Faerraven / Michieal
* Nicu
## Translations ## Translations
* Wuzzy * Wuzzy
@ -185,12 +178,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 +188,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.82 (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,3 @@
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 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

@ -155,6 +155,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 +163,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)
if mt_reason.approved then
mcl_damage.run_death_callbacks(player, mcl_damage.from_mt(mt_reason)) 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

@ -102,7 +102,6 @@ function check_events(dtime)
for _,e in pairs(mcl_events.registered_events) do for _,e in pairs(mcl_events.registered_events) do
local pp = e.cond_start() local pp = e.cond_start()
if pp then if pp then
--minetest.log("It's gonna start the raid maybe")
for _,p in pairs(pp) do for _,p in pairs(pp) do
local start = true local start = true
if e.exclusive_to_area then if e.exclusive_to_area then
@ -111,14 +110,11 @@ function check_events(dtime)
end end
end end
if start then if start then
--minetest.log("It's gonna start the raid definitely")
start_event(p,e) start_event(p,e)
elseif DBG then elseif DBG then
mcl_log("[mcl_events] Event "..e.readable_name.." already active at "..minetest.pos_to_string(vector.round(p.pos))) mcl_log("[mcl_events] Event "..e.readable_name.." already active at "..minetest.pos_to_string(vector.round(p.pos)))
end end
end end
else
--minetest.log("Do not start this raid")
end end
end end
for idx,ae in pairs(active_events) do for idx,ae in pairs(active_events) do

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,67 +35,53 @@ 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
@ -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
@ -192,16 +181,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 +196,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 +217,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

@ -18,15 +18,35 @@ Glass breaking sounds (CC BY 3.0):
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,9 +22,9 @@ function table.update_nil(t, ...)
return t return t
end end
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_default", false) local LOGGING_ON = minetest.settings:get_bool("mcl_logging_default",false)
local LOG_MODULE = "[MCL2]" local LOG_MODULE = "[MCL2]"
function mcl_util.mcl_log(message, module, bypass_default_logger) function mcl_util.mcl_log (message, module, bypass_default_logger)
local selected_module = LOG_MODULE local selected_module = LOG_MODULE
if module then if module then
selected_module = module selected_module = module
@ -34,6 +34,7 @@ function mcl_util.mcl_log(message, module, bypass_default_logger)
end end
end end
function mcl_util.file_exists(name) function mcl_util.file_exists(name)
if type(name) ~= "string" then return end if type(name) ~= "string" then return end
local f = io.open(name) local f = io.open(name)
@ -150,23 +151,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 +185,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
@ -408,7 +409,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 +456,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
@ -642,80 +643,78 @@ 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
@ -729,285 +728,3 @@ function mcl_util.set_bone_position(obj, bone, pos, rot)
obj:set_bone_position(bone, pos or current_pos, rot or current_rot) obj:set_bone_position(bone, pos or current_pos, rot or current_rot)
end end
end end
---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

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=黒曜石のボート

View File

@ -7,24 +7,31 @@ local pool = {}
local tick = false local tick = false
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_item_entities", false) local LOGGING_ON = minetest.settings:get_bool("mcl_logging_item_entities",false)
local function mcl_log(message) local function mcl_log (message)
if LOGGING_ON then if LOGGING_ON then
mcl_util.mcl_log(message, "[Item Entities]", true) mcl_util.mcl_log (message, "[Item Entities]", true)
end end
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
@ -45,23 +52,16 @@ 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 +74,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 +86,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 +103,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 +125,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 +135,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 +158,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 +179,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 +194,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 +202,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
@ -280,7 +265,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]
@ -309,8 +294,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
@ -322,13 +306,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()
@ -337,7 +321,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
@ -364,7 +348,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
@ -372,9 +356,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
@ -392,16 +376,16 @@ 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) local function hopper_take_item (self, pos)
--mcl_log("self.itemstring: ".. self.itemstring) --mcl_log("self.itemstring: ".. self.itemstring)
--mcl_log("self.itemstring: ".. minetest.pos_to_string(pos)) --mcl_log("self.itemstring: ".. minetest.pos_to_string(pos))
@ -410,17 +394,17 @@ local function hopper_take_item(self, pos)
if objs and self.itemstring then if objs and self.itemstring then
--mcl_log("there is an itemstring. Number of objs: ".. #objs) --mcl_log("there is an itemstring. Number of objs: ".. #objs)
for k, v in pairs(objs) do for k,v in pairs(objs) do
local ent = v:get_luaentity() local ent = v:get_luaentity()
-- Don't forget actual hoppers -- Don't forget actual hoppers
if ent and ent.name == "mcl_minecarts:hopper_minecart" then if ent and ent.name == "mcl_minecarts:hopper_minecart" then
local taken_items = false local taken_items = false
mcl_log("ent.name: " .. tostring(ent.name)) mcl_log("ent.name: ".. tostring(ent.name))
mcl_log("ent pos: " .. tostring(ent.object:get_pos())) mcl_log("ent pos: ".. tostring(ent.object:get_pos()))
local inv = mcl_entity_invs.load_inv(ent, 5) local inv = mcl_entity_invs.load_inv(ent,5)
if not inv then if not inv then
mcl_log("No inv") mcl_log("No inv")
@ -444,7 +428,7 @@ local function hopper_take_item(self, pos)
local items_remaining = current_itemstack:get_count() local items_remaining = current_itemstack:get_count()
-- This will take part of a floating item stack if no slot can hold the full amount -- 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 for i = 1, ent._inv_size,1 do
local stack = inv:get_stack("main", i) local stack = inv:get_stack("main", i)
mcl_log("i: " .. tostring(i)) mcl_log("i: " .. tostring(i))
@ -516,13 +500,13 @@ minetest.register_entity(":__builtin:item", {
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 = "",
}, },
@ -560,11 +544,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,
@ -592,7 +576,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
@ -613,9 +597,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,
@ -711,9 +695,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,
@ -761,8 +745,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
@ -777,22 +761,21 @@ 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 -- If hopper has taken item, it has gone, and no operations should be conducted on this item
if hopper_take_item(self, p) then if hopper_take_item(self, p) then
return return
end end
local node = minetest.get_node(p) local node = minetest.get_node_or_nil(p)
local in_unloaded = node.name == "ignore" local in_unloaded = (node == nil)
if in_unloaded then if in_unloaded then
-- Don't infinetly fall into unloaded map -- Don't infinetly fall into unloaded map
@ -802,13 +785,13 @@ 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
@ -821,8 +804,8 @@ minetest.register_entity(":__builtin:item", {
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
@ -842,7 +825,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()
@ -882,7 +865,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
@ -892,7 +875,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
@ -902,7 +885,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)
@ -924,10 +907,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
@ -958,7 +941,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
@ -971,10 +954,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()
@ -998,7 +980,7 @@ 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

View File

@ -1,36 +0,0 @@
# textdomain: mcl_minecarts
Minecart=トロッコ
Minecarts can be used for a quick transportion on rails.=トロッコは、レールを使った高速輸送を可能にします。
Minecarts only ride on rails and always follow the tracks. At a T-junction with no straight way ahead, they turn left. The speed is affected by the rail type.=トロッコはレール上にしか乗らない為、常に線路に沿って走ります。直進できない丁字路では、取り敢えず左折します。速度はレールの種類によって異なります。
You can place the minecart on rails. Right-click it to enter it. Punch it to get it moving.=レールの上にトロッコを置けます。右クリックで乗り込みます。パンチすると動き出します。
To obtain the minecart, punch it while holding down the sneak key.=トロッコを入手するには、スニークキーを押しながらパンチします。
A minecart with TNT is an explosive vehicle that travels on rail.=TNT付きトロッコは、レール上を行きかう爆薬車両です。
Place it on rails. Punch it to move it. The TNT is ignited with a flint and steel or when the minecart is on an powered activator rail.=レール上に配置。パンチで移動。TNTが着火するのは、火打石と打金を使った時か、稼動中のアクティベーターレール上にトロッコが乗った時です。
To obtain the minecart and TNT, punch them while holding down the sneak key. You can't do this if the TNT was ignited.=トロッコとTNTを入手するには、スニークキーを押しながらパンチしてください。TNTに火が着いていた場合は、無理です。
A minecart with furnace is a vehicle that travels on rails. It can propel itself with fuel.=かまど付きトロッコは、レール上を走行する車両です。燃料で自走できます。
Place it on rails. If you give it some coal, the furnace will start burning for a long time and the minecart will be able to move itself. Punch it to get it moving.=レールの上に置きます。石炭を与えると、かまどが長時間燃え続け、トロッコが自走可能になります。パンチすると動き出します。
To obtain the minecart and furnace, punch them while holding down the sneak key.=トロッコとかまどを入手するには、スニークキーを押しながらパンチします。
Minecart with Chest=チェスト付きトロッコ
Minecart with Furnace=かまど付きトロッコ
Minecart with Command Block=コマンドブロック付きトロッコ
Minecart with Hopper=ホッパー付きトロッコ
Minecart with TNT=TNT付きトロッコ
Place them on the ground to build your railway, the rails will automatically connect to each other and will turn into curves, T-junctions, crossings and slopes as needed.=地面に置いて線路を作ると、レール同士が自動的につながり、必要に応じてカーブや丁字路、踏切、坂道などに変化します。
Rail=レール
Rails can be used to build transport tracks for minecarts. Normal rails slightly slow down minecarts due to friction.=レールを利用して、トロッコの輸送路が敷けます。普通のレールは、摩擦の関係でトロッコが少しずつ減速していきます。
Powered Rail=パワードレール
Rails can be used to build transport tracks for minecarts. Powered rails are able to accelerate and brake minecarts.=レールを利用して、トロッコの輸送路が敷けます。パワードレールは、トロッコを加速させたり、ブレーキをかけたりできます。
Without redstone power, the rail will brake minecarts. To make this rail accelerate minecarts, power it with redstone power.=レッドストーン動力なしだと、このレールはトロッコにブレーキをかけます。このレールでトロッコを加速させるには、レッドストーン動力を供給してください。
Activator Rail=アクティベーターレール
Rails can be used to build transport tracks for minecarts. Activator rails are used to activate special minecarts.=レールを利用して、トロッコの輸送路が敷けます。アクティベーターレールは、特殊なトロッコを作動させるために使われます。
To make this rail activate minecarts, power it with redstone power and send a minecart over this piece of rail.=このレールでトロッコを作動させるには、レッドストーン動力を与えたレール上にトロッコを送り込みます。
Detector Rail=
Rails can be used to build transport tracks for minecarts. A detector rail is able to detect a minecart above it and powers redstone mechanisms.=レールを利用して、トロッコの輸送路が敷けます。ディテクターレールは、その上にあるトロッコを検知でき、その際レッドストーン機構の動力源となります。
To detect a minecart and provide redstone power, connect it to redstone trails or redstone mechanisms and send any minecart over the rail.=トロッコを検知してレッドストーン動力を供給するには、レッドストーン導線またはレッドストーン機構に接続し、任意のトロッコをレール上に送り込みます。
Track for minecarts=トロッコ用の線路
Speed up when powered, slow down when not powered=稼動中は加速、非稼動中は減速
Activates minecarts when powered=稼動中はトロッコを作動
Emits redstone power when a minecart is detected=トロッコを検知するとレッドストーン動力を放出
Vehicle for fast travel on rails=レール上を快速移動するための車両
Can be ignited by tools or powered activator rail=道具や稼動中のアクティベーターレールにより着火が可能
Sneak to dismount=スニークで降りる

View File

@ -2,6 +2,8 @@ local mob_class = mcl_mobs.mob_class
local mob_class_meta = {__index = mcl_mobs.mob_class} local mob_class_meta = {__index = mcl_mobs.mob_class}
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
-- API for Mobs Redo: MineClone 2 Edition (MRM) -- API for Mobs Redo: MineClone 2 Edition (MRM)
local MAX_MOB_NAME_LENGTH = 30
local DEFAULT_FALL_SPEED = -9.81*1.5
local PATHFINDING = "gowp" local PATHFINDING = "gowp"
@ -15,9 +17,21 @@ local function mcl_log (message)
end end
end end
-- Invisibility mod check -- Invisibility mod check
mcl_mobs.invis = {} mcl_mobs.invis = {}
-- localize math functions
local atann = math.atan
local function atan(x)
if not x or x ~= x then
return 0
else
return atann(x)
end
end
local remove_far = true local remove_far = true
local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false
local spawn_protected = minetest.settings:get_bool("mobs_spawn_protected") ~= false local spawn_protected = minetest.settings:get_bool("mobs_spawn_protected") ~= false
@ -283,65 +297,51 @@ function mob_class:mob_activate(staticdata, def, dtime)
end end
end end
-- execute current state (stand, walk, run, attacks)
-- returns true if mob has died
function mob_class:do_states(dtime)
--if self.can_open_doors then check_doors(self) end
if self.state == "stand" then
self:do_states_stand()
elseif self.state == PATHFINDING then
self:check_gowp(dtime)
elseif self.state == "walk" then
self:do_states_walk()
elseif self.state == "runaway" then
-- runaway when punched
self:do_states_runaway()
elseif self.state == "attack" then
-- attack routines (explode, dogfight, shoot, dogshoot)
if self:do_states_attack(dtime) then
return true
end
end
end
local function update_timers (self, dtime)
-- knockback timer. set in on_punch
if self.pause_timer > 0 then
self.pause_timer = self.pause_timer - dtime
return true
end
-- attack timer
self.timer = self.timer + dtime
if self.state ~= "attack" and self.state ~= PATHFINDING then
if self.timer < 1 then
return true
end
self.timer = 0
end
-- never go over 100
if self.timer > 100 then
self.timer = 1
end
end
-- main mob function -- main mob function
function mob_class:on_step(dtime) function mob_class:on_step(dtime)
self.lifetimer = self.lifetimer - dtime
local pos = self.object:get_pos() local pos = self.object:get_pos()
if not pos then return end if not pos then return end
if self:check_despawn(pos) then return true end
if self:check_despawn(pos, dtime) then return true end local d = 0.85
if self:check_dying() then d = 0.92 end
local v = self.object:get_velocity()
if v then
--diffuse object velocity
self.object:set_velocity({x = v.x*d, y = v.y, z = v.z*d})
end
self:slow_mob()
if self:falling(pos) then return end if self:falling(pos) then return end
self:check_suspend()
self:check_suspend()
self:check_water_flow() self:check_water_flow()
self:env_danger_movement_checks (dtime) local yaw = 0
if self:is_at_water_danger() and self.state ~= "attack" then
if math.random(1, 10) <= 6 then
self:set_velocity(0)
self.state = "stand"
self:set_animation( "stand")
yaw = yaw + math.random(-0.5, 0.5)
yaw = self:set_yaw( yaw, 8)
end
else
if self.move_in_group ~= false then
self:check_herd(dtime)
end
end
if self:is_at_cliff_or_danger() then
self:set_velocity(0)
self.state = "stand"
self:set_animation( "stand")
local yaw = self.object:get_yaw() or 0
yaw = self:set_yaw( yaw + 0.78, 8)
end
if not self.fire_resistant then if not self.fire_resistant then
mcl_burning.tick(self.object, dtime, self) mcl_burning.tick(self.object, dtime, self)
@ -353,17 +353,21 @@ function mob_class:on_step(dtime)
if self.state == "die" then return end if self.state == "die" then return end
self:follow_flop() -- Mob following code.
self:set_animation_speed() -- set animation speed relitive to velocity
self:check_smooth_rotation(dtime)
self:check_head_swivel(dtime)
if self.jump_sound_cooloff > 0 then if self.jump_sound_cooloff > 0 then
self.jump_sound_cooloff = self.jump_sound_cooloff - dtime self.jump_sound_cooloff = self.jump_sound_cooloff - dtime
end end
self:do_jump() if self.opinion_sound_cooloff > 0 then
self.opinion_sound_cooloff = self.opinion_sound_cooloff - dtime
end
--Mob following code.
self:follow_flop()
--set animation speed relitive to velocity
self:set_animation_speed()
self:check_smooth_rotation(dtime)
self:check_head_swivel(dtime)
self:do_jump()
self:set_armor_texture() self:set_armor_texture()
self:check_runaway_from() self:check_runaway_from()
@ -374,26 +378,63 @@ function mob_class:on_step(dtime)
-- run custom function (defined in mob lua file) -- run custom function (defined in mob lua file)
if self.do_custom then if self.do_custom then
-- when false skip going any further
if self.do_custom(self, dtime) == false then if self.do_custom(self, dtime) == false then
return return
end end
end end
if update_timers(self, dtime) then return end -- knockback timer
if self.pause_timer > 0 then
self.pause_timer = self.pause_timer - dtime
return
end
-- attack timer
self.timer = self.timer + dtime
if self.state ~= "attack" and self.state ~= PATHFINDING then
if self.timer < 1 then
return
end
self.timer = 0
end
self:check_particlespawners(dtime) self:check_particlespawners(dtime)
self:check_item_pickup() self:check_item_pickup()
if self.opinion_sound_cooloff > 0 then -- never go over 100
self.opinion_sound_cooloff = self.opinion_sound_cooloff - dtime if self.timer > 100 then
self.timer = 1
end end
-- mob plays random sound at times. Should be 120. Zombie and mob farms are ridiculous
-- mob plays random sound at times
if math.random(1, 70) == 1 then if math.random(1, 70) == 1 then
self:mob_sound("random", true) self:mob_sound("random", true)
end end
if self:env_damage (dtime, pos) then return end -- environmental damage timer (every 1 second)
if self:do_states(dtime) then return end self.env_damage_timer = self.env_damage_timer + dtime
if (self.state == "attack" and self.env_damage_timer > 1)
or self.state ~= "attack" then
self:check_entity_cramming()
self.env_damage_timer = 0
-- check for environmental damage (water, fire, lava etc.)
if self:do_env_damage() then
return
end
-- node replace check (cow eats grass etc.)
self:replace(pos)
end
if self:do_states(dtime) then
return
end
if not self.object:get_luaentity() then if not self.object:get_luaentity() then
return false return false

View File

@ -1,8 +1,9 @@
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
local mob_class = mcl_mobs.mob_class local mob_class = mcl_mobs.mob_class
local HORNY_TIME = 30*20 local MAX_MOB_NAME_LENGTH = 30
local HORNY_AGAIN_TIME = 30*20 -- was 300 or 15*20 local HORNY_TIME = 30
local HORNY_AGAIN_TIME = 300
local CHILD_GROW_TIME = 60*20 local CHILD_GROW_TIME = 60*20
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager",false) local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager",false)
@ -178,7 +179,7 @@ function mob_class:check_breeding()
-- jump when fully grown so as not to fall into ground -- jump when fully grown so as not to fall into ground
self.object:set_velocity({ self.object:set_velocity({
x = 0, x = 0,
y = self.jump_height, y = self.jump_height*3,
z = 0 z = 0
}) })
end end
@ -190,10 +191,13 @@ function mob_class:check_breeding()
end end
return return
else end
-- horny animal can mate for HORNY_TIME seconds, -- horny animal can mate for HORNY_TIME seconds,
-- afterwards horny animal cannot mate again for HORNY_AGAIN_TIME seconds -- afterwards horny animal cannot mate again for HORNY_AGAIN_TIME seconds
if self.horny == true then if self.horny == true
and self.hornytimer < HORNY_TIME + HORNY_AGAIN_TIME then
self.hornytimer = self.hornytimer + 1 self.hornytimer = self.hornytimer + 1
if self.hornytimer >= HORNY_TIME + HORNY_AGAIN_TIME then if self.hornytimer >= HORNY_TIME + HORNY_AGAIN_TIME then
@ -201,7 +205,6 @@ function mob_class:check_breeding()
self.horny = false self.horny = false
end end
end end
end
-- find another same animal who is also horny and mate if nearby -- find another same animal who is also horny and mate if nearby
if self.horny == true if self.horny == true

View File

@ -8,18 +8,6 @@ local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false
local stuck_timeout = 3 -- how long before mob gets stuck in place and starts searching local stuck_timeout = 3 -- how long before mob gets stuck in place and starts searching
local stuck_path_timeout = 10 -- how long will mob follow path before giving up local stuck_path_timeout = 10 -- how long will mob follow path before giving up
local enable_pathfinding = true
local atann = math.atan
local function atan(x)
if not x or x ~= x then
return 0
else
return atann(x)
end
end
-- check if daytime and also if mob is docile during daylight hours -- check if daytime and also if mob is docile during daylight hours
function mob_class:day_docile() function mob_class:day_docile()
if self.docile_by_day == false then if self.docile_by_day == false then
@ -806,397 +794,3 @@ function mob_class:check_aggro(dtime)
end end
self._check_aggro_timer = self._check_aggro_timer + dtime self._check_aggro_timer = self._check_aggro_timer + dtime
end end
function mob_class:do_states_attack (dtime)
local yaw = self.object:get_yaw() or 0
local s = self.object:get_pos()
local p = self.attack:get_pos() or s
-- stop attacking if player invisible or out of range
if not self.attack
or not self.attack:get_pos()
or not self:object_in_range(self.attack)
or self.attack:get_hp() <= 0
or (self.attack:is_player() and mcl_mobs.invis[ self.attack:get_player_name() ]) then
self.state = "stand"
self:set_velocity( 0)
self:set_animation( "stand")
self.attack = nil
self.v_start = false
self.timer = 0
self.blinktimer = 0
self.path.way = nil
return
end
-- calculate distance from mob and enemy
local dist = vector.distance(p, s)
if self.attack_type == "explode" then
local vec = {
x = p.x - s.x,
z = p.z - s.z
}
yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
if p.x > s.x then yaw = yaw +math.pi end
yaw = self:set_yaw( yaw, 0, dtime)
local node_break_radius = self.explosion_radius or 1
local entity_damage_radius = self.explosion_damage_radius
or (node_break_radius * 2)
-- start timer when in reach and line of sight
if not self.v_start
and dist <= self.reach
and self:line_of_sight( s, p, 2) then
self.v_start = true
self.timer = 0
self.blinktimer = 0
self:mob_sound("fuse", nil, false)
-- stop timer if out of reach or direct line of sight
elseif self.allow_fuse_reset
and self.v_start
and (dist >= self.explosiontimer_reset_radius
or not self:line_of_sight( s, p, 2)) then
self.v_start = false
self.timer = 0
self.blinktimer = 0
self.blinkstatus = false
self:remove_texture_mod("^[brighten")
end
-- walk right up to player unless the timer is active
if self.v_start and (self.stop_to_explode or dist < self.reach) then
self:set_velocity( 0)
else
self:set_velocity( self.run_velocity)
end
if self.animation and self.animation.run_start then
self:set_animation( "run")
else
self:set_animation( "walk")
end
if self.v_start then
self.timer = self.timer + dtime
self.blinktimer = (self.blinktimer or 0) + dtime
if self.blinktimer > 0.2 then
self.blinktimer = 0
if self.blinkstatus then
self:remove_texture_mod("^[brighten")
else
self:add_texture_mod("^[brighten")
end
self.blinkstatus = not self.blinkstatus
end
if self.timer > self.explosion_timer then
local pos = self.object:get_pos()
if mobs_griefing and not minetest.is_protected(pos, "") then
mcl_explosions.explode(mcl_util.get_object_center(self.object), self.explosion_strength, { drop_chance = 1.0 }, self.object)
else
minetest.sound_play(self.sounds.explode, {
pos = pos,
gain = 1.0,
max_hear_distance = self.sounds.distance or 32
}, true)
self:entity_physics(pos,entity_damage_radius)
mcl_mobs.effect(pos, 32, "mcl_particles_smoke.png", nil, nil, node_break_radius, 1, 0)
end
mcl_burning.extinguish(self.object)
self.object:remove()
return true
end
end
elseif self.attack_type == "dogfight"
or (self.attack_type == "dogshoot" and self:dogswitch(dtime) == 2) and (dist >= self.avoid_distance or not self.shooter_avoid_enemy)
or (self.attack_type == "dogshoot" and dist <= self.reach and self:dogswitch() == 0) then
if self.fly
and dist > self.reach then
local p1 = s
local me_y = math.floor(p1.y)
local p2 = p
local p_y = math.floor(p2.y + 1)
local v = self.object:get_velocity()
if self:flight_check( s) then
if me_y < p_y then
self.object:set_velocity({
x = v.x,
y = 1 * self.walk_velocity,
z = v.z
})
elseif me_y > p_y then
self.object:set_velocity({
x = v.x,
y = -1 * self.walk_velocity,
z = v.z
})
end
else
if me_y < p_y then
self.object:set_velocity({
x = v.x,
y = 0.01,
z = v.z
})
elseif me_y > p_y then
self.object:set_velocity({
x = v.x,
y = -0.01,
z = v.z
})
end
end
end
-- rnd: new movement direction
if self.path.following
and self.path.way
and self.attack_type ~= "dogshoot" then
-- no paths longer than 50
if #self.path.way > 50
or dist < self.reach then
self.path.following = false
return
end
local p1 = self.path.way[1]
if not p1 then
self.path.following = false
return
end
if math.abs(p1.x-s.x) + math.abs(p1.z - s.z) < 0.6 then
-- reached waypoint, remove it from queue
table.remove(self.path.way, 1)
end
-- set new temporary target
p = {x = p1.x, y = p1.y, z = p1.z}
end
local vec = {
x = p.x - s.x,
z = p.z - s.z
}
yaw = (atan(vec.z / vec.x) + math.pi / 2) - self.rotate
if p.x > s.x then yaw = yaw + math.pi end
yaw = self:set_yaw( yaw, 0, dtime)
-- move towards enemy if beyond mob reach
if dist > self.reach then
-- path finding by rnd
if self.pathfinding -- only if mob has pathfinding enabled
and enable_pathfinding then
self:smart_mobs(s, p, dist, dtime)
end
if self:is_at_cliff_or_danger() then
self:set_velocity( 0)
self:set_animation( "stand")
local yaw = self.object:get_yaw() or 0
yaw = self:set_yaw( yaw + 0.78, 8)
else
if self.path.stuck then
self:set_velocity( self.walk_velocity)
else
self:set_velocity( self.run_velocity)
end
if self.animation and self.animation.run_start then
self:set_animation( "run")
else
self:set_animation( "walk")
end
end
else -- rnd: if inside reach range
self.path.stuck = false
self.path.stuck_timer = 0
self.path.following = false -- not stuck anymore
self:set_velocity( 0)
if not self.custom_attack then
if self.timer > 1 then
self.timer = 0
if self.double_melee_attack
and math.random(1, 2) == 1 then
self:set_animation( "punch2")
else
self:set_animation( "punch")
end
local p2 = p
local s2 = s
p2.y = p2.y + .5
s2.y = s2.y + .5
if self:line_of_sight( p2, s2) == true then
-- play attack sound
self:mob_sound("attack")
-- punch player (or what player is attached to)
local attached = self.attack:get_attach()
if attached then
self.attack = attached
end
self.attack:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = self.damage}
}, nil)
end
end
else -- call custom attack every second
if self.custom_attack
and self.timer > 1 then
self.timer = 0
self.custom_attack(self, p)
end
end
end
elseif self.attack_type == "shoot"
or (self.attack_type == "dogshoot" and self:dogswitch(dtime) == 1)
or (self.attack_type == "dogshoot" and (dist > self.reach or dist < self.avoid_distance and self.shooter_avoid_enemy) and self:dogswitch() == 0) then
p.y = p.y - .5
s.y = s.y + .5
local dist = vector.distance(p, s)
local vec = {
x = p.x - s.x,
y = p.y - s.y,
z = p.z - s.z
}
yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
if p.x > s.x then yaw = yaw +math.pi end
yaw = self:set_yaw( yaw, 0, dtime)
local stay_away_from_player = vector.new(0,0,0)
--strafe back and fourth
--stay away from player so as to shoot them
if dist < self.avoid_distance and self.shooter_avoid_enemy then
self:set_animation( "shoot")
stay_away_from_player=vector.multiply(vector.direction(p, s), 0.33)
end
if self.strafes then
if not self.strafe_direction then
self.strafe_direction = 1.57
end
if math.random(40) == 1 then
self.strafe_direction = self.strafe_direction*-1
end
self.acc = vector.add(vector.multiply(vector.rotate_around_axis(vector.direction(s, p), vector.new(0,1,0), self.strafe_direction), 0.3*self.walk_velocity), stay_away_from_player)
else
self:set_velocity( 0)
end
local p = self.object:get_pos()
p.y = p.y + (self.collisionbox[2] + self.collisionbox[5]) / 2
if self.shoot_interval
and self.timer > self.shoot_interval
and not minetest.raycast(vector.add(p, vector.new(0,self.shoot_offset,0)), vector.add(self.attack:get_pos(), vector.new(0,1.5,0)), false, false):next()
and math.random(1, 100) <= 60 then
self.timer = 0
self:set_animation( "shoot")
-- play shoot attack sound
self:mob_sound("shoot_attack")
-- Shoot arrow
if minetest.registered_entities[self.arrow] then
local arrow, ent
local v = 1
if not self.shoot_arrow then
self.firing = true
minetest.after(1, function()
self.firing = false
end)
arrow = minetest.add_entity(p, self.arrow)
ent = arrow:get_luaentity()
if ent.velocity then
v = ent.velocity
end
ent.switch = 1
ent.owner_id = tostring(self.object) -- add unique owner id to arrow
-- important for mcl_shields
ent._shooter = self.object
ent._saved_shooter_pos = self.object:get_pos()
end
local amount = (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) ^ 0.5
-- offset makes shoot aim accurate
vec.y = vec.y + self.shoot_offset
vec.x = vec.x * (v / amount)
vec.y = vec.y * (v / amount)
vec.z = vec.z * (v / amount)
if self.shoot_arrow then
vec = vector.normalize(vec)
self:shoot_arrow(p, vec)
else
arrow:set_velocity(vec)
end
end
end
else
end
end

View File

@ -116,7 +116,6 @@ function mob_class:mob_sound(soundname, is_opinion, fixed_pitch)
-- randomize the pitch a bit -- randomize the pitch a bit
pitch = pitch + math.random(-10, 10) * 0.005 pitch = pitch + math.random(-10, 10) * 0.005
end end
-- Should be 0.1 to 0.2 for mobs. Cow and zombie farms loud. At least have cool down.
minetest.sound_play(sound, { minetest.sound_play(sound, {
object = self.object, object = self.object,
gain = 1.0, gain = 1.0,
@ -280,55 +279,30 @@ local function dir_to_pitch(dir)
return -math.atan2(-dir.y, xz) return -math.atan2(-dir.y, xz)
end end
local function who_are_you_looking_at (self) function mob_class:check_head_swivel(dtime)
if not self.head_swivel or type(self.head_swivel) ~= "string" then return end
local final_rotation = vector.new(0,0,0)
local oldp,oldr = self.object:get_bone_position(self.head_swivel)
local pos = self.object:get_pos() local pos = self.object:get_pos()
local stop_look_at_player_chance = math.random(833/self.curiosity) for _, obj in pairs(minetest.get_objects_inside_radius(pos, 10)) do
-- was 10000 - div by 12 for avg entities as outside loop if obj:is_player() and not self.attack or obj:get_luaentity() and obj:get_luaentity().name == self.name and self ~= obj:get_luaentity() then
if not self._locked_object then
local stop_look_at_player = stop_look_at_player_chance == 1 if math.random(5000/self.curiosity) == 1 or vector.distance(pos,obj:get_pos())<4 and obj:is_player() then
self._locked_object = obj
end
else
if math.random(10000/self.curiosity) == 1 then
self._locked_object = nil
end
end
end
end
if self.attack or self.following then if self.attack or self.following then
self._locked_object = self.attack or self.following self._locked_object = self.attack or self.following
elseif self._locked_object then
if stop_look_at_player then
--minetest.log("Stop look: ".. self.name)
self._locked_object = nil
end end
elseif not self._locked_object then
if math.random(1, 30) then
--minetest.log("Change look check: ".. self.name)
local look_at_player_chance = math.random(20/self.curiosity)
-- was 5000 but called in loop based on entities. so div by 12 as estimate avg of entities found,
-- then div by 20 as less freq lookup
local look_at_player = look_at_player_chance == 1
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 8)) do
if obj:is_player() and vector.distance(pos,obj:get_pos()) < 4 then
--minetest.log("Change look to player: ".. self.name)
self._locked_object = obj
break
elseif obj:is_player() or (obj:get_luaentity() and obj:get_luaentity().name == self.name and self ~= obj:get_luaentity()) then
if look_at_player then
--minetest.log("Change look to mob: ".. self.name)
self._locked_object = obj
break
end
end
end
end
end
end
function mob_class:check_head_swivel(dtime)
if not self.head_swivel or type(self.head_swivel) ~= "string" then return end
who_are_you_looking_at (self)
local final_rotation = vector.new(0,0,0)
local oldp,oldr = self.object:get_bone_position(self.head_swivel)
if self._locked_object and (self._locked_object:is_player() or self._locked_object:get_luaentity()) and self._locked_object:get_hp() > 0 then if self._locked_object and (self._locked_object:is_player() or self._locked_object:get_luaentity()) and self._locked_object:get_hp() > 0 then
local _locked_object_eye_height = 1.5 local _locked_object_eye_height = 1.5
@ -343,7 +317,6 @@ function mob_class:check_head_swivel(dtime)
if self.object:get_attach() then if self.object:get_attach() then
self_rot = self.object:get_attach():get_rotation() self_rot = self.object:get_attach():get_rotation()
end end
if self.rot then if self.rot then
local player_pos = self._locked_object:get_pos() local player_pos = self._locked_object:get_pos()
local direction_player = vector.direction(vector.add(self.object:get_pos(), vector.new(0, self.head_eye_height*.7, 0)), vector.add(player_pos, vector.new(0, _locked_object_eye_height, 0))) local direction_player = vector.direction(vector.add(self.object:get_pos(), vector.new(0, self.head_eye_height*.7, 0)), vector.add(player_pos, vector.new(0, _locked_object_eye_height, 0)))
@ -372,7 +345,7 @@ function mob_class:check_head_swivel(dtime)
elseif not self._locked_object and math.abs(oldr.y) > 3 and math.abs(oldr.x) < 3 then elseif not self._locked_object and math.abs(oldr.y) > 3 and math.abs(oldr.x) < 3 then
final_rotation = vector.multiply(oldr, 0.9) final_rotation = vector.multiply(oldr, 0.9)
else else
--final_rotation = vector.new(0,0,0) final_rotation = vector.new(0,0,0)
end end
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), final_rotation) mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horrizonatal_head_height), final_rotation)

View File

@ -1,11 +0,0 @@
# textdomain: mcl_mobs
Peaceful mode active! No monsters will spawn.=ピースフルモード有効! モンスターは出現しません。
This allows you to place a single mob.=これにより、1体のMOBを配置できます。
Just place it where you want the mob to appear. Animals will spawn tamed, unless you hold down the sneak key while placing. If you place this on a mob spawner, you change the mob it spawns.=MOBを出現させたい場所に、置くだけです。スニークキーを押しながら配置しない限り、動物は飼いならされた状態でスポーンします。MOBスポナーに設置すると、スポーンするMOBが変わります。
You need the “maphack” privilege to change the mob spawner.=MOBスポナーを変更するには、"maphack"権限が必要です。
Name Tag=名札
A name tag is an item to name a mob.=名札は、MOBに名前をつけるためのアイテムです。
Before you use the name tag, you need to set a name at an anvil. Then you can use the name tag to name a mob. This uses up the name tag.=名札を使用する前に、金床で名前の設定をする必要があります。その後、MOBに名前をつけるために名札が使えます。これで名札は使い切ります。
Only peaceful mobs allowed!=平和的なMOBのみ許可
Give names to mobs=MOBに名前を付与
Set name at anvil=金床で名前の設定

View File

@ -4,6 +4,7 @@ local DEFAULT_FALL_SPEED = -9.81*1.5
local FLOP_HEIGHT = 6 local FLOP_HEIGHT = 6
local FLOP_HOR_SPEED = 1.5 local FLOP_HOR_SPEED = 1.5
local PATHFINDING = "gowp" local PATHFINDING = "gowp"
local enable_pathfinding = true
local node_ice = "mcl_core:ice" local node_ice = "mcl_core:ice"
local node_snowblock = "mcl_core:snowblock" local node_snowblock = "mcl_core:snowblock"
@ -268,36 +269,12 @@ function mob_class:is_at_water_danger()
return false return false
end end
function mob_class:env_danger_movement_checks(dtime)
local yaw = 0
if self:is_at_water_danger() and self.state ~= "attack" then
if math.random(1, 10) <= 6 then
self:set_velocity(0)
self.state = "stand"
self:set_animation( "stand")
yaw = yaw + math.random(-0.5, 0.5)
yaw = self:set_yaw( yaw, 8)
end
else
if self.move_in_group ~= false then
self:check_herd(dtime)
end
end
if self:is_at_cliff_or_danger() then
self:set_velocity(0)
self.state = "stand"
self:set_animation( "stand")
local yaw = self.object:get_yaw() or 0
yaw = self:set_yaw( yaw + 0.78, 8)
end
end
-- jump if facing a solid node (not fences or gates) -- jump if facing a solid node (not fences or gates)
function mob_class:do_jump() function mob_class:do_jump()
if not self.jump if not self.jump
or self.jump_height == 0 or self.jump_height == 0
or self.fly or self.fly
or (self.child and self.type ~= "monster")
or self.order == "stand" then or self.order == "stand" then
return false return false
end end
@ -793,9 +770,70 @@ function mob_class:teleport(target)
end end
end end
function mob_class:do_states_walk() -- execute current state (stand, walk, run, attacks)
-- returns true if mob has died
function mob_class:do_states(dtime)
--if self.can_open_doors then check_doors(self) end
local yaw = self.object:get_yaw() or 0 local yaw = self.object:get_yaw() or 0
if self.state == "stand" then
if math.random(1, 4) == 1 then
local s = self.object:get_pos()
local objs = minetest.get_objects_inside_radius(s, 3)
local lp
for n = 1, #objs do
if objs[n]:is_player() then
lp = objs[n]:get_pos()
break
end
end
-- look at any players nearby, otherwise turn randomly
if lp and self.look_at_players then
local vec = {
x = lp.x - s.x,
z = lp.z - s.z
}
yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
if lp.x > s.x then yaw = yaw +math.pi end
else
yaw = yaw + math.random(-0.5, 0.5)
end
yaw = self:set_yaw( yaw, 8)
end
if self.order == "sit" then
self:set_animation( "sit")
self:set_velocity(0)
else
self:set_animation( "stand")
self:set_velocity(0)
end
-- npc's ordered to stand stay standing
if self.order == "stand" or self.order == "sleep" or self.order == "work" then
else
if self.walk_chance ~= 0
and self.facing_fence ~= true
and math.random(1, 100) <= self.walk_chance
and self:is_at_cliff_or_danger() == false then
self:set_velocity(self.walk_velocity)
self.state = "walk"
self:set_animation( "walk")
end
end
elseif self.state == PATHFINDING then
self:check_gowp(dtime)
elseif self.state == "walk" then
local s = self.object:get_pos() local s = self.object:get_pos()
local lp = nil local lp = nil
@ -803,13 +841,21 @@ function mob_class:do_states_walk()
if (self.water_damage > 0 if (self.water_damage > 0
and self.lava_damage > 0) and self.lava_damage > 0)
or self.breath_max ~= -1 then or self.breath_max ~= -1 then
lp = minetest.find_node_near(s, 1, {"group:water", "group:lava"}) lp = minetest.find_node_near(s, 1, {"group:water", "group:lava"})
elseif self.water_damage > 0 then elseif self.water_damage > 0 then
lp = minetest.find_node_near(s, 1, {"group:water"}) lp = minetest.find_node_near(s, 1, {"group:water"})
elseif self.lava_damage > 0 then elseif self.lava_damage > 0 then
lp = minetest.find_node_near(s, 1, {"group:lava"}) lp = minetest.find_node_near(s, 1, {"group:lava"})
elseif self.fire_damage > 0 then elseif self.fire_damage > 0 then
lp = minetest.find_node_near(s, 1, {"group:fire"}) lp = minetest.find_node_near(s, 1, {"group:fire"})
end end
local is_in_danger = false local is_in_danger = false
@ -894,66 +940,9 @@ function mob_class:do_states_walk()
self:set_animation( "walk") self:set_animation( "walk")
end end
end end
end
function mob_class:do_states_stand() -- runaway when punched
local yaw = self.object:get_yaw() or 0 elseif self.state == "runaway" then
if math.random(1, 4) == 1 then
local s = self.object:get_pos()
local objs = minetest.get_objects_inside_radius(s, 3)
local lp
for n = 1, #objs do
if objs[n]:is_player() then
lp = objs[n]:get_pos()
break
end
end
-- look at any players nearby, otherwise turn randomly
if lp and self.look_at_players then
local vec = {
x = lp.x - s.x,
z = lp.z - s.z
}
yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
if lp.x > s.x then yaw = yaw +math.pi end
else
yaw = yaw + math.random(-0.5, 0.5)
end
yaw = self:set_yaw( yaw, 8)
end
if self.order == "sit" then
self:set_animation( "sit")
self:set_velocity(0)
else
self:set_animation( "stand")
self:set_velocity(0)
end
-- npc's ordered to stand stay standing
if self.order == "stand" or self.order == "sleep" or self.order == "work" then
else
if self.walk_chance ~= 0
and self.facing_fence ~= true
and math.random(1, 100) <= self.walk_chance
and self:is_at_cliff_or_danger() == false then
self:set_velocity(self.walk_velocity)
self.state = "walk"
self:set_animation( "walk")
end
end
end
function mob_class:do_states_runaway()
local yaw = self.object:get_yaw() or 0
self.runaway_timer = self.runaway_timer + 1 self.runaway_timer = self.runaway_timer + 1
@ -970,13 +959,402 @@ function mob_class:do_states_runaway()
self:set_velocity( self.run_velocity) self:set_velocity( self.run_velocity)
self:set_animation( "run") self:set_animation( "run")
end end
-- attack routines (explode, dogfight, shoot, dogshoot)
elseif self.state == "attack" then
local s = self.object:get_pos()
local p = self.attack:get_pos() or s
-- stop attacking if player invisible or out of range
if not self.attack
or not self.attack:get_pos()
or not self:object_in_range(self.attack)
or self.attack:get_hp() <= 0
or (self.attack:is_player() and mcl_mobs.invis[ self.attack:get_player_name() ]) then
self.state = "stand"
self:set_velocity( 0)
self:set_animation( "stand")
self.attack = nil
self.v_start = false
self.timer = 0
self.blinktimer = 0
self.path.way = nil
return
end
-- calculate distance from mob and enemy
local dist = vector.distance(p, s)
if self.attack_type == "explode" then
local vec = {
x = p.x - s.x,
z = p.z - s.z
}
yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
if p.x > s.x then yaw = yaw +math.pi end
yaw = self:set_yaw( yaw, 0, dtime)
local node_break_radius = self.explosion_radius or 1
local entity_damage_radius = self.explosion_damage_radius
or (node_break_radius * 2)
-- start timer when in reach and line of sight
if not self.v_start
and dist <= self.reach
and self:line_of_sight( s, p, 2) then
self.v_start = true
self.timer = 0
self.blinktimer = 0
self:mob_sound("fuse", nil, false)
-- stop timer if out of reach or direct line of sight
elseif self.allow_fuse_reset
and self.v_start
and (dist >= self.explosiontimer_reset_radius
or not self:line_of_sight( s, p, 2)) then
self.v_start = false
self.timer = 0
self.blinktimer = 0
self.blinkstatus = false
self:remove_texture_mod("^[brighten")
end
-- walk right up to player unless the timer is active
if self.v_start and (self.stop_to_explode or dist < self.reach) then
self:set_velocity( 0)
else
self:set_velocity( self.run_velocity)
end
if self.animation and self.animation.run_start then
self:set_animation( "run")
else
self:set_animation( "walk")
end
if self.v_start then
self.timer = self.timer + dtime
self.blinktimer = (self.blinktimer or 0) + dtime
if self.blinktimer > 0.2 then
self.blinktimer = 0
if self.blinkstatus then
self:remove_texture_mod("^[brighten")
else
self:add_texture_mod("^[brighten")
end
self.blinkstatus = not self.blinkstatus
end
if self.timer > self.explosion_timer then
local pos = self.object:get_pos()
if mobs_griefing and not minetest.is_protected(pos, "") then
mcl_explosions.explode(mcl_util.get_object_center(self.object), self.explosion_strength, { drop_chance = 1.0 }, self.object)
else
minetest.sound_play(self.sounds.explode, {
pos = pos,
gain = 1.0,
max_hear_distance = self.sounds.distance or 32
}, true)
self:entity_physics(pos,entity_damage_radius)
mcl_mobs.effect(pos, 32, "mcl_particles_smoke.png", nil, nil, node_break_radius, 1, 0)
end
mcl_burning.extinguish(self.object)
self.object:remove()
return true
end
end
elseif self.attack_type == "dogfight"
or (self.attack_type == "dogshoot" and self:dogswitch(dtime) == 2) and (dist >= self.avoid_distance or not self.shooter_avoid_enemy)
or (self.attack_type == "dogshoot" and dist <= self.reach and self:dogswitch() == 0) then
if self.fly
and dist > self.reach then
local p1 = s
local me_y = math.floor(p1.y)
local p2 = p
local p_y = math.floor(p2.y + 1)
local v = self.object:get_velocity()
if self:flight_check( s) then
if me_y < p_y then
self.object:set_velocity({
x = v.x,
y = 1 * self.walk_velocity,
z = v.z
})
elseif me_y > p_y then
self.object:set_velocity({
x = v.x,
y = -1 * self.walk_velocity,
z = v.z
})
end
else
if me_y < p_y then
self.object:set_velocity({
x = v.x,
y = 0.01,
z = v.z
})
elseif me_y > p_y then
self.object:set_velocity({
x = v.x,
y = -0.01,
z = v.z
})
end
end
end
-- rnd: new movement direction
if self.path.following
and self.path.way
and self.attack_type ~= "dogshoot" then
-- no paths longer than 50
if #self.path.way > 50
or dist < self.reach then
self.path.following = false
return
end
local p1 = self.path.way[1]
if not p1 then
self.path.following = false
return
end
if math.abs(p1.x-s.x) + math.abs(p1.z - s.z) < 0.6 then
-- reached waypoint, remove it from queue
table.remove(self.path.way, 1)
end
-- set new temporary target
p = {x = p1.x, y = p1.y, z = p1.z}
end
local vec = {
x = p.x - s.x,
z = p.z - s.z
}
yaw = (atan(vec.z / vec.x) + math.pi / 2) - self.rotate
if p.x > s.x then yaw = yaw + math.pi end
yaw = self:set_yaw( yaw, 0, dtime)
-- move towards enemy if beyond mob reach
if dist > self.reach then
-- path finding by rnd
if self.pathfinding -- only if mob has pathfinding enabled
and enable_pathfinding then
self:smart_mobs(s, p, dist, dtime)
end
if self:is_at_cliff_or_danger() then
self:set_velocity( 0)
self:set_animation( "stand")
local yaw = self.object:get_yaw() or 0
yaw = self:set_yaw( yaw + 0.78, 8)
else
if self.path.stuck then
self:set_velocity( self.walk_velocity)
else
self:set_velocity( self.run_velocity)
end
if self.animation and self.animation.run_start then
self:set_animation( "run")
else
self:set_animation( "walk")
end
end
else -- rnd: if inside reach range
self.path.stuck = false
self.path.stuck_timer = 0
self.path.following = false -- not stuck anymore
self:set_velocity( 0)
if not self.custom_attack then
if self.timer > 1 then
self.timer = 0
if self.double_melee_attack
and math.random(1, 2) == 1 then
self:set_animation( "punch2")
else
self:set_animation( "punch")
end
local p2 = p
local s2 = s
p2.y = p2.y + .5
s2.y = s2.y + .5
if self:line_of_sight( p2, s2) == true then
-- play attack sound
self:mob_sound("attack")
-- punch player (or what player is attached to)
local attached = self.attack:get_attach()
if attached then
self.attack = attached
end
self.attack:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = self.damage}
}, nil)
end
end
else -- call custom attack every second
if self.custom_attack
and self.timer > 1 then
self.timer = 0
self.custom_attack(self, p)
end
end
end
elseif self.attack_type == "shoot"
or (self.attack_type == "dogshoot" and self:dogswitch(dtime) == 1)
or (self.attack_type == "dogshoot" and (dist > self.reach or dist < self.avoid_distance and self.shooter_avoid_enemy) and self:dogswitch() == 0) then
p.y = p.y - .5
s.y = s.y + .5
local dist = vector.distance(p, s)
local vec = {
x = p.x - s.x,
y = p.y - s.y,
z = p.z - s.z
}
yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate
if p.x > s.x then yaw = yaw +math.pi end
yaw = self:set_yaw( yaw, 0, dtime)
local stay_away_from_player = vector.new(0,0,0)
--strafe back and fourth
--stay away from player so as to shoot them
if dist < self.avoid_distance and self.shooter_avoid_enemy then
self:set_animation( "shoot")
stay_away_from_player=vector.multiply(vector.direction(p, s), 0.33)
end
if self.strafes then
if not self.strafe_direction then
self.strafe_direction = 1.57
end
if math.random(40) == 1 then
self.strafe_direction = self.strafe_direction*-1
end
self.acc = vector.add(vector.multiply(vector.rotate_around_axis(vector.direction(s, p), vector.new(0,1,0), self.strafe_direction), 0.3*self.walk_velocity), stay_away_from_player)
else
self:set_velocity( 0)
end
local p = self.object:get_pos()
p.y = p.y + (self.collisionbox[2] + self.collisionbox[5]) / 2
if self.shoot_interval
and self.timer > self.shoot_interval
and not minetest.raycast(vector.add(p, vector.new(0,self.shoot_offset,0)), vector.add(self.attack:get_pos(), vector.new(0,1.5,0)), false, false):next()
and math.random(1, 100) <= 60 then
self.timer = 0
self:set_animation( "shoot")
-- play shoot attack sound
self:mob_sound("shoot_attack")
-- Shoot arrow
if minetest.registered_entities[self.arrow] then
local arrow, ent
local v = 1
if not self.shoot_arrow then
self.firing = true
minetest.after(1, function()
self.firing = false
end)
arrow = minetest.add_entity(p, self.arrow)
ent = arrow:get_luaentity()
if ent.velocity then
v = ent.velocity
end
ent.switch = 1
ent.owner_id = tostring(self.object) -- add unique owner id to arrow
-- important for mcl_shields
ent._shooter = self.object
ent._saved_shooter_pos = self.object:get_pos()
end
local amount = (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) ^ 0.5
-- offset makes shoot aim accurate
vec.y = vec.y + self.shoot_offset
vec.x = vec.x * (v / amount)
vec.y = vec.y * (v / amount)
vec.z = vec.z * (v / amount)
if self.shoot_arrow then
vec = vector.normalize(vec)
self:shoot_arrow(p, vec)
else
arrow:set_velocity(vec)
end
end
end
else
end
end
end end
function mob_class:check_smooth_rotation(dtime) function mob_class:check_smooth_rotation(dtime)
-- smooth rotation by ThomasMonroe314 -- smooth rotation by ThomasMonroe314
if self._turn_to then if self._turn_to then
@ -1020,7 +1398,7 @@ function mob_class:check_smooth_rotation(dtime)
yaw = yaw + (math.random() * 2 - 1) * 5 * dtime yaw = yaw + (math.random() * 2 - 1) * 5 * dtime
end end
self.object:set_yaw(yaw) self.object:set_yaw(yaw)
--self:update_roll() self:update_roll()
end end
-- end rotation -- end rotation
end end

View File

@ -1,24 +1,11 @@
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
local mob_class = mcl_mobs.mob_class local mob_class = mcl_mobs.mob_class
local PATHFINDING_FAIL_THRESHOLD = 100 -- no. of ticks to fail before giving up. 20p/s. 5s helps them get through door local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager",false)
local PATHFINDING_FAIL_WAIT = 30 -- how long to wait before trying to path again
local PATHFINDING = "gowp" local PATHFINDING = "gowp"
local enable_pathfinding = true
local one_down = vector.new(0,-1,0) local LOG_MODULE = "[Mobs]"
local one_up = vector.new(0,1,0)
local plane_adjacents = {
vector.new(1,0,0),
vector.new(-1,0,0),
vector.new(0,0,1),
vector.new(0,0,-1),
}
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_pathfinding",false)
local LOG_MODULE = "[Mobs Pathfinding]"
local function mcl_log (message) local function mcl_log (message)
if LOGGING_ON and message then if LOGGING_ON and message then
minetest.log(LOG_MODULE .. " " .. message) minetest.log(LOG_MODULE .. " " .. message)
@ -34,7 +21,7 @@ function output_table (wp)
end end
function append_paths (wp1, wp2) function append_paths (wp1, wp2)
--mcl_log("Start append") mcl_log("Start append")
if not wp1 or not wp2 then if not wp1 or not wp2 then
mcl_log("Cannot append wp's") mcl_log("Cannot append wp's")
return return
@ -44,7 +31,7 @@ function append_paths (wp1, wp2)
for _,a in pairs (wp2) do for _,a in pairs (wp2) do
table.insert(wp1, a) table.insert(wp1, a)
end end
--mcl_log("End append") mcl_log("End append")
end end
local function output_enriched (wp_out) local function output_enriched (wp_out)
@ -56,12 +43,11 @@ local function output_enriched (wp_out)
local action = outy["action"] local action = outy["action"]
if action then if action then
--mcl_log("Pos ".. i ..":" .. minetest.pos_to_string(outy["pos"]))
mcl_log("type: " .. action["type"]) mcl_log("type: " .. action["type"])
mcl_log("action: " .. action["action"]) mcl_log("action: " .. action["action"])
mcl_log("target: " .. minetest.pos_to_string(action["target"])) mcl_log("target: " .. minetest.pos_to_string(action["target"]))
end end
--mcl_log("failed attempts: " .. outy["failed_attempts"]) mcl_log("failed attempts: " .. outy["failed_attempts"])
end end
end end
@ -70,26 +56,34 @@ end
-- an action, such as to open or close a door where we know that pos requires that action -- an action, such as to open or close a door where we know that pos requires that action
local function generate_enriched_path(wp_in, door_open_pos, door_close_pos, cur_door_pos) local function generate_enriched_path(wp_in, door_open_pos, door_close_pos, cur_door_pos)
local wp_out = {} local wp_out = {}
-- TODO Just pass in door position and the index before is open, the index after is close
local current_door_index = -1
for i, cur_pos in pairs(wp_in) do for i, cur_pos in pairs(wp_in) do
local action = nil local action = nil
local one_down = vector.new(0,-1,0)
local cur_pos_to_add = vector.add(cur_pos, one_down) local cur_pos_to_add = vector.add(cur_pos, one_down)
if door_open_pos and vector.equals (cur_pos, door_open_pos) then if door_open_pos and vector.equals (cur_pos, door_open_pos) then
mcl_log ("Door open match") mcl_log ("Door open match")
action = {type = "door", action = "open", target = cur_door_pos} --action = {type = "door", action = "open"}
action = {}
action["type"] = "door"
action["action"] = "open"
action["target"] = cur_door_pos
cur_pos_to_add = vector.add(cur_pos, one_down) cur_pos_to_add = vector.add(cur_pos, one_down)
elseif door_close_pos and vector.equals(cur_pos, door_close_pos) then elseif door_close_pos and vector.equals(cur_pos, door_close_pos) then
mcl_log ("Door close match") mcl_log ("Door close match")
action = {type = "door", action = "close", target = cur_door_pos} --action = {type = "door", action = "closed"}
action = {}
action["type"] = "door"
action["action"] = "close"
action["target"] = cur_door_pos
cur_pos_to_add = vector.add(cur_pos, one_down) cur_pos_to_add = vector.add(cur_pos, one_down)
elseif cur_door_pos and vector.equals(cur_pos, cur_door_pos) then elseif cur_door_pos and vector.equals(cur_pos, cur_door_pos) then
mcl_log("Current door pos") mcl_log("Current door pos")
action = {type = "door", action = "open", target = cur_door_pos}
cur_pos_to_add = vector.add(cur_pos, one_down) cur_pos_to_add = vector.add(cur_pos, one_down)
action = {}
action["type"] = "door"
action["action"] = "open"
action["target"] = cur_door_pos
else else
cur_pos_to_add = cur_pos cur_pos_to_add = cur_pos
--mcl_log ("Pos doesn't match") --mcl_log ("Pos doesn't match")
@ -107,156 +101,106 @@ local function generate_enriched_path(wp_in, door_open_pos, door_close_pos, cur_
return wp_out return wp_out
end end
function mob_class:ready_to_path() local plane_adjacents = {
mcl_log("Check ready to path") vector.new(1,0,0),
if self._pf_last_failed and (os.time() - self._pf_last_failed) < PATHFINDING_FAIL_WAIT then vector.new(-1,0,0),
mcl_log("Not ready to path as last fail is less than threshold: " .. (os.time() - self._pf_last_failed)) vector.new(0,0,1),
return false vector.new(0,0,-1),
else }
mcl_log("We are ready to pathfind, no previous fail or we are past threshold")
return true
end
end
-- This function is used to see if we can path. We could use to check a route, rather than making people move. -- This function is used to see if we can path. We could use to check a route, rather than making people move.
local function calculate_path_through_door (p, cur_door_pos, t) local function calculate_path_through_door (p, t, target)
if t then -- target is the same as t, just 1 square difference. Maybe we don't need target
mcl_log("Plot route through door from pos: " .. minetest.pos_to_string(p) .. ", to target: " .. minetest.pos_to_string(t)) mcl_log("Plot route from mob: " .. minetest.pos_to_string(p) .. ", to target: " .. minetest.pos_to_string(t))
else
mcl_log("Plot route through door from pos: " .. minetest.pos_to_string(p))
end
local enriched_path = nil local enriched_path = nil
local wp, prospective_wp
local cur_door_pos = nil
local pos_closest_to_door = nil local pos_closest_to_door = nil
local other_side_of_door = nil local other_side_of_door = nil
--Path to door first
local wp = minetest.find_path(p,t,150,1,4)
if not wp then
mcl_log("No direct path. Path through door")
-- This could improve. There could be multiple doors. Check you can path from door to target first.
local cur_door_pos = minetest.find_node_near(target,16,{"group:door"})
if cur_door_pos then if cur_door_pos then
mcl_log("Found a door near: " .. minetest.pos_to_string(cur_door_pos)) mcl_log("Found a door near: " .. minetest.pos_to_string(cur_door_pos))
for _,v in pairs(plane_adjacents) do for _,v in pairs(plane_adjacents) do
pos_closest_to_door = vector.add(cur_door_pos,v) pos_closest_to_door = vector.add(cur_door_pos,v)
other_side_of_door = vector.add(cur_door_pos,-v)
local n = minetest.get_node(pos_closest_to_door) local n = minetest.get_node(pos_closest_to_door)
if n.name == "air" then if n.name == "air" then
mcl_log("We have air space next to door at: " .. minetest.pos_to_string(pos_closest_to_door)) wp = minetest.find_path(p,pos_closest_to_door,150,1,4)
if wp then
prospective_wp = minetest.find_path(p,pos_closest_to_door,150,1,4)
if prospective_wp then
mcl_log("Found a path to next to door".. minetest.pos_to_string(pos_closest_to_door)) mcl_log("Found a path to next to door".. minetest.pos_to_string(pos_closest_to_door))
other_side_of_door = vector.add(cur_door_pos,-v)
mcl_log("Opposite is: ".. minetest.pos_to_string(other_side_of_door)) mcl_log("Opposite is: ".. minetest.pos_to_string(other_side_of_door))
table.insert(prospective_wp, cur_door_pos)
if t then
mcl_log("We have t, lets go from door to target")
local wp_otherside_door_to_target = minetest.find_path(other_side_of_door,t,150,1,4) local wp_otherside_door_to_target = minetest.find_path(other_side_of_door,t,150,1,4)
if wp_otherside_door_to_target and #wp_otherside_door_to_target > 0 then if wp_otherside_door_to_target and #wp_otherside_door_to_target > 0 then
append_paths (prospective_wp, wp_otherside_door_to_target) table.insert(wp, cur_door_pos)
append_paths (wp, wp_otherside_door_to_target)
wp = prospective_wp enriched_path = generate_enriched_path(wp, pos_closest_to_door, other_side_of_door, cur_door_pos)
mcl_log("We have a path from outside door to target") mcl_log("We have a path from outside door to target")
else else
mcl_log("We cannot path from outside door to target") mcl_log("We cannot path from outside door to target")
end end
break
else else
mcl_log("No t, just add other side of door") mcl_log("This block next to door doesn't work.")
table.insert(prospective_wp, other_side_of_door) end
wp = prospective_wp else
mcl_log("Block is not air, it is: ".. n.name)
end end
if wp then
enriched_path = generate_enriched_path(wp, pos_closest_to_door, other_side_of_door, cur_door_pos)
break
end
else
mcl_log("Cannot path to this air block next to door.")
end
end
end end
else else
mcl_log("No door found") mcl_log("No door found")
end end
else
mcl_log("We have a direct route")
end
if wp and not enriched_path then if wp and not enriched_path then
mcl_log("Wp but not enriched")
enriched_path = generate_enriched_path(wp) enriched_path = generate_enriched_path(wp)
end end
return enriched_path return enriched_path
end end
local gopath_last = os.time()
function mob_class:gopath(target,callback_arrived) function mob_class:gopath(target,callback_arrived)
if self.state == PATHFINDING then mcl_log("Already pathfinding, don't set another until done.") return end if self.state == PATHFINDING then mcl_log("Already pathfinding, don't set another until done.") return end
if not self:ready_to_path() then return end
if self._pf_last_failed and (os.time() - self._pf_last_failed) < 30 then
mcl_log("We are not ready to path as last fail is less than threshold: " .. (os.time() - self._pf_last_failed))
return
else
mcl_log("We are ready to pathfind, no previous fail or we are past threshold")
end
--if os.time() - gopath_last < 5 then
-- mcl_log("Not ready to path yet")
-- return
--end
--gopath_last = os.time()
self.order = nil self.order = nil
local p = self.object:get_pos() local p = self.object:get_pos()
local t = vector.offset(target,0,1,0) local t = vector.offset(target,0,1,0)
--Check direct route local wp = calculate_path_through_door(p, t, target)
local wp = minetest.find_path(p,t,150,1,4)
if not wp then
mcl_log("### No direct path. Path through door closest to target.")
local door_near_target = minetest.find_node_near(target, 16, {"group:door"})
wp = calculate_path_through_door(p, door_near_target, t)
if not wp then
mcl_log("### No path though door closest to target. Try door closest to origin.")
local door_closest = minetest.find_node_near(p, 16, {"group:door"})
wp = calculate_path_through_door(p, door_closest, t)
-- Path through 2 doors
if not wp then
mcl_log("### Still not wp. Need to path through 2 doors.")
local path_through_closest_door = calculate_path_through_door(p, door_closest)
if path_through_closest_door and #path_through_closest_door > 0 then
mcl_log("We have path through first door")
mcl_log("Number of pos in path through door: " .. tostring(#path_through_closest_door))
local pos_after_door_entry = path_through_closest_door[#path_through_closest_door]
if pos_after_door_entry then
local pos_after_door = vector.add(pos_after_door_entry["pos"], one_up)
mcl_log("pos_after_door: " .. minetest.pos_to_string(pos_after_door))
local path_after_door = calculate_path_through_door(pos_after_door, door_near_target, t)
if path_after_door and #path_after_door > 1 then
mcl_log("We have path after first door")
table.remove(path_after_door, 1) -- Remove duplicate
wp = path_through_closest_door
append_paths (wp, path_after_door)
else
mcl_log("Path after door is not good")
end
else
mcl_log("No pos after door")
end
else
mcl_log("Path through closest door empty or null")
end
else
mcl_log("ok, we have a path through 1 door")
end
end
else
wp = generate_enriched_path(wp)
mcl_log("We have a direct route")
end
if not wp then if not wp then
mcl_log("Could not calculate path") mcl_log("Could not calculate path")
self._pf_last_failed = os.time() self._pf_last_failed = os.time()
-- If cannot path, don't immediately try again -- Cover for a flaw in pathfind where it chooses the wrong door and gets stuck. Take a break, allow others.
end end
--output_table(wp)
if wp and #wp > 0 then if wp and #wp > 0 then
--output_table(wp)
self._target = t self._target = t
self.callback_arrived = callback_arrived self.callback_arrived = callback_arrived
local current_location = table.remove(wp,1) local current_location = table.remove(wp,1)
@ -325,7 +269,17 @@ function mob_class:do_pathfind_action(action)
end end
end end
local gowp_etime = 0
function mob_class:check_gowp(dtime) function mob_class:check_gowp(dtime)
gowp_etime = gowp_etime + dtime
-- 0.1 is optimal.
--less frequently = villager will get sent back after passing a point.
--more frequently = villager will fail points they shouldn't they just didn't get there yet
--if gowp_etime < 0.05 then return end
--gowp_etime = 0
local p = self.object:get_pos() local p = self.object:get_pos()
-- no destination -- no destination
@ -338,7 +292,7 @@ function mob_class:check_gowp(dtime)
-- arrived at location, finish gowp -- arrived at location, finish gowp
local distance_to_targ = vector.distance(p,self._target) local distance_to_targ = vector.distance(p,self._target)
--mcl_log("Distance to targ: ".. tostring(distance_to_targ)) --mcl_log("Distance to targ: ".. tostring(distance_to_targ))
if distance_to_targ < 1.8 then if distance_to_targ < 2 then
mcl_log("Arrived at _target") mcl_log("Arrived at _target")
self.waypoints = nil self.waypoints = nil
self._target = nil self._target = nil
@ -349,8 +303,6 @@ function mob_class:check_gowp(dtime)
self.object:set_acceleration({x = 0, y = 0, z = 0}) self.object:set_acceleration({x = 0, y = 0, z = 0})
if self.callback_arrived then return self.callback_arrived(self) end if self.callback_arrived then return self.callback_arrived(self) end
return true return true
elseif not self.current_target then
mcl_log("Not close enough to targ: ".. tostring(distance_to_targ))
end end
-- More pathing to be done -- More pathing to be done
@ -363,7 +315,7 @@ function mob_class:check_gowp(dtime)
-- 0.8 is optimal for 0.025 frequency checks and also 1... Actually. 0.8 is winning -- 0.8 is optimal for 0.025 frequency checks and also 1... Actually. 0.8 is winning
-- 0.9 and 1.0 is also good. Stick with unless door open or closing issues -- 0.9 and 1.0 is also good. Stick with unless door open or closing issues
if self.waypoints and #self.waypoints > 0 and ( not self.current_target or not self.current_target["pos"] or distance_to_current_target < 0.9 ) then if self.waypoints and #self.waypoints > 0 and ( not self.current_target or not self.current_target["pos"] or distance_to_current_target < 0.9 ) then
-- We have waypoints, and are at current_target or have no current target. We need a new current_target. -- We have waypoints, and no current target, or we're at it. We need a new current_target.
self:do_pathfind_action (self.current_target["action"]) self:do_pathfind_action (self.current_target["action"])
local failed_attempts = self.current_target["failed_attempts"] local failed_attempts = self.current_target["failed_attempts"]
@ -373,11 +325,10 @@ function mob_class:check_gowp(dtime)
self:go_to_pos(self.current_target["pos"]) self:go_to_pos(self.current_target["pos"])
return return
elseif self.current_target and self.current_target["pos"] then elseif self.current_target and self.current_target["pos"] then
-- No waypoints left, but have current target and not close enough. Potentially last waypoint to go to. -- No waypoints left, but have current target. Potentially last waypoint to go to.
self.current_target["failed_attempts"] = self.current_target["failed_attempts"] + 1 self.current_target["failed_attempts"] = self.current_target["failed_attempts"] + 1
local failed_attempts = self.current_target["failed_attempts"] local failed_attempts = self.current_target["failed_attempts"]
if failed_attempts >= PATHFINDING_FAIL_THRESHOLD then if failed_attempts >= 50 then
mcl_log("Failed to reach position (" .. minetest.pos_to_string(self.current_target["pos"]) .. ") too many times. Abandon route. Times tried: " .. failed_attempts) mcl_log("Failed to reach position (" .. minetest.pos_to_string(self.current_target["pos"]) .. ") too many times. Abandon route. Times tried: " .. failed_attempts)
self.state = "stand" self.state = "stand"
self.current_target = nil self.current_target = nil
@ -397,22 +348,9 @@ function mob_class:check_gowp(dtime)
-- Is a little sensitive and could take 1 - 7 times. A 10 fail count might be a good exit condition. -- Is a little sensitive and could take 1 - 7 times. A 10 fail count might be a good exit condition.
mcl_log("We don't have waypoints or a current target. Let's try to path to target") mcl_log("We don't have waypoints or a current target. Let's try to path to target")
if self.waypoints then
mcl_log("WP: " .. tostring(self.waypoints))
mcl_log("WP num: " .. tostring(#self.waypoints))
else
mcl_log("No wp set")
end
if self.current_target then
mcl_log("Current target: " .. tostring(self.current_target))
else
mcl_log("No current target")
end
local final_wp = minetest.find_path(p,self._target,150,1,4) local final_wp = minetest.find_path(p,self._target,150,1,4)
if final_wp then if final_wp then
mcl_log("We can get to target here.") mcl_log("We might be able to get to target here.")
-- self.waypoints = final_wp -- self.waypoints = final_wp
self:go_to_pos(self._target) self:go_to_pos(self._target)
else else
@ -436,9 +374,9 @@ function mob_class:check_gowp(dtime)
self:go_to_pos(self._current_target) self:go_to_pos(self._current_target)
else else
mcl_log("close to current target: ".. minetest.pos_to_string(self.current_target["pos"])) mcl_log("close to current target: ".. minetest.pos_to_string(self.current_target["pos"]))
mcl_log("target is: ".. minetest.pos_to_string(self._target))
self.current_target = nil self.current_target = nil
end end
return return
end end
end end

View File

@ -5,7 +5,8 @@ local ENTITY_CRAMMING_MAX = 24
local CRAMMING_DAMAGE = 3 local CRAMMING_DAMAGE = 3
local DEATH_DELAY = 0.5 local DEATH_DELAY = 0.5
local DEFAULT_FALL_SPEED = -9.81*1.5 local DEFAULT_FALL_SPEED = -9.81*1.5
local FLOP_HEIGHT = 6
local FLOP_HOR_SPEED = 1.5
local PATHFINDING = "gowp" local PATHFINDING = "gowp"
local mobs_debug = minetest.settings:get_bool("mobs_debug", false) local mobs_debug = minetest.settings:get_bool("mobs_debug", false)
local mobs_drop_items = minetest.settings:get_bool("mobs_drop_items") ~= false local mobs_drop_items = minetest.settings:get_bool("mobs_drop_items") ~= false
@ -182,17 +183,6 @@ function mob_class:collision()
return({x,z}) return({x,z})
end end
function mob_class:slow_mob()
local d = 0.85
if self:check_dying() then d = 0.92 end
local v = self.object:get_velocity()
if v then
--diffuse object velocity
self.object:set_velocity({x = v.x*d, y = v.y, z = v.z*d})
end
end
-- move mob in facing direction -- move mob in facing direction
function mob_class:set_velocity(v) function mob_class:set_velocity(v)
local c_x, c_y = 0, 0 local c_x, c_y = 0, 0
@ -364,7 +354,7 @@ function mob_class:set_yaw(yaw, delay, dtime)
if self.shaking and dtime then if self.shaking and dtime then
yaw = yaw + (math.random() * 2 - 1) * 5 * dtime yaw = yaw + (math.random() * 2 - 1) * 5 * dtime
end end
--self:update_roll() self:update_roll()
return yaw return yaw
end end
@ -788,25 +778,6 @@ function mob_class:do_env_damage()
return self:check_for_death("", {type = "unknown"}) return self:check_for_death("", {type = "unknown"})
end end
function mob_class:env_damage (dtime, pos)
-- environmental damage timer (every 1 second)
self.env_damage_timer = self.env_damage_timer + dtime
if (self.state == "attack" and self.env_damage_timer > 1)
or self.state ~= "attack" then
self:check_entity_cramming()
self.env_damage_timer = 0
-- check for environmental damage (water, fire, lava etc.)
if self:do_env_damage() then
return true
end
-- node replace check (cow eats grass etc.)
self:replace(pos)
end
end
function mob_class:damage_mob(reason,damage) function mob_class:damage_mob(reason,damage)
if not self.health then return end if not self.health then return end
damage = math.floor(damage) damage = math.floor(damage)

View File

@ -169,8 +169,6 @@ local list_of_all_biomes = {
"MushroomIslandShore", "MushroomIslandShore",
"JungleM_shore", "JungleM_shore",
"Jungle_shore", "Jungle_shore",
"BambooJungleM_shore",
"BambooJungle_shore",
"MangroveSwamp_shore", "MangroveSwamp_shore",
-- dimension biome: -- dimension biome:
@ -218,10 +216,6 @@ local list_of_all_biomes = {
"JungleEdge", "JungleEdge",
"SavannaM", "SavannaM",
"MangroveSwamp", "MangroveSwamp",
"BambooJungle",
"BambooJungleEdge",
"BambooJungleEdgeM",
"BambooJungleM",
} }
-- count how many mobs are in an area -- count how many mobs are in an area
@ -250,24 +244,6 @@ local function count_mobs_total(mob_type)
return num return num
end end
local function count_mobs_all()
local mobs_found = {}
local num = 0
for _,entity in pairs(minetest.luaentities) do
if entity.is_mob then
local mob_type = entity.type -- animal / monster / npc
local mob_name = entity.name
if mobs_found[mob_name] then
mobs_found[mob_name] = mobs_found[mob_name] + 1
else
mobs_found[mob_name] = 1
end
num = num + 1
end
end
return mobs_found, num
end
local function count_mobs_total_cap(mob_type) local function count_mobs_total_cap(mob_type)
local num = 0 local num = 0
for _,l in pairs(minetest.luaentities) do for _,l in pairs(minetest.luaentities) do
@ -426,9 +402,11 @@ local two_pi = 2 * math.pi
local function get_next_mob_spawn_pos(pos) local function get_next_mob_spawn_pos(pos)
local distance = math_random(25, 32) local distance = math_random(25, 32)
local angle = math_random() * two_pi local angle = math_random() * two_pi
local xoff = math_round(distance * math_cos(angle)) return {
local yoff = math_round(distance * math_sin(angle)) x = math_round(pos.x + distance * math_cos(angle)),
return vector.offset(pos, xoff, 0, yoff) y = pos.y,
z = math_round(pos.z + distance * math_sin(angle))
}
end end
local function decypher_limits(posy) local function decypher_limits(posy)
@ -581,7 +559,7 @@ local S = minetest.get_translator("mcl_mobs")
minetest.register_chatcommand("spawn_mob",{ minetest.register_chatcommand("spawn_mob",{
privs = { debug = true }, privs = { debug = true },
description=S("spawn_mob is a chatcommand that allows you to type in the name of a mob without 'typing mobs_mc:' all the time like so; 'spawn_mob spider'. however, there is more you can do with this special command, currently you can edit any number, boolean, and string variable you choose with this format: spawn_mob 'any_mob:var<mobs_variable=variable_value>:'. any_mob being your mob of choice, mobs_variable being the variable, and variable value being the value of the chosen variable. and example of this format: \n spawn_mob skeleton:var<passive=true>:\n this would spawn a skeleton that wouldn't attack you. REMEMBER-THIS> when changing a number value always prefix it with 'NUM', example: \n spawn_mob skeleton:var<jump_height=NUM10>:\n this setting the skelly's jump height to 10. if you want to make multiple changes to a mob, you can, example: \n spawn_mob skeleton:var<passive=true>::var<jump_height=NUM10>::var<fly_in=air>::var<fly=true>:\n etc."), description=S("spawn_mob is a chatcommand that allows you to type in the name of a mob without 'typing mobs_mc:' all the time like so; 'spawn_mob spider'. however, there is more you can do with this special command, currently you can edit any number, boolian, and string variable you choose with this format: spawn_mob 'any_mob:var<mobs_variable=variable_value>:'. any_mob being your mob of choice, mobs_variable being the variable, and variable value being the value of the chosen variable. and example of this format: \n spawn_mob skeleton:var<passive=true>:\n this would spawn a skeleton that wouldn't attack you. REMEMBER-THIS> when changing a number value always prefix it with 'NUM', example: \n spawn_mob skeleton:var<jump_height=NUM10>:\n this setting the skelly's jump height to 10. if you want to make multiple changes to a mob, you can, example: \n spawn_mob skeleton:var<passive=true>::var<jump_height=NUM10>::var<fly_in=air>::var<fly=true>:\n etc."),
func = function(n,param) func = function(n,param)
local pos = minetest.get_player_by_name(n):get_pos() local pos = minetest.get_player_by_name(n):get_pos()
@ -601,7 +579,6 @@ minetest.register_chatcommand("spawn_mob",{
local mob = mcl_mobs.spawn(pos,mobname) local mob = mcl_mobs.spawn(pos,mobname)
if mob then
for c=1, #modifiers do for c=1, #modifiers do
modifs = modifiers[c] modifs = modifiers[c]
@ -609,6 +586,8 @@ minetest.register_chatcommand("spawn_mob",{
local mod_start = string.find(modifs, "<") local mod_start = string.find(modifs, "<")
local mod_vals = string.find(modifs, "=") local mod_vals = string.find(modifs, "=")
local mod_end = string.find(modifs, ">") local mod_end = string.find(modifs, ">")
local mod_end = string.find(modifs, ">")
if mob then
local mob_entity = mob:get_luaentity() local mob_entity = mob:get_luaentity()
if string.sub(modifs, mod1+1, mod1+3) == "var" then if string.sub(modifs, mod1+1, mod1+3) == "var" then
if mod1 and mod_start and mod_vals and mod_end then if mod1 and mod_start and mod_vals and mod_end then
@ -639,12 +618,14 @@ minetest.register_chatcommand("spawn_mob",{
minetest.log("warning", n.." couldn't modify "..mobname.." at "..minetest.pos_to_string(pos).. ", missing modification type") minetest.log("warning", n.." couldn't modify "..mobname.." at "..minetest.pos_to_string(pos).. ", missing modification type")
end end
end end
minetest.log("action", n.." spawned "..mobname.." at "..minetest.pos_to_string(pos))
return true, mobname.." spawned at "..minetest.pos_to_string(pos)
else
return false, "Couldn't spawn "..mobname
end end
if mob then
return true, mobname.." spawned at "..minetest.pos_to_string(pos),
minetest.log("action", n.." spawned "..mobname.." at "..minetest.pos_to_string(pos))
end
return false, "Couldn't spawn "..mobname
end end
}) })
@ -652,9 +633,6 @@ if mobs_spawn then
local perlin_noise local perlin_noise
-- Get pos to spawn, x and z are randomised, y is range
local function spawn_a_mob(pos, dimension, y_min, y_max) local function spawn_a_mob(pos, dimension, y_min, y_max)
--create a disconnected clone of the spawn dictionary --create a disconnected clone of the spawn dictionary
--prevents memory leak --prevents memory leak
@ -749,9 +727,7 @@ if mobs_spawn then
end) end)
end end
function mob_class:check_despawn(pos, dtime) function mob_class:check_despawn(pos)
self.lifetimer = self.lifetimer - dtime
-- Despawning: when lifetimer expires, remove mob -- Despawning: when lifetimer expires, remove mob
if remove_far if remove_far
and self.can_despawn == true and self.can_despawn == true
@ -784,18 +760,5 @@ minetest.register_chatcommand("mobstats",{
minetest.chat_send_player(n,"total mobs:"..count_mobs_total()) minetest.chat_send_player(n,"total mobs:"..count_mobs_total())
minetest.chat_send_player(n,"spawning attempts since server start:"..dbg_spawn_attempts) minetest.chat_send_player(n,"spawning attempts since server start:"..dbg_spawn_attempts)
minetest.chat_send_player(n,"successful spawns since server start:"..dbg_spawn_succ) minetest.chat_send_player(n,"successful spawns since server start:"..dbg_spawn_succ)
local mob_counts, total_mobs = count_mobs_all()
if (total_mobs) then
minetest.log("action", "Total mobs found: " .. total_mobs)
end
if mob_counts then
for k, v1 in pairs(mob_counts) do
minetest.log("action", "k: " .. tostring(k))
minetest.log("action", "v1: " .. tostring(v1))
end
end
end end
}) })

View File

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

View File

@ -65,7 +65,7 @@ local axolotl = {
awards.unlock(clicker:get_player_name(), "mcl:cutestPredator") awards.unlock(clicker:get_player_name(), "mcl:cutestPredator")
return return
end end
if self:feed_tame(clicker, 1, true, false) then return end if mcl_mobs:feed_tame(self, clicker, 1, true, false) then return end
end, end,
makes_footstep_sound = false, makes_footstep_sound = false,
fly = true, fly = true,

View File

@ -12,13 +12,13 @@ mcl_mobs.register_mob("mobs_mc:chicken", {
description = S("Chicken"), description = S("Chicken"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
passive = true,
runaway = true,
hp_min = 4, hp_min = 4,
hp_max = 4, hp_max = 4,
xp_min = 1, xp_min = 1,
xp_max = 3, xp_max = 3,
collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.69, 0.2}, collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.69, 0.2},
runaway = true,
floats = 1, floats = 1,
head_swivel = "head.control", head_swivel = "head.control",
bone_eye_height = 4, bone_eye_height = 4,

View File

@ -64,7 +64,7 @@ local cod = {
chance = 1, chance = 1,
min = 1, min = 1,
max = 1,}, max = 1,},
{name = "mcl_bone_meal:bone_meal", {name = "mcl_dye:white",
chance = 20, chance = 20,
min = 1, min = 1,
max = 1,}, max = 1,},

View File

@ -7,13 +7,12 @@ local cow_def = {
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
passive = true, passive = true,
runaway = true,
hp_min = 10, hp_min = 10,
hp_max = 10, hp_max = 10,
xp_min = 1, xp_min = 1,
xp_max = 3, xp_max = 3,
collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.39, 0.45}, collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.39, 0.45},
spawn_in_group = 4, spawn_in_group = 8,
spawn_in_group_min = 3, spawn_in_group_min = 3,
visual = "mesh", visual = "mesh",
mesh = "mobs_mc_cow.b3d", mesh = "mobs_mc_cow.b3d",
@ -41,6 +40,7 @@ local cow_def = {
max = 2, max = 2,
looting = "common",}, looting = "common",},
}, },
runaway = true,
sounds = { sounds = {
random = "mobs_mc_cow", random = "mobs_mc_cow",
damage = "mobs_mc_cow_hurt", damage = "mobs_mc_cow_hurt",

View File

@ -259,7 +259,6 @@ mcl_mobs.register_mob("mobs_mc:enderman", {
description = S("Enderman"), description = S("Enderman"),
type = "monster", type = "monster",
spawn_class = "passive", spawn_class = "passive",
can_despawn = true,
passive = true, passive = true,
pathfinding = 1, pathfinding = 1,
hp_min = 40, hp_min = 40,
@ -443,7 +442,6 @@ mcl_mobs.register_mob("mobs_mc:enderman", {
end end
end end
end end
-- TAKE AND PLACE STUFF BEHAVIOUR BELOW. -- TAKE AND PLACE STUFF BEHAVIOUR BELOW.
if not mobs_griefing then if not mobs_griefing then
return return
@ -471,7 +469,6 @@ mcl_mobs.register_mob("mobs_mc:enderman", {
local dug = minetest.get_node_or_nil(take_pos) local dug = minetest.get_node_or_nil(take_pos)
if dug and dug.name == "air" then if dug and dug.name == "air" then
self._taken_node = node.name self._taken_node = node.name
self.can_despawn = false
local def = minetest.registered_nodes[self._taken_node] local def = minetest.registered_nodes[self._taken_node]
-- Update animation and texture accordingly (adds visibly carried block) -- Update animation and texture accordingly (adds visibly carried block)
local block_type local block_type
@ -522,7 +519,6 @@ mcl_mobs.register_mob("mobs_mc:enderman", {
if success then if success then
local def = minetest.registered_nodes[self._taken_node] local def = minetest.registered_nodes[self._taken_node]
-- Update animation accordingly (removes visible block) -- Update animation accordingly (removes visible block)
self.can_despawn = true
self.animation = select_enderman_animation("normal") self.animation = select_enderman_animation("normal")
self:set_animation(self.animation.current) self:set_animation(self.animation.current)
if def.sounds and def.sounds.place then if def.sounds and def.sounds.place then

View File

@ -1,70 +0,0 @@
# textdomain: mobs_mc
Agent=エージェント
Axolotl=ウーパールーパー
Bat=コウモリ
Blaze=ブレイズ
Chicken=ニワトリ
Cow=ウシ
Mooshroom=ムーシュルーム
Creeper=クリーパー
Ender Dragon=エンダードラゴン
Enderman=エンダーマン
Endermite=エンダーマイト
Ghast=ガスト
Elder Guardian=エルダーガーディアン
Guardian=ガーディアン
Horse=ウマ
Skeleton Horse=スケルトンホース
Zombie Horse=ゾンビホース
Donkey=ロバ
Mule=ラバ
Iron Golem=アイアンゴーレム
Llama=ラマ
Ocelot=ヤマネコ
Parrot=オウム
Pig=ブタ
Polar Bear=シロクマ
Rabbit=ウサギ
Killer Bunny=殺人ウサギ
Sheep=ヒツジ
Shulker=シュルカー
Silverfish=シルバーフィッシュ
Skeleton=スケルトン
Stray=ストレイ
Wither Skeleton=ウィザースケルトン
Magma Cube=マグマキューブ
Slime=スライム
Snow Golem=スノーゴーレム
Spider=クモ
Cave Spider=洞窟グモ
Squid=イカ
Vex=ヴェックス
Evoker=エヴォーカー
Illusioner=イリュージョナー
Villager=村人
Vindicator=ヴィンディケーター
Zombie Villager=村人ゾンビ
Witch=魔女
Wither=ウィザー
Wolf=オオカミ
Husk=ハスク
Zombie=ゾンビ
Zombie Pigman=ゾンビピッグマン
Farmer=農民
Fisherman=漁師
Fletcher=矢師
Shepherd=羊飼い
Librarian=司書
Cartographer=製図家
Armorer=防具鍛冶
Leatherworker=革職人
Butcher=肉屋
Weapon Smith=武器鍛冶
Tool Smith=道具鍛冶
Cleric=聖職者
Nitwit=求職者
Cod=タラ
Salmon=サケ
Dolphin=イルカ
Pillager=ピリジャー
Tropical fish=クマノミ

View File

@ -2,4 +2,4 @@ name = mobs_mc
author = maikerumine author = maikerumine
description = Adds Minecraft-like monsters and animals. description = Adds Minecraft-like monsters and animals.
depends = mcl_init, mcl_particles, mcl_mobs, mcl_wip, mcl_core, mcl_util depends = mcl_init, mcl_particles, mcl_mobs, mcl_wip, mcl_core, mcl_util
optional_depends = default, mcl_tnt, mcl_bows, mcl_throwing, mcl_fishing, bones, mesecons_materials, doc_items optional_depends = default, mcl_tnt, mcl_bows, mcl_throwing, mcl_fishing, bones, mesecons_materials, mobs_mc_gameconfig, doc_items

View File

@ -164,7 +164,7 @@ cat.on_spawn = function(self)
if not self._texture then if not self._texture then
self._texture = cat.textures[math.random(#cat.textures)] self._texture = cat.textures[math.random(#cat.textures)]
end end
self.object:set_properties({textures = self._texture}) self.object:set_properties({textures = {self._texture}})
end end
mcl_mobs.register_mob("mobs_mc:cat", cat) mcl_mobs.register_mob("mobs_mc:cat", cat)

View File

@ -6,7 +6,6 @@ mcl_mobs.register_mob("mobs_mc:pig", {
description = S("Pig"), description = S("Pig"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
passive = true,
runaway = true, runaway = true,
hp_min = 10, hp_min = 10,
hp_max = 10, hp_max = 10,

View File

@ -42,7 +42,7 @@ local salmon = {
chance = 1, chance = 1,
min = 1, min = 1,
max = 1,}, max = 1,},
{name = "mcl_bone_meal:bone_meal", {name = "mcl_dye:white",
chance = 20, chance = 20,
min = 1, min = 1,
max = 1,}, max = 1,},

View File

@ -56,7 +56,6 @@ mcl_mobs.register_mob("mobs_mc:sheep", {
description = S("Sheep"), description = S("Sheep"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
passive = true,
hp_min = 8, hp_min = 8,
hp_max = 8, hp_max = 8,
xp_min = 1, xp_min = 1,

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