Replace screwdriver mod with screwdriver2
parent
29a8222d46
commit
78e166e14a
13
CREDITS.md
13
CREDITS.md
|
@ -6,7 +6,7 @@ External mods used:
|
||||||
|
|
||||||
* `show_wielded_item`
|
* `show_wielded_item`
|
||||||
* `no_fall_damage`
|
* `no_fall_damage`
|
||||||
* `player_api`, `xpanes`, `stairs`, `screwdriver`
|
* `player_api`, `xpanes`, `stairs`, `screwdriver2`
|
||||||
* `xdecor` (heavily modified, non-free textures removed)
|
* `xdecor` (heavily modified, non-free textures removed)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -17,6 +17,7 @@ Textures:
|
||||||
- Crosshair, wieldhand, `smoke_puff.png`: trivial textures by Wuzzy (CC0)
|
- Crosshair, wieldhand, `smoke_puff.png`: trivial textures by Wuzzy (CC0)
|
||||||
- Emitter, detector textures: Derivate works of xdecor textures by jp (CC0)
|
- Emitter, detector textures: Derivate works of xdecor textures by jp (CC0)
|
||||||
- Mirror textures: by Wuzzy (CC0)
|
- Mirror textures: by Wuzzy (CC0)
|
||||||
|
- Screwdriver texture: by 12Me21 (CC0)
|
||||||
|
|
||||||
Models:
|
Models:
|
||||||
- Player models comes from Minetest Game (see license of Minetest Game 5.4.1 for details)
|
- 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)
|
- 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/
|
- Exception 1: Ocean waves come from https://freesound.org/people/inchadney/sounds/135805/
|
||||||
- by inchadney (CC BY 3.0)
|
- by inchadney (CC BY 3.0)
|
||||||
- Excecption 2: Screwdriver sounds
|
|
||||||
- Created by InspectorJ <www.jshaw.co.uk> 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:
|
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)
|
- `xdecor` by jp (BSD-3 clause license; massively-simplified version from the original)
|
||||||
|
|
||||||
Other stuff:
|
Other stuff:
|
||||||
|
|
|
@ -105,7 +105,7 @@ local register_element = function(subname, def)
|
||||||
local def_core = table.copy(def)
|
local def_core = table.copy(def)
|
||||||
def_core.after_place_node = full_update
|
def_core.after_place_node = full_update
|
||||||
def_core.after_dig_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.sounds = lzr_sounds.node_sound_wood_defaults()
|
||||||
def_core._lzr_active = "lzr_laser:"..subname.."_on"
|
def_core._lzr_active = "lzr_laser:"..subname.."_on"
|
||||||
def_core.tiles = def.tiles_off
|
def_core.tiles = def.tiles_off
|
||||||
|
|
|
@ -75,7 +75,7 @@ end
|
||||||
local function reset_inventory(player)
|
local function reset_inventory(player)
|
||||||
clear_inventory(player)
|
clear_inventory(player)
|
||||||
local inv = player:get_inventory()
|
local inv = player:get_inventory()
|
||||||
inv:add_item("main", "screwdriver:screwdriver")
|
inv:add_item("main", "screwdriver2:screwdriver")
|
||||||
end
|
end
|
||||||
|
|
||||||
local current_level = nil
|
local current_level = nil
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
name = lzr_levels
|
name = lzr_levels
|
||||||
depends = lzr_core, lzr_mapgen, lzr_globals
|
depends = lzr_core, lzr_mapgen, lzr_globals, screwdriver2
|
||||||
|
|
|
@ -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 <www.jshaw.co.uk> 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)
|
|
|
@ -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,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
|
@ -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/
|
|
|
@ -1,2 +0,0 @@
|
||||||
name = screwdriver
|
|
||||||
description = A screwdriver allows rotating blocks
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 182 B |
|
@ -0,0 +1,13 @@
|
||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
Version 2, December 2004
|
||||||
|
|
||||||
|
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
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.
|
|
@ -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
|
|
@ -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,
|
||||||
|
})
|
|
@ -0,0 +1,3 @@
|
||||||
|
name = screwdriver2
|
||||||
|
description = A more intuitive node rotation tool.
|
||||||
|
optional_depends = screwdriver, worldedit_commands, default
|
|
@ -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
|
Binary file not shown.
After Width: | Height: | Size: 286 B |
Binary file not shown.
After Width: | Height: | Size: 273 B |
Loading…
Reference in New Issue