diff --git a/CREDITS.md b/CREDITS.md index 8945835..be6f127 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -6,7 +6,7 @@ External mods used: * `show_wielded_item` * `no_fall_damage` -* `player_api`, `xpanes`, `stairs`, `screwdriver` +* `player_api`, `xpanes`, `stairs`, `screwdriver2` * `xdecor` (heavily modified, non-free textures removed) --- @@ -17,6 +17,7 @@ Textures: - Crosshair, wieldhand, `smoke_puff.png`: trivial textures by Wuzzy (CC0) - Emitter, detector textures: Derivate works of xdecor textures by jp (CC0) - Mirror textures: by Wuzzy (CC0) +- Screwdriver texture: by 12Me21 (CC0) Models: - Player models comes from Minetest Game (see license of Minetest Game 5.4.1 for details) @@ -25,16 +26,10 @@ Sounds: - All sounds come from Minetest Game (see license of Minetest Game 5.4.1 for details) - Exception 1: Ocean waves come from https://freesound.org/people/inchadney/sounds/135805/ - by inchadney (CC BY 3.0) -- Excecption 2: Screwdriver sounds - - Created by InspectorJ of Freesound.org (CC BY 3.0): - - `screwdriver_use.1.ogg` - - `screwdriver_use.2.ogg` - - `screwdriver_use.3.ogg` - - `screwdriver_use.4.ogg` - - (Original file name: Screwdriver, Ratchet, C.wav) Code: -- `player_api`, `stairs`, `xpanes`, `screwdriver` come from Minetest Game 5.4.1 (mods modified for Lazarr!), by Minetest Game developers (see README.txt in those folders) +- `player_api`, `stairs`, `xpanes` come from Minetest Game 5.4.1 (mods modified for Lazarr!), by Minetest Game developers (see README.txt in those folders) +- `screwdriver2` by 12Me21, modified version (CC0) - `xdecor` by jp (BSD-3 clause license; massively-simplified version from the original) Other stuff: diff --git a/mods/lzr_laser/blocks.lua b/mods/lzr_laser/blocks.lua index 54126fd..7a0f289 100644 --- a/mods/lzr_laser/blocks.lua +++ b/mods/lzr_laser/blocks.lua @@ -105,7 +105,7 @@ local register_element = function(subname, def) local def_core = table.copy(def) def_core.after_place_node = full_update def_core.after_dig_node = full_update - def_core.after_rotate = after_rotate + def_core._after_rotate = after_rotate def_core.sounds = lzr_sounds.node_sound_wood_defaults() def_core._lzr_active = "lzr_laser:"..subname.."_on" def_core.tiles = def.tiles_off diff --git a/mods/lzr_levels/init.lua b/mods/lzr_levels/init.lua index bc5dc3f..cbacf9a 100644 --- a/mods/lzr_levels/init.lua +++ b/mods/lzr_levels/init.lua @@ -75,7 +75,7 @@ end local function reset_inventory(player) clear_inventory(player) local inv = player:get_inventory() - inv:add_item("main", "screwdriver:screwdriver") + inv:add_item("main", "screwdriver2:screwdriver") end local current_level = nil diff --git a/mods/lzr_levels/mod.conf b/mods/lzr_levels/mod.conf index f3cd865..0f476d5 100644 --- a/mods/lzr_levels/mod.conf +++ b/mods/lzr_levels/mod.conf @@ -1,2 +1,2 @@ name = lzr_levels -depends = lzr_core, lzr_mapgen, lzr_globals +depends = lzr_core, lzr_mapgen, lzr_globals, screwdriver2 diff --git a/mods/screwdriver/README.txt b/mods/screwdriver/README.txt deleted file mode 100644 index 1f762ee..0000000 --- a/mods/screwdriver/README.txt +++ /dev/null @@ -1,21 +0,0 @@ -Minetest Game mod: screwdriver -============================== -See license.txt for license information. - -License of source code ----------------------- -Originally by RealBadAngel, Maciej Kasatkin (LGPLv2.1+) -Various Minetest developers and contributors (LGPLv2.1+) - -License of media (textures) ---------------------------- -Created by Gambit (CC BY-SA 3.0): - screwdriver.png - -Created by InspectorJ of Freesound.org (CC BY 3.0): - screwdriver_use.1.ogg - screwdriver_use.2.ogg - screwdriver_use.3.ogg - screwdriver_use.4.ogg - - (Original file name: Screwdriver, Ratchet, C.wav) diff --git a/mods/screwdriver/init.lua b/mods/screwdriver/init.lua deleted file mode 100644 index 3df7335..0000000 --- a/mods/screwdriver/init.lua +++ /dev/null @@ -1,183 +0,0 @@ --- screwdriver/init.lua - -screwdriver = {} - --- Load support for MT game translation. -local S = minetest.get_translator("screwdriver") - -local USES_DEFAULT = 200 - -screwdriver.ROTATE_FACE = 1 -screwdriver.ROTATE_AXIS = 2 -screwdriver.disallow = function(pos, node, user, mode, new_param2) - return false -end -screwdriver.rotate_simple = function(pos, node, user, mode, new_param2) - if mode ~= screwdriver.ROTATE_FACE then - return false - end -end - --- For attached wallmounted nodes: returns true if rotation is valid --- simplified version of minetest:builtin/game/falling.lua#L148. -local function check_attached_node(pos, rotation) - local d = minetest.wallmounted_to_dir(rotation) - local p2 = vector.add(pos, d) - local n = minetest.get_node(p2).name - local def2 = minetest.registered_nodes[n] - if def2 and not def2.walkable then - return false - end - return true -end - -screwdriver.rotate = {} - -local facedir_tbl = { - [screwdriver.ROTATE_FACE] = { - [0] = 1, [1] = 2, [2] = 3, [3] = 0, - [4] = 5, [5] = 6, [6] = 7, [7] = 4, - [8] = 9, [9] = 10, [10] = 11, [11] = 8, - [12] = 13, [13] = 14, [14] = 15, [15] = 12, - [16] = 17, [17] = 18, [18] = 19, [19] = 16, - [20] = 21, [21] = 22, [22] = 23, [23] = 20, - }, - [screwdriver.ROTATE_AXIS] = { - [0] = 4, [1] = 4, [2] = 4, [3] = 4, - [4] = 8, [5] = 8, [6] = 8, [7] = 8, - [8] = 12, [9] = 12, [10] = 12, [11] = 12, - [12] = 16, [13] = 16, [14] = 16, [15] = 16, - [16] = 20, [17] = 20, [18] = 20, [19] = 20, - [20] = 0, [21] = 0, [22] = 0, [23] = 0, - }, -} - -screwdriver.rotate.facedir = function(pos, node, mode) - local rotation = node.param2 % 32 -- get first 5 bits - local other = node.param2 - rotation - rotation = facedir_tbl[mode][rotation] or 0 - return rotation + other -end - -screwdriver.rotate.colorfacedir = screwdriver.rotate.facedir - -local wallmounted_tbl = { - [screwdriver.ROTATE_FACE] = {[2] = 5, [3] = 4, [4] = 2, [5] = 3, [1] = 0, [0] = 1}, - [screwdriver.ROTATE_AXIS] = {[2] = 1, [3] = 0, [4] = 1, [5] = 0, [1] = 3, [0] = 2} -} - -screwdriver.rotate.wallmounted = function(pos, node, mode) - local rotation = node.param2 % 8 -- get first 3 bits - local other = node.param2 - rotation - rotation = wallmounted_tbl[mode][rotation] or 0 - if minetest.get_item_group(node.name, "attached_node") ~= 0 then - -- find an acceptable orientation - for i = 1, 5 do - if not check_attached_node(pos, rotation) then - rotation = wallmounted_tbl[mode][rotation] or 0 - else - break - end - end - end - return rotation + other -end - -screwdriver.rotate.colorwallmounted = screwdriver.rotate.wallmounted - --- Handles rotation -screwdriver.handler = function(itemstack, user, pointed_thing, mode, uses) - if pointed_thing.type ~= "node" then - return - end - - local pos = pointed_thing.under - local player_name = user and user:get_player_name() or "" - - if minetest.is_protected(pos, player_name) and not minetest.check_player_privs(player_name, "protection_bypass") then - minetest.record_protection_violation(pos, player_name) - return - end - - local node = minetest.get_node(pos) - local ndef = minetest.registered_nodes[node.name] - if not ndef then - return itemstack - end - -- Node MUST have 'rotatable' group - if not ndef.groups.rotatable then - return itemstack - end - if mode == screwdriver.ROTATE_AXIS and ndef and ndef.on_rightclick and - ((not user) or (user and not user:get_player_control().sneak)) then - return ndef.on_rightclick(pos, node, user, itemstack, - pointed_thing) or itemstack - end - - -- can we rotate this paramtype2? - local fn = screwdriver.rotate[ndef.paramtype2] - if not fn and not ndef.on_rotate then - return itemstack - end - - local should_rotate = true - local new_param2 - if fn then - new_param2 = fn(pos, node, mode) - else - new_param2 = node.param2 - end - - -- Node provides a handler, so let the handler decide instead if the node can be rotated - if ndef.on_rotate == false then - return - elseif ndef.on_rotate == "simple" then - if mode ~= screwdriver.ROTATE_FACE then - return - end - elseif ndef.on_rotate then - -- Copy pos and node because callback can modify it - local result = ndef.on_rotate(vector.new(pos), - {name = node.name, param1 = node.param1, param2 = node.param2}, - user, mode, new_param2) - minetest.sound_play({name="screwdriver_use", gain=0.5}, {pos=pos, max_hear_distance=16}, true) - if result == false then -- Disallow rotation - return itemstack - elseif result == true then - should_rotate = false - end - elseif ndef.on_rotate == false then - return itemstack - elseif ndef.can_dig and not ndef.can_dig(pos, user) then - return itemstack - end - - if should_rotate and new_param2 ~= node.param2 then - node.param2 = new_param2 - minetest.swap_node(pos, node) - minetest.check_for_falling(pos) - minetest.sound_play({name="screwdriver_use", gain=0.5}, {pos=pos, max_hear_distance=16}, true) - if ndef.after_rotate then - ndef.after_rotate(vector.new(pos)) - end - end - - return itemstack -end - --- Screwdriver -minetest.register_tool("screwdriver:screwdriver", { - description = S("Mirror Rotator") .. "\n" .. S("Punch to rotate face, place to rotates axis"), - inventory_image = "screwdriver.png", - groups = {tool = 1}, - on_use = function(itemstack, user, pointed_thing) - screwdriver.handler(itemstack, user, pointed_thing, screwdriver.ROTATE_FACE, USES_DEFAULT) - return itemstack - end, - on_place = function(itemstack, user, pointed_thing) - screwdriver.handler(itemstack, user, pointed_thing, screwdriver.ROTATE_AXIS, USES_DEFAULT) - return itemstack - end, -}) - - diff --git a/mods/screwdriver/license.txt b/mods/screwdriver/license.txt deleted file mode 100644 index d9b721b..0000000 --- a/mods/screwdriver/license.txt +++ /dev/null @@ -1,50 +0,0 @@ -License of source code ----------------------- - -GNU Lesser General Public License, version 2.1 -Copyright (C) 2013-2016 RealBadAngel, Maciej Kasatkin -Copyright (C) 2013-2016 Various Minetest developers and contributors - -This program is free software; you can redistribute it and/or modify it under the terms -of the GNU Lesser General Public License as published by the Free Software Foundation; -either version 2.1 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 Lesser General Public License for more details: -https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html - - -Licenses of media (textures) ----------------------------- - -Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) -Copyright (C) 2013-2016 Gambit - -You are free to: -Share — copy and redistribute the material in any medium or format. -Adapt — remix, transform, and build upon the material for any purpose, even commercially. -The licensor cannot revoke these freedoms as long as you follow the license terms. - -Under the following terms: - -Attribution — You must give appropriate credit, provide a link to the license, and -indicate if changes were made. You may do so in any reasonable manner, but not in any way -that suggests the licensor endorses you or your use. - -ShareAlike — If you remix, transform, or build upon the material, you must distribute -your contributions under the same license as the original. - -No additional restrictions — You may not apply legal terms or technological measures that -legally restrict others from doing anything the license permits. - -Notices: - -You do not have to comply with the license for elements of the material in the public -domain or where your use is permitted by an applicable exception or limitation. -No warranties are given. The license may not give you all of the permissions necessary -for your intended use. For example, other rights such as publicity, privacy, or moral -rights may limit how you use the material. - -For more details: -http://creativecommons.org/licenses/by-sa/3.0/ diff --git a/mods/screwdriver/mod.conf b/mods/screwdriver/mod.conf deleted file mode 100644 index 38051ef..0000000 --- a/mods/screwdriver/mod.conf +++ /dev/null @@ -1,2 +0,0 @@ -name = screwdriver -description = A screwdriver allows rotating blocks diff --git a/mods/screwdriver/sounds/screwdriver_use.1.ogg b/mods/screwdriver/sounds/screwdriver_use.1.ogg deleted file mode 100644 index ca25d92..0000000 Binary files a/mods/screwdriver/sounds/screwdriver_use.1.ogg and /dev/null differ diff --git a/mods/screwdriver/sounds/screwdriver_use.2.ogg b/mods/screwdriver/sounds/screwdriver_use.2.ogg deleted file mode 100644 index fff44d9..0000000 Binary files a/mods/screwdriver/sounds/screwdriver_use.2.ogg and /dev/null differ diff --git a/mods/screwdriver/sounds/screwdriver_use.3.ogg b/mods/screwdriver/sounds/screwdriver_use.3.ogg deleted file mode 100644 index a11b3e5..0000000 Binary files a/mods/screwdriver/sounds/screwdriver_use.3.ogg and /dev/null differ diff --git a/mods/screwdriver/sounds/screwdriver_use.4.ogg b/mods/screwdriver/sounds/screwdriver_use.4.ogg deleted file mode 100644 index 32e700f..0000000 Binary files a/mods/screwdriver/sounds/screwdriver_use.4.ogg and /dev/null differ diff --git a/mods/screwdriver/textures/screwdriver.png b/mods/screwdriver/textures/screwdriver.png deleted file mode 100644 index e20f063..0000000 Binary files a/mods/screwdriver/textures/screwdriver.png and /dev/null differ diff --git a/mods/screwdriver2/LICENSE.txt b/mods/screwdriver2/LICENSE.txt new file mode 100644 index 0000000..8cffccc --- /dev/null +++ b/mods/screwdriver2/LICENSE.txt @@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. \ No newline at end of file diff --git a/mods/screwdriver2/README.md b/mods/screwdriver2/README.md new file mode 100644 index 0000000..4ef01a8 --- /dev/null +++ b/mods/screwdriver2/README.md @@ -0,0 +1,5 @@ +Improved node rotation tool. + +![bbcode>markdown](http://kland.smilebasicsource.com/i/kwdeu.png) + +https://forum.minetest.net/viewtopic.php?f=9&t=20856 diff --git a/mods/screwdriver2/init.lua b/mods/screwdriver2/init.lua new file mode 100644 index 0000000..9f5b4a5 --- /dev/null +++ b/mods/screwdriver2/init.lua @@ -0,0 +1,249 @@ +local S = minetest.get_translator("screwdriver2") + +if not minetest.raycast then + minetest.log("error", "screwdriver2 requires minetest version 5.0 or newer") + return +end + +screwdriver2 = {} + +local function rotate_simple(_, _, _, _, new_param2) + if new_param2 % 32 > 3 then return false end +end + +-- If the screwdriver mod is not installed, create a fake screwdriver variable. +-- (This mod has an optional dependancy on screwdriver, so minetest loads screwdriver first if it exists.) +-- - Some mods will only set on_rotate when `screwdriver` exists. +-- - Mods may expect `screwdiver` to exist if `on_rotate` is called. +if not minetest.global_exists("screwdriver") then + screwdriver = { + ROTATE_FACE = 1, + ROTATE_AXIS = 2, + rotate_simple = rotate_simple, + disallow = false, -- I doubt anyone actually used screwdriver.disallow but whatever. + } +end + +local get_pointed = dofile(minetest.get_modpath("screwdriver2").."/pointed.lua") + +-- Functions to choose rotation based on pointed location +local insanity_2 = {xy = 1, yz = 1, zx = 1; zy = -1, yx = -1, xz = -1} -- Don't worry about this +local function push_edge(normal, point) + local biggest = 0 + local biggest_axis + local normal_axis + -- Find the normal axis, and the axis of the with the + -- greatest magnitude (other than the normal axis) + for axis in pairs(point) do + if normal[axis] ~= 0 then + normal_axis = axis + elseif math.abs(point[axis])>biggest then + biggest = math.abs(point[axis]) + biggest_axis = axis + end + end + -- Find the third axis, which is the one to rotate around + if normal_axis and biggest_axis then + + for axis in pairs(point) do + if axis ~= normal_axis and axis ~= biggest_axis then + -- Decide which direction to rotate (+ or -) + return axis, insanity_2[normal_axis..biggest_axis] * math.sign(normal[normal_axis] * point[biggest_axis]) + end + end + end + return "y", 0 +end +local function rotate_face(normal, _) + -- Find the normal axis + for axis, value in pairs(normal) do + if value ~= 0 then + return axis, math.sign(value) + end + end + return "y", 0 +end + +-- Numbers taken from https://forum.minetest.net/viewtopic.php?p=73195&sid=1d2d2e4e76ce2ef9c84646481a4b84bc#p73195 +-- "How to rotate (clockwise) by axis from any facedir:" +-- "(this will be made into a lua function)" +-- 5 years later... +local facedir_cycles = { + x = {{12,13,14,15},{16,19,18,17},{ 0, 4,22, 8},{ 1, 5,23, 9},{ 2, 6,20,10},{ 3, 7,21,11}}, + y = {{ 0, 1, 2, 3},{20,23,22,21},{ 4,13,10,19},{ 8,17, 6,15},{12, 9,18, 7},{16, 5,14,11}}, + z = {{ 4, 5, 6, 7},{ 8,11,10, 9},{ 0,16,20,12},{ 1,17,21,13},{ 2,18,22,14},{ 3,19,23,15}}, +} +local wallmounted_cycles = { + x = {0, 4, 1, 5}, + y = {4, 2, 5, 3}, + z = {0, 3, 1, 2}, +} +-- Functions to rotate a facedir/wallmounted value around an axis by a certain amount +local rotate = { + -- Facedir: lower 5 bits used for direction, 0 - 23 + facedir = function(param2, axis, amount) + local facedir = param2 % 32 + for _, cycle in ipairs(facedir_cycles[axis]) do + -- Find the current facedir + -- Minetest adds table.indexof, but I refuse to use it because it returns -1 rather than nil + for i, fd in ipairs(cycle) do + if fd == facedir then + return param2 - facedir + cycle[1+(i-1 + amount) % 4] -- If only Lua didn't use 1 indexing... + end + end + end + return param2 + end, + -- Wallmounted: lower 3 bits used, 0 - 5 + wallmounted = function(param2, axis, amount) + local wallmounted = param2 % 8 + for i, wm in ipairs(wallmounted_cycles[axis]) do + if wm == wallmounted then + return param2 - wallmounted + wallmounted_cycles[axis][1+(i-1 + amount) % 4] + end + end + return param2 + end +} +rotate.colorfacedir = rotate.facedir +rotate.colorwallmounted = rotate.wallmounted +--Todo: maybe support degrotate? + +local function rect(angle, radius) + return math.cos(2*math.pi * angle) * radius, math.sin(2*math.pi * angle) * radius +end + +-- Generate the screwdriver particle effects +local other_axes = {x = {"y","z"}, y = {"z","x"}, z = {"x","y"}} +local function particle_ring(pos, axis, direction) + local axis2, axis3 = unpack(other_axes[axis]) + local particle_pos = vector.new() + local particle_vel = vector.new() + for i = 0, 0.999, 1/6 do + particle_pos[axis3], particle_pos[axis2] = rect(i, 0.5^0.5) + particle_vel[axis3], particle_vel[axis2] = rect(i - 1/4 * direction, 2) + + minetest.add_particle({ + pos = vector.add(pos, particle_pos), + velocity = particle_vel, + acceleration = vector.multiply(particle_pos, -7), + expirationtime = 0.25, + size = 2, + texture = "screwdriver2.png", + }) + -- Smaller particles that last slightly longer, to give the illusion of + -- the particles disappearing smoothly + -- ? + -- minetest.add_particle({ + -- pos = vector.add(pos, particle_pos), + -- velocity = particle_vel, + -- acceleration = vector.multiply(particle_pos, -7), + -- expirationtime = 0.3, + -- size = 1, + -- texture = "screwdriver2.png", + -- }) + end +end + +-- Main +-- Idea: split this into 2 functions +-- 1: on_use parameters -> axis/amount/etc. +-- 2: param2/axis/amount/etc. -> new param2 +function screwdriver.use(itemstack, player, pointed_thing, is_right_click) + if pointed_thing.type ~= "node" then return end + local pos = pointed_thing.under + + -- Check protection + local player_name = player:get_player_name() + if minetest.is_protected(pos, player_name) then + minetest.record_protection_violation(pos, player_name) + return + end + + -- Get node info + local node = minetest.get_node_or_nil(pos) + if not node then return end + local def = minetest.registered_nodes[node.name] + if not def then return end -- probably unnessesary + + -- Node MUST have 'rotatable' group + if not def.groups.rotatable then + return itemstack + end + + local on_rotate = def.on_rotate + if on_rotate == false then return end + --if on_rotate == nil and def.can_dig and not def.can_dig(vector.new(pos), player) then return end + + -- Choose rotation function based on paramtype2 (facedir/wallmounted) + local rotate_function = rotate[def.paramtype2] + if not rotate_function then return end + + -- Choose rotation axis/direction and param2 based on click type and pointed location + local axis, amount + local normal, point = get_pointed(player, pointed_thing) + if not normal or vector.length(normal) == 0 then return end -- Raycast failed or player is inside selection box + + local control = player:get_player_control() + if is_right_click then + axis, amount = rotate_face(normal, point) + -- This line intentionally left blank. + else + axis, amount = push_edge(normal, point) + if control.sneak then amount = -amount end + end + local new_param2 = rotate_function(node.param2, axis, amount) + + -- Calculate particle position + local particle_offset = vector.new() + particle_offset[axis] = point[axis]--math.sign(normal[axis]) * 0.5 + + -- Handle node's on_rotate function + local handled + if type(on_rotate) == "function" then + -- If a mod is loaded after screwdriver but before screwdriver2, + -- it will still end up using the old `rotate_simple` function. + -- So, we'll check that here, and override it in that case. + if on_rotate == screwdriver.rotate_simple then on_rotate = rotate_simple end + local result = on_rotate( + vector.new(pos), + table.copy(node), + player, + is_right_click and 2 or 1, -- Deprecated + new_param2, + -- New: + axis, -- "x", "y", or "z" + amount, -- 90 degrees = 1, etc. + rotate_function -- function(node.param2, axis, amount) -> new_param2 + ) + if result == false then + return + elseif result == true then + handled = true + end + end + + -- Draw particles (TODO: check if rotation was actually done) + particle_ring(vector.add(pos, particle_offset), axis, amount) + -- TODO: Play sound + + -- Replace node + if not handled then + if new_param2 == node.param2 then return end -- no rotation was done + node.param2 = new_param2 + minetest.swap_node(pos, node) + end + minetest.check_for_falling(pos) + if def._after_rotate then def._after_rotate(pos) end +end + +minetest.register_tool("screwdriver2:screwdriver",{ + description = S("Screwdriver").."\n"..S("Punch to push edge, place to rotate face"), + inventory_image = "screwdriver2.png", + on_use = function(itemstack, player, pointed_thing) + return screwdriver.use(itemstack, player, pointed_thing, false) + end, + on_place = function(itemstack, player, pointed_thing) + return screwdriver.use(itemstack, player, pointed_thing, true) + end, +}) diff --git a/mods/screwdriver2/mod.conf b/mods/screwdriver2/mod.conf new file mode 100644 index 0000000..39e3d6a --- /dev/null +++ b/mods/screwdriver2/mod.conf @@ -0,0 +1,3 @@ +name = screwdriver2 +description = A more intuitive node rotation tool. +optional_depends = screwdriver, worldedit_commands, default \ No newline at end of file diff --git a/mods/screwdriver2/pointed.lua b/mods/screwdriver2/pointed.lua new file mode 100644 index 0000000..c4eceee --- /dev/null +++ b/mods/screwdriver2/pointed.lua @@ -0,0 +1,91 @@ +-- returns function: +-- -------------------------------------------------------------------------- +-- normal, point, box_id = function(player, pointed_thing) +-- ========================================================================== +-- normal - unit vector pointing out from the face which is pointed at +-- point - point (relative to the node position) which is being pointed at +-- box_id - index of the selection box which is being pointed at +-- ========================================================================== + +-- Try to get the exact point the player is looking at. +-- There is some inaccuracy due to the client-side view bobbing animation. +-- To prevent the wrong node face from being found, it checks to make sure +-- the position returned by the raycaster matches pointed_thing. +-- If it doesn't match, the raycast is done again with slight offsets. +-- This will never return the WRONG node face, but may not be able to find the correct one in rare situations. + +local function disp(...) + for _, x in ipairs({...}) do + minetest.chat_send_all(dump(x)) + end +end + +local bob_amount = (minetest.settings:get("view_bobbing_amount") or 1) + +-- Calculate offsets for one cycle of the view bobbing animation +-- https://github.com/minetest/minetest/blob/b298b0339c79db7f5b3873e73ff9ea0130f05a8a/src/camera.cpp#L344 +local check_points = {} +for i = 0, 0.99999, 1/20 do + local bobfrac = i * 2 % 1 + local bobdir = i < 0.5 and 1 or -1 + local bobtmp = math.sin(bobfrac ^ 1.2 * math.pi) + local x = (0.3 * bobdir * math.sin(bobfrac * math.pi)) * bob_amount/10 -- Why is this divided by 10? + local y = (-0.28 * bobtmp ^ 2) * bob_amount/10 + -- I'm not exactly sure how the roll actually works, and it has a very small effect. + --local roll = -0.03 * bobdir * bobtmp * math.pi * bob_amount/10 + table.insert(check_points, { + x = x,-- * math.cos(roll) - y * math.sin(roll), + y = y,-- * math.cos(roll) - x * math.sin(roll), + -- no Z offset + }) +end + +-- Get the start and end points for the raycaster +local function get_look_dir(player) + local placer_pos = player:get_pos() + placer_pos.y = placer_pos.y + player:get_properties().eye_height + return placer_pos, vector.multiply(player:get_look_dir(), 20) +end + +local function try_raycast(pos, look_dir, pointed_thing, offset) + if offset then + --disp(offset.x .. " " .. offset.z) + pos = vector.add(pos, offset) + end + local raycast = minetest.raycast(pos, vector.add(pos, look_dir), false) + local pointed = raycast:next() + if pointed and pointed.type == "node" then + -- minetest.add_particle({ + -- pos = pointed.intersection_point, + -- expirationtime = 5, + -- size = 0.1, + -- texture = "heart.png", + -- glow = 14, + -- }) + if vector.equals(pointed.under, pointed_thing.under) and vector.equals(pointed.above, pointed_thing.above) then + return + pointed.intersection_normal, + vector.subtract(pointed.intersection_point, pointed.under), + pointed.box_id + end + end +end + +-- Get the point the player is looking at +return function(player, pointed_thing) + local pos, look_dir = get_look_dir(player) + + local pitch = player:get_look_vertical() + local yaw = player:get_look_horizontal() + --disp(angle) + for i, offset in ipairs(check_points) do + local a, b, c = try_raycast(pos, look_dir, pointed_thing, i > 1 and { -- (don't apply offset for the first check) + x = math.sin(-yaw) * math.sin(pitch) * offset.y + math.cos(yaw) * offset.x, + y = math.cos(pitch) * offset.y, + z = math.cos(-yaw) * math.sin(pitch) * offset.y + math.sin(yaw) * offset.x, + }) + if a then return a, b, c end + end + + minetest.log("warning", "Could not get pointed position") +end \ No newline at end of file diff --git a/mods/screwdriver2/textures/screwdriver2.png b/mods/screwdriver2/textures/screwdriver2.png new file mode 100644 index 0000000..10d24d6 Binary files /dev/null and b/mods/screwdriver2/textures/screwdriver2.png differ diff --git a/mods/screwdriver2/textures/screwdriver2_screw.png b/mods/screwdriver2/textures/screwdriver2_screw.png new file mode 100644 index 0000000..7ce2a22 Binary files /dev/null and b/mods/screwdriver2/textures/screwdriver2_screw.png differ