From 74e3c942b26fd6b7045a7826d54e3f37d0422126 Mon Sep 17 00:00:00 2001 From: Emojigit <55009343+Emojigit@users.noreply.github.com> Date: Mon, 3 Aug 2020 17:56:23 +0800 Subject: [PATCH] Add files via upload --- changelog.md | 4 + init.lua | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++ license.md | 9 ++ mod.conf | 3 + 4 files changed, 267 insertions(+) create mode 100644 changelog.md create mode 100644 init.lua create mode 100644 license.md create mode 100644 mod.conf diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..a2255ff --- /dev/null +++ b/changelog.md @@ -0,0 +1,4 @@ +# Changelog +All time are in UTC+8 (HKT) +## 2020/08/03 +17:48 Edited it to make it cut grass, not tree. \ No newline at end of file diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..a5e1526 --- /dev/null +++ b/init.lua @@ -0,0 +1,251 @@ +-- Configuration + +local grassc_max_charge = 30000 -- Maximum charge of the saw +-- Gives 2500 nodes on a single charge (about 50 complete normal trees) +local chainsaw_charge_per_node = 12 +-- Cut down tree leaves. Leaf decay may cause slowness on large trees +-- if this is disabled. +local chainsaw_leaves = true + +-- First value is node name; second is whether the node is considered even if chainsaw_leaves is false. +local nodes = { + -- The default grasses + {"default:grass_1",true}, + {"default:grass_2",true}, + {"default:grass_3",true}, + {"default:grass_4",true}, + {"default:grass_5",true}, + {"default:dry_grass_1",true}, + {"default:dry_grass_2",true}, + {"default:dry_grass_3",true}, + {"default:dry_grass_4",true}, + {"default:dry_grass_5",true}, + {"default:junglegrass",true}, + {"default:dry_shrub",true}, + -- ethereal + {"ethereal:fern",true}, + {"ethereal:onion_1",true}, + {"ethereal:onion_2",true}, + {"ethereal:onion_3",true}, + {"ethereal:onion_4",true}, + {"ethereal:onion_5",true}, + {"ethereal:crystalgrass",true}, + {"ethereal:crystal_spike",true}, + {"ethereal:snowygrass",true}, +} + +local timber_nodenames = {} +for _, node in pairs(nodes) do + if chainsaw_leaves or node[2] then + timber_nodenames[node[1]] = true + end +end + +local S = technic.getter + +technic.register_power_tool("technic_grass_clean:grass_cleaner", grassc_max_charge) + +-- This function checks if the specified node should be sawed +local function check_if_node_sawed(pos) + local node_name = minetest.get_node(pos).name + if timber_nodenames[node_name] then + return true + end + + return false +end + +-- Table for saving what was sawed down +local produced = {} + +-- Save the items sawed down so that we can drop them in a nice single stack +local function handle_drops(drops) + for _, item in ipairs(drops) do + local stack = ItemStack(item) + local name = stack:get_name() + local p = produced[name] + if not p then + produced[name] = stack + else + p:set_count(p:get_count() + stack:get_count()) + end + end +end + +--- Iterator over positions to try to saw around a sawed node. +-- This returns positions in a 3x1x3 area around the position, plus the +-- position above it. This does not return the bottom position to prevent +-- the chainsaw from cutting down nodes below the cutting position. +-- @param pos Sawing position. +local function iterSawTries(pos) + -- Copy position to prevent mangling it + local pos = vector.new(pos) + local i = 0 + + return function() + i = i + 1 + -- Given a (top view) area like so (where 5 is the starting position): + -- X --> + -- Z 123 + -- | 456 + -- V 789 + -- This will return positions 1, 4, 7, 2, 8 (skip 5), 3, 6, 9, + -- and the position above 5. + if i == 1 then + -- Move to starting position + pos.x = pos.x - 1 + pos.z = pos.z - 1 + elseif i == 4 or i == 7 then + -- Move to next X and back to start of Z when we reach + -- the end of a Z line. + pos.x = pos.x + 1 + pos.z = pos.z - 2 + elseif i == 5 then + -- Skip the middle position (we've already run on it) + -- and double-increment the counter. + pos.z = pos.z + 2 + i = i + 1 + elseif i <= 9 then + -- Go to next Z. + pos.z = pos.z + 1 + elseif i == 10 then + -- Move back to center and up. + -- The Y+ position must be last so that we don't dig + -- straight upward and not come down (since the Y- + -- position isn't checked). + pos.x = pos.x - 1 + pos.z = pos.z - 1 + pos.y = pos.y + 1 + else + return nil + end + return pos + end +end + +-- This function does all the hard work. Recursively we dig the node at hand +-- if it is in the table and then search the surroundings for more stuff to dig. +local function recursive_dig(pos, remaining_charge) + if remaining_charge < chainsaw_charge_per_node then + return remaining_charge + end + local node = minetest.get_node(pos) + + if not check_if_node_sawed(pos) then + return remaining_charge + end + + -- Wood found - cut it + handle_drops(minetest.get_node_drops(node.name, "")) + minetest.remove_node(pos) + remaining_charge = remaining_charge - chainsaw_charge_per_node + + -- Check surroundings and run recursively if any charge left + for npos in iterSawTries(pos) do + if remaining_charge < chainsaw_charge_per_node then + break + end + if check_if_node_sawed(npos) then + remaining_charge = recursive_dig(npos, remaining_charge) + else + minetest.check_for_falling(npos) + end + end + return remaining_charge +end + +-- Function to randomize positions for new node drops +local function get_drop_pos(pos) + local drop_pos = {} + + for i = 0, 8 do + -- Randomize position for a new drop + drop_pos.x = pos.x + math.random(-3, 3) + drop_pos.y = pos.y - 1 + drop_pos.z = pos.z + math.random(-3, 3) + + -- Move the randomized position upwards until + -- the node is air or unloaded. + for y = drop_pos.y, drop_pos.y + 5 do + drop_pos.y = y + local node = minetest.get_node_or_nil(drop_pos) + + if not node then + -- If the node is not loaded yet simply drop + -- the item at the original digging position. + return pos + elseif node.name == "air" then + -- Add variation to the entity drop position, + -- but don't let drops get too close to the edge + drop_pos.x = drop_pos.x + (math.random() * 0.8) - 0.5 + drop_pos.z = drop_pos.z + (math.random() * 0.8) - 0.5 + return drop_pos + end + end + end + + -- Return the original position if this takes too long + return pos +end + +-- Chainsaw entry point +local function chainsaw_dig(pos, current_charge) + -- Start sawing things down + local remaining_charge = recursive_dig(pos, current_charge) + minetest.sound_play("chainsaw", {pos = pos, gain = 1.0, + max_hear_distance = 10}) + + -- Now drop items for the player + for name, stack in pairs(produced) do + -- Drop stacks of stack max or less + local count, max = stack:get_count(), stack:get_stack_max() + stack:set_count(max) + while count > max do + minetest.add_item(get_drop_pos(pos), stack) + count = count - max + end + stack:set_count(count) + minetest.add_item(get_drop_pos(pos), stack) + end + + -- Clean up + produced = {} + + return remaining_charge +end + + +minetest.register_tool("technic_grass_clean:grass_cleaner", { + description = "Grass Cleaner", + inventory_image = "technic_chainsaw.png", + stack_max = 1, + wear_represents = "technic_RE_charge", + on_refill = technic.refill_RE_charge, + on_use = function(itemstack, user, pointed_thing) + if pointed_thing.type ~= "node" then + return itemstack + end + + local meta = minetest.deserialize(itemstack:get_metadata()) + if not meta or not meta.charge or + meta.charge < chainsaw_charge_per_node then + return + end + + local name = user:get_player_name() + if minetest.is_protected(pointed_thing.under, name) then + minetest.record_protection_violation(pointed_thing.under, name) + return + end + + -- Send current charge to digging function so that the + -- chainsaw will stop after digging a number of nodes + meta.charge = chainsaw_dig(pointed_thing.under, meta.charge) + if not technic.creative_mode then + technic.set_RE_wear(itemstack, meta.charge, chainsaw_max_charge) + itemstack:set_metadata(minetest.serialize(meta)) + end + return itemstack + end, +}) + diff --git a/license.md b/license.md new file mode 100644 index 0000000..77f313b --- /dev/null +++ b/license.md @@ -0,0 +1,9 @@ +# License +Copyright (C) 2020 Cato Yiu (Emoji) + +Technic chests code is licensed under the GNU LGPLv2+. + +Note: I am call Emoji(Service) on most all place, for example, my name is Emojigit on git hosting website like github. +Except but not only: + - Emojiwiki on wikimedia + - Emojinotabug on NotABug diff --git a/mod.conf b/mod.conf new file mode 100644 index 0000000..e60fe8d --- /dev/null +++ b/mod.conf @@ -0,0 +1,3 @@ +name = technic_grass_clean +depends = technic, default +description = A tool like chainsaw, but cut grass, not tree. \ No newline at end of file