3 ws
.registered_globalhacks
= {}
14 local nodes_this_tick
=0
16 function ws
.s(name
,value
)
18 return ws
.c
.settings
:get(name
)
20 ws
.c
.settings
:set(name
,value
)
21 return ws
.c
.settings
:get(name
)
24 function ws
.sb(name
,value
)
26 return ws
.c
.settings
:get_bool(name
)
28 ws
.c
.settings
:set_bool(name
,value
)
29 return ws
.c
.settings
:get_bool(name
)
34 return minetest
.display_chat_message(msg
)
36 function ws
.set_bool_bulk(settings
,value
)
37 if type(settings
) ~= 'table' then return false end
38 for k
,v
in pairs(settings
) do
39 minetest
.settings
:set_bool(v
,value
)
44 function ws
.shuffle(tbl
)
45 for i
= #tbl
, 2, -1 do
46 local j
= math
.random(i
)
47 tbl
[i
], tbl
[j
] = tbl
[j
], tbl
[i
]
52 function ws
.in_list(val
, list
)
53 if type(list
) ~= "table" then return false end
54 for i
, v
in pairs(list
) do
62 function ws
.random_table_element(tbl
)
64 for k
in pairs(tbl
) do
67 return tbl
[ks
[math
.random(#ks
)]]
71 --local lp=ws.dircoord(0,0,0)
72 --minetest.localplayer:set_pos(lp)
75 function ws
.globalhacktemplate(setting
,func
,funcstart
,funcstop
,daughters
,delay
)
76 funcstart
= funcstart
or function() end
77 funcstop
= funcstop
or function() end
80 if not minetest
.localplayer
then return end
81 if minetest
.settings
:get_bool(setting
) then
82 if tps_client
and tps_client
.ping
and tps_client
.ping
> 1000 then return end
84 if nextact
[setting
] and nextact
[setting
] > os
.clock() then return end
85 nextact
[setting
] = os
.clock() + delay
86 if not ghwason
[setting
] then
87 if not funcstart() then
88 ws
.set_bool_bulk(daughters
,true)
89 ghwason
[setting
] = true
90 --ws.dcm(setting.. " activated")
92 minetest
.settings
:set('last-dir',ws
.getdir())
93 minetest
.settings
:set('last-y',ws
.dircoord(0,0,0).y
)
94 else minetest
.settings
:set_bool(setting
,false)
100 elseif ghwason
[setting
] then
101 ghwason
[setting
] = false
102 ws
.set_bool_bulk(daughters
,false)
104 --ws.dcm(setting.. " deactivated")
109 function ws
.register_globalhack(func
)
110 table.insert(ws
.registered_globalhacks
,func
)
113 function ws
.register_globalhacktemplate(name
,category
,setting
,func
,funcstart
,funcstop
,daughters
)
114 ws
.register_globalhack(ws
.globalhacktemplate(setting
,func
,funcstart
,funcstop
,daughters
))
115 minetest
.register_cheat(name
,category
,setting
)
118 ws
.rg
=ws
.register_globalhacktemplate
120 function ws
.step_globalhacks(dtime
)
121 for i
, v
in ipairs(ws
.registered_globalhacks
) do
126 minetest
.register_globalstep(function(dtime
) ws
.step_globalhacks(dtime
) end)
127 minetest
.settings
:set_bool('continuous_forward',false)
128 function ws
.on_connect(func
)
129 if not minetest
.localplayer
then minetest
.after(0,function() ws
.on_connect(func
) end) return end
130 if func
then func() end
133 ws
.on_connect(function()
134 local ldir
=minetest
.settings
:get('last-dir')
135 if ldir
then ws
.setdir(ldir
) end
141 function ws
.is_same_pos(pos1
,pos2
)
142 return vector
.distance(vector
.round(pos1
),vector
.round(pos2
)) == 0
144 function ws
.get_reachable_positions(range
,under
)
148 local lp
=minetest
.localplayer
:get_pos()
150 if under
then ylim
=-1 end
151 for x
= -range
,range
,1 do
152 for y
= -range
,ylim
,1 do
153 for z
= -range
,range
,1 do
154 table.insert(rt
,vector
.add(lp
,vector
.new(x
,y
,z
)))
161 function ws
.do_area(radius
,func
,plane
)
162 for k
,v
in pairs(ws
.get_reachable_positions(range
)) do
163 if not plane
or v
.y
== minetest
.localplayer
:get_pos().y
-1 then
169 function ws
.get_hud_by_texture(texture
)
174 def
= minetest
.localplayer
:hud_get(i
)
175 until not def
or def
.text
== texture
184 function ws
.display_wp(pos
,name
)
185 local ix
= #ws
.displayed_wps
+ 1
186 ws
.displayed_wps
[ix
] = minetest
.localplayer
:hud_add({
187 hud_elem_type
= 'waypoint',
196 function ws
.clear_wp(ix
)
197 table.remove(ws
.displayed_wps
,ix
)
200 function ws
.clear_wps()
201 for k
,v
in ipairs(ws
.displayed_wps
) do
202 minetest
.localplayer
:hud_remove(v
)
203 table.remove(ws
.displayed_wps
,k
)
207 function ws
.register_chatcommand_alias(old
, ...)
208 local def
= assert(minetest
.registered_chatcommands
[old
])
210 for i
= 1, select('#', ...) do
211 minetest
.register_chatcommand(select(i
, ...), table.copy(def
))
215 function ws
.round2(num
, numDecimalPlaces
)
216 return tonumber(string.format("%." .. (numDecimalPlaces
or 0) .. "f", num
))
219 function ws
.pos_to_string(pos
)
220 if type(pos
) == 'table' then
221 pos
= minetest
.pos_to_string(vector
.round(pos
))
223 if type(pos
) == 'string' then
229 function ws
.string_to_pos(pos
)
230 if type(pos
) == 'string' then
231 pos
= minetest
.string_to_pos(pos
)
233 if type(pos
) == 'table' then
234 return vector
.round(pos
)
242 function ws
.find_item_in_table(items
,rnd
)
243 if type(items
) == 'string' then
244 return minetest
.find_item(items
)
246 if type(items
) ~= 'table' then return end
247 if rnd
then items
=ws
.shuffle(items
) end
248 for i
, v
in pairs(items
) do
249 local n
= minetest
.find_item(v
)
257 function ws
.find_empty(inv
)
258 for i
, v
in ipairs(inv
) do
266 function ws
.find_named(inv
, name
)
267 if not inv
then return -1 end
268 if not name
then return end
269 for i
, v
in ipairs(inv
) do
270 if v
:get_name():find(name
) then
276 function ws
.itemnameformat(description
)
277 description
= description
:gsub(string.char(0x1b) .. "%(.@[^)]+%)", "")
278 description
= description
:match("([^\n]*)")
282 function ws
.find_nametagged(list
, name
)
283 for i
, v
in ipairs(list
) do
284 if ws
.itemnameformat(v
:get_description()) == name
then
291 function ws
.to_hotbar(it
,hslot
)
293 local plinv
= minetest
.get_inventory("current_player")
294 if hslot
and hslot
< 10 then
297 for i
, v
in ipairs(plinv
.main
) do
298 if i
<10 and v
:is_empty() then
304 if tpos
== nil then tpos
=hotbar_slot
end
305 local mv
= InventoryAction("move")
306 mv
:from("current_player", "main", it
)
307 mv
:to("current_player", "main", tpos
)
312 function ws
.switch_to_item(itname
,hslot
)
313 if not minetest
.localplayer
then return false end
314 local plinv
= minetest
.get_inventory("current_player")
315 for i
, v
in ipairs(plinv
.main
) do
316 if i
<10 and v
:get_name() == itname
then
317 minetest
.localplayer
:set_wield_index(i
)
321 local pos
= ws
.find_named(plinv
.main
, itname
)
323 minetest
.localplayer
:set_wield_index(ws
.to_hotbar(pos
,hslot
))
328 function ws
.in_inv(itname
)
329 if not minetest
.localplayer
then return false end
330 local plinv
= minetest
.get_inventory("current_player")
331 local pos
= ws
.find_named(plinv
.main
, itname
)
337 function core
.switch_to_item(item
) return ws
.switch_to_item(item
) end
339 function ws
.switch_inv_or_echest(name
,max_count
,hslot
)
340 if not minetest
.localplayer
then return false end
341 local plinv
= minetest
.get_inventory("current_player")
342 if ws
.switch_to_item(name
) then return true end
344 local epos
= ws
.find_named(plinv
.enderchest
, name
)
347 for i
, v
in ipairs(plinv
.main
) do
348 if i
< 9 and v
:is_empty() then
353 if not tpos
then tpos
=hotbar_slot
end
356 local mv
= InventoryAction("move")
357 mv
:from("current_player", "enderchest", epos
)
358 mv
:to("current_player", "main", tpos
)
360 mv
:set_count(max_count
)
363 minetest
.localplayer
:set_wield_index(tpos
)
370 local function posround(n
)
371 return math
.floor(n
+ 0.5)
374 local function fmt(c
)
375 return tostring(posround(c
.x
))..","..tostring(posround(c
.y
))..","..tostring(posround(c
.z
))
378 local function map_pos(value
)
382 return {x
= value
[1], y
= value
[2], z
= value
[3]}
386 function ws
.invparse(location
)
387 if type(location
) == "string" then
388 if string.match(location
, "^[-]?[0-9]+,[-]?[0-9]+,[-]?[0-9]+$") then
389 return "nodemeta:" .. location
393 elseif type(location
) == "table" then
394 return "nodemeta:" .. fmt(map_pos(location
))
398 function ws
.invpos(p
)
399 return "nodemeta:"..p
.x
..","..p
.y
..","..p
.z
406 local function check_tool(stack
, node_groups
, old_best_time
)
407 local toolcaps
= stack
:get_tool_capabilities()
408 if not toolcaps
then return end
409 local best_time
= old_best_time
410 for group
, groupdef
in pairs(toolcaps
.groupcaps
) do
411 local level
= node_groups
[group
]
413 local this_time
= groupdef
.times
[level
]
414 if this_time
and this_time
< best_time
then
415 best_time
= this_time
419 return best_time
< old_best_time
, best_time
422 local function find_best_tool(nodename
, switch
)
423 local player
= minetest
.localplayer
424 local inventory
= minetest
.get_inventory("current_player")
425 local node_groups
= minetest
.get_node_def(nodename
).groups
426 local new_index
= player
:get_wield_index()
427 local is_better
, best_time
= false, math
.huge
429 is_better
, best_time
= check_tool(player
:get_wielded_item(), node_groups
, best_time
)
430 if inventory
.hand
then
431 is_better
, best_time
= check_tool(inventory
.hand
[1], node_groups
, best_time
)
434 for index
, stack
in ipairs(inventory
.main
) do
435 is_better
, best_time
= check_tool(stack
, node_groups
, best_time
)
441 return new_index
,best_time
444 function ws
.get_digtime(nodename
)
445 local idx
,tm
=find_best_tool(nodename
)
449 function ws
.select_best_tool(pos
)
450 local nd
=minetest
.get_node_or_nil(pos
)
452 if nd
then nodename
=nd
.name
end
453 local t
=find_best_tool(nodename
)
454 minetest
.localplayer
:set_wield_index(ws
.to_hotbar(t
,hotbar_slot
))
455 --minetest.localplayer:set_wield_index(find_best_tool(nodename))
459 function ws
.coord(x
, y
, z
)
460 return vector
.new(x
,y
,z
)
462 function ws
.ordercoord(c
)
464 return {x
= c
[1], y
= c
[2], z
= c
[3]}
470 -- x or {x,y,z} or {x=x,y=y,z=z}
471 function ws
.optcoord(x
, y
, z
)
473 return ws
.coord(x
, y
, z
)
475 return ws
.ordercoord(x
)
478 function ws
.cadd(c1
, c2
)
479 return vector
.add(c1
,c2
)
480 --return ws.coord(c1.x + c2.x, c1.y + c2.y, c1.z + c2.z)
483 function ws
.relcoord(x
, y
, z
, rpos
)
484 local pos
= rpos
or minetest
.localplayer
:get_pos()
485 pos
.y
=math
.ceil(pos
.y
)
486 --math.floor(pos.y) + 0.5
487 return ws
.cadd(pos
, ws
.optcoord(x
, y
, z
))
490 local function between(x
, y
, z
) -- x is between y and z (inclusive)
491 return y
<= x
and x
<= z
494 function ws
.getdir(yaw
) --
495 local rot
= yaw
or minetest
.localplayer
:get_yaw() % 360
496 if between(rot
, 315, 360) or between(rot
, 0, 45) then
498 elseif between(rot
, 135, 225) then
500 elseif between(rot
, 225, 315) then
502 elseif between(rot
, 45, 135) then
507 function ws
.getaxis()
508 local dir
=ws
.getdir()
509 if dir
== "north" or dir
== "south" then return "z" end
512 function ws
.setdir(dir
) --
513 if dir
== "north" then
514 minetest
.localplayer
:set_yaw(0)
515 elseif dir
== "south" then
516 minetest
.localplayer
:set_yaw(180)
517 elseif dir
== "east" then
518 minetest
.localplayer
:set_yaw(270)
519 elseif dir
== "west" then
520 minetest
.localplayer
:set_yaw(90)
524 function ws
.dircoord(f
, y
, r
,rpos
, rdir
)
525 local dir
= ws
.getdir(rdir
)
526 local coord
= ws
.optcoord(f
, y
, r
)
530 local lp
= rpos
or minetest
.localplayer
:get_pos()
531 if dir
== "north" then
532 return ws
.relcoord(r
, y
, f
,rpos
)
533 elseif dir
== "south" then
534 return ws
.relcoord(-r
, y
, -f
,rpos
)
535 elseif dir
== "east" then
536 return ws
.relcoord(f
, y
, -r
,rpos
)
537 elseif dir
== "west" then
538 return ws
.relcoord(-f
, y
, r
,rpos
)
540 return ws
.relcoord(0, 0, 0,rpos
)
543 function ws
.get_dimension(pos
)
544 if pos
.y
> -65 then return "overworld"
545 elseif pos
.y
> -8000 then return "void"
546 elseif pos
.y
> -27000 then return "end"
547 elseif pos
.y
> -28930 then return "void"
548 elseif pos
.y
> -31000 then return "nether"
553 function ws
.aim(tpos
)
554 local ppos
=minetest
.localplayer
:get_pos()
555 local dir
=vector
.direction(ppos
,tpos
)
559 yyaw
= math
.atan2(-dir
.x
, dir
.z
) + (math
.pi
* 2)
561 yyaw
= math
.atan2(-dir
.x
, dir
.z
)
563 yyaw
= ws
.round2(math
.deg(yyaw
),2)
564 pitch
= ws
.round2(math
.deg(math
.asin(-dir
.y
) * 1),2);
565 minetest
.localplayer
:set_yaw(yyaw
)
566 minetest
.localplayer
:set_pitch(pitch
)
569 function ws
.gaim(tpos
,v
,g
)
572 local ppos
=minetest
.localplayer
:get_pos()
573 local dir
=vector
.direction(ppos
,tpos
)
577 yyaw
= math
.atan2(-dir
.x
, dir
.z
) + (math
.pi
* 2)
579 yyaw
= math
.atan2(-dir
.x
, dir
.z
)
581 yyaw
= ws
.round2(math
.deg(yyaw
),2)
584 local x
= vector
.length(dir
)
585 pitch
=math
.atan(math
.pow(v
, 2) / (g
* x
) + math
.sqrt(math
.pow(v
, 4)/(math
.pow(g
, 2) * math
.pow(x
, 2)) - 2 * math
.pow(v
, 2) * y
/(g
* math
.pow(x
, 2)) - 1))
586 --pitch = ws.round2(math.deg(math.asin(-dir.y) * 1),2);
587 minetest
.localplayer
:set_yaw(yyaw
)
588 minetest
.localplayer
:set_pitch(math
.deg(pitch
))
591 local function tablearg(arg
)
593 if type(arg
) == 'string' then
595 elseif type(arg
) == 'table' then
597 elseif type(arg
) == 'function' then
603 function ws
.isnode(pos
,arg
)--arg is either an itemstring, a table of itemstrings or a function returning an itemstring
604 local nodename
=tablearg(arg
)
605 local nd
=minetest
.get_node_or_nil(pos
)
606 if nd
and nodename
and ws
.in_list(nd
.name
,nodename
) then
611 function ws
.can_place_at(pos
)
612 local node
= minetest
.get_node_or_nil(pos
)
613 return (node
and (node
.name
== "air" or node
.name
=="mcl_core:water_source" or node
.name
=="mcl_core:water_flowing" or node
.name
=="mcl_core:lava_source" or node
.name
=="mcl_core:lava_flowing" or minetest
.get_node_def(node
.name
).buildable_to
))
616 -- should check if wield is placeable
617 -- minetest.get_node(wielded:get_name()) ~= nil should probably work
618 -- otherwise it equips armor and eats food
619 function ws
.can_place_wielded_at(pos
)
620 local wield_empty
= minetest
.localplayer
:get_wielded_item():is_empty()
621 return not wield_empty
and ws
.can_place_at(pos
)
625 function ws
.find_any_swap(items
,hslot
)
627 for i
, v
in ipairs(items
) do
628 local n
= minetest
.find_item(v
)
630 ws
.switch_to_item(v
,hslot
)
638 -- swaps to any of the items and places if need be
639 -- returns true if placed and in inventory or already there, false otherwise
645 function ws
.place(pos
,items
,hslot
, place
)
646 --if nodes_this_tick > 8 then return end
647 --nodes_this_tick = nodes_this_tick + 1
648 --if not inside_constraints(pos) then return end
649 if not pos
then return end
650 items
=tablearg(items
)
652 place
= place
or minetest
.place_node
654 local node
= minetest
.get_node_or_nil(pos
)
655 if not node
then return end
657 if ws
.isnode(pos
,items
) then
660 local swapped
= ws
.find_any_swap(items
,hslot
)
663 if swapped
and ws
.can_place_at(pos
) then
664 --minetest.after("0.05",place,pos)
674 function ws
.place_if_able(pos
)
675 if not pos
then return end
676 if not inside_constraints(pos
) then return end
677 if ws
.can_place_wielded_at(pos
) then
678 minetest
.place_node(pos
)
682 function ws
.is_diggable(pos
)
683 if not pos
then return false end
684 local nd
=minetest
.get_node_or_nil(pos
)
685 if not nd
then return false end
686 local n
= minetest
.get_node_def(nd
.name
)
687 if n
and n
.diggable
then return true end
691 function ws
.dig(pos
,condition
,autotool
)
692 --if not inside_constraints(pos) then return end
693 if autotool
== nil then autotool
= true end
694 if condition
and not condition(pos
) then return false end
695 if not ws
.is_diggable(pos
) then return end
696 local nd
=minetest
.get_node_or_nil(pos
)
697 if nd
and minetest
.get_node_def(nd
.name
).diggable
then
698 if autotool
then ws
.select_best_tool(pos
) end
699 minetest
.dig_node(pos
)
704 function ws
.chunk_loaded()
705 local ign
=minetest
.find_nodes_near(ws
.dircoord(0,0,0),10,{'ignore'},true)
706 if #ign
== 0 then return true end
710 function ws
.get_near(nodes
,range
)
712 local nds
=minetest
.find_nodes_near(ws
.dircoord(0,0,0),rang
,nodes
,true)
713 if #nds
> 0 then return nds
end
717 function ws
.is_laggy()
718 if tps_client
and tps_client
.ping
and tps_client
.ping
> 1000 then return true end
722 function ws
.donodes(poss
,func
,condition
)
723 if ws
.is_laggy() then return end
725 for k
,v
in pairs(poss
) do
726 local nd
=minetest
.get_node_or_nil(v
)
727 if nd
and nd
.name
~= 'air' then
731 if condition
== nil or condition(v
) then
739 function ws
.dignodes(poss
,condition
)
740 local func
=function(p
) ws
.dig(p
) end
741 ws
.donodes(poss
,func
,condition
)
745 function ws
.replace(pos
,arg
)
747 local nd
=minetest
.get_node_or_nil(pos
)
748 if nd
and not ws
.in_list(nd
.name
,arg
) and nd
.name
~= 'air' then
749 local tm
=ws
.get_digtime(nd
.name
) or 0
751 minetest
.after(tm
+ 0.1,function()
759 function ws
.playeron(p
)
760 local pls
=minetest
.get_player_names()
761 for k
,v
in pairs(pls
) do
762 if v
== p
then return true end
768 function ws
.between(x
, y
, z
) -- x is between y and z (inclusive)
769 return y
<= x
and x
<= z
773 local wall_pos1
={x
=-1255,y
=6,z
=792}
774 local wall_pos2
={x
=-1452,y
=80,z
=981}
775 local iwall_pos1
={x
=-1266,y
=6,z
=802}
776 local iwall_pos2
={x
=-1442,y
=80,z
=971}
778 function ws
.in_cube(tpos
,wpos1
,wpos2
)
787 if wpos1
.x
> wpos2
.x
then
791 if wpos1
.y
> wpos2
.y
then
795 if wpos1
.z
> wpos2
.z
then
799 if ws
.between(tpos
.x
,xmin
,xmax
) and ws
.between(tpos
.y
,ymin
,ymax
) and ws
.between(tpos
.z
,zmin
,zmax
) then
805 function ws
.in_wall(pos
)
806 if ws
.in_cube(pos
,wall_pos1
,wall_pos2
) and not in_cube(pos
,iwall_pos1
,iwall_pos2
) then
811 function ws
.inside_wall(pos
)
814 if ws
.in_cube(pos
,p1
,p2
) then return true end
820 local function printwieldedmeta()
821 ws
.dcm(dump(minetest
.localplayer
:get_wielded_item():get_meta():to_table()))
823 minetest
.register_cheat('ItemMeta','Test',printwieldedmeta
)