Compare commits
1 Commits
master
...
water_foot
Author | SHA1 | Date |
---|---|---|
iliekprogrammar | 6111f3465a |
|
@ -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!
|
|
|
@ -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!
|
|
|
@ -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?
|
|
|
@ -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!
|
|
|
@ -4,4 +4,3 @@
|
||||||
*.blend2
|
*.blend2
|
||||||
*.blend3
|
*.blend3
|
||||||
/.idea/
|
/.idea/
|
||||||
*.xcf
|
|
10
CREDITS.md
|
@ -35,8 +35,7 @@
|
||||||
* SumianVoice
|
* SumianVoice
|
||||||
* MrRar
|
* MrRar
|
||||||
* talamh
|
* talamh
|
||||||
* Faerraven / Michieal
|
* Faerraven
|
||||||
* FossFanatic
|
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
* Laurent Rocher
|
* Laurent Rocher
|
||||||
|
@ -97,8 +96,6 @@
|
||||||
* TheOnlyJoeEnderman
|
* TheOnlyJoeEnderman
|
||||||
* Ranko Saotome
|
* Ranko Saotome
|
||||||
* Gregor Parzefall
|
* Gregor Parzefall
|
||||||
* Wbjitscool
|
|
||||||
* b3nderman
|
|
||||||
|
|
||||||
## MineClone5
|
## MineClone5
|
||||||
* kay27
|
* kay27
|
||||||
|
@ -150,13 +147,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 +166,6 @@
|
||||||
* RandomLegoBrick
|
* RandomLegoBrick
|
||||||
* cora
|
* cora
|
||||||
* Faerraven / Michieal
|
* Faerraven / Michieal
|
||||||
* Nicu
|
|
||||||
|
|
||||||
## Translations
|
## Translations
|
||||||
* Wuzzy
|
* Wuzzy
|
||||||
|
@ -189,8 +183,6 @@
|
||||||
|
|
||||||
## Funders
|
## Funders
|
||||||
* 40W
|
* 40W
|
||||||
* bauknecht
|
|
||||||
* Cora
|
|
||||||
|
|
||||||
## Special thanks
|
## Special thanks
|
||||||
* celeron55 for creating Minetest
|
* celeron55 for creating Minetest
|
||||||
|
|
|
@ -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!
|
|
|
@ -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):
|
||||||
|
|
17
RELEASE.md
|
@ -1,22 +1,19 @@
|
||||||
#File to document release steps with a view to evolving into a script
|
#File to document release steps with a view to evolving into a script
|
||||||
|
|
||||||
#Update CREDITS.md
|
#Update CREDITS.md
|
||||||
#Update version in game.conf
|
#Update version in README.md (soon to be game.conf from of 0.82.0)
|
||||||
|
|
||||||
lua tools/generate_ingame_credits.lua
|
lua tools/generate_ingame_credits.lua
|
||||||
|
|
||||||
git add CREDITS.md
|
git add CREDITS.md
|
||||||
git add mods/HUD/mcl_credits/people.lua
|
git add mods/HUD/mcl_credits/people.lua
|
||||||
git add game.conf
|
|
||||||
|
|
||||||
#git add RELEASE.md
|
git add README.md
|
||||||
|
# To uncomment when applicable
|
||||||
|
#git add game.conf
|
||||||
|
|
||||||
git commit -m "Pre-release update credits and set version 0.82.0"
|
git commit -m "Pre-release update credits and set version 0.81.1"
|
||||||
|
|
||||||
git tag 0.82.0
|
git tag 0.81.1
|
||||||
|
|
||||||
git push origin 0.82.0
|
git push origin 0.81.1
|
||||||
|
|
||||||
#Update version in game.conf to -SNAPSHOT
|
|
||||||
|
|
||||||
git commit -m "Post-release set version 0.82.0-SNAPSHOT"
|
|
|
@ -1,4 +1,4 @@
|
||||||
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
|
version=MCL2-0.82-indev
|
|
@ -204,7 +204,7 @@ end
|
||||||
|
|
||||||
-- Checks if the given node would drop its useful drop if dug by a given tool.
|
-- Checks if the given node would drop its useful drop if dug by a given tool.
|
||||||
-- Returns true if it will yield its useful drop, false otherwise.
|
-- Returns true if it will yield its useful drop, false otherwise.
|
||||||
function mcl_autogroup.can_harvest(nodename, toolname, player)
|
function mcl_autogroup.can_harvest(nodename, toolname)
|
||||||
local ndef = minetest.registered_nodes[nodename]
|
local ndef = minetest.registered_nodes[nodename]
|
||||||
|
|
||||||
if not ndef then
|
if not ndef then
|
||||||
|
@ -228,9 +228,7 @@ function mcl_autogroup.can_harvest(nodename, toolname, player)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if it can be dug by hand
|
-- Check if it can be dug by hand
|
||||||
if not player or not player:is_player() then return false end
|
local tdef = minetest.registered_tools[""]
|
||||||
local name = player:get_inventory():get_stack("hand", 1):get_name()
|
|
||||||
local tdef = minetest.registered_items[name]
|
|
||||||
if tdef then
|
if tdef then
|
||||||
for g, gdef in pairs(tdef._mcl_diggroups) do
|
for g, gdef in pairs(tdef._mcl_diggroups) do
|
||||||
if ndef.groups[g] then
|
if ndef.groups[g] then
|
||||||
|
@ -262,7 +260,7 @@ local function get_tool_capabilities(tdef)
|
||||||
|
|
||||||
-- If the damage group and punch interval from hand is not included,
|
-- If the damage group and punch interval from hand is not included,
|
||||||
-- then the user will not be able to attack with the tool.
|
-- then the user will not be able to attack with the tool.
|
||||||
local hand_toolcaps = mcl_meshhand.survival_hand_tool_caps
|
local hand_toolcaps = minetest.registered_tools[""].tool_capabilities
|
||||||
return {
|
return {
|
||||||
full_punch_interval = hand_toolcaps.full_punch_interval,
|
full_punch_interval = hand_toolcaps.full_punch_interval,
|
||||||
damage_groups = hand_toolcaps.damage_groups
|
damage_groups = hand_toolcaps.damage_groups
|
||||||
|
@ -282,7 +280,7 @@ end
|
||||||
-- would have to add _mcl_autogroup as a dependency which would break the mod
|
-- would have to add _mcl_autogroup as a dependency which would break the mod
|
||||||
-- loading order.
|
-- loading order.
|
||||||
function mcl_autogroup.get_groupcaps(toolname, efficiency)
|
function mcl_autogroup.get_groupcaps(toolname, efficiency)
|
||||||
local tdef = minetest.registered_items[toolname]
|
local tdef = minetest.registered_tools[toolname]
|
||||||
local groupcaps = table.copy(get_tool_capabilities(tdef).groupcaps or {})
|
local groupcaps = table.copy(get_tool_capabilities(tdef).groupcaps or {})
|
||||||
add_groupcaps(toolname, groupcaps, tdef._mcl_diggroups, efficiency)
|
add_groupcaps(toolname, groupcaps, tdef._mcl_diggroups, efficiency)
|
||||||
return groupcaps
|
return groupcaps
|
||||||
|
@ -352,7 +350,7 @@ local function overwrite()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for tname, tdef in pairs(minetest.registered_items) do
|
for tname, tdef in pairs(minetest.registered_tools) do
|
||||||
-- Assign groupcaps for digging the registered digging groups
|
-- Assign groupcaps for digging the registered digging groups
|
||||||
-- depending on the _mcl_diggroups in the tool definition
|
-- depending on the _mcl_diggroups in the tool definition
|
||||||
if tdef._mcl_diggroups then
|
if tdef._mcl_diggroups then
|
||||||
|
@ -362,12 +360,6 @@ local function overwrite()
|
||||||
minetest.override_item(tname, {
|
minetest.override_item(tname, {
|
||||||
tool_capabilities = toolcaps
|
tool_capabilities = toolcaps
|
||||||
})
|
})
|
||||||
else
|
|
||||||
-- This is needed to deal damage when punching mobs
|
|
||||||
-- with random items in hand in survival mode
|
|
||||||
minetest.override_item(tname, {
|
|
||||||
tool_capabilities = mcl_meshhand.survival_hand_tool_caps
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
# mcl_autogroup
|
# mcl_autogroup
|
||||||
This mod emulate digging times from mc.
|
This mod emulate digging times from mc.
|
||||||
|
|
||||||
## mcl_autogroup.can_harvest(nodename, toolname, player)
|
## mcl_autogroup.can_harvest(nodename, toolname)
|
||||||
Return true if <nodename> can be dig with <toolname> by <player>.
|
Return true if <nodename> can be dig with <toolname>.
|
||||||
* nodename: string, valid nodename
|
* nodename: string, valid nodename
|
||||||
* toolname: (optional) string, valid toolname
|
* toolname: (optional) string, valid toolname
|
||||||
* player: (optinal) ObjectRef, valid player
|
|
||||||
|
|
||||||
## mcl_autogroup.get_groupcaps(toolname, efficiency)
|
## mcl_autogroup.get_groupcaps(toolname, efficiency)
|
||||||
This function is used to calculate diggroups for tools.
|
This function is used to calculate diggroups for tools.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -39,8 +39,8 @@ Metal sounds:
|
||||||
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):
|
original by anonymous (CC0 1.0), mastering by iliekprogrammar (CC0 1.0):
|
||||||
https://www.freesound.org/people/AGFX/packs/1253/
|
https://freesound.org/people/deleted_user_2104797/sounds/166313/
|
||||||
default_water_footstep.*.ogg
|
default_water_footstep.*.ogg
|
||||||
|
|
||||||
blukotek (CC0 1.0):
|
blukotek (CC0 1.0):
|
||||||
|
|
|
@ -166,7 +166,7 @@ end
|
||||||
function mcl_sounds.node_sound_water_defaults(table)
|
function mcl_sounds.node_sound_water_defaults(table)
|
||||||
table = table or {}
|
table = table or {}
|
||||||
table.footstep = table.footstep or
|
table.footstep = table.footstep or
|
||||||
{name = "default_water_footstep", gain = 0.2}
|
{name = "default_water_footstep", gain = 0.05}
|
||||||
table.place = table.place or
|
table.place = table.place or
|
||||||
{name = "mcl_sounds_place_node_water", gain = 1.0}
|
{name = "mcl_sounds_place_node_water", gain = 1.0}
|
||||||
table.dug = table.dug or
|
table.dug = table.dug or
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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
|
||||||
|
@ -252,17 +237,10 @@ function minetest.handle_node_drops(pos, drops, digger)
|
||||||
-- NOTE: This function override allows digger to be nil.
|
-- NOTE: This function override allows digger to be nil.
|
||||||
-- This means there is no digger. This is a special case which allows this function to be called
|
-- This means there is no digger. This is a special case which allows this function to be called
|
||||||
-- by hand. Creative Mode is intentionally ignored in this case.
|
-- by hand. Creative Mode is intentionally ignored in this case.
|
||||||
if digger and digger:is_player() and minetest.is_creative_enabled(digger:get_player_name()) then
|
|
||||||
local inv = digger:get_inventory()
|
if (digger and digger:is_player() and minetest.is_creative_enabled(digger:get_player_name())) or doTileDrops == false then
|
||||||
if inv then
|
|
||||||
for _, item in ipairs(drops) do
|
|
||||||
if not inv:contains_item("main", item, true) then
|
|
||||||
inv:add_item("main", item)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return
|
return
|
||||||
elseif not doTileDrops then return end
|
end
|
||||||
|
|
||||||
-- Check if node will yield its useful drop by the digger's tool
|
-- Check if node will yield its useful drop by the digger's tool
|
||||||
local dug_node = minetest.get_node(pos)
|
local dug_node = minetest.get_node(pos)
|
||||||
|
@ -270,9 +248,9 @@ function minetest.handle_node_drops(pos, drops, digger)
|
||||||
local tool
|
local tool
|
||||||
if digger then
|
if digger then
|
||||||
tool = digger:get_wielded_item()
|
tool = digger:get_wielded_item()
|
||||||
tooldef = minetest.registered_items[tool:get_name()]
|
tooldef = minetest.registered_tools[tool:get_name()]
|
||||||
|
|
||||||
if not mcl_autogroup.can_harvest(dug_node.name, tool:get_name(), digger) then
|
if not mcl_autogroup.can_harvest(dug_node.name, tool:get_name()) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -287,7 +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]
|
||||||
|
@ -316,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
|
||||||
|
@ -329,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()
|
||||||
|
@ -344,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
|
||||||
|
@ -371,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
|
||||||
|
@ -379,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
|
||||||
|
@ -399,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))
|
||||||
|
|
||||||
|
@ -417,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")
|
||||||
|
@ -451,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))
|
||||||
|
@ -523,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 = "",
|
||||||
},
|
},
|
||||||
|
@ -567,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,
|
||||||
|
@ -599,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
|
||||||
|
@ -620,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,
|
||||||
|
@ -718,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,
|
||||||
|
|
||||||
|
@ -768,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
|
||||||
|
@ -784,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
|
||||||
|
@ -809,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
|
||||||
|
@ -828,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
|
||||||
|
@ -849,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()
|
||||||
|
@ -889,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
|
||||||
|
@ -899,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
|
||||||
|
@ -909,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)
|
||||||
|
|
||||||
|
@ -931,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
|
||||||
|
@ -965,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
|
||||||
|
@ -978,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()
|
||||||
|
@ -1005,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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
if self:check_death_and_slow_mob() then
|
local v = self.object:get_velocity()
|
||||||
--minetest.log("action", "Mob is dying: ".. tostring(self.name))
|
if v then
|
||||||
-- Do we abandon out of here now?
|
--diffuse object velocity
|
||||||
|
self.object:set_velocity({x = v.x*d, y = v.y, z = v.z*d})
|
||||||
end
|
end
|
||||||
|
|
||||||
if self:falling(pos) then return end
|
if self:falling(pos) then return end
|
||||||
|
|
||||||
self:check_suspend()
|
self:check_suspend()
|
||||||
|
self:check_water_flow()
|
||||||
|
|
||||||
|
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)
|
||||||
|
@ -349,24 +349,25 @@ function mob_class:on_step(dtime)
|
||||||
if not self.object:get_pos() then return end
|
if not self.object:get_pos() then return end
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.state == "die" then return end
|
|
||||||
|
|
||||||
self:check_water_flow()
|
|
||||||
self:env_danger_movement_checks (dtime)
|
|
||||||
|
|
||||||
if mobs_debug then self:update_tag() end
|
if mobs_debug then self:update_tag() end
|
||||||
|
|
||||||
self:follow_flop() -- Mob following code.
|
if self.state == "die" then return end
|
||||||
|
|
||||||
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()
|
||||||
|
|
||||||
|
@ -377,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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
@ -746,7 +734,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
|
||||||
|
|
||||||
local name = hitter:get_player_name() or ""
|
local name = hitter:get_player_name() or ""
|
||||||
|
|
||||||
-- attack puncher
|
-- attack puncher and call other mobs for help
|
||||||
if self.passive == false
|
if self.passive == false
|
||||||
and self.state ~= "flop"
|
and self.state ~= "flop"
|
||||||
and (self.child == false or self.type == "monster")
|
and (self.child == false or self.type == "monster")
|
||||||
|
@ -758,7 +746,6 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
|
||||||
self:do_attack(hitter)
|
self:do_attack(hitter)
|
||||||
self._aggro= true
|
self._aggro= true
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
-- alert others to the attack
|
-- alert others to the attack
|
||||||
local objs = minetest.get_objects_inside_radius(hitter:get_pos(), self.view_range)
|
local objs = minetest.get_objects_inside_radius(hitter:get_pos(), self.view_range)
|
||||||
|
@ -777,7 +764,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
|
||||||
obj:do_attack(hitter)
|
obj:do_attack(hitter)
|
||||||
elseif type(obj.group_attack) == "table" then
|
elseif type(obj.group_attack) == "table" then
|
||||||
for i=1, #obj.group_attack do
|
for i=1, #obj.group_attack do
|
||||||
if obj.group_attack[i] == self.name then
|
if obj.name == obj.group_attack[i] then
|
||||||
obj._aggro = true
|
obj._aggro = true
|
||||||
obj:do_attack(hitter)
|
obj:do_attack(hitter)
|
||||||
break
|
break
|
||||||
|
@ -792,6 +779,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function mob_class:check_aggro(dtime)
|
function mob_class:check_aggro(dtime)
|
||||||
|
@ -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
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,32 +269,6 @@ 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
|
|
||||||
-- This code should probably be moved to movement code
|
|
||||||
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
|
||||||
|
@ -794,9 +769,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
|
||||||
|
|
||||||
|
@ -804,13 +840,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
|
||||||
|
@ -895,66 +939,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
|
||||||
|
|
||||||
|
@ -971,13 +958,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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
@ -47,8 +48,7 @@ end
|
||||||
|
|
||||||
function mob_class:player_in_active_range()
|
function mob_class:player_in_active_range()
|
||||||
for _,p in pairs(minetest.get_connected_players()) do
|
for _,p in pairs(minetest.get_connected_players()) do
|
||||||
local pos = self.object:get_pos()
|
if vector.distance(self.object:get_pos(),p:get_pos()) <= mob_active_range then return true end
|
||||||
if pos and vector.distance(pos, p:get_pos()) <= mob_active_range then return true end
|
|
||||||
-- slightly larger than the mc 32 since mobs spawn on that circle and easily stand still immediately right after spawning.
|
-- slightly larger than the mc 32 since mobs spawn on that circle and easily stand still immediately right after spawning.
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -183,19 +183,6 @@ function mob_class:collision()
|
||||||
return({x,z})
|
return({x,z})
|
||||||
end
|
end
|
||||||
|
|
||||||
function mob_class:check_death_and_slow_mob()
|
|
||||||
local d = 0.85
|
|
||||||
local dying = self:check_dying()
|
|
||||||
if 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
|
|
||||||
return dying
|
|
||||||
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
|
||||||
|
@ -522,16 +509,17 @@ function mob_class:check_for_death(cause, cmi_cause)
|
||||||
|
|
||||||
self:set_velocity(0)
|
self:set_velocity(0)
|
||||||
local acc = self.object:get_acceleration()
|
local acc = self.object:get_acceleration()
|
||||||
if acc then
|
|
||||||
acc.x, acc.y, acc.z = 0, DEFAULT_FALL_SPEED, 0
|
acc.x, acc.y, acc.z = 0, DEFAULT_FALL_SPEED, 0
|
||||||
self.object:set_acceleration(acc)
|
self.object:set_acceleration(acc)
|
||||||
end
|
|
||||||
|
|
||||||
local length
|
local length
|
||||||
-- default death function and die animation (if defined)
|
-- default death function and die animation (if defined)
|
||||||
if self.instant_death then
|
if self.instant_death then
|
||||||
length = 0
|
length = 0
|
||||||
elseif self.animation and self.animation.die_start and self.animation.die_end then
|
elseif self.animation
|
||||||
|
and self.animation.die_start
|
||||||
|
and self.animation.die_end then
|
||||||
|
|
||||||
local frames = self.animation.die_end - self.animation.die_start
|
local frames = self.animation.die_end - self.animation.die_start
|
||||||
local speed = self.animation.die_speed or 15
|
local speed = self.animation.die_speed or 15
|
||||||
length = math.max(frames / speed, 0) + DEATH_DELAY
|
length = math.max(frames / speed, 0) + DEATH_DELAY
|
||||||
|
@ -547,6 +535,7 @@ function mob_class:check_for_death(cause, cmi_cause)
|
||||||
if not self.object:get_luaentity() then
|
if not self.object:get_luaentity() then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
death_handle(self)
|
death_handle(self)
|
||||||
local dpos = self.object:get_pos()
|
local dpos = self.object:get_pos()
|
||||||
local cbox = self.collisionbox
|
local cbox = self.collisionbox
|
||||||
|
@ -555,7 +544,6 @@ function mob_class:check_for_death(cause, cmi_cause)
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
mcl_mobs.death_effect(dpos, yaw, cbox, not self.instant_death)
|
mcl_mobs.death_effect(dpos, yaw, cbox, not self.instant_death)
|
||||||
end
|
end
|
||||||
|
|
||||||
if length <= 0 then
|
if length <= 0 then
|
||||||
kill(self)
|
kill(self)
|
||||||
else
|
else
|
||||||
|
@ -790,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)
|
||||||
|
@ -872,8 +841,9 @@ function mob_class:falling(pos)
|
||||||
|
|
||||||
-- floating in water (or falling)
|
-- floating in water (or falling)
|
||||||
local v = self.object:get_velocity()
|
local v = self.object:get_velocity()
|
||||||
if v then
|
|
||||||
if v.y > 0 then
|
if v.y > 0 then
|
||||||
|
|
||||||
-- apply gravity when moving up
|
-- apply gravity when moving up
|
||||||
self.object:set_acceleration({
|
self.object:set_acceleration({
|
||||||
x = 0,
|
x = 0,
|
||||||
|
@ -882,6 +852,7 @@ function mob_class:falling(pos)
|
||||||
})
|
})
|
||||||
|
|
||||||
elseif v.y <= 0 and v.y > self.fall_speed then
|
elseif v.y <= 0 and v.y > self.fall_speed then
|
||||||
|
|
||||||
-- fall downwards at set speed
|
-- fall downwards at set speed
|
||||||
self.object:set_acceleration({
|
self.object:set_acceleration({
|
||||||
x = 0,
|
x = 0,
|
||||||
|
@ -892,12 +863,11 @@ function mob_class:falling(pos)
|
||||||
-- stop accelerating once max fall speed hit
|
-- stop accelerating once max fall speed hit
|
||||||
self.object:set_acceleration({x = 0, y = 0, z = 0})
|
self.object:set_acceleration({x = 0, y = 0, z = 0})
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
local acc = self.object:get_acceleration()
|
|
||||||
|
|
||||||
if minetest.registered_nodes[node_ok(pos).name].groups.lava then
|
if minetest.registered_nodes[node_ok(pos).name].groups.lava then
|
||||||
if acc and self.floats_on_lava == 1 then
|
|
||||||
|
if self.floats_on_lava == 1 then
|
||||||
|
|
||||||
self.object:set_acceleration({
|
self.object:set_acceleration({
|
||||||
x = 0,
|
x = 0,
|
||||||
y = -self.fall_speed / (math.max(1, v.y) ^ 2),
|
y = -self.fall_speed / (math.max(1, v.y) ^ 2),
|
||||||
|
@ -908,7 +878,9 @@ function mob_class:falling(pos)
|
||||||
|
|
||||||
-- in water then float up
|
-- in water then float up
|
||||||
if minetest.registered_nodes[node_ok(pos).name].groups.water then
|
if minetest.registered_nodes[node_ok(pos).name].groups.water then
|
||||||
if acc and self.floats == 1 then
|
|
||||||
|
if self.floats == 1 then
|
||||||
|
|
||||||
self.object:set_acceleration({
|
self.object:set_acceleration({
|
||||||
x = 0,
|
x = 0,
|
||||||
y = -self.fall_speed / (math.max(1, v.y) ^ 2),
|
y = -self.fall_speed / (math.max(1, v.y) ^ 2),
|
||||||
|
@ -916,8 +888,10 @@ function mob_class:falling(pos)
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
||||||
-- fall damage onto solid ground
|
-- fall damage onto solid ground
|
||||||
if self.fall_damage == 1 and self.object:get_velocity().y == 0 then
|
if self.fall_damage == 1
|
||||||
|
and self.object:get_velocity().y == 0 then
|
||||||
local n = node_ok(vector.offset(pos,0,-1,0)).name
|
local n = node_ok(vector.offset(pos,0,-1,0)).name
|
||||||
local d = (self.old_y or 0) - self.object:get_pos().y
|
local d = (self.old_y or 0) - self.object:get_pos().y
|
||||||
|
|
||||||
|
@ -978,24 +952,18 @@ end
|
||||||
function mob_class:check_dying()
|
function mob_class:check_dying()
|
||||||
if ((self.state and self.state=="die") or self:check_for_death()) and not self.animation.die_end then
|
if ((self.state and self.state=="die") or self:check_for_death()) and not self.animation.die_end then
|
||||||
local rot = self.object:get_rotation()
|
local rot = self.object:get_rotation()
|
||||||
if rot then
|
|
||||||
rot.z = ((math.pi/2-rot.z)*.2)+rot.z
|
rot.z = ((math.pi/2-rot.z)*.2)+rot.z
|
||||||
self.object:set_rotation(rot)
|
self.object:set_rotation(rot)
|
||||||
end
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function mob_class:check_suspend()
|
function mob_class:check_suspend()
|
||||||
|
if not self:player_in_active_range() then
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
if pos and not self:player_in_active_range() then
|
|
||||||
local node_under = node_ok(vector.offset(pos,0,-1,0)).name
|
local node_under = node_ok(vector.offset(pos,0,-1,0)).name
|
||||||
|
|
||||||
self:set_animation( "stand", true)
|
|
||||||
|
|
||||||
local acc = self.object:get_acceleration()
|
local acc = self.object:get_acceleration()
|
||||||
if acc then
|
self:set_animation( "stand", true)
|
||||||
if acc.y > 0 or node_under ~= "air" then
|
if acc.y > 0 or node_under ~= "air" then
|
||||||
self.object:set_acceleration(vector.new(0,0,0))
|
self.object:set_acceleration(vector.new(0,0,0))
|
||||||
self.object:set_velocity(vector.new(0,0,0))
|
self.object:set_velocity(vector.new(0,0,0))
|
||||||
|
@ -1003,7 +971,6 @@ function mob_class:check_suspend()
|
||||||
if acc.y == 0 and node_under == "air" then
|
if acc.y == 0 and node_under == "air" then
|
||||||
self:falling(pos)
|
self:falling(pos)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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
|
||||||
|
@ -652,9 +628,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 +722,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 +755,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
|
||||||
})
|
})
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -7,7 +7,6 @@ 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,
|
||||||
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -15,7 +15,7 @@ mcl_mobs.register_mob("mobs_mc:iron_golem", {
|
||||||
description = S("Iron Golem"),
|
description = S("Iron Golem"),
|
||||||
type = "npc",
|
type = "npc",
|
||||||
spawn_class = "passive",
|
spawn_class = "passive",
|
||||||
passive = false,
|
passive = true,
|
||||||
hp_min = 100,
|
hp_min = 100,
|
||||||
hp_max = 100,
|
hp_max = 100,
|
||||||
breath_max = -1,
|
breath_max = -1,
|
||||||
|
@ -42,7 +42,7 @@ mcl_mobs.register_mob("mobs_mc:iron_golem", {
|
||||||
damage = 14,
|
damage = 14,
|
||||||
knock_back = false,
|
knock_back = false,
|
||||||
reach = 3,
|
reach = 3,
|
||||||
group_attack = { "mobs_mc:villager" },
|
group_attack = true,
|
||||||
attacks_monsters = true,
|
attacks_monsters = true,
|
||||||
attack_type = "dogfight",
|
attack_type = "dogfight",
|
||||||
_got_poppy = false,
|
_got_poppy = false,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -235,7 +235,7 @@ local professions = {
|
||||||
librarian = {
|
librarian = {
|
||||||
name = N("Librarian"),
|
name = N("Librarian"),
|
||||||
texture = "mobs_mc_villager_librarian.png",
|
texture = "mobs_mc_villager_librarian.png",
|
||||||
jobsite = "mcl_lectern:lectern",
|
jobsite = "mcl_books:bookshelf", --FIXME: lectern
|
||||||
trades = {
|
trades = {
|
||||||
{
|
{
|
||||||
{ { "mcl_core:paper", 24, 36 }, E1 },
|
{ { "mcl_core:paper", 24, 36 }, E1 },
|
||||||
|
@ -641,7 +641,7 @@ function get_activity(tod)
|
||||||
else
|
else
|
||||||
activity = "chill"
|
activity = "chill"
|
||||||
end
|
end
|
||||||
--mcl_log("Time is " .. tod ..". Activity is: ".. activity)
|
mcl_log("Time is " .. tod ..". Activity is: ".. activity)
|
||||||
return activity
|
return activity
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -770,7 +770,7 @@ local function check_bed (entity)
|
||||||
local n = minetest.get_node(b)
|
local n = minetest.get_node(b)
|
||||||
|
|
||||||
local is_bed_bottom = string.find(n.name,"_bottom")
|
local is_bed_bottom = string.find(n.name,"_bottom")
|
||||||
--mcl_log("is bed bottom: " .. tostring(is_bed_bottom))
|
mcl_log("" .. tostring(is_bed_bottom))
|
||||||
if n and not is_bed_bottom then
|
if n and not is_bed_bottom then
|
||||||
mcl_log("Where did my bed go?!")
|
mcl_log("Where did my bed go?!")
|
||||||
entity._bed = nil --the stormtroopers have killed uncle owen
|
entity._bed = nil --the stormtroopers have killed uncle owen
|
||||||
|
@ -836,7 +836,6 @@ end
|
||||||
|
|
||||||
local function take_bed (entity)
|
local function take_bed (entity)
|
||||||
if not entity then return end
|
if not entity then return end
|
||||||
if not entity:ready_to_path() then return end
|
|
||||||
|
|
||||||
local p = entity.object:get_pos()
|
local p = entity.object:get_pos()
|
||||||
|
|
||||||
|
@ -1060,9 +1059,9 @@ local function look_for_job(self, requested_jobsites)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local function get_a_job(self)
|
local function get_a_job(self)
|
||||||
if self.order == WORK then self.order = nil end
|
if self.order == WORK then self.order = nil end
|
||||||
if not self:ready_to_path() then return end
|
|
||||||
|
|
||||||
mcl_log("I'm unemployed or lost my job block and have traded. Can I get a job?")
|
mcl_log("I'm unemployed or lost my job block and have traded. Can I get a job?")
|
||||||
|
|
||||||
|
@ -1136,19 +1135,22 @@ local function validate_jobsite(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function do_work (self)
|
local function do_work (self)
|
||||||
|
--debug_trades(self)
|
||||||
if not self or self.child then
|
if self.child then
|
||||||
mcl_log("No self, or a child so don't work")
|
mcl_log("A child so don't send to work")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
--mcl_log("Time for work")
|
--mcl_log("Time for work")
|
||||||
local jobsite_node = retrieve_my_jobsite (self)
|
|
||||||
|
|
||||||
if jobsite_node then
|
-- Don't try if looking_for_work, or gowp possibly
|
||||||
|
if validate_jobsite(self) then
|
||||||
|
--mcl_log("My jobsite is valid. Do i need to travel?")
|
||||||
|
|
||||||
|
local jobsite2 = retrieve_my_jobsite (self)
|
||||||
local jobsite = self._jobsite
|
local jobsite = self._jobsite
|
||||||
|
|
||||||
local distance_to_jobsite = vector.distance(self.object:get_pos(), jobsite)
|
if self and jobsite2 and self._jobsite then
|
||||||
|
local distance_to_jobsite = vector.distance(self.object:get_pos(),self._jobsite)
|
||||||
--mcl_log("Villager: ".. minetest.pos_to_string(self.object:get_pos()) .. ", jobsite: " .. minetest.pos_to_string(self._jobsite) .. ", distance to jobsite: ".. distance_to_jobsite)
|
--mcl_log("Villager: ".. minetest.pos_to_string(self.object:get_pos()) .. ", jobsite: " .. minetest.pos_to_string(self._jobsite) .. ", distance to jobsite: ".. distance_to_jobsite)
|
||||||
|
|
||||||
if distance_to_jobsite < 2 then
|
if distance_to_jobsite < 2 then
|
||||||
|
@ -1165,7 +1167,7 @@ local function do_work (self)
|
||||||
self.order = nil
|
self.order = nil
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
self:gopath(jobsite, function(self, jobsite)
|
self:gopath(jobsite, function(self,jobsite)
|
||||||
if not self then
|
if not self then
|
||||||
--mcl_log("missing self. not good")
|
--mcl_log("missing self. not good")
|
||||||
return false
|
return false
|
||||||
|
@ -1183,38 +1185,18 @@ local function do_work (self)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
elseif self._profession == "unemployed" or has_traded(self) then
|
||||||
end
|
get_a_job(self)
|
||||||
|
|
||||||
local below_vec = vector.new(0, -1, 0)
|
|
||||||
|
|
||||||
local function get_ground_below_floating_object (float_pos)
|
|
||||||
local pos = float_pos
|
|
||||||
repeat
|
|
||||||
mcl_log("Current pos: " .. minetest.pos_to_string(pos))
|
|
||||||
pos = vector.add(pos, below_vec)
|
|
||||||
local node = minetest.get_node(pos)
|
|
||||||
mcl_log("First non air materials: ".. tostring(node.name))
|
|
||||||
until node.name ~= "air"
|
|
||||||
|
|
||||||
-- If pos is 1 below float_pos, then just return float_pos as there is no air below it
|
|
||||||
if pos.y == float_pos.y - 1 then
|
|
||||||
--mcl_log("pos is only 1 lower than float pos so no air below")
|
|
||||||
return float_pos
|
|
||||||
else
|
|
||||||
--mcl_log("pos is more than 1 lower than float pos so air is below")
|
|
||||||
return pos
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return pos
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function go_to_town_bell(self)
|
local function go_to_town_bell(self)
|
||||||
if self.order == GATHERING then return
|
if self.order == GATHERING then
|
||||||
else mcl_log("Current order" .. self.order) end
|
mcl_log("Already gathering")
|
||||||
|
return
|
||||||
if not self:ready_to_path() then return end
|
else
|
||||||
|
mcl_log("Current order" .. self.order)
|
||||||
|
end
|
||||||
mcl_log("Go to town bell")
|
mcl_log("Go to town bell")
|
||||||
|
|
||||||
local looking_for_type={}
|
local looking_for_type={}
|
||||||
|
@ -1226,9 +1208,8 @@ local function go_to_town_bell(self)
|
||||||
--Ideally should check for closest available. It'll make pathing easier.
|
--Ideally should check for closest available. It'll make pathing easier.
|
||||||
for _,n in pairs(nn) do
|
for _,n in pairs(nn) do
|
||||||
mcl_log("Found bell")
|
mcl_log("Found bell")
|
||||||
local target_point = get_ground_below_floating_object(n)
|
|
||||||
|
|
||||||
local gp = self:gopath(target_point,function(self)
|
local gp = self:gopath(n,function(self)
|
||||||
if self then
|
if self then
|
||||||
self.order = GATHERING
|
self.order = GATHERING
|
||||||
mcl_log("Callback has a self")
|
mcl_log("Callback has a self")
|
||||||
|
@ -1296,45 +1277,22 @@ local function validate_bed(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function do_activity (self)
|
local function do_activity (self)
|
||||||
|
-- Maybe just check we're pathfinding first?
|
||||||
if self.following then
|
if self.following then
|
||||||
mcl_log("Following, so do not do activity.")
|
mcl_log("Following, so do not do activity.")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if self.state == PATHFINDING then
|
|
||||||
mcl_log("Pathfinding, so do not do activity.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local jobsite_valid = false
|
if not validate_bed(self) and self.state ~= PATHFINDING then
|
||||||
|
|
||||||
if not mcl_beds.is_night() then
|
|
||||||
if self.order == SLEEP then self.order = nil end
|
if self.order == SLEEP then self.order = nil end
|
||||||
|
mcl_log("Villager has no bed. Currently at location: "..minetest.pos_to_string(self.object:get_pos()))
|
||||||
if not validate_jobsite(self) then
|
|
||||||
--debug_trades(self)
|
|
||||||
if self._profession == "unemployed" or has_traded(self) then
|
|
||||||
get_a_job(self)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
else
|
|
||||||
jobsite_valid = true
|
|
||||||
--mcl_log("My jobsite is valid. Do i need to travel?")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if self.order == WORK then self.order = nil end
|
|
||||||
|
|
||||||
if not validate_bed(self) then
|
|
||||||
if self.order == SLEEP then self.order = nil end
|
|
||||||
mcl_log("Villager at this location has no bed: " .. minetest.pos_to_string(self.object:get_pos()))
|
|
||||||
take_bed (self)
|
take_bed (self)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
-- Only check in day or during thunderstorm but wandered_too_far code won't work
|
-- Only check in day or during thunderstorm but wandered_too_far code won't work
|
||||||
local wandered_too_far = false
|
local wandered_too_far = false
|
||||||
if check_bed (self) then
|
if check_bed (self) then
|
||||||
wandered_too_far = vector.distance(self.object:get_pos(),self._bed) > 50
|
wandered_too_far = ( self.state ~= PATHFINDING ) and (vector.distance(self.object:get_pos(),self._bed) > 50 )
|
||||||
end
|
end
|
||||||
|
|
||||||
if wandered_too_far then
|
if wandered_too_far then
|
||||||
|
@ -1342,7 +1300,7 @@ local function do_activity (self)
|
||||||
go_home(self, false)
|
go_home(self, false)
|
||||||
elseif get_activity() == SLEEP then
|
elseif get_activity() == SLEEP then
|
||||||
go_home(self, true)
|
go_home(self, true)
|
||||||
elseif get_activity() == WORK and jobsite_valid then
|
elseif get_activity() == WORK then
|
||||||
do_work(self)
|
do_work(self)
|
||||||
elseif get_activity() == GATHERING then
|
elseif get_activity() == GATHERING then
|
||||||
go_to_town_bell(self)
|
go_to_town_bell(self)
|
||||||
|
@ -1351,6 +1309,13 @@ local function do_activity (self)
|
||||||
self.order = nil
|
self.order = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Daytime is work and play time
|
||||||
|
if not mcl_beds.is_night() then
|
||||||
|
if self.order == SLEEP then self.order = nil end
|
||||||
|
else
|
||||||
|
if self.order == WORK then self.order = nil end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function update_max_tradenum(self)
|
local function update_max_tradenum(self)
|
||||||
|
@ -1930,6 +1895,8 @@ end)
|
||||||
|
|
||||||
--[=======[ MOB REGISTRATION AND SPAWNING ]=======]
|
--[=======[ MOB REGISTRATION AND SPAWNING ]=======]
|
||||||
|
|
||||||
|
local pick_up = { "mcl_farming:bread", "mcl_farming:carrot_item", "mcl_farming:beetroot_item" , "mcl_farming:potato_item" }
|
||||||
|
|
||||||
mcl_mobs.register_mob("mobs_mc:villager", {
|
mcl_mobs.register_mob("mobs_mc:villager", {
|
||||||
description = S("Villager"),
|
description = S("Villager"),
|
||||||
type = "npc",
|
type = "npc",
|
||||||
|
@ -1974,7 +1941,7 @@ mcl_mobs.register_mob("mobs_mc:villager", {
|
||||||
head_shake_start = 131, head_shake_end = 141, head_shake_loop = false,
|
head_shake_start = 131, head_shake_end = 141, head_shake_loop = false,
|
||||||
head_nod_start = 121, head_nod_end = 131, head_nod_loop = false,
|
head_nod_start = 121, head_nod_end = 131, head_nod_loop = false,
|
||||||
},
|
},
|
||||||
follow = { "mcl_farming:bread", "mcl_farming:carrot_item", "mcl_farming:beetroot_item" , "mcl_farming:potato_item" },
|
follow = pick_up,
|
||||||
nofollow = true,
|
nofollow = true,
|
||||||
view_range = 16,
|
view_range = 16,
|
||||||
fear_height = 4,
|
fear_height = 4,
|
||||||
|
@ -1984,7 +1951,7 @@ mcl_mobs.register_mob("mobs_mc:villager", {
|
||||||
_id = nil,
|
_id = nil,
|
||||||
_profession = "unemployed",
|
_profession = "unemployed",
|
||||||
look_at_player = true,
|
look_at_player = true,
|
||||||
pick_up = { "mcl_farming:bread", "mcl_farming:carrot_item", "mcl_farming:beetroot_item" , "mcl_farming:potato_item" },
|
pick_up = pick_up,
|
||||||
can_open_doors = true,
|
can_open_doors = true,
|
||||||
on_pick_up = function(self,itementity)
|
on_pick_up = function(self,itementity)
|
||||||
local clicker
|
local clicker
|
||||||
|
@ -2001,7 +1968,6 @@ mcl_mobs.register_mob("mobs_mc:villager", {
|
||||||
return it
|
return it
|
||||||
end,
|
end,
|
||||||
on_rightclick = function(self, clicker)
|
on_rightclick = function(self, clicker)
|
||||||
--minetest.log("In villager right click")
|
|
||||||
if self.child or self._profession == "unemployed" or self._profession == "nitwit" then
|
if self.child or self._profession == "unemployed" or self._profession == "nitwit" then
|
||||||
self.order = nil
|
self.order = nil
|
||||||
return
|
return
|
||||||
|
|
|
@ -109,7 +109,6 @@ mcl_mobs.register_mob("mobs_mc:villager_zombie", {
|
||||||
clicker:set_wielded_item(wielditem)
|
clicker:set_wielded_item(wielditem)
|
||||||
self._curing = math.random(3 * 60, 5 * 60)
|
self._curing = math.random(3 * 60, 5 * 60)
|
||||||
self.shaking = true
|
self.shaking = true
|
||||||
self.can_despawn = false
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
|
@ -109,7 +109,7 @@ mcl_mobs.register_mob("mobs_mc:zombie", zombie)
|
||||||
|
|
||||||
local baby_zombie = table.copy(zombie)
|
local baby_zombie = table.copy(zombie)
|
||||||
baby_zombie.description = S("Baby Zombie")
|
baby_zombie.description = S("Baby Zombie")
|
||||||
baby_zombie.collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.98, 0.25}
|
baby_zombie.collisionbox = {-0.25, -0.01, -0.25, 0.25, 1, 0.25}
|
||||||
baby_zombie.xp_min = 12
|
baby_zombie.xp_min = 12
|
||||||
baby_zombie.xp_max = 12
|
baby_zombie.xp_max = 12
|
||||||
baby_zombie.walk_velocity = 1.2
|
baby_zombie.walk_velocity = 1.2
|
||||||
|
|
|
@ -136,16 +136,9 @@ mcl_weather.skycolor = {
|
||||||
local biomesky
|
local biomesky
|
||||||
local biomefog
|
local biomefog
|
||||||
if mg_name ~= "v6" and mg_name ~= "singlenode" then
|
if mg_name ~= "v6" and mg_name ~= "singlenode" then
|
||||||
local biome_index = minetest.get_biome_data(player:get_pos()).biome
|
local biome = minetest.get_biome_name(minetest.get_biome_data(player:get_pos()).biome)
|
||||||
local biome_name = minetest.get_biome_name(biome_index)
|
biomesky = minetest.registered_biomes[biome]._mcl_skycolor
|
||||||
local biome = minetest.registered_biomes[biome_name]
|
biomefog = minetest.registered_biomes[biome]._mcl_fogcolor
|
||||||
if biome then
|
|
||||||
--minetest.log("action", string.format("Biome found for number: %s in biome: %s", tostring(biome_index), biome_name))
|
|
||||||
biomesky = biome._mcl_skycolor
|
|
||||||
biomefog = biome._mcl_fogcolor
|
|
||||||
else
|
|
||||||
--minetest.log("action", string.format("No biome for number: %s in biome: %s", tostring(biome_index), biome_name))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
if (mcl_weather.state == "none") then
|
if (mcl_weather.state == "none") then
|
||||||
-- Clear weather
|
-- Clear weather
|
||||||
|
@ -210,23 +203,9 @@ mcl_weather.skycolor = {
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif dim == "end" then
|
elseif dim == "end" then
|
||||||
local biomesky = "#000000"
|
|
||||||
local biomefog = "#A080A0"
|
|
||||||
if mg_name ~= "v6" and mg_name ~= "singlenode" then
|
|
||||||
local biome_index = minetest.get_biome_data(player:get_pos()).biome
|
|
||||||
local biome_name = minetest.get_biome_name(biome_index)
|
|
||||||
local biome = minetest.registered_biomes[biome_name]
|
|
||||||
if biome then
|
|
||||||
--minetest.log("action", string.format("Biome found for number: %s in biome: %s", tostring(biome_index), biome_name))
|
|
||||||
biomesky = biome._mcl_skycolor
|
|
||||||
biomefog = biome._mcl_fogcolor -- The End biomes seemingly don't use the fog colour, despite having this value according to the wiki. The sky colour is seemingly used for both sky and fog?
|
|
||||||
else
|
|
||||||
--minetest.log("action", string.format("No biome for number: %s in biome: %s", tostring(biome_index), biome_name))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local t = "mcl_playerplus_end_sky.png"
|
local t = "mcl_playerplus_end_sky.png"
|
||||||
player:set_sky({ type = "skybox",
|
player:set_sky({ type = "skybox",
|
||||||
base_color = biomesky,
|
base_color = "#000000",
|
||||||
textures = {t,t,t,t,t,t},
|
textures = {t,t,t,t,t,t},
|
||||||
clouds = false,
|
clouds = false,
|
||||||
})
|
})
|
||||||
|
@ -235,29 +214,24 @@ mcl_weather.skycolor = {
|
||||||
player:set_stars({visible = false})
|
player:set_stars({visible = false})
|
||||||
mcl_weather.skycolor.override_day_night_ratio(player, 0.5)
|
mcl_weather.skycolor.override_day_night_ratio(player, 0.5)
|
||||||
elseif dim == "nether" then
|
elseif dim == "nether" then
|
||||||
local biomesky = "#6EB1FF"
|
local nether_sky = {
|
||||||
local biomefog = "#330808"
|
Nether = "#300808",
|
||||||
if mg_name ~= "v6" and mg_name ~= "singlenode" then
|
BasaltDelta = "#685F70",
|
||||||
local biome_index = minetest.get_biome_data(player:get_pos()).biome
|
SoulsandValley = "#1B4745",
|
||||||
local biome_name = minetest.get_biome_name(biome_index)
|
CrimsonForest = "#330303",
|
||||||
local biome = minetest.registered_biomes[biome_name]
|
WarpedForest = "#1A051A"
|
||||||
if biome then
|
}
|
||||||
--minetest.log("action", string.format("Biome found for number: %s in biome: %s", tostring(biome_index), biome_name))
|
local biometint = nether_sky[minetest.get_biome_name(minetest.get_biome_data(player:get_pos()).biome)]
|
||||||
biomesky = biome._mcl_skycolor -- The Nether biomes seemingly don't use the sky colour, despite having this value according to the wiki. The fog colour is used for both sky and fog.
|
|
||||||
biomefog = biome._mcl_fogcolor
|
|
||||||
else
|
|
||||||
--minetest.log("action", string.format("No biome for number: %s in biome: %s", tostring(biome_index), biome_name))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
mcl_weather.set_sky_color(player, {
|
mcl_weather.set_sky_color(player, {
|
||||||
type = "regular",
|
type = "regular",
|
||||||
sky_color = {
|
sky_color = {
|
||||||
day_sky = biomefog,
|
day_sky = "#300808",
|
||||||
day_horizon = biomefog,
|
day_horizon = biometint,
|
||||||
dawn_sky = biomefog,
|
dawn_sky = "#300808",
|
||||||
dawn_horizon = biomefog,
|
dawn_horizon = biometint,
|
||||||
night_sky = biomefog,
|
night_sky = "#300808",
|
||||||
night_horizon = biomefog,
|
night_horizon = biometint,
|
||||||
},
|
},
|
||||||
clouds = false,
|
clouds = false,
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
local zombie_siege_enabled = minetest.settings:get_bool("mcl_raids_zombie_siege", false)
|
|
||||||
|
|
||||||
local function check_spawn_pos(pos)
|
local function check_spawn_pos(pos)
|
||||||
return minetest.get_natural_light(pos) < 7
|
return minetest.get_natural_light(pos) < 7
|
||||||
|
@ -34,13 +33,6 @@ mcl_events.register_event("zombie_siege",{
|
||||||
--minetest.log("Cond start zs")
|
--minetest.log("Cond start zs")
|
||||||
local r = {}
|
local r = {}
|
||||||
|
|
||||||
if not zombie_siege_enabled then
|
|
||||||
--minetest.log("action", "Zombie siege disabled")
|
|
||||||
return r
|
|
||||||
else
|
|
||||||
--minetest.log("action", "Zombie siege start check")
|
|
||||||
end
|
|
||||||
|
|
||||||
local t = minetest.get_timeofday()
|
local t = minetest.get_timeofday()
|
||||||
local pr = PseudoRandom(minetest.get_day_count())
|
local pr = PseudoRandom(minetest.get_day_count())
|
||||||
local rnd = pr:next(1,10)
|
local rnd = pr:next(1,10)
|
||||||
|
@ -50,7 +42,7 @@ mcl_events.register_event("zombie_siege",{
|
||||||
for _,p in pairs(minetest.get_connected_players()) do
|
for _,p in pairs(minetest.get_connected_players()) do
|
||||||
local village = mcl_raids.find_village(p:get_pos())
|
local village = mcl_raids.find_village(p:get_pos())
|
||||||
if village then
|
if village then
|
||||||
minetest.log("action", "Zombie siege is starting")
|
--minetest.log("Found village")
|
||||||
table.insert(r,{ player = p:get_player_name(), pos = village})
|
table.insert(r,{ player = p:get_player_name(), pos = village})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -305,7 +305,7 @@ function awards.unlock(name, award)
|
||||||
local one = player:hud_add({
|
local one = player:hud_add({
|
||||||
hud_elem_type = "image",
|
hud_elem_type = "image",
|
||||||
name = "award_bg",
|
name = "award_bg",
|
||||||
scale = {x = 1.25, y = 1},
|
scale = {x = 1, y = 1},
|
||||||
text = background,
|
text = background,
|
||||||
position = {x = 0.5, y = 0},
|
position = {x = 0.5, y = 0},
|
||||||
offset = {x = 0, y = 138},
|
offset = {x = 0, y = 138},
|
||||||
|
@ -329,7 +329,7 @@ function awards.unlock(name, award)
|
||||||
scale = {x = 100, y = 20},
|
scale = {x = 100, y = 20},
|
||||||
text = hud_announce,
|
text = hud_announce,
|
||||||
position = {x = 0.5, y = 0},
|
position = {x = 0.5, y = 0},
|
||||||
offset = {x = 30, y = 40},
|
offset = {x = 0, y = 40},
|
||||||
alignment = {x = 0, y = -1},
|
alignment = {x = 0, y = -1},
|
||||||
z_index = 102,
|
z_index = 102,
|
||||||
})
|
})
|
||||||
|
@ -340,7 +340,7 @@ function awards.unlock(name, award)
|
||||||
scale = {x = 100, y = 20},
|
scale = {x = 100, y = 20},
|
||||||
text = title,
|
text = title,
|
||||||
position = {x = 0.5, y = 0},
|
position = {x = 0.5, y = 0},
|
||||||
offset = {x = 35, y = 100},
|
offset = {x = 30, y = 100},
|
||||||
alignment = {x = 0, y = -1},
|
alignment = {x = 0, y = -1},
|
||||||
z_index = 102,
|
z_index = 102,
|
||||||
})
|
})
|
||||||
|
@ -355,7 +355,7 @@ function awards.unlock(name, award)
|
||||||
number = 2,
|
number = 2,
|
||||||
text = icon,
|
text = icon,
|
||||||
position = {x = 0.5, y = 0},
|
position = {x = 0.5, y = 0},
|
||||||
offset = {x = -138, y = 62},
|
offset = {x = -110, y = 62},
|
||||||
alignment = {x = 0, y = 0},
|
alignment = {x = 0, y = 0},
|
||||||
direction = 0,
|
direction = 0,
|
||||||
z_index = 102,
|
z_index = 102,
|
||||||
|
|
|
@ -337,7 +337,7 @@ awards.register_achievement("mcl:fishyBusiness", {
|
||||||
|
|
||||||
-- Triggered in mcl_compass
|
-- Triggered in mcl_compass
|
||||||
awards.register_achievement("mcl:countryLode", {
|
awards.register_achievement("mcl:countryLode", {
|
||||||
title = S("Country Lode, Take Me Home"),
|
title = S("Country Lode,\nTake Me Home"),
|
||||||
description = S("Use a compass on a Lodestone."),
|
description = S("Use a compass on a Lodestone."),
|
||||||
icon = "lodestone_side4.png",
|
icon = "lodestone_side4.png",
|
||||||
type = "Advancement",
|
type = "Advancement",
|
||||||
|
|
|
@ -67,7 +67,7 @@ Withering Heights=Les Witherables
|
||||||
Summon the wither from the dead.=Invoquez le Wither d'entre les morts.
|
Summon the wither from the dead.=Invoquez le Wither d'entre les morts.
|
||||||
Fishy Business=Merci pour le poisson
|
Fishy Business=Merci pour le poisson
|
||||||
Catch a fish.@nHint: Catch a fish, salmon, clownfish, or pufferfish.=Attrapez un poisson. \nAstuce : attrapez un poisson, saumon, poisson-clown, ou poisson-globe.
|
Catch a fish.@nHint: Catch a fish, salmon, clownfish, or pufferfish.=Attrapez un poisson. \nAstuce : attrapez un poisson, saumon, poisson-clown, ou poisson-globe.
|
||||||
Country Lode, Take Me Home=Petit Poucet
|
Country Lode,@nTake Me Home=Petit Poucet
|
||||||
Use a compass on a Lodestone.=utiliser une boussole sur une magnétite.
|
Use a compass on a Lodestone.=utiliser une boussole sur une magnétite.
|
||||||
Serious Dedication=Sérieux dévouement
|
Serious Dedication=Sérieux dévouement
|
||||||
Use a Netherite Ingot to upgrade a hoe, and then completely reevaluate your life choices.=Utilisez un lingot de netherite pour améliorez une houe, puis réévaluez complètement vos choix de vie.
|
Use a Netherite Ingot to upgrade a hoe, and then completely reevaluate your life choices.=Utilisez un lingot de netherite pour améliorez une houe, puis réévaluez complètement vos choix de vie.
|
||||||
|
|
|
@ -69,7 +69,7 @@ The Cutest Predator=いちばんカワイイ捕食者
|
||||||
Catch an Axolotl with a bucket!=バケツでウーパールーパーを捕まえよう!
|
Catch an Axolotl with a bucket!=バケツでウーパールーパーを捕まえよう!
|
||||||
Fishy Business=フィッシー・ビジネス
|
Fishy Business=フィッシー・ビジネス
|
||||||
Catch a fish.@nHint: Catch a fish, salmon, clownfish, or pufferfish.=魚を獲ろう。@nヒント:タラ、サケ、クマノミ、フグ等を釣ります。
|
Catch a fish.@nHint: Catch a fish, salmon, clownfish, or pufferfish.=魚を獲ろう。@nヒント:タラ、サケ、クマノミ、フグ等を釣ります。
|
||||||
Country Lode, Take Me Home=この道ずっとゆけば 鉱脈につづいてる
|
Country Lode,@nTake Me Home=この道ずっとゆけば@n鉱脈につづいてる
|
||||||
Use a compass on a Lodestone.=ロードストーンにコンパスを使おう。
|
Use a compass on a Lodestone.=ロードストーンにコンパスを使おう。
|
||||||
Serious Dedication=真摯な取り組み
|
Serious Dedication=真摯な取り組み
|
||||||
Use a Netherite Ingot to upgrade a hoe, and then completely reevaluate your life choices.=ネザライトインゴットでクワをアップグレードしたら、人生設計の完全な見直しを図ろう。
|
Use a Netherite Ingot to upgrade a hoe, and then completely reevaluate your life choices.=ネザライトインゴットでクワをアップグレードしたら、人生設計の完全な見直しを図ろう。
|
||||||
|
|
|
@ -69,7 +69,7 @@ The Cutest Predator=
|
||||||
Catch an Axolotl with a bucket!
|
Catch an Axolotl with a bucket!
|
||||||
Fishy Business=
|
Fishy Business=
|
||||||
Catch a fish.@nHint: Catch a fish, salmon, clownfish, or pufferfish.=
|
Catch a fish.@nHint: Catch a fish, salmon, clownfish, or pufferfish.=
|
||||||
Country Lode, Take Me Home=
|
Country Lode,@nTake Me Home=
|
||||||
Use a compass on a Lodestone.=
|
Use a compass on a Lodestone.=
|
||||||
Serious Dedication=
|
Serious Dedication=
|
||||||
Use a Netherite Ingot to upgrade a hoe, and then completely reevaluate your life choices.=
|
Use a Netherite Ingot to upgrade a hoe, and then completely reevaluate your life choices.=
|
||||||
|
|
Before Width: | Height: | Size: 969 B After Width: | Height: | Size: 1.1 KiB |
|
@ -36,8 +36,7 @@ return {
|
||||||
"SumianVoice",
|
"SumianVoice",
|
||||||
"MrRar",
|
"MrRar",
|
||||||
"talamh",
|
"talamh",
|
||||||
"Faerraven / Michieal",
|
"Faerraven",
|
||||||
"FossFanatic",
|
|
||||||
}},
|
}},
|
||||||
{S("Contributors"), 0x52FF00, {
|
{S("Contributors"), 0x52FF00, {
|
||||||
"Laurent Rocher",
|
"Laurent Rocher",
|
||||||
|
@ -97,9 +96,6 @@ return {
|
||||||
"anarquimico",
|
"anarquimico",
|
||||||
"TheOnlyJoeEnderman",
|
"TheOnlyJoeEnderman",
|
||||||
"Ranko Saotome",
|
"Ranko Saotome",
|
||||||
"Gregor Parzefall",
|
|
||||||
"Wbjitscool",
|
|
||||||
"b3nderman",
|
|
||||||
}},
|
}},
|
||||||
{S("MineClone5"), 0xA60014, {
|
{S("MineClone5"), 0xA60014, {
|
||||||
"kay27",
|
"kay27",
|
||||||
|
@ -151,13 +147,11 @@ return {
|
||||||
"jordan4ibanez",
|
"jordan4ibanez",
|
||||||
"paramat",
|
"paramat",
|
||||||
"cora",
|
"cora",
|
||||||
"Faerraven / Michieal",
|
|
||||||
}},
|
}},
|
||||||
{S("3D Models"), 0x0019FF, {
|
{S("3D Models"), 0x0019FF, {
|
||||||
"22i",
|
"22i",
|
||||||
"tobyplowy",
|
"tobyplowy",
|
||||||
"epCode",
|
"epCode",
|
||||||
"Faerraven / Michieal",
|
|
||||||
}},
|
}},
|
||||||
{S("Textures"), 0xFF9705, {
|
{S("Textures"), 0xFF9705, {
|
||||||
"XSSheep",
|
"XSSheep",
|
||||||
|
@ -172,7 +166,6 @@ return {
|
||||||
"RandomLegoBrick",
|
"RandomLegoBrick",
|
||||||
"cora",
|
"cora",
|
||||||
"Faerraven / Michieal",
|
"Faerraven / Michieal",
|
||||||
"Nicu",
|
|
||||||
}},
|
}},
|
||||||
{S("Translations"), 0x00FF60, {
|
{S("Translations"), 0x00FF60, {
|
||||||
"Wuzzy",
|
"Wuzzy",
|
||||||
|
@ -186,12 +179,9 @@ return {
|
||||||
"Emojigit",
|
"Emojigit",
|
||||||
"snowyu",
|
"snowyu",
|
||||||
"3raven",
|
"3raven",
|
||||||
"SakuraRiu",
|
|
||||||
}},
|
}},
|
||||||
{S("Funders"), 0xF7FF00, {
|
{S("Funders"), 0xF7FF00, {
|
||||||
"40W",
|
"40W",
|
||||||
"bauknecht",
|
|
||||||
"Cora",
|
|
||||||
}},
|
}},
|
||||||
{S("Special thanks"), 0x00E9FF, {
|
{S("Special thanks"), 0x00E9FF, {
|
||||||
"celeron55 for creating Minetest",
|
"celeron55 for creating Minetest",
|
||||||
|
@ -199,6 +189,5 @@ return {
|
||||||
"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/",
|
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
local S = minetest.get_translator(minetest.get_current_modname())
|
local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
|
|
||||||
local ASSIST_TIMEOUT_SEC = 5
|
|
||||||
|
|
||||||
mcl_death_messages = {
|
mcl_death_messages = {
|
||||||
assist = {},
|
assist = {},
|
||||||
messages = {
|
messages = {
|
||||||
|
@ -151,11 +149,6 @@ mcl_death_messages = {
|
||||||
plain = "@1 went off with a bang",
|
plain = "@1 went off with a bang",
|
||||||
item = "@1 went off with a bang due to a firework fired from @3 by @2", -- order is intentional
|
item = "@1 went off with a bang due to a firework fired from @3 by @2", -- order is intentional
|
||||||
},
|
},
|
||||||
sweet_berry = {
|
|
||||||
_translator = S,
|
|
||||||
plain = "@1 died a sweet death",
|
|
||||||
assist = "@1 was poked to death by a sweet berry bush whilst trying to escape @2",
|
|
||||||
},
|
|
||||||
-- Missing snowballs: The Minecraft wiki mentions them but the MC source code does not.
|
-- Missing snowballs: The Minecraft wiki mentions them but the MC source code does not.
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -183,10 +176,8 @@ local function get_killer_message(obj, messages, reason)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_assist_message(obj, messages, reason)
|
local function get_assist_message(obj, messages, reason)
|
||||||
-- Avoid a timing issue if the assist passes its timeout.
|
if messages.assist and mcl_death_messages.assist[obj] then
|
||||||
local assist_details = mcl_death_messages.assist[obj]
|
return messages._translator(messages.assist, mcl_util.get_object_name(obj), mcl_death_messages.assist[obj].name)
|
||||||
if messages.assist and assist_details then
|
|
||||||
return messages._translator(messages.assist, mcl_util.get_object_name(obj), assist_details.name)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -236,17 +227,20 @@ mcl_damage.register_on_death(function(obj, reason)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
mcl_damage.register_on_damage(function(obj, damage, reason)
|
mcl_damage.register_on_damage(function(obj, damage, reason)
|
||||||
if (obj:get_hp() - damage > 0) and reason.source and
|
if obj:get_hp() - damage > 0 then
|
||||||
(reason.source:is_player() or obj:get_luaentity()) then
|
if reason.source then
|
||||||
-- To avoid timing issues we cancel the previous job before adding a new one.
|
mcl_death_messages.assist[obj] = {name = mcl_util.get_object_name(reason.source), timeout = 5}
|
||||||
if mcl_death_messages.assist[obj] then
|
else
|
||||||
mcl_death_messages.assist[obj].job:cancel()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add a new assist object with a timeout job.
|
|
||||||
local new_job = minetest.after(ASSIST_TIMEOUT_SEC, function()
|
|
||||||
mcl_death_messages.assist[obj] = nil
|
mcl_death_messages.assist[obj] = nil
|
||||||
end)
|
end
|
||||||
mcl_death_messages.assist[obj] = {name = mcl_util.get_object_name(reason.source), job = new_job}
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_globalstep(function(dtime)
|
||||||
|
for obj, tbl in pairs(mcl_death_messages.assist) do
|
||||||
|
tbl.timeout = tbl.timeout - dtime
|
||||||
|
if not obj:is_player() and not obj:get_luaentity() or tbl.timeout > 0 then
|
||||||
|
mcl_death_messages.assist[obj] = nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -156,7 +156,6 @@ local function set_inv_page(page, player)
|
||||||
creative_list = inventory_lists[page]
|
creative_list = inventory_lists[page]
|
||||||
end
|
end
|
||||||
inv:set_size("main", #creative_list)
|
inv:set_size("main", #creative_list)
|
||||||
players[playername].inv_size = #creative_list
|
|
||||||
inv:set_list("main", creative_list)
|
inv:set_list("main", creative_list)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -305,21 +304,37 @@ minetest.register_on_joinplayer(function (player)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
function mcl_inventory.set_creative_formspec(player)
|
function mcl_inventory.set_creative_formspec(player, start_i, pagenum, inv_size, show, page, filter)
|
||||||
local playername = player:get_player_name()
|
--reset_menu_item_bg()
|
||||||
if not players[playername] then return end
|
pagenum = math.floor(pagenum) or 1
|
||||||
|
|
||||||
local start_i = players[playername].start_i
|
local playername = player:get_player_name()
|
||||||
local pagenum = start_i / (9*5) + 1
|
|
||||||
local name = players[playername].page
|
if not inv_size then
|
||||||
local inv_size = players[playername].inv_size
|
if page == "nix" then
|
||||||
local filter = players[playername].filter
|
local inv = minetest.get_inventory({type="detached", name="creative_"..playername})
|
||||||
|
inv_size = inv:get_size("main")
|
||||||
|
elseif page and page ~= "inv" then
|
||||||
|
inv_size = #(inventory_lists[page])
|
||||||
|
else
|
||||||
|
inv_size = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
local pagemax = math.max(1, math.floor((inv_size-1) / (9*5) + 1))
|
local pagemax = math.max(1, math.floor((inv_size-1) / (9*5) + 1))
|
||||||
|
local name = "nix"
|
||||||
local main_list
|
local main_list
|
||||||
local listrings = "listring[detached:creative_"..playername..";main]"..
|
local listrings = "listring[detached:creative_"..playername..";main]"..
|
||||||
"listring[current_player;main]"..
|
"listring[current_player;main]"..
|
||||||
"listring[detached:trash;main]"
|
"listring[detached:trash;main]"
|
||||||
|
|
||||||
|
if page then
|
||||||
|
name = page
|
||||||
|
if players[playername] then
|
||||||
|
players[playername].page = page
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--bg[name] = "crafting_creative_bg.png"
|
||||||
|
|
||||||
local inv_bg = "crafting_inventory_creative.png"
|
local inv_bg = "crafting_inventory_creative.png"
|
||||||
if name == "inv" then
|
if name == "inv" then
|
||||||
inv_bg = "crafting_inventory_creative_survival.png"
|
inv_bg = "crafting_inventory_creative_survival.png"
|
||||||
|
@ -478,6 +493,9 @@ function mcl_inventory.set_creative_formspec(player)
|
||||||
listrings
|
listrings
|
||||||
|
|
||||||
if name == "nix" then
|
if name == "nix" then
|
||||||
|
if filter == nil then
|
||||||
|
filter = ""
|
||||||
|
end
|
||||||
formspec = formspec .. "field[5.3,1.34;4,0.75;search;;"..minetest.formspec_escape(filter).."]"
|
formspec = formspec .. "field[5.3,1.34;4,0.75;search;;"..minetest.formspec_escape(filter).."]"
|
||||||
formspec = formspec .. "field_close_on_enter[search;false]"
|
formspec = formspec .. "field_close_on_enter[search;false]"
|
||||||
end
|
end
|
||||||
|
@ -564,11 +582,16 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
|
||||||
if page then
|
if page then
|
||||||
players[name].page = page
|
players[name].page = page
|
||||||
else
|
end
|
||||||
|
if players[name].page then
|
||||||
page = players[name].page
|
page = players[name].page
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Figure out current scroll bar from formspec
|
||||||
|
--local formspec = player:get_inventory_formspec()
|
||||||
|
|
||||||
local start_i = players[name].start_i
|
local start_i = players[name].start_i
|
||||||
|
|
||||||
if fields.creative_prev then
|
if fields.creative_prev then
|
||||||
start_i = start_i - 9*5
|
start_i = start_i - 9*5
|
||||||
elseif fields.creative_next then
|
elseif fields.creative_next then
|
||||||
|
@ -590,7 +613,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
else
|
else
|
||||||
inv_size = 0
|
inv_size = 0
|
||||||
end
|
end
|
||||||
players[name].inv_size = inv_size
|
|
||||||
|
|
||||||
if start_i >= inv_size then
|
if start_i >= inv_size then
|
||||||
start_i = start_i - 9*5
|
start_i = start_i - 9*5
|
||||||
|
@ -600,19 +622,72 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
end
|
end
|
||||||
players[name].start_i = start_i
|
players[name].start_i = start_i
|
||||||
|
|
||||||
if not fields.nix and fields.search then
|
local filter = ""
|
||||||
players[name].filter = fields.search
|
if not fields.nix and fields.search and fields.search ~= "" then
|
||||||
else
|
filter = fields.search
|
||||||
players[name].filter = ""
|
players[name].filter = filter
|
||||||
end
|
end
|
||||||
|
|
||||||
mcl_inventory.set_creative_formspec(player)
|
mcl_inventory.set_creative_formspec(player, start_i, start_i / (9*5) + 1, inv_size, false, page, filter)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack)
|
if minetest.is_creative_enabled("") then
|
||||||
return placer and placer:is_player() and minetest.is_creative_enabled(placer:get_player_name())
|
minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack)
|
||||||
end)
|
-- Place infinite nodes, except for shulker boxes
|
||||||
|
local group = minetest.get_item_group(itemstack:get_name(), "shulker_box")
|
||||||
|
return group == 0 or group == nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
function minetest.handle_node_drops(pos, drops, digger)
|
||||||
|
if not digger or not digger:is_player() then
|
||||||
|
for _,item in ipairs(drops) do
|
||||||
|
minetest.add_item(pos, item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local inv = digger:get_inventory()
|
||||||
|
if inv then
|
||||||
|
for _,item in ipairs(drops) do
|
||||||
|
if not inv:contains_item("main", item, true) then
|
||||||
|
inv:add_item("main", item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mcl_inventory.update_inventory_formspec = function(player)
|
||||||
|
local page
|
||||||
|
|
||||||
|
local name = player:get_player_name()
|
||||||
|
|
||||||
|
if players[name].page then
|
||||||
|
page = players[name].page
|
||||||
|
else
|
||||||
|
page = "nix"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Figure out current scroll bar from formspec
|
||||||
|
--local formspec = player:get_inventory_formspec()
|
||||||
|
local start_i = players[name].start_i
|
||||||
|
|
||||||
|
local inv_size
|
||||||
|
if page == "nix" then
|
||||||
|
local inv = minetest.get_inventory({type="detached", name="creative_"..name})
|
||||||
|
inv_size = inv:get_size("main")
|
||||||
|
elseif page and page ~= "inv" then
|
||||||
|
inv_size = #(inventory_lists[page])
|
||||||
|
else
|
||||||
|
inv_size = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local filter = players[name].filter
|
||||||
|
if filter == nil then
|
||||||
|
filter = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
mcl_inventory.set_creative_formspec(player, start_i, start_i / (9*5) + 1, inv_size, false, page, filter)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
minetest.register_on_joinplayer(function(player)
|
minetest.register_on_joinplayer(function(player)
|
||||||
-- Initialize variables and inventory
|
-- Initialize variables and inventory
|
||||||
|
@ -625,7 +700,7 @@ minetest.register_on_joinplayer(function(player)
|
||||||
end
|
end
|
||||||
init(player)
|
init(player)
|
||||||
-- Setup initial creative inventory to the "nix" page.
|
-- Setup initial creative inventory to the "nix" page.
|
||||||
mcl_inventory.set_creative_formspec(player)
|
mcl_inventory.set_creative_formspec(player, 0, 1, nil, false, "nix", "")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info)
|
minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info)
|
||||||
|
|
|
@ -46,9 +46,14 @@ function return_fields(player, name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function set_inventory(player)
|
local function set_inventory(player, armor_change_only)
|
||||||
if minetest.is_creative_enabled(player:get_player_name()) then
|
if minetest.is_creative_enabled(player:get_player_name()) then
|
||||||
mcl_inventory.set_creative_formspec(player)
|
if armor_change_only then
|
||||||
|
-- Stay on survival inventory plage if only the armor has been changed
|
||||||
|
mcl_inventory.set_creative_formspec(player, 0, 0, nil, nil, "inv")
|
||||||
|
else
|
||||||
|
mcl_inventory.set_creative_formspec(player, 0, 1)
|
||||||
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local inv = player:get_inventory()
|
local inv = player:get_inventory()
|
||||||
|
@ -138,7 +143,11 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
mcl_inventory.update_inventory_formspec = set_inventory
|
if not minetest.is_creative_enabled("") then
|
||||||
|
function mcl_inventory.update_inventory_formspec(player)
|
||||||
|
set_inventory(player)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Drop crafting grid items on leaving
|
-- Drop crafting grid items on leaving
|
||||||
minetest.register_on_leaveplayer(function(player)
|
minetest.register_on_leaveplayer(function(player)
|
||||||
|
@ -190,6 +199,24 @@ function minetest.is_creative_enabled(name)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--Insta "digging" nodes in gamemode-creative
|
||||||
|
minetest.register_on_punchnode(function(pos, node, puncher, pointed_thing)
|
||||||
|
if not puncher or not puncher:is_player() then return end
|
||||||
|
local name = puncher:get_player_name()
|
||||||
|
if not minetest.is_creative_enabled(name) then return end
|
||||||
|
if pointed_thing.type ~= "node" then return end
|
||||||
|
local def = minetest.registered_nodes[node.name]
|
||||||
|
if def then
|
||||||
|
minetest.node_dig(pos,node,puncher)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
--Don't subtract from inv when placing in gamemode-creative
|
||||||
|
minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
|
||||||
|
if placer and placer:is_player() and minetest.is_creative_enabled(placer:get_player_name()) then return true end
|
||||||
|
end)
|
||||||
|
|
||||||
local function in_table(n,h)
|
local function in_table(n,h)
|
||||||
for k,v in pairs(h) do
|
for k,v in pairs(h) do
|
||||||
if v == n then return true end
|
if v == n then return true end
|
||||||
|
@ -211,7 +238,6 @@ function mcl_inventory.player_set_gamemode(p,g)
|
||||||
elseif g == "creative" then
|
elseif g == "creative" then
|
||||||
mcl_experience.remove_hud(p)
|
mcl_experience.remove_hud(p)
|
||||||
end
|
end
|
||||||
mcl_meshhand.update_player(p)
|
|
||||||
set_inventory(p)
|
set_inventory(p)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,226 +0,0 @@
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright © 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
||||||
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The GNU General Public License is a free, copyleft license for software and other kinds of works.
|
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
|
|
||||||
|
|
||||||
Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.
|
|
||||||
|
|
||||||
For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.
|
|
||||||
|
|
||||||
Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.
|
|
||||||
|
|
||||||
Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and modification follow.
|
|
||||||
TERMS AND CONDITIONS
|
|
||||||
0. Definitions.
|
|
||||||
|
|
||||||
“This License” refers to version 3 of the GNU General Public License.
|
|
||||||
|
|
||||||
“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
|
|
||||||
|
|
||||||
“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations.
|
|
||||||
|
|
||||||
To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work.
|
|
||||||
|
|
||||||
A “covered work” means either the unmodified Program or a work based on the Program.
|
|
||||||
|
|
||||||
To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
|
|
||||||
|
|
||||||
To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
|
|
||||||
|
|
||||||
An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
|
|
||||||
1. Source Code.
|
|
||||||
|
|
||||||
The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work.
|
|
||||||
|
|
||||||
A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
|
|
||||||
|
|
||||||
The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
|
|
||||||
|
|
||||||
The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
|
|
||||||
|
|
||||||
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
|
|
||||||
|
|
||||||
The Corresponding Source for a work in source code form is that same work.
|
|
||||||
2. Basic Permissions.
|
|
||||||
|
|
||||||
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
|
|
||||||
|
|
||||||
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
|
|
||||||
|
|
||||||
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
|
|
||||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
|
||||||
|
|
||||||
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
|
|
||||||
|
|
||||||
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
|
|
||||||
4. Conveying Verbatim Copies.
|
|
||||||
|
|
||||||
You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
|
|
||||||
|
|
||||||
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
|
|
||||||
5. Conveying Modified Source Versions.
|
|
||||||
|
|
||||||
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
|
|
||||||
b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”.
|
|
||||||
c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
|
|
||||||
d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
|
|
||||||
|
|
||||||
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
|
|
||||||
6. Conveying Non-Source Forms.
|
|
||||||
|
|
||||||
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
|
|
||||||
|
|
||||||
a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
|
|
||||||
b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
|
|
||||||
c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
|
|
||||||
d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
|
|
||||||
e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
|
|
||||||
|
|
||||||
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
|
|
||||||
|
|
||||||
A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
|
|
||||||
|
|
||||||
“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
|
|
||||||
|
|
||||||
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
|
|
||||||
|
|
||||||
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
|
|
||||||
|
|
||||||
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
|
|
||||||
7. Additional Terms.
|
|
||||||
|
|
||||||
“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
|
|
||||||
|
|
||||||
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
|
|
||||||
|
|
||||||
a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
|
|
||||||
b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
|
|
||||||
c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
|
|
||||||
d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
|
|
||||||
e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
|
|
||||||
f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
|
|
||||||
|
|
||||||
All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
|
|
||||||
|
|
||||||
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
|
|
||||||
|
|
||||||
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
|
|
||||||
8. Termination.
|
|
||||||
|
|
||||||
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
|
|
||||||
|
|
||||||
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
|
|
||||||
|
|
||||||
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
|
|
||||||
|
|
||||||
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
|
|
||||||
9. Acceptance Not Required for Having Copies.
|
|
||||||
|
|
||||||
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
|
|
||||||
10. Automatic Licensing of Downstream Recipients.
|
|
||||||
|
|
||||||
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
|
|
||||||
|
|
||||||
An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
|
|
||||||
|
|
||||||
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
|
|
||||||
11. Patents.
|
|
||||||
|
|
||||||
A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”.
|
|
||||||
|
|
||||||
A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
|
|
||||||
|
|
||||||
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
|
|
||||||
|
|
||||||
In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
|
|
||||||
|
|
||||||
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
|
|
||||||
|
|
||||||
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
|
|
||||||
|
|
||||||
A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
|
|
||||||
|
|
||||||
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
|
|
||||||
12. No Surrender of Others' Freedom.
|
|
||||||
|
|
||||||
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
|
|
||||||
13. Use with the GNU Affero General Public License.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.
|
|
||||||
14. Revised Versions of this License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
|
|
||||||
|
|
||||||
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
|
|
||||||
15. Disclaimer of Warranty.
|
|
||||||
|
|
||||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
||||||
16. Limitation of Liability.
|
|
||||||
|
|
||||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
17. Interpretation of Sections 15 and 16.
|
|
||||||
|
|
||||||
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:
|
|
||||||
|
|
||||||
<program> Copyright (C) <year> <name of author>
|
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <https://www.gnu.org/licenses/why-not-lgpl.html>.
|
|
|
@ -1,26 +1,19 @@
|
||||||
mcl_bamboo
|
mcl_bamboo
|
||||||
=========
|
=========
|
||||||
|
|
||||||
This mod adds working, familiar bamboo nodes to your Mineclone 2 world.
|
This mod adds simple bamboo nodes to your Mineclone 2 world.
|
||||||
|
|
||||||
Code: MineClone2 dev team. Original (basic) bamboo code by: Small Joker.
|
Code redo for Mineclone 2: Michieal. Original bamboo code by: Krock.
|
||||||
|
|
||||||
License for code: GPLv3.
|
License for code: GPL3; images / textures: CC-BY-SA.
|
||||||
License for images / textures: CC-BY-SA except where noted.
|
Images Created by Michieal, except for:
|
||||||
Images Created by Nicu, except for:
|
Inventory / wield image: created by RandomLegoBrick#8692 and is CC0.
|
||||||
|
|
||||||
* Inventory / wield image for Bamboo Stalk: created by RandomLegoBrick#8692 and is CC0.
|
|
||||||
|
|
||||||
Dependencies: mcl_core, mcl_sounds, mcl_tools
|
Dependencies: mcl_core, mcl_sounds, mcl_tools
|
||||||
|
|
||||||
Optional Dependencies = mcl_flowerpots, mclx_stairs, mcl_doors, mcl_signs, mesecons_pressureplates, mcl_fences,
|
Optional Dependencies = mcl_flowerpots, mclx_stairs, mcl_doors, mcl_signs, mesecons_pressureplates, mcl_fences, mesecons_button
|
||||||
mesecons_button.
|
|
||||||
Note that "mcl_boats" may be used at a later date.
|
|
||||||
|
|
||||||
Special thanks to Nicu for help with a ton of things from testing, to encouragement, to graphic design and nodebox work.
|
Special thanks to Nicu for help with the nodebox stalk design.
|
||||||
Nicu - You Rock!
|
|
||||||
|
|
||||||
Small Joker's bamboo forum topic:
|
Original code's forum topic:
|
||||||
Forum topic: https://forum.minetest.net/viewtopic.php?id=8289
|
Forum topic: https://forum.minetest.net/viewtopic.php?id=8289
|
||||||
|
|
||||||
Scaffold inspiration: Cora, because she said that it couldn't be done.
|
|
|
@ -1,401 +0,0 @@
|
||||||
---
|
|
||||||
--- Generated by EmmyLua(https://github.com/EmmyLua)
|
|
||||||
--- Created by michieal.
|
|
||||||
--- DateTime: 12/29/22 12:33 PM -- Restructure Date
|
|
||||||
--- Copyright (C) 2022 - 2023, Michieal. See License.txt
|
|
||||||
|
|
||||||
-- CONSTS
|
|
||||||
local DOUBLE_DROP_CHANCE = 8
|
|
||||||
-- Used everywhere. Often this is just the name, but it makes sense to me as BAMBOO, because that's how I think of it...
|
|
||||||
-- "BAMBOO" goes here.
|
|
||||||
local BAMBOO = "mcl_bamboo:bamboo"
|
|
||||||
local BAMBOO_ENDCAP_NAME = "mcl_bamboo:bamboo_endcap"
|
|
||||||
local BAMBOO_PLANK = BAMBOO .. "_plank"
|
|
||||||
|
|
||||||
-- LOCALS
|
|
||||||
local modname = minetest.get_current_modname()
|
|
||||||
local S = minetest.get_translator(modname)
|
|
||||||
local node_sound = mcl_sounds.node_sound_wood_defaults()
|
|
||||||
local pr = PseudoRandom((os.time() + 15766) * 12) -- switched from math.random() to PseudoRandom because the random wasn't very random.
|
|
||||||
|
|
||||||
local on_rotate
|
|
||||||
if minetest.get_modpath("screwdriver") then
|
|
||||||
on_rotate = screwdriver.disallow
|
|
||||||
end
|
|
||||||
|
|
||||||
-- basic bamboo nodes.
|
|
||||||
local bamboo_def = {
|
|
||||||
description = "Bamboo",
|
|
||||||
tiles = {"mcl_bamboo_bamboo_bottom.png", "mcl_bamboo_bamboo_bottom.png", "mcl_bamboo_bamboo.png"},
|
|
||||||
drawtype = "nodebox",
|
|
||||||
paramtype = "light",
|
|
||||||
groups = {handy = 1, axey = 1, choppy = 1, flammable = 3},
|
|
||||||
sounds = node_sound,
|
|
||||||
|
|
||||||
drop = {
|
|
||||||
max_items = 1,
|
|
||||||
-- From the API:
|
|
||||||
-- max_items: Maximum number of item lists to drop.
|
|
||||||
-- The entries in 'items' are processed in order. For each:
|
|
||||||
-- Item filtering is applied, chance of drop is applied, if both are
|
|
||||||
-- successful the entire item list is dropped.
|
|
||||||
-- Entry processing continues until the number of dropped item lists
|
|
||||||
-- equals 'max_items'.
|
|
||||||
-- Therefore, entries should progress from low to high drop chance.
|
|
||||||
items = {
|
|
||||||
-- Examples:
|
|
||||||
{
|
|
||||||
-- 1 in DOUBLE_DROP_CHANCE chance of dropping.
|
|
||||||
-- Default rarity is '1'.
|
|
||||||
rarity = DOUBLE_DROP_CHANCE,
|
|
||||||
items = {BAMBOO .. " 2"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
-- 1 in 1 chance of dropping. (Note: this means that it will drop 100% of the time.)
|
|
||||||
-- Default rarity is '1'.
|
|
||||||
rarity = 1,
|
|
||||||
items = {BAMBOO},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
inventory_image = "mcl_bamboo_bamboo_shoot.png",
|
|
||||||
wield_image = "mcl_bamboo_bamboo_shoot.png",
|
|
||||||
_mcl_blast_resistance = 1,
|
|
||||||
_mcl_hardness = 1.5,
|
|
||||||
node_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.175, -0.5, -0.195, 0.05, 0.5, 0.030},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
collision_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.175, -0.5, -0.195, 0.05, 0.5, 0.030},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selection_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.175, -0.5, -0.195, 0.05, 0.5, 0.030},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
node_placement_prediction = "",
|
|
||||||
|
|
||||||
on_rotate = on_rotate,
|
|
||||||
|
|
||||||
on_place = function(itemstack, placer, pointed_thing)
|
|
||||||
if pointed_thing.type ~= "node" then
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
local node = minetest.get_node(pointed_thing.under)
|
|
||||||
local pos = pointed_thing.under
|
|
||||||
local nodename = node.name -- intentional use of nodename.
|
|
||||||
|
|
||||||
mcl_bamboo.mcl_log("Node placement data:")
|
|
||||||
mcl_bamboo.mcl_log(dump(pointed_thing))
|
|
||||||
mcl_bamboo.mcl_log("node name: " .. nodename)
|
|
||||||
|
|
||||||
mcl_bamboo.mcl_log("Checking for protected placement of bamboo.")
|
|
||||||
if mcl_bamboo.is_protected(pos, placer) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
mcl_bamboo.mcl_log("placement of bamboo is not protected.")
|
|
||||||
|
|
||||||
-- Use pointed node's on_rightclick function first, if present
|
|
||||||
if placer and not placer:get_player_control().sneak then
|
|
||||||
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
|
||||||
mcl_bamboo.mcl_log("Attempting targeted node's on_rightclick.")
|
|
||||||
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if mcl_bamboo.is_bamboo(nodename) == false and nodename ~= BAMBOO_ENDCAP_NAME then
|
|
||||||
-- not bamboo...
|
|
||||||
mcl_bamboo.mcl_log("not bamboo...")
|
|
||||||
if nodename ~= "mcl_flowerpots:flower_pot" then
|
|
||||||
if mcl_bamboo.is_dirt(nodename) == false then
|
|
||||||
mcl_bamboo.mcl_log("bamboo dirt node not found; node name: " .. nodename)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
mcl_bamboo.mcl_log("placing bamboo directly.")
|
|
||||||
|
|
||||||
local dir = vector.subtract(pointed_thing.under, pointed_thing.above)
|
|
||||||
local wdir = minetest.dir_to_wallmounted(dir)
|
|
||||||
local fdir = minetest.dir_to_facedir(dir)
|
|
||||||
if wdir ~= 1 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local place_item = ItemStack(itemstack) -- make a copy so that we don't indirectly mess with the original.
|
|
||||||
|
|
||||||
local bamboo_node = mcl_bamboo.is_bamboo(nodename) or 0
|
|
||||||
mcl_bamboo.mcl_log("node name: " .. nodename .. "\nbamboo_node: " .. bamboo_node)
|
|
||||||
|
|
||||||
local rand_height
|
|
||||||
local BAMBOO_MAX_HEIGHT = 16 -- maximum height of 16, per wiki.
|
|
||||||
local first_shoot
|
|
||||||
local meta
|
|
||||||
|
|
||||||
if bamboo_node and bamboo_node > 0 then
|
|
||||||
place_item = ItemStack(mcl_bamboo.bamboo_index[bamboo_node])
|
|
||||||
|
|
||||||
-- height check for placing bamboo nodes. because... lmfao bamboo stalk to the sky.
|
|
||||||
-- variables used in more than one spot.
|
|
||||||
local chk_pos
|
|
||||||
local node_name = ""
|
|
||||||
local dist = 0
|
|
||||||
local height = -1
|
|
||||||
|
|
||||||
local BAMBOO_SOIL_DIST = BAMBOO_MAX_HEIGHT * -1
|
|
||||||
-- -------------------
|
|
||||||
for py = -1, BAMBOO_SOIL_DIST, -1 do
|
|
||||||
chk_pos = vector.offset(pos, 0, py, 0)
|
|
||||||
node_name = minetest.get_node(chk_pos).name
|
|
||||||
if mcl_bamboo.is_dirt(node_name) then
|
|
||||||
first_shoot = vector.offset(chk_pos, 0, 1, 0)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
if mcl_bamboo.is_bamboo(node_name) == false then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- requires knowing where the soil node is.
|
|
||||||
if first_shoot == nil then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
meta = minetest.get_meta(first_shoot)
|
|
||||||
if meta then
|
|
||||||
height = meta:get_int("height", -1)
|
|
||||||
end
|
|
||||||
|
|
||||||
dist = vector.distance(first_shoot, pos) + 1 -- +1 for the ground offset.
|
|
||||||
mcl_bamboo.mcl_log("Distance: " .. dist .. " Height: " .. height .. " Bamboo to place: " .. mcl_bamboo.bamboo_index[bamboo_node])
|
|
||||||
-- okay, so don't go beyond max height...
|
|
||||||
-- Height is determined when the first node grows or is placed.
|
|
||||||
-- here, it's not found, so let them do 4-5 nodes up. (should help it grow.)
|
|
||||||
if dist < 5 and height < 5 then
|
|
||||||
-- allow
|
|
||||||
else
|
|
||||||
-- else, it's complicated.
|
|
||||||
if dist > 5 and height < 5 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if dist > height - 1 then
|
|
||||||
-- height found. here, we let them do it until they reach where the endcap will go.
|
|
||||||
return
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local placed_type = pr:next(1, 4) -- randomly choose which one to place.
|
|
||||||
mcl_bamboo.mcl_log("Place_Bamboo_Shoot--Type: " .. placed_type)
|
|
||||||
place_item = ItemStack(mcl_bamboo.bamboo_index[placed_type])
|
|
||||||
rand_height = pr:next(BAMBOO_MAX_HEIGHT - 4, BAMBOO_MAX_HEIGHT)
|
|
||||||
end
|
|
||||||
|
|
||||||
local node_above_name = minetest.get_node(pointed_thing.above).name
|
|
||||||
mcl_bamboo.mcl_log("\n\n\nnode_above name: " .. node_above_name)
|
|
||||||
if node_above_name ~= "mcl_core:water_source" and node_above_name ~= "mcl_core:lava_source"
|
|
||||||
and node_above_name ~= "mcl_nether:nether_lava_source" then
|
|
||||||
local _, position = minetest.item_place(place_item, placer, pointed_thing, fdir)
|
|
||||||
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
|
||||||
itemstack:take_item(1)
|
|
||||||
end
|
|
||||||
if rand_height and rand_height > 1 then
|
|
||||||
if position then
|
|
||||||
mcl_bamboo.mcl_log("Setting Height Data...")
|
|
||||||
meta = minetest.get_meta(position)
|
|
||||||
if meta then
|
|
||||||
meta:set_int("height", rand_height)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return itemstack, pointed_thing.under
|
|
||||||
else
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
|
|
||||||
on_destruct = function(pos)
|
|
||||||
-- Node destructor; called before removing node.
|
|
||||||
local new_pos = vector.offset(pos, 0, 1, 0)
|
|
||||||
local node_above = minetest.get_node(new_pos)
|
|
||||||
local bamboo_node = mcl_bamboo.is_bamboo(node_above.name) or 0
|
|
||||||
local istack = ItemStack(BAMBOO)
|
|
||||||
local sound_params = {
|
|
||||||
pos = new_pos,
|
|
||||||
gain = 1.0, -- default
|
|
||||||
max_hear_distance = 10, -- default, uses a Euclidean metric
|
|
||||||
}
|
|
||||||
|
|
||||||
if node_above and ((bamboo_node and bamboo_node > 0) or node_above.name == BAMBOO_ENDCAP_NAME) then
|
|
||||||
minetest.remove_node(new_pos)
|
|
||||||
minetest.sound_play(node_sound.dug, sound_params, true)
|
|
||||||
if pr:next(1, DOUBLE_DROP_CHANCE) == 1 then
|
|
||||||
minetest.add_item(new_pos, istack)
|
|
||||||
end
|
|
||||||
minetest.add_item(new_pos, istack)
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
minetest.register_node(BAMBOO, bamboo_def)
|
|
||||||
|
|
||||||
local bamboo_top = table.copy(bamboo_def)
|
|
||||||
bamboo_top.groups = {not_in_creative_inventory = 1, handy = 1, axey = 1, choppy = 1, flammable = 3}
|
|
||||||
bamboo_top.tiles = {"mcl_bamboo_endcap.png"}
|
|
||||||
bamboo_top.drawtype = "plantlike_rooted" --"plantlike"
|
|
||||||
--bamboo_top.paramtype2 = "meshoptions"
|
|
||||||
--bamboo_top.param2 = 2
|
|
||||||
-- bamboo_top.waving = 2
|
|
||||||
bamboo_top.special_tiles = {{name = "mcl_bamboo_endcap.png"}}
|
|
||||||
bamboo_top.nodebox = nil
|
|
||||||
bamboo_top.selection_box = nil
|
|
||||||
bamboo_top.collision_box = nil
|
|
||||||
|
|
||||||
bamboo_top.on_place = function(itemstack, _, _)
|
|
||||||
-- Should never occur... but, if it does, then nix it.
|
|
||||||
itemstack:set_name(BAMBOO)
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.register_node(BAMBOO_ENDCAP_NAME, bamboo_top)
|
|
||||||
|
|
||||||
local bamboo_block_def = {
|
|
||||||
description = "Bamboo Block",
|
|
||||||
tiles = {"mcl_bamboo_bamboo_bottom.png", "mcl_bamboo_bamboo_bottom.png", "mcl_bamboo_bamboo_block.png"},
|
|
||||||
groups = {handy = 1, building_block = 1, axey = 1, flammable = 2, material_wood = 1, bamboo_block = 1, fire_encouragement = 5, fire_flammability = 5},
|
|
||||||
sounds = node_sound,
|
|
||||||
paramtype2 = "facedir",
|
|
||||||
drops = "mcl_bamboo:bamboo_block",
|
|
||||||
_mcl_blast_resistance = 3,
|
|
||||||
_mcl_hardness = 2,
|
|
||||||
_mcl_stripped_variant = "mcl_bamboo:bamboo_block_stripped", -- this allows us to use the built in Axe's strip block.
|
|
||||||
on_place = function(itemstack, placer, pointed_thing)
|
|
||||||
|
|
||||||
local pos = pointed_thing.under
|
|
||||||
|
|
||||||
if mcl_bamboo.is_protected(pos, placer) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Use pointed node's on_rightclick function first, if present
|
|
||||||
local node = minetest.get_node(pointed_thing.under)
|
|
||||||
if placer and not placer:get_player_control().sneak then
|
|
||||||
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
|
||||||
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return minetest.item_place(itemstack, placer, pointed_thing, minetest.dir_to_facedir(vector.direction(pointed_thing.above, pointed_thing.under)))
|
|
||||||
end,
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
minetest.register_node("mcl_bamboo:bamboo_block", bamboo_block_def)
|
|
||||||
|
|
||||||
local bamboo_stripped_block = table.copy(bamboo_block_def)
|
|
||||||
bamboo_stripped_block.on_rightclick = nil
|
|
||||||
bamboo_stripped_block.description = S("Stripped Bamboo Block")
|
|
||||||
bamboo_stripped_block.tiles = {"mcl_bamboo_bamboo_bottom_stripped.png", "mcl_bamboo_bamboo_bottom_stripped.png",
|
|
||||||
"mcl_bamboo_bamboo_block_stripped.png"}
|
|
||||||
minetest.register_node("mcl_bamboo:bamboo_block_stripped", bamboo_stripped_block)
|
|
||||||
minetest.register_node("mcl_bamboo:bamboo_plank", {
|
|
||||||
description = S("Bamboo Plank"),
|
|
||||||
_doc_items_longdesc = S("Bamboo Plank"),
|
|
||||||
_doc_items_hidden = false,
|
|
||||||
tiles = {"mcl_bamboo_bamboo_plank.png"},
|
|
||||||
stack_max = 64,
|
|
||||||
is_ground_content = false,
|
|
||||||
groups = {handy = 1, axey = 1, flammable = 3, wood = 1, building_block = 1, material_wood = 1, fire_encouragement = 5, fire_flammability = 20},
|
|
||||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
|
||||||
_mcl_blast_resistance = 3,
|
|
||||||
_mcl_hardness = 2,
|
|
||||||
})
|
|
||||||
|
|
||||||
-- Bamboo Part 2 Base nodes.
|
|
||||||
-- Bamboo Mosaic
|
|
||||||
local bamboo_mosaic = table.copy(minetest.registered_nodes[BAMBOO_PLANK])
|
|
||||||
bamboo_mosaic.tiles = {"mcl_bamboo_bamboo_plank_mosaic.png"}
|
|
||||||
bamboo_mosaic.groups = {handy = 1, axey = 1, flammable = 3, fire_encouragement = 5, fire_flammability = 20}
|
|
||||||
bamboo_mosaic.description = S("Bamboo Mosaic Plank")
|
|
||||||
bamboo_mosaic._doc_items_longdesc = S("Bamboo Mosaic Plank")
|
|
||||||
minetest.register_node("mcl_bamboo:bamboo_mosaic", bamboo_mosaic)
|
|
||||||
|
|
||||||
--[[ Bamboo alternative node types. Note that the table.copy's are very important! if you use a common node def and
|
|
||||||
make changes, even after registering them, the changes overwrite the previous node definitions, and in this case,
|
|
||||||
you will end up with 4 nodes all being type 3. --]]
|
|
||||||
|
|
||||||
local bamboo_one_def = table.copy(bamboo_def)
|
|
||||||
bamboo_one_def.node_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.05, -0.5, 0.285, -0.275, 0.5, 0.06},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bamboo_one_def.collision_box = {
|
|
||||||
-- see [Node boxes] for possibilities
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.05, -0.5, 0.285, -0.275, 0.5, 0.06},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bamboo_one_def.selection_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.05, -0.5, 0.285, -0.275, 0.5, 0.06},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bamboo_one_def.groups = {not_in_creative_inventory = 1, handy = 1, axey = 1, choppy = 1, flammable = 3}
|
|
||||||
mcl_bamboo.mcl_log(dump(mcl_bamboo.bamboo_index))
|
|
||||||
minetest.register_node(mcl_bamboo.bamboo_index[2], bamboo_one_def)
|
|
||||||
local bamboo_two_def = table.copy(bamboo_def)
|
|
||||||
|
|
||||||
bamboo_two_def.node_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{0.25, -0.5, 0.325, 0.025, 0.5, 0.100},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bamboo_two_def.collision_box = {
|
|
||||||
-- see [Node boxes] for possibilities
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{0.25, -0.5, 0.325, 0.025, 0.5, 0.100},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bamboo_two_def.selection_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{0.25, -0.5, 0.325, 0.025, 0.5, 0.100},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bamboo_two_def.groups = {not_in_creative_inventory = 1, handy = 1, axey = 1, choppy = 1, flammable = 3}
|
|
||||||
minetest.register_node(mcl_bamboo.bamboo_index[3], bamboo_two_def)
|
|
||||||
local bamboo_three_def = table.copy(bamboo_def)
|
|
||||||
|
|
||||||
bamboo_three_def.node_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.125, -0.5, 0.125, -0.3125, 0.5, 0.3125},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bamboo_three_def.collision_box = {
|
|
||||||
-- see [Node boxes] for possibilities
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.125, -0.5, 0.125, -0.3125, 0.5, 0.3125},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bamboo_three_def.selection_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.125, -0.5, 0.125, -0.3125, 0.5, 0.3125},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bamboo_three_def.groups = {not_in_creative_inventory = 1, handy = 1, axey = 1, choppy = 1, flammable = 3}
|
|
||||||
minetest.register_node(mcl_bamboo.bamboo_index[4], bamboo_three_def)
|
|
|
@ -1,600 +0,0 @@
|
||||||
---
|
|
||||||
--- Generated by EmmyLua(https://github.com/EmmyLua)
|
|
||||||
--- Created by michieal.
|
|
||||||
--- DateTime: 12/29/22 12:38 PM -- Restructure Date
|
|
||||||
--- Copyright (C) 2022 - 2023, Michieal. See License.txt
|
|
||||||
|
|
||||||
-- CONSTS
|
|
||||||
-- Due to door fix #2736, doors are displayed backwards. When this is fixed, set this variable to false.
|
|
||||||
local BROKEN_DOORS = true
|
|
||||||
|
|
||||||
-- FUTURE USE VARIABLE. MUST REMAIN FALSE UNTIL IT HAS BEEN FULLY IMPLEMENTED. DO NOT ENABLE.
|
|
||||||
local SIDE_SCAFFOLDING = false
|
|
||||||
local SIDE_SCAFFOLD_NAME = "mcl_bamboo:scaffolding_horizontal"
|
|
||||||
-- ---------------------------------------------------------------------------
|
|
||||||
local SCAFFOLDING_NAME = "mcl_bamboo:scaffolding"
|
|
||||||
-- Used everywhere. Often this is just the name, but it makes sense to me as BAMBOO, because that's how I think of it...
|
|
||||||
-- "BAMBOO" goes here.
|
|
||||||
local BAMBOO = "mcl_bamboo:bamboo"
|
|
||||||
local BAMBOO_PLANK = BAMBOO .. "_plank"
|
|
||||||
|
|
||||||
-- LOCALS
|
|
||||||
local modname = minetest.get_current_modname()
|
|
||||||
local S = minetest.get_translator(modname)
|
|
||||||
local adj_nodes = {
|
|
||||||
vector.new(0, 0, 1),
|
|
||||||
vector.new(1, 0, 0),
|
|
||||||
vector.new(0, 0, -1),
|
|
||||||
vector.new(-1, 0, 0),
|
|
||||||
}
|
|
||||||
local node_sound = mcl_sounds.node_sound_wood_defaults()
|
|
||||||
|
|
||||||
-- specific bamboo nodes (Items)... Pt. 1
|
|
||||||
if minetest.get_modpath("mcl_flowerpots") then
|
|
||||||
mcl_bamboo.mcl_log("FlowerPot Section Entrance. Modpath exists.")
|
|
||||||
if mcl_flowerpots ~= nil then
|
|
||||||
-- Flower-potted Bamboo...
|
|
||||||
local flwr_name = BAMBOO
|
|
||||||
local flwr_def = {name = "bamboo_plant",
|
|
||||||
desc = S("Bamboo"),
|
|
||||||
image = "mcl_bamboo_bamboo_fpm.png", -- use with "register_potted_cube"
|
|
||||||
-- "mcl_bamboo_flower_pot.png", -- use with "register_potted_flower"
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Chose cube over "potted_flower" as "potted flower" looks bad.
|
|
||||||
mcl_flowerpots.register_potted_cube(flwr_name, flwr_def) -- mcl_flowerpots.register_potted_flower(flwr_name, flwr_def)
|
|
||||||
minetest.register_alias("bamboo_flower_pot", "mcl_flowerpots:flower_pot_bamboo_plant")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if minetest.get_modpath("mcl_doors") then
|
|
||||||
if mcl_doors then
|
|
||||||
local top_door_tiles = {}
|
|
||||||
local bot_door_tiles = {}
|
|
||||||
|
|
||||||
if BROKEN_DOORS then
|
|
||||||
top_door_tiles = {"mcl_bamboo_door_top_alt.png", "mcl_bamboo_door_top.png"}
|
|
||||||
bot_door_tiles = {"mcl_bamboo_door_bottom_alt.png", "mcl_bamboo_door_bottom.png"}
|
|
||||||
else
|
|
||||||
top_door_tiles = {"mcl_bamboo_door_top.png", "mcl_bamboo_door_top.png"}
|
|
||||||
bot_door_tiles = {"mcl_bamboo_door_bottom.png", "mcl_bamboo_door_bottom.png"}
|
|
||||||
end
|
|
||||||
|
|
||||||
local name = "mcl_bamboo:bamboo_door"
|
|
||||||
local def = {
|
|
||||||
description = S("Bamboo Door."),
|
|
||||||
inventory_image = "mcl_bamboo_door_wield.png",
|
|
||||||
wield_image = "mcl_bamboo_door_wield.png",
|
|
||||||
groups = {handy = 1, axey = 1, material_wood = 1, flammable = -1},
|
|
||||||
_mcl_hardness = 3,
|
|
||||||
_mcl_blast_resistance = 3,
|
|
||||||
tiles_bottom = bot_door_tiles,
|
|
||||||
tiles_top = top_door_tiles,
|
|
||||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
|
||||||
}
|
|
||||||
|
|
||||||
mcl_doors:register_door(name, def)
|
|
||||||
|
|
||||||
name = "mcl_bamboo:bamboo_trapdoor"
|
|
||||||
local trap_def = {
|
|
||||||
description = S("Bamboo Trapdoor."),
|
|
||||||
inventory_image = "mcl_bamboo_door_complete.png",
|
|
||||||
groups = {},
|
|
||||||
tile_front = "mcl_bamboo_trapdoor_side.png",
|
|
||||||
tile_side = "mcl_bamboo_trapdoor_side.png",
|
|
||||||
_doc_items_longdesc = S("Wooden trapdoors are horizontal barriers which can be opened and closed by hand or a redstone signal. They occupy the upper or lower part of a block, depending on how they have been placed. When open, they can be climbed like a ladder."),
|
|
||||||
_doc_items_usagehelp = S("To open or close the trapdoor, rightclick it or send a redstone signal to it."),
|
|
||||||
wield_image = "mcl_bamboo_trapdoor_side.png",
|
|
||||||
inventory_image = "mcl_bamboo_trapdoor_side.png",
|
|
||||||
groups = {handy = 1, axey = 1, mesecon_effector_on = 1, material_wood = 1, flammable = -1},
|
|
||||||
_mcl_hardness = 3,
|
|
||||||
_mcl_blast_resistance = 3,
|
|
||||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
|
||||||
}
|
|
||||||
|
|
||||||
mcl_doors:register_trapdoor(name, trap_def)
|
|
||||||
|
|
||||||
minetest.register_alias("bamboo_door", "mcl_bamboo:bamboo_door")
|
|
||||||
minetest.register_alias("bamboo_trapdoor", "mcl_bamboo:bamboo_trapdoor")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if minetest.get_modpath("mcl_stairs") then
|
|
||||||
if mcl_stairs ~= nil then
|
|
||||||
mcl_stairs.register_stair_and_slab_simple(
|
|
||||||
"bamboo_block",
|
|
||||||
"mcl_bamboo:bamboo_block",
|
|
||||||
S("Bamboo Stair"),
|
|
||||||
S("Bamboo Slab"),
|
|
||||||
S("Double Bamboo Slab")
|
|
||||||
)
|
|
||||||
mcl_stairs.register_stair_and_slab_simple(
|
|
||||||
"bamboo_stripped",
|
|
||||||
"mcl_bamboo:bamboo_block_stripped",
|
|
||||||
S("Stripped Bamboo Stair"),
|
|
||||||
S("Stripped Bamboo Slab"),
|
|
||||||
S("Double Stripped Bamboo Slab")
|
|
||||||
)
|
|
||||||
mcl_stairs.register_stair_and_slab_simple(
|
|
||||||
"bamboo_plank",
|
|
||||||
BAMBOO_PLANK,
|
|
||||||
S("Bamboo Plank Stair"),
|
|
||||||
S("Bamboo Plank Slab"),
|
|
||||||
S("Double Bamboo Plank Slab")
|
|
||||||
)
|
|
||||||
|
|
||||||
-- let's add plank slabs to the wood_slab group.
|
|
||||||
local bamboo_plank_slab = "mcl_stairs:slab_bamboo_plank"
|
|
||||||
local node_groups = {
|
|
||||||
wood_slab = 1,
|
|
||||||
building_block = 1,
|
|
||||||
slab = 1,
|
|
||||||
axey = 1,
|
|
||||||
handy = 1,
|
|
||||||
stair = 1,
|
|
||||||
flammable = 1,
|
|
||||||
fire_encouragement = 5,
|
|
||||||
fire_flammability = 20
|
|
||||||
}
|
|
||||||
|
|
||||||
minetest.override_item(bamboo_plank_slab, {groups = node_groups})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if minetest.get_modpath("mesecons_pressureplates") then
|
|
||||||
|
|
||||||
if mesecon ~= nil and mesecon.register_pressure_plate ~= nil then
|
|
||||||
-- make sure that pressure plates are installed.
|
|
||||||
|
|
||||||
-- Bamboo Pressure Plate...
|
|
||||||
|
|
||||||
-- Register a Pressure Plate (api command doc.)
|
|
||||||
-- basename: base name of the pressure plate
|
|
||||||
-- description: description displayed in the player's inventory
|
|
||||||
-- textures_off:textures of the pressure plate when inactive
|
|
||||||
-- textures_on: textures of the pressure plate when active
|
|
||||||
-- image_w: wield image of the pressure plate
|
|
||||||
-- image_i: inventory image of the pressure plate
|
|
||||||
-- recipe: crafting recipe of the pressure plate
|
|
||||||
-- sounds: sound table (like in minetest.register_node)
|
|
||||||
-- plusgroups: group memberships (attached_node=1 and not_in_creative_inventory=1 are already used)
|
|
||||||
-- activated_by: optimal table with elements denoting by which entities this pressure plate is triggered
|
|
||||||
-- Possible table fields:
|
|
||||||
-- * player=true: Player
|
|
||||||
-- * mob=true: Mob
|
|
||||||
-- By default, is triggered by all entities
|
|
||||||
-- longdesc: Customized long description for the in-game help (if omitted, a dummy text is used)
|
|
||||||
|
|
||||||
mesecon.register_pressure_plate(
|
|
||||||
"mcl_bamboo:pressure_plate_bamboo_wood",
|
|
||||||
S("Bamboo Pressure Plate"),
|
|
||||||
{"mcl_bamboo_bamboo_plank.png"},
|
|
||||||
{"mcl_bamboo_bamboo_plank.png"},
|
|
||||||
"mcl_bamboo_bamboo_plank.png",
|
|
||||||
nil,
|
|
||||||
{{BAMBOO_PLANK, BAMBOO_PLANK}},
|
|
||||||
mcl_sounds.node_sound_wood_defaults(),
|
|
||||||
{axey = 1, material_wood = 1},
|
|
||||||
nil,
|
|
||||||
S("A wooden pressure plate is a redstone component which supplies its surrounding blocks with redstone power while any movable object (including dropped items, players and mobs) rests on top of it."))
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = "mcl_bamboo:pressure_plate_bamboo_wood_off",
|
|
||||||
burntime = 15
|
|
||||||
})
|
|
||||||
minetest.register_alias("bamboo_pressure_plate", "mcl_bamboo:pressure_plate_bamboo_wood")
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if minetest.get_modpath("mcl_signs") then
|
|
||||||
mcl_bamboo.mcl_log("Signs Section Entrance. Modpath exists.")
|
|
||||||
if mcl_signs ~= nil then
|
|
||||||
-- Bamboo Signs...
|
|
||||||
mcl_signs.register_sign_custom("mcl_bamboo", "_bamboo", "mcl_bamboo_bamboo_sign.png",
|
|
||||||
"#ffffff", "mcl_bamboo_bamboo_sign_wield.png", "mcl_bamboo_bamboo_sign_wield.png",
|
|
||||||
"Bamboo Sign")
|
|
||||||
mcl_signs.register_sign_craft("mcl_bamboo", BAMBOO_PLANK, "_bamboo")
|
|
||||||
minetest.register_alias("bamboo_sign", "mcl_signs:wall_sign_bamboo")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if minetest.get_modpath("mcl_fences") then
|
|
||||||
mcl_bamboo.mcl_log("Fences Section Entrance. Modpath exists.")
|
|
||||||
|
|
||||||
local id = "bamboo_fence"
|
|
||||||
local wood_groups = {handy = 1, axey = 1, flammable = 2, fence_wood = 1, fire_encouragement = 5, fire_flammability = 20}
|
|
||||||
local wood_connect = {"group:fence_wood"}
|
|
||||||
|
|
||||||
local fence_id = mcl_fences.register_fence(id, S("Bamboo Fence"), "mcl_bamboo_fence_bamboo.png", wood_groups,
|
|
||||||
2, 15, wood_connect, node_sound)
|
|
||||||
local gate_id = mcl_fences.register_fence_gate(id, S("Bamboo Fence Gate"), "mcl_bamboo_fence_gate_bamboo.png",
|
|
||||||
wood_groups, 2, 15, node_sound) -- note: about missing params.. will use defaults.
|
|
||||||
|
|
||||||
mcl_bamboo.mcl_log(dump(fence_id))
|
|
||||||
mcl_bamboo.mcl_log(dump(gate_id))
|
|
||||||
end
|
|
||||||
|
|
||||||
if minetest.get_modpath("mesecons_button") then
|
|
||||||
if mesecon ~= nil then
|
|
||||||
mesecon.register_button(
|
|
||||||
"bamboo",
|
|
||||||
S("Bamboo Button"),
|
|
||||||
"mcl_bamboo_bamboo_plank.png",
|
|
||||||
BAMBOO_PLANK,
|
|
||||||
node_sound,
|
|
||||||
{material_wood = 1, handy = 1, pickaxey = 1, flammable = 3, fire_flammability = 20, fire_encouragement = 5, },
|
|
||||||
1,
|
|
||||||
false,
|
|
||||||
S("A bamboo button is a redstone component made out of stone which can be pushed to provide redstone power. When pushed, it powers adjacent redstone components for 1 second."),
|
|
||||||
"mesecons_button_push")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if minetest.get_modpath("mcl_stairs") then
|
|
||||||
if mcl_stairs ~= nil then
|
|
||||||
mcl_stairs.register_stair_and_slab_simple(
|
|
||||||
"bamboo_mosaic",
|
|
||||||
"mcl_bamboo:bamboo_mosaic",
|
|
||||||
S("Bamboo Mosaic Stair"),
|
|
||||||
S("Bamboo Mosaic Slab"),
|
|
||||||
S("Double Bamboo Mosaic Slab")
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local disallow_on_rotate
|
|
||||||
if minetest.get_modpath("screwdriver") then
|
|
||||||
disallow_on_rotate = screwdriver.disallow
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.register_node(SCAFFOLDING_NAME, {
|
|
||||||
description = S("Scaffolding"),
|
|
||||||
doc_items_longdesc = S("Scaffolding block used to climb up or out across areas."),
|
|
||||||
doc_items_hidden = false,
|
|
||||||
tiles = {"mcl_bamboo_scaffolding_top.png", "mcl_bamboo_scaffolding_top.png", "mcl_bamboo_scaffolding_bottom.png"},
|
|
||||||
drawtype = "nodebox",
|
|
||||||
paramtype = "light",
|
|
||||||
use_texture_alpha = "clip",
|
|
||||||
node_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.5, 0.375, -0.5, 0.5, 0.5, 0.5},
|
|
||||||
{-0.5, -0.5, -0.5, -0.375, 0.5, -0.375},
|
|
||||||
{0.375, -0.5, -0.5, 0.5, 0.5, -0.375},
|
|
||||||
{0.375, -0.5, 0.375, 0.5, 0.5, 0.5},
|
|
||||||
{-0.5, -0.5, 0.375, -0.375, 0.5, 0.5},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selection_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
buildable_to = false,
|
|
||||||
is_ground_content = false,
|
|
||||||
walkable = false,
|
|
||||||
climbable = true,
|
|
||||||
physical = true,
|
|
||||||
node_placement_prediction = "",
|
|
||||||
groups = {handy = 1, axey = 1, flammable = 3, building_block = 1, material_wood = 1, fire_encouragement = 5, fire_flammability = 20, falling_node = 1, stack_falling = 1},
|
|
||||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
|
||||||
_mcl_blast_resistance = 0,
|
|
||||||
_mcl_hardness = 0,
|
|
||||||
|
|
||||||
on_rotate = disallow_on_rotate,
|
|
||||||
|
|
||||||
on_place = function(itemstack, placer, pointed)
|
|
||||||
mcl_bamboo.mcl_log("Checking for protected placement of scaffolding.")
|
|
||||||
local node = minetest.get_node(pointed.under)
|
|
||||||
local pos = pointed.under
|
|
||||||
local h = 0
|
|
||||||
local current_base_node = node -- Current Base Node.
|
|
||||||
local below_node = minetest.get_node(vector.offset(pos, 0, -1, 0)) -- current node below the current_base_node.
|
|
||||||
|
|
||||||
mcl_bamboo.mcl_log("Below Node: " .. below_node.name)
|
|
||||||
|
|
||||||
-- check protected placement.
|
|
||||||
if mcl_bamboo.is_protected(pos, placer) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
mcl_bamboo.mcl_log("placement of scaffolding is not protected.")
|
|
||||||
-- place on solid nodes
|
|
||||||
-- Need to add in a check here... to prevent placing scaffolds against doors, chests, etc.
|
|
||||||
-- Added in a quick check. need to test it.
|
|
||||||
if node.name ~= SCAFFOLDING_NAME then
|
|
||||||
-- Start temp fix: This is a temp fix... will NOT work in final scaffolding implementation.
|
|
||||||
-- Use pointed node's on_rightclick function first, if present
|
|
||||||
if placer and not placer:get_player_control().sneak then
|
|
||||||
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
|
||||||
mcl_bamboo.mcl_log("attempting placement of bamboo via targeted node's on_rightclick.")
|
|
||||||
return minetest.registered_nodes[node.name].on_rightclick(pointed.under, node, placer, itemstack) or itemstack
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- End: Temp fix
|
|
||||||
|
|
||||||
-- A quick check, that may or may not work, to attempt to prevent placing things on the side of other nodes.
|
|
||||||
local dir = vector.subtract(pointed.under, pointed.above)
|
|
||||||
local wdir = minetest.dir_to_wallmounted(dir)
|
|
||||||
if wdir == 1 then
|
|
||||||
minetest.set_node(pointed.above, {name = SCAFFOLDING_NAME, param2 = 0})
|
|
||||||
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
|
||||||
itemstack:take_item(1)
|
|
||||||
end
|
|
||||||
return itemstack
|
|
||||||
else
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--build up when placing on existing scaffold
|
|
||||||
--[[
|
|
||||||
Quick explanation. scaffolding should be placed at the ground level ONLY. To do this, we look at a few
|
|
||||||
different nodes. Current node (current_node) is the top node being placed - make sure that it is air / unoccupied.
|
|
||||||
below_node (below node) is the node below the bottom node; Used to check to see if we are up in the air putting
|
|
||||||
more scaffolds on the top.. current_base_node (Current Base Node) is the targeted node for placement; we can only place
|
|
||||||
scaffolding on this one, to stack them up in the air.
|
|
||||||
--]]
|
|
||||||
repeat -- loop through, allowing placement.
|
|
||||||
pos = vector.offset(pos, 0, 1, 0) -- cleaned up vector.
|
|
||||||
local current_node = minetest.get_node(pos) -- current node.
|
|
||||||
if current_node.name == "air" then
|
|
||||||
-- first step to making scaffolding work like scaffolding should.
|
|
||||||
-- Prevent running up, and putting down new scaffolding
|
|
||||||
if current_base_node.name == SCAFFOLDING_NAME and below_node == SCAFFOLDING_NAME and SIDE_SCAFFOLDING == false then
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Make sure that the uppermost scaffolding doesn't violate protected areas.
|
|
||||||
if mcl_bamboo.is_protected(pos, placer) then
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
|
|
||||||
-- okay, we're good. place the node and take the item unless we are in creative mode.
|
|
||||||
minetest.set_node(pos, node)
|
|
||||||
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
|
||||||
itemstack:take_item(1)
|
|
||||||
end
|
|
||||||
-- set the wielded item to the correct itemstack. (possibly unneeded code. but, works.)
|
|
||||||
placer:set_wielded_item(itemstack)
|
|
||||||
return itemstack -- finally, return the itemstack to finish on_place.
|
|
||||||
end
|
|
||||||
h = h + 1
|
|
||||||
until current_node.name ~= node.name or itemstack:get_count() == 0 or h >= 128 -- loop check.
|
|
||||||
end,
|
|
||||||
on_destruct = function(pos)
|
|
||||||
-- Node destructor; called before removing node.
|
|
||||||
local new_pos = vector.offset(pos, 0, 1, 0)
|
|
||||||
local node_above = minetest.get_node(new_pos)
|
|
||||||
if node_above and node_above.name == SCAFFOLDING_NAME then
|
|
||||||
local sound_params = {
|
|
||||||
pos = new_pos,
|
|
||||||
gain = 1.0, -- default
|
|
||||||
max_hear_distance = 10, -- default, uses a Euclidean metric
|
|
||||||
}
|
|
||||||
|
|
||||||
minetest.remove_node(new_pos)
|
|
||||||
minetest.sound_play(node_sound.dug, sound_params, true)
|
|
||||||
local istack = ItemStack(SCAFFOLDING_NAME)
|
|
||||||
minetest.add_item(new_pos, istack)
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
-- FOR FUTURE USE. DO NOT ENABLE. DO NOT UNCOMMENT OUT. THIS WILL BREAK THE SCAFFOLDING, IF NOT FINISHED.
|
|
||||||
-- YOU HAVE BEEN WARNED.
|
|
||||||
--[[
|
|
||||||
if SIDE_SCAFFOLDING then
|
|
||||||
minetest.register_node(SCAFFOLDING_NAME, {
|
|
||||||
description = S("Scaffolding"),
|
|
||||||
doc_items_longdesc = S("Scaffolding block used to climb up or out across areas."),
|
|
||||||
doc_items_hidden = false,
|
|
||||||
tiles = {"mcl_bamboo_scaffolding_top.png", "mcl_bamboo_scaffolding_top.png", "mcl_bamboo_scaffolding_bottom.png"},
|
|
||||||
drawtype = "nodebox",
|
|
||||||
paramtype = "light",
|
|
||||||
use_texture_alpha = "clip",
|
|
||||||
node_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.5, 0.375, -0.5, 0.5, 0.5, 0.5},
|
|
||||||
{-0.5, -0.5, -0.5, -0.375, 0.5, -0.375},
|
|
||||||
{0.375, -0.5, -0.5, 0.5, 0.5, -0.375},
|
|
||||||
{0.375, -0.5, 0.375, 0.5, 0.5, 0.5},
|
|
||||||
{-0.5, -0.5, 0.375, -0.375, 0.5, 0.5},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selection_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
buildable_to = false,
|
|
||||||
is_ground_content = false,
|
|
||||||
walkable = false,
|
|
||||||
climbable = true,
|
|
||||||
physical = true,
|
|
||||||
node_placement_prediction = "",
|
|
||||||
groups = {handy = 1, axey = 1, flammable = 3, building_block = 1, material_wood = 1, fire_encouragement = 5, fire_flammability = 20, falling_node = 1, stack_falling = 1},
|
|
||||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
|
||||||
_mcl_blast_resistance = 0,
|
|
||||||
_mcl_hardness = 0,
|
|
||||||
|
|
||||||
on_rotate = disallow_on_rotate,
|
|
||||||
|
|
||||||
on_place = function(itemstack, placer, pointed)
|
|
||||||
mcl_bamboo.mcl_log("Checking for protected placement of scaffolding.")
|
|
||||||
local node = minetest.get_node(pointed.under)
|
|
||||||
local pos = pointed.under
|
|
||||||
local dir = vector.subtract(pointed.under, pointed.above)
|
|
||||||
local wdir = minetest.dir_to_wallmounted(dir)
|
|
||||||
local h = 0
|
|
||||||
mcl_bamboo.mcl_log("WDIR: " .. wdir)
|
|
||||||
local fdir = minetest.dir_to_facedir(dir, true)
|
|
||||||
mcl_bamboo.mcl_log("FDIR: " .. fdir)
|
|
||||||
|
|
||||||
local down_two = minetest.get_node(vector.offset(pointed.under, 0, -1, 0))
|
|
||||||
|
|
||||||
if wdir == 1 then
|
|
||||||
-- standing placement.
|
|
||||||
|
|
||||||
if mcl_bamboo.is_protected(pos, placer) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
mcl_bamboo.mcl_log("placement of scaffolding is not protected.")
|
|
||||||
-- place on solid nodes
|
|
||||||
if node.name ~= SCAFFOLDING_NAME then
|
|
||||||
minetest.set_node(pointed.above, {name = SCAFFOLDING_NAME, param2 = 0})
|
|
||||||
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
|
||||||
itemstack:take_item(1)
|
|
||||||
end
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
--build up when placing on existing scaffold
|
|
||||||
repeat
|
|
||||||
pos.y = pos.y + 1
|
|
||||||
local current_node = minetest.get_node(pos)
|
|
||||||
local current_base_node = node
|
|
||||||
local below_node = down_two
|
|
||||||
if current_node.name == "air" then
|
|
||||||
-- first step to making scaffolding work like Minecraft scaffolding.
|
|
||||||
if current_base_node.name == SCAFFOLDING_NAME and below_node == SCAFFOLDING_NAME and SIDE_SCAFFOLDING == false then
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
|
|
||||||
if mcl_bamboo.is_protected(pos, placer) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.set_node(pos, node)
|
|
||||||
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
|
||||||
itemstack:take_item(1)
|
|
||||||
end
|
|
||||||
placer:set_wielded_item(itemstack)
|
|
||||||
return itemstack
|
|
||||||
end
|
|
||||||
h = h + 1
|
|
||||||
until current_node.name ~= node.name or itemstack:get_count() == 0 or h >= 128
|
|
||||||
|
|
||||||
-- Commenting out untested code, for commit.
|
|
||||||
if SIDE_SCAFFOLDING == true then
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
|
|
||||||
if not meta then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
-- local count = meta:get_int("count", 0)
|
|
||||||
|
|
||||||
h = minetest.get_node(pointed.under).param2
|
|
||||||
local new_pos = pointed.under
|
|
||||||
repeat
|
|
||||||
local ctrl = placer:get_player_control()
|
|
||||||
if ctrl and ctrl.sneak then
|
|
||||||
if node.name == SCAFFOLDING_NAME or node.name == SIDE_SCAFFOLD_NAME then
|
|
||||||
local param_2 = h
|
|
||||||
|
|
||||||
local node_param2 = param_2 + 1
|
|
||||||
fdir = fdir + 1 -- convert fdir to a base of one.
|
|
||||||
local target_offset = adj_nodes[fdir]
|
|
||||||
|
|
||||||
new_pos = vector.offset(new_pos, target_offset.x, 0, target_offset.z)
|
|
||||||
if mcl_bamboo.is_protected(new_pos, placer) then
|
|
||||||
-- disallow placement in protected area
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
itemstack:take_item(1)
|
|
||||||
if minetest.get_node(new_pos).name == "air" then
|
|
||||||
minetest.set_node(new_pos, {name = SIDE_SCAFFOLD_NAME, param2 = node_param2})
|
|
||||||
if node_param2 >= 6 then
|
|
||||||
node_param2 = 6
|
|
||||||
minetest.minetest.dig_node(new_pos)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return itemstack
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
h = h + 1
|
|
||||||
|
|
||||||
end
|
|
||||||
until h >= 7 or itemstack.get_count() <= 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
on_destruct = function(pos)
|
|
||||||
-- Node destructor; called before removing node.
|
|
||||||
local new_pos = vector.offset(pos, 0, 1, 0)
|
|
||||||
local node_above = minetest.get_node(new_pos)
|
|
||||||
if node_above and node_above.name == SCAFFOLDING_NAME then
|
|
||||||
local sound_params = {
|
|
||||||
pos = new_pos,
|
|
||||||
gain = 1.0, -- default
|
|
||||||
max_hear_distance = 10, -- default, uses a Euclidean metric
|
|
||||||
}
|
|
||||||
|
|
||||||
minetest.remove_node(new_pos)
|
|
||||||
minetest.sound_play(node_sound.dug, sound_params, true)
|
|
||||||
local istack = ItemStack(SCAFFOLDING_NAME)
|
|
||||||
minetest.add_item(new_pos, istack)
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_node(SIDE_SCAFFOLD_NAME, {
|
|
||||||
description = S("Scaffolding"),
|
|
||||||
doc_items_longdesc = S("Scaffolding block used to climb up or out across areas."),
|
|
||||||
doc_items_hidden = false,
|
|
||||||
tiles = {"mcl_bamboo_scaffolding_top.png", "mcl_bamboo_scaffolding_top.png", "mcl_bamboo_scaffolding_bottom.png"},
|
|
||||||
drop = "mcl_bamboo:scaffolding",
|
|
||||||
drawtype = "nodebox",
|
|
||||||
paramtype = "light",
|
|
||||||
use_texture_alpha = "clip",
|
|
||||||
node_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.5, 0.375, -0.5, 0.5, 0.5, 0.5},
|
|
||||||
{-0.5, -0.5, -0.5, -0.375, 0.5, -0.375},
|
|
||||||
{0.375, -0.5, -0.5, 0.5, 0.5, -0.375},
|
|
||||||
{0.375, -0.5, 0.375, 0.5, 0.5, 0.5},
|
|
||||||
{-0.5, -0.5, 0.375, -0.375, 0.5, 0.5},
|
|
||||||
{-0.5, -0.5, -0.5, 0.5, -0.375, 0.5},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selection_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
groups = {handy = 1, axey = 1, flammable = 3, building_block = 1, material_wood = 1, fire_encouragement = 5, fire_flammability = 20, not_in_creative_inventory = 1, falling_node = 1},
|
|
||||||
_mcl_after_falling = function(pos)
|
|
||||||
if minetest.get_node(pos).name == "mcl_bamboo:scaffolding_horizontal" then
|
|
||||||
if minetest.get_node(vector.offset(pos, 0, 0, 0)).name ~= SCAFFOLDING_NAME then
|
|
||||||
minetest.remove_node(pos)
|
|
||||||
minetest.add_item(pos, SCAFFOLDING_NAME)
|
|
||||||
else
|
|
||||||
minetest.set_node(vector.offset(pos, 0, 1, 0), {name = SIDE_SCAFFOLD_NAME})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
buildable_to = false,
|
|
||||||
is_ground_content = false,
|
|
||||||
walkable = false,
|
|
||||||
climbable = true,
|
|
||||||
physical = true,
|
|
||||||
|
|
||||||
on_rotate = disallow_on_rotate,
|
|
||||||
|
|
||||||
on_place = function(itemstack, placer, pointed_thing)
|
|
||||||
-- this function shouldn't be called, as this is never placed by the user.
|
|
||||||
-- it's placed only as a variant of regular scaffolding.
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
})
|
|
||||||
end
|
|
||||||
--]]
|
|
|
@ -1,269 +0,0 @@
|
||||||
---
|
|
||||||
--- Generated by EmmyLua(https://github.com/EmmyLua)
|
|
||||||
--- Created by michieal.
|
|
||||||
--- DateTime: 12/29/22 12:34 PM -- Restructure Date
|
|
||||||
--- Copyright (C) 2022 - 2023, Michieal. See License.txt
|
|
||||||
|
|
||||||
local DEBUG = false
|
|
||||||
|
|
||||||
local rand = math.random
|
|
||||||
math.randomseed((os.time() + 31) * 31415) -- try to make a valid seed
|
|
||||||
local BAMBOO_MAX_HEIGHT = 16 -- base height check.
|
|
||||||
|
|
||||||
local BAMBOO_SOIL_DIST = BAMBOO_MAX_HEIGHT * -1
|
|
||||||
local BAM_MAX_HEIGHT_STPCHK = BAMBOO_MAX_HEIGHT - 5
|
|
||||||
local BAM_MAX_HEIGHT_TOP = BAMBOO_MAX_HEIGHT - 1
|
|
||||||
local GROW_DOUBLE_CHANCE = 32
|
|
||||||
|
|
||||||
--Bamboo can be planted on moss blocks, grass blocks, dirt, coarse dirt, rooted dirt, gravel, mycelium, podzol, sand, red sand, or mud
|
|
||||||
mcl_bamboo.bamboo_dirt_nodes = {
|
|
||||||
"mcl_core:redsand",
|
|
||||||
"mcl_core:sand",
|
|
||||||
"mcl_core:dirt",
|
|
||||||
"mcl_core:coarse_dirt",
|
|
||||||
"mcl_core:dirt_with_grass",
|
|
||||||
"mcl_core:podzol",
|
|
||||||
"mcl_core:mycelium",
|
|
||||||
"mcl_lush_caves:rooted_dirt",
|
|
||||||
"mcl_lush_caves:moss",
|
|
||||||
"mcl_mud:mud",
|
|
||||||
}
|
|
||||||
|
|
||||||
function mcl_bamboo.is_dirt(node_name)
|
|
||||||
local index = table.indexof(mcl_bamboo.bamboo_dirt_nodes, node_name)
|
|
||||||
if index == -1 then
|
|
||||||
return false
|
|
||||||
else
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
mcl_bamboo.bamboo_index = {
|
|
||||||
"mcl_bamboo:bamboo",
|
|
||||||
"mcl_bamboo:bamboo_1",
|
|
||||||
"mcl_bamboo:bamboo_2",
|
|
||||||
"mcl_bamboo:bamboo_3",
|
|
||||||
}
|
|
||||||
|
|
||||||
function mcl_bamboo.is_bamboo(node_name)
|
|
||||||
local index = table.indexof(mcl_bamboo.bamboo_index, node_name)
|
|
||||||
if index == -1 then
|
|
||||||
return false
|
|
||||||
else
|
|
||||||
return index
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- pos: node position; placer: ObjectRef that is placing the item
|
|
||||||
--- returns: true if protected, otherwise false.
|
|
||||||
function mcl_bamboo.is_protected(pos, placer)
|
|
||||||
local name = placer:get_player_name()
|
|
||||||
if minetest.is_protected(pos, name) then
|
|
||||||
minetest.record_protection_violation(pos, name)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local BAMBOO_ENDCAP_NAME = "mcl_bamboo:bamboo_endcap"
|
|
||||||
|
|
||||||
function mcl_bamboo.grow_bamboo(pos, bonemeal_applied)
|
|
||||||
local node_above = minetest.get_node(vector.offset(pos, 0, 1, 0))
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo called; bonemeal: " .. tostring(bonemeal_applied))
|
|
||||||
|
|
||||||
if not bonemeal_applied and mcl_bamboo.is_bamboo(node_above.name) ~= false then
|
|
||||||
return false -- short circuit this function if we're trying to grow (std) the bamboo and it's not the top shoot.
|
|
||||||
end
|
|
||||||
if minetest.get_node_light(pos) < 8 then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- variables used in more than one spot.
|
|
||||||
local first_shoot
|
|
||||||
local chk_pos
|
|
||||||
local soil_pos
|
|
||||||
local node_name = ""
|
|
||||||
local dist = 0
|
|
||||||
local node_below
|
|
||||||
-- -------------------
|
|
||||||
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; checking for soil: ")
|
|
||||||
-- the soil node below the bamboo.
|
|
||||||
for py = -1, BAMBOO_SOIL_DIST, -1 do
|
|
||||||
chk_pos = vector.offset(pos, 0, py, 0)
|
|
||||||
node_name = minetest.get_node(chk_pos).name
|
|
||||||
if mcl_bamboo.is_dirt(node_name) then
|
|
||||||
soil_pos = chk_pos
|
|
||||||
break
|
|
||||||
end
|
|
||||||
if mcl_bamboo.is_bamboo(node_name) == false then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- requires knowing where the soil node is.
|
|
||||||
if soil_pos == nil then
|
|
||||||
return false -- returning false means don't use up the bonemeal.
|
|
||||||
end
|
|
||||||
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; soil found. ")
|
|
||||||
local grow_amount = rand(1, GROW_DOUBLE_CHANCE)
|
|
||||||
grow_amount = rand(1, GROW_DOUBLE_CHANCE)
|
|
||||||
grow_amount = rand(1, GROW_DOUBLE_CHANCE) -- because yeah, not truly random, or even a good prng.
|
|
||||||
grow_amount = rand(1, GROW_DOUBLE_CHANCE)
|
|
||||||
local init_height = rand(BAM_MAX_HEIGHT_STPCHK + 1, BAM_MAX_HEIGHT_TOP + 1)
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; random height: " .. init_height)
|
|
||||||
|
|
||||||
node_name = ""
|
|
||||||
|
|
||||||
-- update: add randomized max height to first node's meta data.
|
|
||||||
first_shoot = vector.offset(soil_pos, 0, 1, 0)
|
|
||||||
local meta = minetest.get_meta(first_shoot)
|
|
||||||
node_below = minetest.get_node(first_shoot).name
|
|
||||||
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; checking height meta ")
|
|
||||||
-- check the meta data for the first node, to see how high to make the stalk.
|
|
||||||
if not meta then
|
|
||||||
-- if no metadata, set the metadata!!!
|
|
||||||
meta:set_int("height", init_height)
|
|
||||||
end
|
|
||||||
local height = meta:get_int("height", -1)
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; meta-height: " .. height)
|
|
||||||
if height <= 10 then
|
|
||||||
height = init_height
|
|
||||||
meta:set_int("height", init_height)
|
|
||||||
end
|
|
||||||
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; height: " .. height)
|
|
||||||
|
|
||||||
-- Bonemeal: Grows the bamboo by 1-2 stems. (per the minecraft wiki.)
|
|
||||||
if bonemeal_applied then
|
|
||||||
-- handle applying bonemeal.
|
|
||||||
for py = 1, BAM_MAX_HEIGHT_TOP do
|
|
||||||
-- find the top node of bamboo.
|
|
||||||
chk_pos = vector.offset(pos, 0, py, 0)
|
|
||||||
node_name = minetest.get_node(chk_pos).name
|
|
||||||
dist = vector.distance(soil_pos, chk_pos)
|
|
||||||
if mcl_bamboo.is_bamboo(node_name) == false or node_name == BAMBOO_ENDCAP_NAME then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; dist: " .. dist)
|
|
||||||
|
|
||||||
if node_name == BAMBOO_ENDCAP_NAME then
|
|
||||||
-- prevent overgrowth
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- check to see if we have a full stalk of bamboo.
|
|
||||||
if dist >= height - 1 then
|
|
||||||
if dist == height - 1 then
|
|
||||||
-- equals top of the stalk before the cap
|
|
||||||
if node_name == "air" then
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; Placing endcap")
|
|
||||||
minetest.set_node(vector.offset(chk_pos, 0, 1, 0), {name = BAMBOO_ENDCAP_NAME})
|
|
||||||
return true -- returning true means use up the bonemeal.
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- okay, we're higher than the end cap, fail out.
|
|
||||||
return false -- returning false means don't use up the bonemeal.
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- and now, the meat of the section... add bamboo to the stalk.
|
|
||||||
-- at this point, we should be lower than the generated maximum height. ~ about height -2 or lower.
|
|
||||||
if dist <= height - 2 then
|
|
||||||
if node_name == "air" then
|
|
||||||
-- here we can check to see if we can do up to 2 bamboo shoots onto the stalk
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; Placing bamboo.")
|
|
||||||
minetest.set_node(chk_pos, {name = node_below})
|
|
||||||
-- handle growing a second node.
|
|
||||||
if grow_amount == 2 then
|
|
||||||
chk_pos = vector.offset(chk_pos, 0, 1, 0)
|
|
||||||
if minetest.get_node(chk_pos).name == "air" then
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; OOOH! It's twofer day!")
|
|
||||||
minetest.set_node(chk_pos, {name = node_below})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true -- exit out with a success. We've added 1-2 nodes, per the wiki.
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Non-Bonemeal growth.
|
|
||||||
for py = 1, BAM_MAX_HEIGHT_TOP do
|
|
||||||
-- Find the topmost node above the stalk, and check it for "air"
|
|
||||||
chk_pos = vector.offset(pos, 0, py, 0)
|
|
||||||
node_below = minetest.get_node(pos).name
|
|
||||||
node_name = minetest.get_node(chk_pos).name
|
|
||||||
dist = vector.distance(soil_pos, chk_pos)
|
|
||||||
|
|
||||||
if node_name ~= "air" and mcl_bamboo.is_bamboo(node_name) == false then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
-- stop growing check. ie, handle endcap placement.
|
|
||||||
if dist >= height - 1 then
|
|
||||||
local above_node_name = minetest.get_node(vector.offset(chk_pos, 0, 1, 0)).name
|
|
||||||
if node_name == "air" and above_node_name == "air" then
|
|
||||||
if height - 1 == dist then
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; Placing endcap")
|
|
||||||
minetest.set_node(chk_pos, {name = BAMBOO_ENDCAP_NAME})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
-- handle regular node placement.
|
|
||||||
-- find the air node above the top shoot. place a node. And then, if short enough,
|
|
||||||
-- check for second node placement.
|
|
||||||
if node_name == "air" then
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; dist: " .. dist)
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; Placing bamboo.")
|
|
||||||
minetest.set_node(chk_pos, {name = node_below})
|
|
||||||
-- handle growing a second node. (1 in 32 chance.)
|
|
||||||
if grow_amount == 2 and dist <= height - 2 then
|
|
||||||
chk_pos = vector.offset(chk_pos, 0, 1, 0)
|
|
||||||
if minetest.get_node(chk_pos).name == "air" then
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; OOOH! It's twofer day!")
|
|
||||||
minetest.set_node(chk_pos, {name = node_below})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add Groups function, courtesy of Warr1024.
|
|
||||||
function mcl_bamboo.add_groups(name, ...)
|
|
||||||
local def = minetest.registered_items[name] or error(name .. " not found")
|
|
||||||
local groups = {}
|
|
||||||
for k, v in pairs(def.groups) do
|
|
||||||
groups[k] = v
|
|
||||||
end
|
|
||||||
local function add_all(x, ...)
|
|
||||||
if not x then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
groups[x] = 1
|
|
||||||
return add_all(...)
|
|
||||||
end
|
|
||||||
addall(...)
|
|
||||||
return minetest.override_item(name, {groups = groups})
|
|
||||||
end
|
|
||||||
|
|
||||||
function mcl_bamboo.mcl_log(m, l)
|
|
||||||
if not m then
|
|
||||||
minetest.log("error", "expected string, received: " .. m)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if DEBUG then
|
|
||||||
if not l then
|
|
||||||
minetest.log("[mcl_bamboo]: " .. m)
|
|
||||||
else
|
|
||||||
minetest.log(l, "[mcl_bamboo]: " .. m)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,73 +1,841 @@
|
||||||
-- [bamboo] mod by SmallJoker, Made for MineClone 2 by Michieal (as mcl_bamboo).
|
-- [bamboo] mod by Krock, modified by SmallJoker, Made for MineClone 2 by Michieal (as mcl_bamboo).
|
||||||
-- Parts of mcl_scaffolding were used. Mcl_scaffolding originally created by Cora; Fixed and heavily reworked
|
-- Parts of mcl_scaffolding were used. Mcl_scaffolding originally created by Cora; modified for mcl_bamboo by Michieal.
|
||||||
-- for mcl_bamboo by Michieal.
|
|
||||||
-- Creation date: 12-01-2022 (Dec 1st, 2022)
|
-- Creation date: 12-01-2022 (Dec 1st, 2022)
|
||||||
-- License for Media: CC-BY-SA 4.0 (except where noted); Code: GPLv3
|
-- License for everything: GPL3
|
||||||
-- Copyright (C) 2022 - 2023, Michieal. See License.txt
|
-- Bamboo max height: 12-16
|
||||||
|
|
||||||
-- LOCALS
|
-- LOCALS
|
||||||
local modname = minetest.get_current_modname()
|
local modname = minetest.get_current_modname()
|
||||||
-- Used everywhere. Often this is just the name, but it makes sense to me as BAMBOO, because that's how I think of it...
|
local S = minetest.get_translator(modname)
|
||||||
-- "BAMBOO" goes here.
|
local bamboo = "mcl_bamboo:bamboo"
|
||||||
local BAMBOO = "mcl_bamboo:bamboo"
|
local adj_nodes = {
|
||||||
|
vector.new(0, 0, 1),
|
||||||
|
vector.new(0, 0, -1),
|
||||||
|
vector.new(1, 0, 0),
|
||||||
|
vector.new(-1, 0, 0),
|
||||||
|
}
|
||||||
|
local node_sound = mcl_sounds.node_sound_wood_defaults()
|
||||||
|
|
||||||
mcl_bamboo = {}
|
-- CONSTS
|
||||||
|
local SIDE_SCAFFOLDING = false
|
||||||
|
local MAKE_STAIRS = true
|
||||||
|
local DEBUG = false
|
||||||
|
local USE_END_CAPS = false
|
||||||
|
|
||||||
-- BAMBOO GLOBALS
|
-- Due to door fix #2736, doors are displayed backwards. When this is fixed, set this variable to false.
|
||||||
dofile(minetest.get_modpath(modname) .. "/globals.lua")
|
local BROKEN_DOORS = true
|
||||||
-- BAMBOO Base Nodes
|
|
||||||
dofile(minetest.get_modpath(modname) .. "/bamboo_base.lua")
|
|
||||||
-- BAMBOO ITEMS
|
|
||||||
dofile(minetest.get_modpath(modname) .. "/bamboo_items.lua")
|
|
||||||
-- BAMBOO RECIPES
|
|
||||||
dofile(minetest.get_modpath(modname) .. "/recipes.lua")
|
|
||||||
|
|
||||||
-- ------------------------------------------------------------
|
-- LOCAL FUNCTIONS
|
||||||
|
|
||||||
|
-- Add Groups function, courtesy of Warr1024.
|
||||||
|
function addgroups(name, ...)
|
||||||
|
local def = minetest.registered_items[name] or error(name .. " not found")
|
||||||
|
local groups = {}
|
||||||
|
for k, v in pairs(def.groups) do
|
||||||
|
groups[k] = v
|
||||||
|
end
|
||||||
|
local function addall(x, ...)
|
||||||
|
if not x then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
groups[x] = 1
|
||||||
|
return addall(...)
|
||||||
|
end
|
||||||
|
addall(...)
|
||||||
|
return minetest.override_item(name, {groups = groups})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function create_nodes()
|
||||||
|
|
||||||
|
local bamboo_def = {
|
||||||
|
description = "Bamboo",
|
||||||
|
tiles = {"mcl_bamboo_bamboo_bottom.png", "mcl_bamboo_bamboo_bottom.png", "mcl_bamboo_bamboo.png"},
|
||||||
|
drawtype = "nodebox",
|
||||||
|
paramtype = "light",
|
||||||
|
groups = {handy = 1, axey = 1, choppy = 1, flammable = 3},
|
||||||
|
sounds = node_sound,
|
||||||
|
drops = "mcl_bamboo:bamboo",
|
||||||
|
inventory_image = "mcl_bamboo_bamboo_shoot.png",
|
||||||
|
wield_image = "mcl_bamboo_bamboo_shoot.png",
|
||||||
|
_mcl_blast_resistance = 1,
|
||||||
|
_mcl_hardness = 2,
|
||||||
|
node_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = {
|
||||||
|
-- {0.1875, -0.5, -0.125, 0.4125, 0.5, 0.0625},
|
||||||
|
-- {-0.125, -0.5, 0.125, -0.3125, 0.5, 0.3125},
|
||||||
|
-- {-0.25, -0.5, -0.3125, 0, 0.5, -0.125},
|
||||||
|
{-0.175, -0.5, -0.195, 0.05, 0.5, 0.030},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Node Box definitions for alternative styles.
|
||||||
|
{-0.05, -0.5, 0.285, -0.275, 0.5, 0.06},
|
||||||
|
{0.25, -0.5, 0.325, 0.025, 0.5, 0.100},
|
||||||
|
{-0.125, -0.5, 0.125, -0.3125, 0.5, 0.3125},
|
||||||
|
--]]
|
||||||
|
|
||||||
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
|
if pointed_thing.type ~= "node" then
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
local node = minetest.get_node(pointed_thing.under)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
if DEBUG then
|
||||||
|
minetest.log("mcl_bamboo::Node placement data:")
|
||||||
|
minetest.log(dump(pointed_thing))
|
||||||
|
minetest.log(dump(node))
|
||||||
|
end
|
||||||
|
|
||||||
|
if DEBUG then
|
||||||
|
minetest.log("mcl_bamboo::Checking for protected placement of bamboo.")
|
||||||
|
end
|
||||||
|
local pname = placer:get_player_name()
|
||||||
|
if minetest.is_protected(pos, pname) then
|
||||||
|
minetest.record_protection_violation(pos, pname)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if DEBUG then
|
||||||
|
minetest.log("mcl_bamboo::placement of bamboo is not protected.")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Use pointed node's on_rightclick function first, if present
|
||||||
|
if placer and not placer:get_player_control().sneak then
|
||||||
|
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||||
|
if DEBUG then
|
||||||
|
minetest.log("mcl_bamboo::attempting placement of bamboo via targeted node's on_rightclick.")
|
||||||
|
end
|
||||||
|
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if node.name ~= "mcl_bamboo:bamboo" then
|
||||||
|
if node.name ~= "mcl_flowerpots:flower_pot" then
|
||||||
|
if minetest.get_item_group(node.name, "dirt") == 0 then
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if DEBUG then
|
||||||
|
minetest.log("mcl_bamboo::placing bamboo directly.")
|
||||||
|
end
|
||||||
|
return minetest.item_place(itemstack, placer, pointed_thing, minetest.dir_to_facedir(vector.direction(pointed_thing.above, pointed_thing.under)))
|
||||||
|
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_destruct = function(pos)
|
||||||
|
-- Node destructor; called before removing node.
|
||||||
|
local new_pos = vector.offset(pos, 0, 1, 0)
|
||||||
|
local node_above = minetest.get_node(new_pos)
|
||||||
|
if node_above and node_above.name == "mcl_bamboo:bamboo" then
|
||||||
|
local sound_params = {
|
||||||
|
pos = new_pos,
|
||||||
|
gain = 1.0, -- default
|
||||||
|
max_hear_distance = 10, -- default, uses a Euclidean metric
|
||||||
|
}
|
||||||
|
|
||||||
|
minetest.remove_node(new_pos)
|
||||||
|
minetest.sound_play(node_sound.dug, sound_params, true)
|
||||||
|
local istack = ItemStack("mcl_bamboo:bamboo")
|
||||||
|
minetest.add_item(new_pos, istack)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
minetest.register_node("mcl_bamboo:bamboo", bamboo_def)
|
||||||
|
local bamboo_top = table.copy(bamboo_def)
|
||||||
|
bamboo_top.groups = {not_in_creative_inventory = 1, handy = 1, axey = 1, choppy = 1, flammable = 3}
|
||||||
|
|
||||||
|
bamboo_top.on_place = function(itemstack, placer, pointed_thing)
|
||||||
|
if pointed_thing.type ~= "node" then
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
local node = minetest.get_node(pointed_thing.under)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
if DEBUG then
|
||||||
|
minetest.log("mcl_bamboo::Node placement data:")
|
||||||
|
minetest.log(dump(pointed_thing))
|
||||||
|
minetest.log(dump(node))
|
||||||
|
end
|
||||||
|
|
||||||
|
if DEBUG then
|
||||||
|
minetest.log("mcl_bamboo::Checking for protected placement of bamboo.")
|
||||||
|
end
|
||||||
|
local pname = placer:get_player_name()
|
||||||
|
if pname then
|
||||||
|
if minetest.is_protected(pos, pname) then
|
||||||
|
minetest.record_protection_violation(pos, pname)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
--not for player use.
|
||||||
|
if minetest.is_creative_enabled(pname) == false then
|
||||||
|
itemstack:set_count(0)
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if DEBUG then
|
||||||
|
minetest.log("mcl_bamboo::placement of bamboo is not protected.")
|
||||||
|
end
|
||||||
|
|
||||||
|
if node.name ~= "mcl_bamboo:bamboo" then
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
if DEBUG then
|
||||||
|
minetest.log("mcl_bamboo::placing bamboo directly.")
|
||||||
|
end
|
||||||
|
return minetest.item_place(itemstack, placer, pointed_thing, minetest.dir_to_facedir(vector.direction(pointed_thing.above, pointed_thing.under)))
|
||||||
|
end,
|
||||||
|
|
||||||
|
minetest.register_node("mcl_bamboo:bamboo_top", bamboo_top)
|
||||||
|
|
||||||
|
local bamboo_block_def = {
|
||||||
|
description = "Bamboo Block",
|
||||||
|
tiles = {"mcl_bamboo_bamboo_bottom.png", "mcl_bamboo_bamboo_bottom.png", "mcl_bamboo_bamboo_block.png"},
|
||||||
|
groups = {handy = 1, building_block = 1, axey = 1, flammable = 2, material_wood = 1, bamboo_block = 1, fire_encouragement = 5, fire_flammability = 5},
|
||||||
|
sounds = node_sound,
|
||||||
|
paramtype2 = "facedir",
|
||||||
|
drops = "mcl_bamboo:bamboo_block",
|
||||||
|
_mcl_blast_resistance = 3,
|
||||||
|
_mcl_hardness = 2,
|
||||||
|
_mcl_stripped_variant = "mcl_bamboo:bamboo_block_stripped", -- this allows us to use the built in Axe's strip block.
|
||||||
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
|
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
|
||||||
|
local pname = placer:get_player_name()
|
||||||
|
if minetest.is_protected(pos, pname) then
|
||||||
|
minetest.record_protection_violation(pos, pname)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Use pointed node's on_rightclick function first, if present
|
||||||
|
local node = minetest.get_node(pointed_thing.under)
|
||||||
|
if placer and not placer:get_player_control().sneak then
|
||||||
|
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||||
|
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return minetest.item_place(itemstack, placer, pointed_thing, minetest.dir_to_facedir(vector.direction(pointed_thing.above, pointed_thing.under)))
|
||||||
|
end,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
-- basic bamboo nodes.
|
||||||
|
minetest.register_node("mcl_bamboo:bamboo_block", bamboo_block_def)
|
||||||
|
local bamboo_stripped_block = table.copy(bamboo_block_def)
|
||||||
|
bamboo_stripped_block.on_rightclick = nil
|
||||||
|
bamboo_stripped_block.description = S("Stripped Bamboo Block")
|
||||||
|
bamboo_stripped_block.tiles = {"mcl_bamboo_bamboo_bottom.png", "mcl_bamboo_bamboo_bottom.png", "mcl_bamboo_bamboo_block_stripped.png"}
|
||||||
|
minetest.register_node("mcl_bamboo:bamboo_block_stripped", bamboo_stripped_block)
|
||||||
|
minetest.register_node("mcl_bamboo:bamboo_plank", {
|
||||||
|
description = S("Bamboo Plank"),
|
||||||
|
_doc_items_longdesc = S("Bamboo Plank"),
|
||||||
|
_doc_items_hidden = false,
|
||||||
|
tiles = {"mcl_bamboo_bamboo_plank.png"},
|
||||||
|
stack_max = 64,
|
||||||
|
is_ground_content = false,
|
||||||
|
groups = {handy = 1, axey = 1, flammable = 3, wood = 1, building_block = 1, material_wood = 1, fire_encouragement = 5, fire_flammability = 20},
|
||||||
|
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||||
|
_mcl_blast_resistance = 3,
|
||||||
|
_mcl_hardness = 2,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- specific bamboo nodes...
|
||||||
|
if minetest.get_modpath("mcl_flowerpots") then
|
||||||
|
if DEBUG then
|
||||||
|
minetest.log("mcl_bamboo::FlowerPot Section Entrance. Modpath exists.")
|
||||||
|
end
|
||||||
|
if mcl_flowerpots ~= nil then
|
||||||
|
-- Flower-potted Bamboo...
|
||||||
|
local flwr_name = "mcl_bamboo:bamboo"
|
||||||
|
local flwr_def = {name = "bamboo_plant",
|
||||||
|
desc = S("Bamboo"),
|
||||||
|
image = "mcl_bamboo_bamboo_fpm.png", -- use with "register_potted_cube"
|
||||||
|
-- "mcl_bamboo_flower_pot.png", -- use with "register_potted_flower"
|
||||||
|
}
|
||||||
|
|
||||||
|
mcl_flowerpots.register_potted_cube(flwr_name, flwr_def)
|
||||||
|
-- mcl_flowerpots.register_potted_flower(flwr_name, flwr_def)
|
||||||
|
minetest.register_alias("bamboo_flower_pot", "mcl_flowerpots:flower_pot_bamboo_plant")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if minetest.get_modpath("mcl_doors") then
|
||||||
|
if mcl_doors then
|
||||||
|
local top_door_tiles = {}
|
||||||
|
local bot_door_tiles = {}
|
||||||
|
|
||||||
|
if BROKEN_DOORS then
|
||||||
|
top_door_tiles = {"mcl_bamboo_door_top_alt.png", "mcl_bamboo_door_top.png"}
|
||||||
|
bot_door_tiles = {"mcl_bamboo_door_bottom_alt.png", "mcl_bamboo_door_bottom.png"}
|
||||||
|
else
|
||||||
|
top_door_tiles = {"mcl_bamboo_door_top.png", "mcl_bamboo_door_top.png"}
|
||||||
|
bot_door_tiles = {"mcl_bamboo_door_bottom.png", "mcl_bamboo_door_bottom.png"}
|
||||||
|
end
|
||||||
|
|
||||||
|
local name = "mcl_bamboo:bamboo_door"
|
||||||
|
local def = {
|
||||||
|
description = S("Bamboo Door."),
|
||||||
|
inventory_image = "mcl_bamboo_door_wield.png",
|
||||||
|
wield_image = "mcl_bamboo_door_wield.png",
|
||||||
|
groups = {handy = 1, axey = 1, material_wood = 1, flammable = -1},
|
||||||
|
_mcl_hardness = 3,
|
||||||
|
_mcl_blast_resistance = 3,
|
||||||
|
tiles_bottom = bot_door_tiles,
|
||||||
|
tiles_top = top_door_tiles,
|
||||||
|
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||||
|
}
|
||||||
|
|
||||||
|
--[[ Registers a door
|
||||||
|
-- name: The name of the door
|
||||||
|
-- def: a table with the folowing fields:
|
||||||
|
-- description
|
||||||
|
-- inventory_image
|
||||||
|
-- groups
|
||||||
|
-- tiles_bottom: the tiles of the bottom part of the door {front, side}
|
||||||
|
-- tiles_top: the tiles of the bottom part of the door {front, side}
|
||||||
|
-- If the following fields are not defined the default values are used
|
||||||
|
-- node_box_bottom
|
||||||
|
-- node_box_top
|
||||||
|
-- selection_box_bottom
|
||||||
|
-- selection_box_top
|
||||||
|
-- only_placer_can_open: if true only the player who placed the door can
|
||||||
|
-- open it
|
||||||
|
-- only_redstone_can_open: if true, the door can only be opened by redstone,
|
||||||
|
-- not by rightclicking it
|
||||||
|
--]]
|
||||||
|
|
||||||
|
mcl_doors:register_door(name, def)
|
||||||
|
|
||||||
|
name = "mcl_bamboo:bamboo_trapdoor"
|
||||||
|
local trap_def = {
|
||||||
|
description = S("Bamboo Trapdoor."),
|
||||||
|
inventory_image = "mcl_bamboo_door_complete.png",
|
||||||
|
groups = {},
|
||||||
|
tile_front = "mcl_bamboo_trapdoor_top.png",
|
||||||
|
tile_side = "mcl_bamboo_trapdoor_side.png",
|
||||||
|
_doc_items_longdesc = S("Wooden trapdoors are horizontal barriers which can be opened and closed by hand or a redstone signal. They occupy the upper or lower part of a block, depending on how they have been placed. When open, they can be climbed like a ladder."),
|
||||||
|
_doc_items_usagehelp = S("To open or close the trapdoor, rightclick it or send a redstone signal to it."),
|
||||||
|
wield_image = "mcl_bamboo_trapdoor_wield.png",
|
||||||
|
inventory_image = "mcl_bamboo_trapdoor_wield.png",
|
||||||
|
groups = {handy = 1, axey = 1, mesecon_effector_on = 1, material_wood = 1, flammable = -1},
|
||||||
|
_mcl_hardness = 3,
|
||||||
|
_mcl_blast_resistance = 3,
|
||||||
|
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||||
|
}
|
||||||
|
|
||||||
|
mcl_doors:register_trapdoor(name, trap_def)
|
||||||
|
|
||||||
|
minetest.register_alias("bamboo_door", "mcl_bamboo:bamboo_door")
|
||||||
|
minetest.register_alias("bamboo_trapdoor", "mcl_bamboo:bamboo_trapdoor")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if MAKE_STAIRS then
|
||||||
|
if minetest.get_modpath("mcl_stairs") then
|
||||||
|
if mcl_stairs ~= nil then
|
||||||
|
mcl_stairs.register_stair_and_slab_simple(
|
||||||
|
"bamboo_block",
|
||||||
|
"mcl_bamboo:bamboo_block",
|
||||||
|
S("Bamboo Stair"),
|
||||||
|
S("Bamboo Slab"),
|
||||||
|
S("Double Bamboo Slab")
|
||||||
|
)
|
||||||
|
mcl_stairs.register_stair_and_slab_simple(
|
||||||
|
"bamboo_stripped",
|
||||||
|
"mcl_bamboo:bamboo_block_stripped",
|
||||||
|
S("Stripped Bamboo Stair"),
|
||||||
|
S("Stripped Bamboo Slab"),
|
||||||
|
S("Double Stripped Bamboo Slab")
|
||||||
|
)
|
||||||
|
mcl_stairs.register_stair_and_slab_simple(
|
||||||
|
"bamboo_plank",
|
||||||
|
"mcl_bamboo:bamboo_plank",
|
||||||
|
S("Bamboo Plank Stair"),
|
||||||
|
S("Bamboo Plank Slab"),
|
||||||
|
S("Double Bamboo Plank Slab")
|
||||||
|
)
|
||||||
|
|
||||||
|
-- let's add plank slabs to the wood_slab group.
|
||||||
|
local bamboo_plank_slab = "mcl_stairs:slab_bamboo_plank"
|
||||||
|
local node_groups = {
|
||||||
|
wood_slab = 1,
|
||||||
|
building_block = 1,
|
||||||
|
slab = 1,
|
||||||
|
axey = 1,
|
||||||
|
handy = 1,
|
||||||
|
stair = 1,
|
||||||
|
flammable = 1,
|
||||||
|
fire_encouragement = 5,
|
||||||
|
fire_flammability = 20
|
||||||
|
}
|
||||||
|
|
||||||
|
minetest.override_item(bamboo_plank_slab, {groups = node_groups})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if minetest.get_modpath("mesecons_pressureplates") then
|
||||||
|
|
||||||
|
if mesecon ~= nil and mesecon.register_pressure_plate ~= nil then
|
||||||
|
-- make sure that pressure plates are installed.
|
||||||
|
|
||||||
|
-- Bamboo Pressure Plate...
|
||||||
|
|
||||||
|
-- Register a Pressure Plate (api command doc.)
|
||||||
|
-- basename: base name of the pressure plate
|
||||||
|
-- description: description displayed in the player's inventory
|
||||||
|
-- textures_off:textures of the pressure plate when inactive
|
||||||
|
-- textures_on: textures of the pressure plate when active
|
||||||
|
-- image_w: wield image of the pressure plate
|
||||||
|
-- image_i: inventory image of the pressure plate
|
||||||
|
-- recipe: crafting recipe of the pressure plate
|
||||||
|
-- sounds: sound table (like in minetest.register_node)
|
||||||
|
-- plusgroups: group memberships (attached_node=1 and not_in_creative_inventory=1 are already used)
|
||||||
|
-- activated_by: optimal table with elements denoting by which entities this pressure plate is triggered
|
||||||
|
-- Possible table fields:
|
||||||
|
-- * player=true: Player
|
||||||
|
-- * mob=true: Mob
|
||||||
|
-- By default, is triggered by all entities
|
||||||
|
-- longdesc: Customized long description for the in-game help (if omitted, a dummy text is used)
|
||||||
|
|
||||||
|
mesecon.register_pressure_plate(
|
||||||
|
"mcl_bamboo:pressure_plate_bamboo_wood",
|
||||||
|
S("Bamboo Pressure Plate"),
|
||||||
|
{"mcl_bamboo_bamboo_plank.png"},
|
||||||
|
{"mcl_bamboo_bamboo_plank.png"},
|
||||||
|
"mcl_bamboo_bamboo_plank.png",
|
||||||
|
nil,
|
||||||
|
{{"mcl_bamboo:bamboo_plank", "mcl_bamboo:bamboo_plank"}},
|
||||||
|
mcl_sounds.node_sound_wood_defaults(),
|
||||||
|
{axey = 1, material_wood = 1},
|
||||||
|
nil,
|
||||||
|
S("A wooden pressure plate is a redstone component which supplies its surrounding blocks with redstone power while any movable object (including dropped items, players and mobs) rests on top of it."))
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "fuel",
|
||||||
|
recipe = "mcl_bamboo:pressure_plate_bamboo_wood_off",
|
||||||
|
burntime = 15
|
||||||
|
})
|
||||||
|
minetest.register_alias("bamboo_pressure_plate", "mcl_bamboo:pressure_plate_bamboo_wood")
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if minetest.get_modpath("mcl_signs") then
|
||||||
|
if DEBUG then
|
||||||
|
minetest.log("mcl_bamboo::Signs Section Entrance. Modpath exists.")
|
||||||
|
end
|
||||||
|
if mcl_signs ~= nil then
|
||||||
|
-- Bamboo Signs...
|
||||||
|
mcl_signs.register_sign_custom("mcl_bamboo", "_bamboo", "mcl_signs_sign_greyscale.png",
|
||||||
|
"#f6dc91", "default_sign_greyscale.png", "default_sign_greyscale.png",
|
||||||
|
"Bamboo Sign")
|
||||||
|
mcl_signs.register_sign_craft("mcl_bamboo", "mcl_bamboo:bamboo_plank", "_bamboo")
|
||||||
|
minetest.register_alias("bamboo_sign", "mcl_signs:wall_sign_bamboo")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if minetest.get_modpath("mcl_fences") then
|
||||||
|
if DEBUG then
|
||||||
|
minetest.log("mcl_bamboo::Fences Section Entrance. Modpath exists.")
|
||||||
|
end
|
||||||
|
local id = "bamboo_fence"
|
||||||
|
local id_gate = "bamboo_fence_gate"
|
||||||
|
local wood_groups = {handy = 1, axey = 1, flammable = 2, fence_wood = 1, fire_encouragement = 5, fire_flammability = 20}
|
||||||
|
local wood_connect = {"group:fence_wood"}
|
||||||
|
|
||||||
|
local fence_id = mcl_fences.register_fence(id, S("Bamboo Fence"), "mcl_bamboo_fence_bamboo.png", wood_groups,
|
||||||
|
2, 15, wood_connect, node_sound)
|
||||||
|
local gate_id = mcl_fences.register_fence_gate(id, S("Bamboo Fence Gate"), "mcl_bamboo_fence_gate_bamboo.png",
|
||||||
|
wood_groups, 2, 15, node_sound) -- note: about missing params.. will use defaults.
|
||||||
|
|
||||||
|
if DEBUG then
|
||||||
|
minetest.log(dump(fence_id))
|
||||||
|
minetest.log(dump(gate_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
local craft_wood = "mcl_bamboo:bamboo_plank"
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_bamboo:" .. id .. " 3",
|
||||||
|
recipe = {
|
||||||
|
{craft_wood, "mcl_core:stick", craft_wood},
|
||||||
|
{craft_wood, "mcl_core:stick", craft_wood},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_bamboo:" .. id_gate,
|
||||||
|
recipe = {
|
||||||
|
{"mcl_core:stick", craft_wood, "mcl_core:stick"},
|
||||||
|
{"mcl_core:stick", craft_wood, "mcl_core:stick"},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
-- mcl_fences.register_fence("nether_brick_fence", S("Nether Brick Fence"), "mcl_fences_fence_nether_brick.png", {pickaxey=1, deco_block=1, fence_nether_brick=1}, 2, 30, {"group:fence_nether_brick"}, mcl_sounds.node_sound_stone_defaults())
|
||||||
|
minetest.register_alias("bamboo_fence", "mcl_fences:" .. id)
|
||||||
|
minetest.register_alias("bamboo_fence_gate", "mcl_fences:" .. id_gate)
|
||||||
|
end
|
||||||
|
|
||||||
|
if minetest.get_modpath("mesecons_button") then
|
||||||
|
if mesecon ~= nil then
|
||||||
|
mesecon.register_button(
|
||||||
|
"bamboo",
|
||||||
|
S("Bamboo Button"),
|
||||||
|
"mcl_bamboo_bamboo_plank.png",
|
||||||
|
"mcl_bamboo:bamboo_plank",
|
||||||
|
node_sound,
|
||||||
|
{material_wood = 1, handy = 1, pickaxey = 1, flammable = 3, fire_flammability = 20, fire_encouragement = 5, },
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
S("A bamboo button is a redstone component made out of stone which can be pushed to provide redstone power. When pushed, it powers adjacent redstone components for 1 second."),
|
||||||
|
"mesecons_button_push")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_node("mcl_bamboo:scaffolding", {
|
||||||
|
description = S("Scaffolding"),
|
||||||
|
doc_items_longdesc = S("Scaffolding block used to climb up or out across areas."),
|
||||||
|
doc_items_hidden = false,
|
||||||
|
tiles = {"mcl_bamboo_scaffolding_top.png", "mcl_bamboo_scaffolding_top.png", "mcl_bamboo_scaffolding_bottom.png"},
|
||||||
|
drawtype = "nodebox",
|
||||||
|
paramtype = "light",
|
||||||
|
use_texture_alpha = "clip",
|
||||||
|
node_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = {
|
||||||
|
{-0.5, 0.375, -0.5, 0.5, 0.5, 0.5},
|
||||||
|
{-0.5, -0.5, -0.5, -0.375, 0.5, -0.375},
|
||||||
|
{0.375, -0.5, -0.5, 0.5, 0.5, -0.375},
|
||||||
|
{0.375, -0.5, 0.375, 0.5, 0.5, 0.5},
|
||||||
|
{-0.5, -0.5, 0.375, -0.375, 0.5, 0.5},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selection_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = {
|
||||||
|
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
buildable_to = false,
|
||||||
|
is_ground_content = false,
|
||||||
|
walkable = false,
|
||||||
|
climbable = true,
|
||||||
|
physical = true,
|
||||||
|
node_placement_prediction = "",
|
||||||
|
groups = {handy = 1, axey = 1, flammable = 3, building_block = 1, material_wood = 1, fire_encouragement = 5, fire_flammability = 20, falling_node = 1, stack_falling = 1},
|
||||||
|
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||||
|
_mcl_blast_resistance = 0,
|
||||||
|
_mcl_hardness = 0,
|
||||||
|
on_place = function(itemstack, placer, ptd)
|
||||||
|
if SIDE_SCAFFOLDING then
|
||||||
|
-- count param2 up when placing to the sides. Fall when > 6
|
||||||
|
local ctrl = placer:get_player_control()
|
||||||
|
if ctrl and ctrl.sneak then
|
||||||
|
local pp2 = minetest.get_node(ptd.under).param2
|
||||||
|
local np2 = pp2 + 1
|
||||||
|
if minetest.get_node(vector.offset(ptd.above, 0, -1, 0)).name == "air" then
|
||||||
|
minetest.set_node(ptd.above, {name = "mcl_bamboo:scaffolding_horizontal", param2 = np2})
|
||||||
|
itemstack:take_item(1)
|
||||||
|
end
|
||||||
|
if np2 > 6 then
|
||||||
|
minetest.check_single_for_falling(ptd.above)
|
||||||
|
end
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--place on solid nodes
|
||||||
|
local node = minetest.get_node(ptd.under)
|
||||||
|
if itemstack:get_name() ~= node.name then
|
||||||
|
minetest.set_node(ptd.above, {name = "mcl_bamboo:scaffolding", param2 = 0})
|
||||||
|
itemstack:take_item(1)
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
--build up when placing on existing scaffold
|
||||||
|
local h = 0
|
||||||
|
local pos = ptd.under
|
||||||
|
repeat
|
||||||
|
pos.y = pos.y + 1
|
||||||
|
h = h + 1
|
||||||
|
local cn = minetest.get_node(pos)
|
||||||
|
if cn.name == "air" then
|
||||||
|
minetest.set_node(pos, node)
|
||||||
|
itemstack:take_item(1)
|
||||||
|
placer:set_wielded_item(itemstack)
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
until cn.name ~= node.name or h >= 32
|
||||||
|
end,
|
||||||
|
on_destruct = function(pos)
|
||||||
|
-- Node destructor; called before removing node.
|
||||||
|
local new_pos = vector.offset(pos, 0, 1, 0)
|
||||||
|
local node_above = minetest.get_node(new_pos)
|
||||||
|
if node_above and node_above.name == "mcl_bamboo:scaffolding" then
|
||||||
|
local sound_params = {
|
||||||
|
pos = new_pos,
|
||||||
|
gain = 1.0, -- default
|
||||||
|
max_hear_distance = 10, -- default, uses a Euclidean metric
|
||||||
|
}
|
||||||
|
|
||||||
|
minetest.remove_node(new_pos)
|
||||||
|
minetest.sound_play(node_sound.dug, sound_params, true)
|
||||||
|
local istack = ItemStack("mcl_bamboo:scaffolding")
|
||||||
|
minetest.add_item(new_pos, istack)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
if SIDE_SCAFFOLDING then
|
||||||
|
--currently, disabled.
|
||||||
|
minetest.register_node("mcl_bamboo:scaffolding_horizontal", {
|
||||||
|
description = S("Scaffolding (horizontal)"),
|
||||||
|
doc_items_longdesc = S("Scaffolding block used to climb up or out across areas."),
|
||||||
|
doc_items_hidden = false,
|
||||||
|
tiles = {"mcl_bamboo_scaffolding_top.png", "mcl_bamboo_scaffolding_top.png", "mcl_bamboo_scaffolding_bottom.png"},
|
||||||
|
drawtype = "nodebox",
|
||||||
|
paramtype = "light",
|
||||||
|
use_texture_alpha = "clip",
|
||||||
|
node_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = {
|
||||||
|
{-0.5, 0.375, -0.5, 0.5, 0.5, 0.5},
|
||||||
|
{-0.5, -0.5, -0.5, -0.375, 0.5, -0.375},
|
||||||
|
{0.375, -0.5, -0.5, 0.5, 0.5, -0.375},
|
||||||
|
{0.375, -0.5, 0.375, 0.5, 0.5, 0.5},
|
||||||
|
{-0.5, -0.5, 0.375, -0.375, 0.5, 0.5},
|
||||||
|
{-0.5, -0.5, -0.5, 0.5, -0.375, 0.5},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selection_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = {
|
||||||
|
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
groups = {handy = 1, axey = 1, flammable = 3, building_block = 1, material_wood = 1, fire_encouragement = 5, fire_flammability = 20, not_in_creative_inventory = 1, falling_node = 1},
|
||||||
|
_mcl_after_falling = function(pos)
|
||||||
|
if minetest.get_node(pos).name == "mcl_bamboo:scaffolding_horizontal" then
|
||||||
|
if minetest.get_node(vector.offset(pos, 0, 0, 0)).name ~= "mcl_bamboo:scaffolding" then
|
||||||
|
minetest.remove_node(pos)
|
||||||
|
minetest.add_item(pos, "mcl_bamboo:scaffolding")
|
||||||
|
else
|
||||||
|
minetest.set_node(vector.offset(pos, 0, 1, 0), {name = "mcl_bamboo:scaffolding"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function register_craftings()
|
||||||
|
-- Craftings
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = bamboo .. "_block",
|
||||||
|
recipe = {
|
||||||
|
{bamboo, bamboo, bamboo},
|
||||||
|
{bamboo, bamboo, bamboo},
|
||||||
|
{bamboo, bamboo, bamboo},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = bamboo .. "_plank 2",
|
||||||
|
recipe = {
|
||||||
|
{bamboo .. "_block"},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = bamboo .. "_plank 2",
|
||||||
|
recipe = {
|
||||||
|
{bamboo .. "_block_stripped"},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_core:stick",
|
||||||
|
recipe = {
|
||||||
|
{bamboo},
|
||||||
|
{bamboo},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_bamboo:scaffolding 6",
|
||||||
|
recipe = {{bamboo, "mcl_mobitems:string", bamboo},
|
||||||
|
{bamboo, "", bamboo},
|
||||||
|
{bamboo, "", bamboo}}
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_bamboo:bamboo_door 3",
|
||||||
|
recipe = {
|
||||||
|
{bamboo .. "_plank", bamboo .. "_plank"},
|
||||||
|
{bamboo .. "_plank", bamboo .. "_plank"},
|
||||||
|
{bamboo .. "_plank", bamboo .. "_plank"}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_bamboo:bamboo_trapdoor 2",
|
||||||
|
recipe = {
|
||||||
|
{bamboo .. "_plank", bamboo .. "_plank", bamboo .. "_plank"},
|
||||||
|
{bamboo .. "_plank", bamboo .. "_plank", bamboo .. "_plank"},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Fuels
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "fuel",
|
||||||
|
recipe = "mcl_bamboo:bamboo_door",
|
||||||
|
burntime = 10,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "fuel",
|
||||||
|
recipe = "mcl_bamboo:bamboo_trapdoor",
|
||||||
|
burntime = 15,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "fuel",
|
||||||
|
recipe = bamboo,
|
||||||
|
burntime = 2.5, -- supposed to be 1/2 that of a stick, per minecraft wiki as of JE 1.19.3
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "fuel",
|
||||||
|
recipe = bamboo .. "_block",
|
||||||
|
burntime = 15,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "fuel",
|
||||||
|
recipe = bamboo .. "_block_stripped",
|
||||||
|
burntime = 15,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "fuel",
|
||||||
|
recipe = bamboo .. "_plank",
|
||||||
|
burntime = 7.5,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "fuel",
|
||||||
|
recipe = "mcl_bamboo:scaffolding",
|
||||||
|
burntime = 20
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "fuel",
|
||||||
|
recipe = "mcl_stairs:slab_bamboo_plank",
|
||||||
|
burntime = 7.5,
|
||||||
|
})
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "fuel",
|
||||||
|
recipe = "mcl_stairs:slab_bamboo_block",
|
||||||
|
burntime = 7.5,
|
||||||
|
})
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "fuel",
|
||||||
|
recipe = "mcl_stairs:slab_bamboo_stripped",
|
||||||
|
burntime = 7.5,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "fuel",
|
||||||
|
recipe = "mesecons_button:button_bamboo_off",
|
||||||
|
burntime = 5,
|
||||||
|
})
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
create_nodes()
|
||||||
|
register_craftings()
|
||||||
|
|
||||||
|
-- MAPGEN
|
||||||
|
dofile(minetest.get_modpath(modname) .. "/mapgen.lua")
|
||||||
|
|
||||||
|
local BAMBOO_MAX_HEIGHT_CHECK = -16
|
||||||
|
|
||||||
--ABMs
|
--ABMs
|
||||||
minetest.register_abm({
|
minetest.register_abm({
|
||||||
nodenames = mcl_bamboo.bamboo_index,
|
nodenames = {"mcl_bamboo:bamboo"},
|
||||||
interval = 10,
|
interval = 40,
|
||||||
chance = 20,
|
chance = 40,
|
||||||
action = function(pos, _)
|
action = function(pos, node)
|
||||||
mcl_bamboo.grow_bamboo(pos, false)
|
local soil_pos = nil
|
||||||
|
if minetest.get_node_light(pos) < 8 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local found_soil = false
|
||||||
|
for py = -1, BAMBOO_MAX_HEIGHT_CHECK, -1 do
|
||||||
|
local chk_pos = vector.offset(pos, 0, py, 0)
|
||||||
|
local name = minetest.get_node(chk_pos).name
|
||||||
|
if minetest.get_item_group(name, "soil") ~= 0 then
|
||||||
|
found_soil = true
|
||||||
|
soil_pos = chk_pos
|
||||||
|
break
|
||||||
|
elseif name ~= "mcl_bamboo:bamboo" then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not found_soil then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
for py = 1, 14 do
|
||||||
|
local npos = vector.offset(pos, 0, py, 0)
|
||||||
|
local name = minetest.get_node(npos).name
|
||||||
|
if vector.distance(soil_pos, npos) >= 15 then
|
||||||
|
-- stop growing check.
|
||||||
|
if USE_END_CAPS then
|
||||||
|
if name == "air" then
|
||||||
|
minetest.set_node(npos, {name = "mcl_bamboo:bamboo_top"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if name == "air" then
|
||||||
|
minetest.set_node(npos, {name = "mcl_bamboo:bamboo"})
|
||||||
|
break
|
||||||
|
elseif name ~= "mcl_bamboo:bamboo" then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- Base Aliases.
|
-- Base Aliases.
|
||||||
local SCAFFOLDING_NAME = "mcl_bamboo:scaffolding"
|
|
||||||
minetest.register_alias("bamboo_block", "mcl_bamboo:bamboo_block")
|
minetest.register_alias("bamboo_block", "mcl_bamboo:bamboo_block")
|
||||||
minetest.register_alias("bamboo_strippedblock", "mcl_bamboo:bamboo_block_stripped")
|
minetest.register_alias("bamboo_strippedblock", "mcl_bamboo:bamboo_block_stripped")
|
||||||
minetest.register_alias("bamboo", BAMBOO)
|
minetest.register_alias("bamboo", "mcl_bamboo:bamboo")
|
||||||
minetest.register_alias("bamboo_plank", "mcl_bamboo:bamboo_plank")
|
minetest.register_alias("bamboo_plank", "mcl_bamboo:bamboo_plank")
|
||||||
minetest.register_alias("bamboo_mosaic", "mcl_bamboo:bamboo_mosaic")
|
|
||||||
|
|
||||||
minetest.register_alias("mcl_stairs:stair_bamboo", "mcl_stairs:stair_bamboo_block")
|
minetest.register_alias("mcl_stairs:stair_bamboo", "mcl_stairs:stair_bamboo_block")
|
||||||
minetest.register_alias("bamboo_stairs", "mcl_stairs:stair_bamboo_block")
|
minetest.register_alias("bamboo:bamboo", "mcl_bamboo:bamboo")
|
||||||
minetest.register_alias("bamboo:bamboo", BAMBOO)
|
|
||||||
minetest.register_alias("scaffold", SCAFFOLDING_NAME)
|
|
||||||
minetest.register_alias("mcl_scaffolding:scaffolding", SCAFFOLDING_NAME)
|
|
||||||
minetest.register_alias("mcl_scaffolding:scaffolding_horizontal", SCAFFOLDING_NAME)
|
|
||||||
|
|
||||||
minetest.register_alias("bamboo_fence", "mcl_fences:bamboo_fence")
|
|
||||||
minetest.register_alias("bamboo_fence_gate", "mcl_fences:bamboo_fence_gate")
|
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
todo -- make scaffolds do side scaffold blocks, so that they jut out. (Shelved.)
|
todo -- make scaffolds do side scaffold blocks, so that they jut out.
|
||||||
todo -- Also, make those blocks collapse (break) when a nearby connected scaffold breaks.
|
todo -- Also, make those blocks collapse (break) when a nearby connected scaffold breaks.
|
||||||
|
todo -- add in alternative bamboo styles to simulate random placement. (see commented out nde box definitions.
|
||||||
|
todo -- make endcap node for bamboo, so that they can be 12-16 nodes high and stop growing.
|
||||||
|
todo -- mash all of that together so that it drops as one item, and chooses what version to be, in on_place.
|
||||||
|
todo -- Raft
|
||||||
|
todo -- Raft with Chest.
|
||||||
|
todo -- Add in Extras.
|
||||||
|
todo: Added a new "Mosaic" plank variant that is unique to Bamboo called Bamboo Mosaic
|
||||||
|
It can be crafted with 1x2 Bamboo Slabs in a vertical strip
|
||||||
|
You can craft Stair and Slab variants of Bamboo Mosaic
|
||||||
|
Bamboo Mosaic blocks cannot be used as a crafting ingredient where other wooden blocks are used, but they can be
|
||||||
|
used as fuel.
|
||||||
|
|
||||||
waiting on specific things:
|
todo -- add in fuel recipes for:
|
||||||
todo -- Raft -- need model
|
[-] bamboo slab + stripped bamboo slab
|
||||||
todo -- Raft with Chest. same.
|
[-] bamboo stair + stripped bamboo stair + bamboo plank stair
|
||||||
todo -- handle bonemeal... (shelved until after redoing the bonemeal api).
|
|
||||||
|
|
||||||
-----------------------------------------------------------
|
|
||||||
todo -- Add in Extras. -- Moved to Official Mod Pack.
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
When bone meal is used on it, it grows by 1–2 blocks. Bamboo can grow up to 12–16 blocks tall.
|
|
||||||
The top of a bamboo plant requires a light level of 9 or above to grow.
|
|
||||||
|
|
||||||
Design Decision - to not make bamboo saplings, and not make them go through a ton of transformations.
|
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
# textdomain: mcl_bamboo
|
# textdomain: mcl_bamboo
|
||||||
|
|
||||||
### bamboo_base.lua ###
|
|
||||||
|
|
||||||
Bamboo Mosaic Plank=
|
### init.lua ###
|
||||||
Bamboo Plank=
|
|
||||||
Stripped Bamboo Block=
|
|
||||||
|
|
||||||
### bamboo_items.lua ###
|
|
||||||
|
|
||||||
A bamboo button is a redstone component made out of stone which can be pushed to provide redstone power. When pushed, it powers adjacent redstone components for 1 second.=
|
A bamboo button is a redstone component made out of stone which can be pushed to provide redstone power. When pushed, it powers adjacent redstone components for 1 second.=
|
||||||
|
|
||||||
|
@ -17,18 +12,18 @@ Bamboo Button=
|
||||||
Bamboo Door.=
|
Bamboo Door.=
|
||||||
Bamboo Fence=
|
Bamboo Fence=
|
||||||
Bamboo Fence Gate=
|
Bamboo Fence Gate=
|
||||||
Bamboo Mosaic Slab=
|
Bamboo Plank=
|
||||||
Bamboo Mosaic Stair=
|
|
||||||
Bamboo Plank Slab=
|
Bamboo Plank Slab=
|
||||||
Bamboo Plank Stair=
|
Bamboo Plank Stair=
|
||||||
Bamboo Pressure Plate=
|
Bamboo Pressure Plate=
|
||||||
|
Bamboo Sign=
|
||||||
Bamboo Slab=
|
Bamboo Slab=
|
||||||
Bamboo Stair=
|
Bamboo Stair=
|
||||||
Bamboo Trapdoor.=
|
Bamboo Trapdoor.=
|
||||||
Double Bamboo Mosaic Slab=
|
|
||||||
Double Bamboo Plank Slab=
|
Double Bamboo Plank Slab=
|
||||||
Double Bamboo Slab=
|
Double Bamboo Slab=
|
||||||
Double Stripped Bamboo Slab=
|
Double Stripped Bamboo Slab=
|
||||||
|
Nether Brick Fence=
|
||||||
Scaffolding=
|
Scaffolding=
|
||||||
Scaffolding (horizontal)=
|
Scaffolding (horizontal)=
|
||||||
Scaffolding block used to climb up or out across areas.=
|
Scaffolding block used to climb up or out across areas.=
|
||||||
|
@ -38,3 +33,4 @@ Stripped Bamboo Stair=
|
||||||
To open or close the trapdoor, rightclick it or send a redstone signal to it.=
|
To open or close the trapdoor, rightclick it or send a redstone signal to it.=
|
||||||
|
|
||||||
Wooden trapdoors are horizontal barriers which can be opened and closed by hand or a redstone signal. They occupy the upper or lower part of a block, depending on how they have been placed. When open, they can be climbed like a ladder.=
|
Wooden trapdoors are horizontal barriers which can be opened and closed by hand or a redstone signal. They occupy the upper or lower part of a block, depending on how they have been placed. When open, they can be climbed like a ladder.=
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
local item_water, item_dirt, item_grass
|
||||||
|
|
||||||
|
item_water = "mcl_core:water_source"
|
||||||
|
item_dirt = "mcl_core:dirt"
|
||||||
|
item_grass = "mcl_core:dirt_with_grass"
|
||||||
|
local function make_bamboo(pos, size)
|
||||||
|
for y = 0, size - 1 do
|
||||||
|
local p = {x = pos.x, y = pos.y + y, z = pos.z}
|
||||||
|
if minetest.get_node(p).name ~= "air" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
minetest.set_node(p, {name = "mcl_bamboo:bamboo"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_on_generated(function(minp, maxp, seed)
|
||||||
|
if maxp.y < 2 and minp.y > 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local c_grass = minetest.get_content_id(item_grass)
|
||||||
|
local n_bamboo = minetest.get_perlin(8234, 3, 0.6, 100)
|
||||||
|
|
||||||
|
local vm = minetest.get_voxel_manip()
|
||||||
|
local emin, emax = vm:read_from_map(minp, maxp)
|
||||||
|
local area = VoxelArea:new {MinEdge = emin, MaxEdge = emax}
|
||||||
|
local data = vm:get_data()
|
||||||
|
|
||||||
|
local rand = PseudoRandom(seed % 8000)
|
||||||
|
for z = minp.z + 2, maxp.z - 2, 4 do
|
||||||
|
for x = minp.x + 2, maxp.x - 2, 4 do
|
||||||
|
local bamboo_amount = math.floor(n_bamboo:get_2d({x = x, y = z}) * 7 - 3)
|
||||||
|
for i = 1, bamboo_amount do
|
||||||
|
local p_pos = {
|
||||||
|
x = rand:next(x - 2, x + 2),
|
||||||
|
y = 0,
|
||||||
|
z = rand:next(z - 2, z + 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
local found = false
|
||||||
|
local node = -1
|
||||||
|
for y = 4, 0, -1 do
|
||||||
|
p_pos.y = y
|
||||||
|
node = data[area:index(p_pos.x, p_pos.y, p_pos.z)]
|
||||||
|
if node == c_grass then
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if found and
|
||||||
|
minetest.find_node_near(p_pos, 5, {"group:water", item_water}) then
|
||||||
|
p_pos.y = p_pos.y + 1
|
||||||
|
make_bamboo(p_pos, rand:next(4, 12))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
|
@ -1,200 +0,0 @@
|
||||||
---
|
|
||||||
--- Generated by EmmyLua(https://github.com/EmmyLua)
|
|
||||||
--- Created by michieal.
|
|
||||||
--- DateTime: 12/29/22 12:46 PM -- Restructure Date
|
|
||||||
--- These are all of the fuel recipes and all of the crafting recipes, consolidated into one place.
|
|
||||||
--- Copyright (C) 2022 - 2023, Michieal. See License.txt
|
|
||||||
|
|
||||||
-- Used everywhere. Often this is just the name, but it makes sense to me as BAMBOO, because that's how I think of it...
|
|
||||||
-- "BAMBOO" goes here.
|
|
||||||
local BAMBOO = "mcl_bamboo:bamboo"
|
|
||||||
local BAMBOO_PLANK = BAMBOO .. "_plank"
|
|
||||||
-- Craftings
|
|
||||||
-- Basic Bamboo craftings
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "mcl_core:stick",
|
|
||||||
recipe = {
|
|
||||||
{BAMBOO},
|
|
||||||
{BAMBOO},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = BAMBOO .. "_block",
|
|
||||||
recipe = {
|
|
||||||
{BAMBOO, BAMBOO, BAMBOO},
|
|
||||||
{BAMBOO, BAMBOO, BAMBOO},
|
|
||||||
{BAMBOO, BAMBOO, BAMBOO},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = BAMBOO_PLANK .. " 2",
|
|
||||||
recipe = {
|
|
||||||
{BAMBOO .. "_block"},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = BAMBOO_PLANK .. " 2",
|
|
||||||
recipe = {
|
|
||||||
{BAMBOO .. "_block_stripped"},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = BAMBOO .. "_mosaic",
|
|
||||||
recipe = {
|
|
||||||
{"mcl_stair:slab_bamboo_plank"},
|
|
||||||
{"mcl_stair:slab_bamboo_plank"},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
-- Bamboo specific items
|
|
||||||
|
|
||||||
if minetest.get_modpath("mcl_doors") and mcl_doors then
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "mcl_bamboo:bamboo_door 3",
|
|
||||||
recipe = {
|
|
||||||
{BAMBOO_PLANK, BAMBOO_PLANK},
|
|
||||||
{BAMBOO_PLANK, BAMBOO_PLANK},
|
|
||||||
{BAMBOO_PLANK, BAMBOO_PLANK}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "mcl_bamboo:bamboo_trapdoor 2",
|
|
||||||
recipe = {
|
|
||||||
{BAMBOO_PLANK, BAMBOO_PLANK, BAMBOO_PLANK},
|
|
||||||
{BAMBOO_PLANK, BAMBOO_PLANK, BAMBOO_PLANK},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
end
|
|
||||||
if minetest.get_modpath("mcl_fences") then
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "mcl_bamboo:bamboo_fence 3",
|
|
||||||
recipe = {
|
|
||||||
{BAMBOO_PLANK, "mcl_core:stick", BAMBOO_PLANK},
|
|
||||||
{BAMBOO_PLANK, "mcl_core:stick", BAMBOO_PLANK},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "mcl_bamboo:bamboo_fence_gate",
|
|
||||||
recipe = {
|
|
||||||
{"mcl_core:stick", BAMBOO_PLANK, "mcl_core:stick"},
|
|
||||||
{"mcl_core:stick", BAMBOO_PLANK, "mcl_core:stick"},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "mcl_bamboo:scaffolding 6",
|
|
||||||
recipe = {{BAMBOO, "mcl_mobitems:string", BAMBOO},
|
|
||||||
{BAMBOO, "", BAMBOO},
|
|
||||||
{BAMBOO, "", BAMBOO}}
|
|
||||||
})
|
|
||||||
|
|
||||||
-- Fuels
|
|
||||||
-- Basic Bamboo nodes
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = BAMBOO,
|
|
||||||
burntime = 2.5, -- supposed to be 1/2 that of a stick, per minecraft wiki as of JE 1.19.3
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = BAMBOO .. "_block",
|
|
||||||
burntime = 15,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = BAMBOO .. "_block_stripped",
|
|
||||||
burntime = 15,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = BAMBOO_PLANK,
|
|
||||||
burntime = 7.5,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = BAMBOO .. "_mosaic",
|
|
||||||
burntime = 7.5,
|
|
||||||
})
|
|
||||||
|
|
||||||
-- Bamboo Items
|
|
||||||
if minetest.get_modpath("mcl_doors") then
|
|
||||||
if mcl_doors then
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = "mcl_bamboo:bamboo_door",
|
|
||||||
burntime = 10,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = "mcl_bamboo:bamboo_trapdoor",
|
|
||||||
burntime = 15,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if minetest.get_modpath("mcl_stairs") then
|
|
||||||
if mcl_stairs ~= nil then
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = "mcl_stairs:slab_bamboo_plank",
|
|
||||||
burntime = 7.5,
|
|
||||||
})
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = "mcl_stairs:slab_bamboo_block",
|
|
||||||
burntime = 7.5,
|
|
||||||
})
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = "mcl_stairs:slab_bamboo_stripped",
|
|
||||||
burntime = 7.5,
|
|
||||||
})
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = "mcl_stairs:stair_bamboo_plank",
|
|
||||||
burntime = 15,
|
|
||||||
})
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = "mcl_stairs:stair_bamboo_block",
|
|
||||||
burntime = 15,
|
|
||||||
})
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = "mcl_stairs:stair_bamboo_stripped",
|
|
||||||
burntime = 15,
|
|
||||||
})
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = "mcl_stairs:slab_bamboo_mosaic",
|
|
||||||
burntime = 7.5,
|
|
||||||
})
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = "mcl_stairs:stair_bamboo_mosaic",
|
|
||||||
burntime = 15,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = "mesecons_button:button_bamboo_off",
|
|
||||||
burntime = 5,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
type = "fuel",
|
|
||||||
recipe = "mcl_bamboo:scaffolding",
|
|
||||||
burntime = 20
|
|
||||||
})
|
|
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 243 B After Width: | Height: | Size: 375 B |
Before Width: | Height: | Size: 234 B After Width: | Height: | Size: 375 B |
Before Width: | Height: | Size: 151 B After Width: | Height: | Size: 516 B |
Before Width: | Height: | Size: 148 B |
Before Width: | Height: | Size: 338 B After Width: | Height: | Size: 427 B |
Before Width: | Height: | Size: 376 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 448 B |
Before Width: | Height: | Size: 612 B After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 622 B After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 577 B After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 567 B After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 485 B After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 257 B |
Before Width: | Height: | Size: 451 B After Width: | Height: | Size: 388 B |
Before Width: | Height: | Size: 451 B After Width: | Height: | Size: 371 B |
Before Width: | Height: | Size: 324 B After Width: | Height: | Size: 205 B |
Before Width: | Height: | Size: 662 B After Width: | Height: | Size: 244 B |
Before Width: | Height: | Size: 588 B After Width: | Height: | Size: 650 B |
After Width: | Height: | Size: 628 B |
After Width: | Height: | Size: 684 B |
|
@ -139,7 +139,7 @@ local function bucket_get_pointed_thing(user)
|
||||||
local start = user:get_pos()
|
local start = user:get_pos()
|
||||||
start.y = start.y + user:get_properties().eye_height
|
start.y = start.y + user:get_properties().eye_height
|
||||||
local look_dir = user:get_look_dir()
|
local look_dir = user:get_look_dir()
|
||||||
local _end = vector.add(start, vector.multiply(look_dir, 5))
|
_end = vector.add(start, vector.multiply(look_dir, 5))
|
||||||
|
|
||||||
local ray = raycast(start, _end, false, true)
|
local ray = raycast(start, _end, false, true)
|
||||||
for pointed_thing in ray do
|
for pointed_thing in ray do
|
||||||
|
|
|
@ -3,7 +3,7 @@ local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
mcl_cocoas = {}
|
mcl_cocoas = {}
|
||||||
|
|
||||||
-- Place cocoa
|
-- Place cocoa
|
||||||
local function cocoa_place(itemstack, placer, pt, plantname)
|
function mcl_cocoas.place(itemstack, placer, pt, plantname)
|
||||||
-- check if pointing at a node
|
-- check if pointing at a node
|
||||||
if not pt or pt.type ~= "node" then
|
if not pt or pt.type ~= "node" then
|
||||||
return
|
return
|
||||||
|
@ -90,11 +90,7 @@ local crop_def = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
groups = {
|
groups = {
|
||||||
handy = 1, axey = 1,
|
handy=1,axey=1, cocoa=1, not_in_creative_inventory=1, dig_by_water=1, destroy_by_lava_flow=1, dig_by_piston=1, attached_node_facedir=1,
|
||||||
dig_by_water=1, destroy_by_lava_flow=1, dig_by_piston=1,
|
|
||||||
attached_node_facedir=1,
|
|
||||||
not_in_creative_inventory=1,
|
|
||||||
cocoa=1
|
|
||||||
},
|
},
|
||||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||||
on_rotate = false,
|
on_rotate = false,
|
||||||
|
|
|
@ -809,7 +809,7 @@ function mcl_core.get_grass_palette_index(pos)
|
||||||
local biome_name = minetest.get_biome_name(biome)
|
local biome_name = minetest.get_biome_name(biome)
|
||||||
local reg_biome = minetest.registered_biomes[biome_name]
|
local reg_biome = minetest.registered_biomes[biome_name]
|
||||||
if reg_biome then
|
if reg_biome then
|
||||||
index = reg_biome._mcl_grass_palette_index
|
index = reg_biome._mcl_palette_index
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return index
|
return index
|
||||||
|
@ -939,7 +939,7 @@ minetest.register_lbm({
|
||||||
else
|
else
|
||||||
node.name = "mcl_core:dirt_with_grass"
|
node.name = "mcl_core:dirt_with_grass"
|
||||||
end
|
end
|
||||||
node.param2 = reg_biome._mcl_grass_palette_index
|
node.param2 = reg_biome._mcl_palette_index
|
||||||
-- Fall back to savanna palette index
|
-- Fall back to savanna palette index
|
||||||
if not node.param2 then
|
if not node.param2 then
|
||||||
node.param2 = SAVANNA_INDEX
|
node.param2 = SAVANNA_INDEX
|
||||||
|
|
|
@ -24,7 +24,7 @@ Andesite is an igneous rock.=Andesit ist ein magmatisches Gestein.
|
||||||
Apple=Apfel
|
Apple=Apfel
|
||||||
Apples are food items which can be eaten.=Äpfel sind essbare Gegenstände.
|
Apples are food items which can be eaten.=Äpfel sind essbare Gegenstände.
|
||||||
Barrier=Barriere
|
Barrier=Barriere
|
||||||
Barriers are invisible walkable blocks. They are used to create boundaries of adventure maps and the like. Monsters and animals won't appear on barriers, and fences do not connect to barriers. Other blocks can be built on barriers like on any other block.=Barrieren sind unsichtbare feste Blöcke. Sie sind nützlich, um Grenzen für Abenteuerkarten und ähnliches zu bauen. Monster und Tiere werden auf Barrieren nicht auftauchen, und Zäune verbinden sich nicht mit Barrieren. Andere Blöcke können an Barrieren gebaut werden, wie bei allen anderen Blöcken.
|
Barriers are invisble walkable blocks. They are used to create boundaries of adventure maps and the like. Monsters and animals won't appear on barriers, and fences do not connect to barriers. Other blocks can be built on barriers like on any other block.=Barrieren sind unsichtbare feste Blöcke. Sie sind nützlich, um Grenzen für Abenteuerkarten und ähnliches zu bauen. Monster und Tiere werden auf Barrieren nicht auftauchen, und Zäune verbinden sich nicht mit Barrieren. Andere Blöcke können an Barrieren gebaut werden, wie bei allen anderen Blöcken.
|
||||||
Bedrock=Grundgestein
|
Bedrock=Grundgestein
|
||||||
Bedrock is a very hard type of rock. It can not be broken, destroyed, collected or moved by normal means, unless in Creative Mode.=Grundgestein ist ein sehr harter Gesteinstyp. Er kann unter normalen Umständen nicht abgebaut, zerstört, aufgesammelt oder verschoben werden, außer im Kreativmodus.
|
Bedrock is a very hard type of rock. It can not be broken, destroyed, collected or moved by normal means, unless in Creative Mode.=Grundgestein ist ein sehr harter Gesteinstyp. Er kann unter normalen Umständen nicht abgebaut, zerstört, aufgesammelt oder verschoben werden, außer im Kreativmodus.
|
||||||
Birch Bark=Birkenrinde
|
Birch Bark=Birkenrinde
|
||||||
|
|
|
@ -24,7 +24,7 @@ Andesite is an igneous rock.=La andesita es una roca ígnea.
|
||||||
Apple=Manzana
|
Apple=Manzana
|
||||||
Apples are food items which can be eaten.=Las manzanas son alimentos que se pueden comer.
|
Apples are food items which can be eaten.=Las manzanas son alimentos que se pueden comer.
|
||||||
Barrier=Barrera
|
Barrier=Barrera
|
||||||
Barriers are invisible walkable blocks. They are used to create boundaries of adventure maps and the like. Monsters and animals won't appear on barriers, and fences do not connect to barriers. Other blocks can be built on barriers like on any other block.=Las barreras son bloques transitables invisibles. Se utilizan para crear límites de mapas de aventura y similares. Los monstruos y los animales no aparecerán en las barreras, y las cercas no se conectan a las barreras. Otros bloques pueden construirse sobre barreras como en cualquier otro bloque.
|
Barriers are invisble walkable blocks. They are used to create boundaries of adventure maps and the like. Monsters and animals won't appear on barriers, and fences do not connect to barriers. Other blocks can be built on barriers like on any other block.=Las barreras son bloques transitables invisibles. Se utilizan para crear límites de mapas de aventura y similares. Los monstruos y los animales no aparecerán en las barreras, y las cercas no se conectan a las barreras. Otros bloques pueden construirse sobre barreras como en cualquier otro bloque.
|
||||||
Bedrock=Lecho de roca
|
Bedrock=Lecho de roca
|
||||||
Bedrock is a very hard type of rock. It can not be broken, destroyed, collected or moved by normal means, unless in Creative Mode.=El lecho de roca es un tipo de roca muy duro. No se puede romper, destruir, recoger o mover por medios normales, a menos que esté en modo creativo.
|
Bedrock is a very hard type of rock. It can not be broken, destroyed, collected or moved by normal means, unless in Creative Mode.=El lecho de roca es un tipo de roca muy duro. No se puede romper, destruir, recoger o mover por medios normales, a menos que esté en modo creativo.
|
||||||
Birch Bark=Madera de abedul sin corteza
|
Birch Bark=Madera de abedul sin corteza
|
||||||
|
|
|
@ -24,7 +24,7 @@ Andesite is an igneous rock.=L'andésite est une roche ignée.
|
||||||
Apple=Pomme
|
Apple=Pomme
|
||||||
Apples are food items which can be eaten.=Les pommes sont des aliments qui peuvent être consommés.
|
Apples are food items which can be eaten.=Les pommes sont des aliments qui peuvent être consommés.
|
||||||
Barrier=Barrière invisible
|
Barrier=Barrière invisible
|
||||||
Barriers are invisible walkable blocks. They are used to create boundaries of adventure maps and the like. Monsters and animals won't appear on barriers, and fences do not connect to barriers. Other blocks can be built on barriers like on any other block.=Les barrières sont des blocs accessibles à pied. Ils sont utilisés pour créer des limites de cartes d'aventure et similaires. Les monstres et les animaux n'apparaissent pas sur les barrières, et les clôtures ne se connectent pas aux barrières. D'autres blocs peuvent être construits sur des barrières comme sur n'importe quel autre bloc.
|
Barriers are invisble walkable blocks. They are used to create boundaries of adventure maps and the like. Monsters and animals won't appear on barriers, and fences do not connect to barriers. Other blocks can be built on barriers like on any other block.=Les barrières sont des blocs accessibles à pied. Ils sont utilisés pour créer des limites de cartes d'aventure et similaires. Les monstres et les animaux n'apparaissent pas sur les barrières, et les clôtures ne se connectent pas aux barrières. D'autres blocs peuvent être construits sur des barrières comme sur n'importe quel autre bloc.
|
||||||
Bedrock=Bedrock
|
Bedrock=Bedrock
|
||||||
Bedrock is a very hard type of rock. It can not be broken, destroyed, collected or moved by normal means, unless in Creative Mode.=Le bedrock est un type de roche très dur. Il ne peut pas être brisé, détruit, collecté ou déplacé par des moyens normaux, sauf en mode créatif.
|
Bedrock is a very hard type of rock. It can not be broken, destroyed, collected or moved by normal means, unless in Creative Mode.=Le bedrock est un type de roche très dur. Il ne peut pas être brisé, détruit, collecté ou déplacé par des moyens normaux, sauf en mode créatif.
|
||||||
Birch Bark=Bois de Bouleau
|
Birch Bark=Bois de Bouleau
|
||||||
|
@ -286,6 +286,3 @@ Stackable=Empilable
|
||||||
Crying Obsidian=Obsidienne pleureuse
|
Crying Obsidian=Obsidienne pleureuse
|
||||||
Crying obsidian is a luminous obsidian that can generate as part of ruined portals.=L'obsidienne pleureuse est une obsidienne luminause qui peut être générée dans les portails en ruine.
|
Crying obsidian is a luminous obsidian that can generate as part of ruined portals.=L'obsidienne pleureuse est une obsidienne luminause qui peut être générée dans les portails en ruine.
|
||||||
Enchanted Golden Apple=Pomme dorée enchantée
|
Enchanted Golden Apple=Pomme dorée enchantée
|
||||||
Light=Lumière
|
|
||||||
Lights are invisible blocks. They are used to light up adventure maps and the like.=Les lumières sont des blocs invisibles. Ils sont utilisés pour éclairer les cartes d'aventure.
|
|
||||||
When you hold a light in hand, you reveal all placed lights in a short distance around you.=Lorsque vous tenez une lumière en main, vous révélez toutes les lumières placées à une courte distance autour de vous.
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ Andesite is an igneous rock.=Andezyt jest skałą pochodzenia wulkanicznego.
|
||||||
Apple=Jabłko
|
Apple=Jabłko
|
||||||
Apples are food items which can be eaten.=Jabłka to przedmioty które można zjeść.
|
Apples are food items which can be eaten.=Jabłka to przedmioty które można zjeść.
|
||||||
Barrier=Bariera
|
Barrier=Bariera
|
||||||
Barriers are invisible walkable blocks. They are used to create boundaries of adventure maps and the like. Monsters and animals won't appear on barriers, and fences do not connect to barriers. Other blocks can be built on barriers like on any other block.=Bariery to niewidzialne bloki po których można chodzić. Są użyteczne do tworzenia ograniczeń na mapach przygodowych i im podobnych. Potwory i zwierzęta nie pojawiają się na barierach, a płoty się z nimi nie łączą. Inne bloki mogą być na nich budowane podobnie jak na innych blokach.
|
Barriers are invisble walkable blocks. They are used to create boundaries of adventure maps and the like. Monsters and animals won't appear on barriers, and fences do not connect to barriers. Other blocks can be built on barriers like on any other block.=Bariery to niewidzialne bloki po których można chodzić. Są użyteczne do tworzenia ograniczeń na mapach przygodowych i im podobnych. Potwory i zwierzęta nie pojawiają się na barierach, a płoty się z nimi nie łączą. Inne bloki mogą być na nich budowane podobnie jak na innych blokach.
|
||||||
Bedrock=Skała macierzysta
|
Bedrock=Skała macierzysta
|
||||||
Bedrock is a very hard type of rock. It can not be broken, destroyed, collected or moved by normal means, unless in Creative Mode.=Skała macierzysta jest rodzajem bardzo twardej skały. Nie może być ona zniszczona, zebrana lub przesunięta normalnymi metodami, jeśli nie jesteś w trybie kreatywnym.
|
Bedrock is a very hard type of rock. It can not be broken, destroyed, collected or moved by normal means, unless in Creative Mode.=Skała macierzysta jest rodzajem bardzo twardej skały. Nie może być ona zniszczona, zebrana lub przesunięta normalnymi metodami, jeśli nie jesteś w trybie kreatywnym.
|
||||||
Birch Bark=Brzozowa kora
|
Birch Bark=Brzozowa kora
|
||||||
|
|