autofly: cleanup
[waspsaliva.git] / clientmods / autofly / init.lua
blob418e6a937c95e054d504e3b2a345253c3e8b8f78
1 -- autofly by cora
2 -- gui shit shamelessly stolen from advmarkers
3 -- https://git.minetest.land/luk3yx/advmarkers-csm
4 --[[
5 PATCHING MINETEST: (for autoaim)
6 in l_localplayer.h add:
7 static int l_set_yaw(lua_State *L);
8 static int l_set_pitch(lua_State *L);
10 in l_localplayer.cpp add:
11 int LuaLocalPlayer::l_set_yaw(lua_State *L)
13 LocalPlayer *player = getobject(L, 1);
14 f32 p = (float) luaL_checkinteger(L, 2);
15 player->setYaw(p);
16 g_game->cam_view.camera_yaw = p;
17 g_game->cam_view_target.camera_yaw = p;
18 player->setYaw(p);
19 return 0;
21 int LuaLocalPlayer::l_set_pitch(lua_State *L)
23 LocalPlayer *player = getobject(L, 1);
24 f32 p = (float) luaL_checkinteger(L, 2);
25 player->setPitch(p);
26 g_game->cam_view.camera_pitch = p;
27 g_game->cam_view_target.camera_pitch = p;
28 player->setPitch(p);
29 return 0;
31 in src/client/game.h, below class Game { public: add:
32 CameraOrientation cam_view = {0};
33 CameraOrientation cam_view_target = { 0 };
35 from src/client/game.cpp remove
36 CameraOrientation cam_view = {0};
37 CameraOrientation cam_view_target = { 0 };
39 --]]
41 -- Chat commands:
42 -- .wa x,y,z name - add waypoint with coords and name
43 -- .wah - quickadd this location (name will be time and date)
44 -- .wp - open the selection menu
45 -- .cls - remove hud
47 autofly = {}
48 wps={}
51 local landing_distance=5
52 local speed=0;
53 local ltime=0
55 local storage = minetest.get_mod_storage()
56 local oldpm=false
57 local lpos={x=0,y=0,z=0}
58 local info=minetest.get_server_info()
59 local stprefix="autofly-".. info['address'] .. '-'
60 local hud_wps={}
61 autofly.flying=false
62 autofly.cruiseheight = 30
64 local modname = minetest.get_current_modname()
65 local modpath = minetest.get_modpath(modname)
66 dofile(modpath .. "/wpforms.lua")
67 dofile(modpath .. "/pathfly.lua")
69 local hud_wp
70 local hud_info
71 -- /COMMON
72 local pos_to_string = ws.pos_to_string
73 local string_to_pos = ws.string_to_pos
74 local round2 = ws.round2
77 function autofly.get2ddst(pos1,pos2)
78 return vector.distance({x=pos1.x,y=0,z=pos1.z},{x=pos2.x,y=0,z=pos2.z})
79 end
81 local last_sprint = false
83 minetest.register_globalstep(function()
84 if not minetest.localplayer then return end
85 autofly.axissnap()
86 if minetest.settings:get_bool("autosprint") or (minetest.settings:get_bool("continuous_forward") and minetest.settings:get_bool("autofsprint")) then
87 core.set_keypress("special1", true)
88 last_sprint = true
89 elseif last_sprint then
90 core.set_keypress("special1", false)
91 last_sprint = false
92 end
93 if not autofly.flying then autofly.set_hud_info("")
94 else
95 autofly.set_hud_info("")
96 local pos = autofly.last_coords
97 if pos then
98 local dst = vector.distance(pos,minetest.localplayer:get_pos())
99 local etatime=-1
100 if not (speed == 0) then etatime = round2(dst / speed / 60,2) end
101 autofly.etatime=etatime
102 autofly.set_hud_info(autofly.last_name .. "\n" .. pos_to_string(pos) .. "\n" .. "ETA" .. etatime .. " mins")
103 local hdst=autofly.get2ddst(pos,minetest.localplayer:get_pos())
104 if autofly.flying and hdst < landing_distance then
105 autofly.arrived()
110 if not minetest.settings:get_bool("freecam") and autofly.flying and (minetest.settings:get_bool('afly_autoaim')) then
111 autofly.aim(autofly.last_coords)
114 if ( os.time() < ltime + 1 ) then return end
115 ltime=os.time()
116 if lpos then
117 local dst=vector.distance(minetest.localplayer:get_pos(),lpos)
118 speed=round2(dst,1)
119 autofly.speed=speed
121 lpos=minetest.localplayer:get_pos()
122 autofly.cruise()
123 end)
126 function autofly.set_hud_wp(pos, title)
127 if hud_wp then
128 minetest.localplayer:hud_remove(hud_wp)
130 pos = string_to_pos(pos)
131 hud_wp=nil
132 if not pos then return end
133 if not title then
134 title = pos.x .. ', ' .. pos.y .. ', ' .. pos.z
136 autofly.last_name=title
137 if hud_wp then
138 minetest.localplayer:hud_change(hud_wp, 'name', title)
139 minetest.localplayer:hud_change(hud_wp, 'world_pos', pos)
140 else
141 hud_wp = minetest.localplayer:hud_add({
142 hud_elem_type = 'waypoint',
143 name = title,
144 text = 'm',
145 number = 0x00ff00,
146 world_pos = pos
149 return true
152 local hud_info
153 function autofly.get_quad()
154 local lp=minetest.localplayer:get_pos()
155 local quad=""
157 if lp.z < 0 then quad="Q: South"
158 else quad="Q: North" end
160 if lp.x < 0 then quad=quad.."-west"
161 else quad=quad.."-east" end
163 return quad
166 function autofly.get_local_name()
167 local ww=autofly.getwps()
168 local lp=minetest.localplayer:get_pos()
169 local odst=500;
170 local rt=false
171 for k,v in pairs(ww) do
172 local lwp=autofly.get_waypoint(v)
173 if type(lwp) == 'table' then
174 local dst=vector.distance(lp,lwp)
175 if dst < 500 then
176 if dst < odst then
177 odst=dst
178 rt=v
183 if not rt then rt=autofly.get_quad() end
184 return rt
188 function autofly.set_hud_info(text)
189 if not minetest.localplayer then return end
190 if type(text) ~= "string" then return end
191 local lp=minetest.localplayer
192 local vspeed=lp:get_velocity()
193 local ttext=text.."\nSpeed: "..speed.."n/s\n"
194 ..round2(vspeed.x,2) ..','
195 ..round2(vspeed.y,2) ..','
196 ..round2(vspeed.z,2) .."\n"
197 .."Yaw:"..round2(lp:get_yaw(),2).."° Pitch:" ..round2(lp:get_pitch(),2).."° "
198 if turtle then ttext=ttext..turtle.getdir() end
199 if minetest.settings:get_bool('afly_shownames') then
200 ttext=ttext.."\n"..autofly.get_local_name()
202 if hud_info then
203 minetest.localplayer:hud_change(hud_info,'text',ttext)
204 else
205 hud_info = minetest.localplayer:hud_add({
206 hud_elem_type = 'text',
207 name = "Flight Info",
208 text = ttext,
209 number = 0x00ff00,
210 direction = 0,
211 position = {x=0,y=0.8},
212 alignment ={x=1,y=1},
213 offset = {x=0, y=0}
216 return true
219 function autofly.display(pos,name)
220 if name == nil then name=pos_to_string(pos) end
221 local pos=string_to_pos(pos)
222 autofly.set_hud_wp(pos, name)
223 return true
227 function autofly.display_waypoint(name)
228 local pos=name
229 if type(name) ~= 'table' then pos=autofly.get_waypoint(name) end
230 autofly.last_name = name
231 --autofly.last_coords = pos
232 autofly.set_hud_info(name)
233 autofly.aim(autofly.last_coords)
234 autofly.display(pos,name)
235 return true
238 function autofly.goto_waypoint(name)
239 local wp=autofly.get_waypoint(name)
240 autofly.goto(wp)
241 autofly.last_name=name
242 autofly.display_waypoint(autofly.last_name)
243 return true
246 function autofly.goto(pos)
247 oldpm=minetest.settings:get_bool("pitch_move")
248 minetest.settings:set_bool("pitch_move",true)
249 minetest.settings:set_bool("free_move",true)
250 minetest.settings:set_bool("continuous_forward",true)
251 if minetest.settings:get_bool("afly_sprint") then
252 minetest.settings:set_bool("autofsprint",true)
253 minetest.settings:set_bool("autoeat_timed",true)
255 minetest.settings:set_bool("afly_autoaim",true)
256 autofly.last_coords = pos
257 autofly.last_name = minetest.pos_to_string(pos)
258 autofly.aim(autofly.last_coords)
259 autofly.flying=true
260 autofly.set_hud_wp(autofly.last_coords, autofly.last_name)
261 return true
264 function autofly.arrived()
265 if not autofly.flying then return end
266 minetest.settings:set("continuous_forward", "false")
267 minetest.settings:set_bool("autofsprint",false)
268 minetest.settings:set_bool("pitch_move",oldpm)
269 minetest.settings:set_bool("afly_autoaim",false)
270 minetest.settings:set_bool("autoeat_timed",false)
271 autofly.set_hud_info("Arrived!")
272 autofly.flying = false
273 minetest.sound_play({name = "default_alert", gain = 1.0})
276 local cruise_wason=false
277 local nfctr=0
280 function autofly.cruise()
281 if not minetest.settings:get_bool('afly_cruise') then
282 if cruise_wason then
283 cruise_wason=false
284 core.set_keypress("jump",false)
285 core.set_keypress("sneak",false)
287 return end
289 local lp=minetest.localplayer:get_pos()
290 local pos1 = vector.add(lp,{x=16,y=100,z=16})
291 local pos2 = vector.add(lp,{x=-16,y=-100,z=-16})
292 local nds=minetest.find_nodes_in_area_under_air(pos1, pos2, nlist.get_mclnodes())
293 local y=0
294 local found=false
297 for k,v in ipairs(nds) do
298 local nd = minetest.get_node_or_nil(v)
299 if nd ~= nil and nd.name ~= "air" then
300 if v.y > y then
301 y=v.y
302 found=true
306 if (autofly.cruiseheight ~= nil) then y=y+autofly.cruiseheight end
307 local diff = math.ceil(lp.y - y)
309 if not cruise_wason then --initially set the cruiseheight to the current value above ground
310 -- if not found then return end --wait with activation til a ground node has been found.
311 local clr,nnd=minetest.line_of_sight(lp,vector.add(lp,{x=1,y=-200,z=1}))
312 if not clr then diff = math.ceil(lp.y - nnd.y)
313 elseif not found then return end
314 if diff < 1 then autofly.cruiseheight = 20
315 else autofly.cruiseheight = diff end
317 cruise_wason=true
318 minetest.display_chat_message("cruise mode activated. target height set to " .. diff .. " nodes above ground.")
321 if not found then
322 if nfctr<20 then nfctr = nfctr + 1 return end
323 --minetest.display_chat_message("no nodes found for 20 iterations. lowering altitude.")
324 nfctr=0
325 minetest.settings:set_bool("free_move",false)
326 core.set_keypress("jump",false)
327 core.set_keypress("sneak",false)
328 return
331 local tolerance = 1
332 if diff < -tolerance then
333 minetest.settings:set_bool("free_move",true)
334 core.set_keypress("jump",true)
335 core.set_keypress("sneak",false)
336 --minetest.display_chat_message("too low: " .. y)
337 elseif diff > tolerance * 10 then
338 core.set_keypress("jump",false)
339 core.set_keypress("sneak",true)
340 minetest.settings:set_bool("free_move",false)
341 --minetest.display_chat_message("too high: " .. y)
342 elseif diff > tolerance then
343 core.set_keypress("jump",false)
344 core.set_keypress("sneak",true)
345 else
346 minetest.settings:set_bool("free_move",true)
347 core.set_keypress("jump",false)
348 core.set_keypress("sneak",false)
349 --minetest.display_chat_message("target height reached: " .. y)
355 function autofly.aim(tpos)
356 local ppos=minetest.localplayer:get_pos()
357 --local dir=tpos
358 local dir=vector.direction(ppos,tpos)
359 local yyaw=0;
360 local pitch=0;
361 if dir.x < 0 then
362 yyaw = math.atan2(-dir.x, dir.z) + (math.pi * 2)
363 else
364 yyaw = math.atan2(-dir.x, dir.z)
366 yyaw = round2(math.deg(yyaw),2)
367 pitch = round2(math.deg(math.asin(-dir.y) * 1),2);
368 minetest.localplayer:set_yaw(yyaw)
369 minetest.localplayer:set_pitch(pitch)
373 function autofly.autotp(tpname)
374 if minetest.localplayer == nil then autofly.autotp(tpname) end
375 local tpos=nil
376 if tpname == nil then
377 tpos = autofly.get_waypoint('AUTOTP')
378 elseif type(tpname) == "table" then
379 tpos = tpname
380 else
381 tpos=autofly.get_waypoint(tpname)
383 if tpos == nil then return end
384 local lp=minetest.localplayer
385 local dst=vector.distance(lp:get_pos(),tpos)
386 if (dst < 300) then
387 minetest.sound_play({name = "default_alert", gain = 3.0})
388 autofly.delete_waypoint('AUTOTP')
389 return true
391 autofly.set_waypoint(tpos,'AUTOTP')
392 local boat_found=false
393 for k, v in ipairs(lp.get_nearby_objects(4)) do
394 local txt = v:get_item_textures()
395 if ( txt:find('mcl_boats_texture')) then
396 boat_found=true
397 minetest.display_chat_message("boat found. entering and tping to "..minetest.pos_to_string(autofly.get_waypoint('AUTOTP')))
398 autofly.aim(vector.add(v:get_pos(),{x=0,y=-1.5,z=0}))
399 minetest.after("0.2",function()
400 minetest.interact("place") end)
401 minetest.after("1.5",function()
402 autofly.warpae('AUTOTP')
403 end)
404 return true
407 if not boat_found then
408 minetest.display_chat_message("no boat found. trying again in 5.")
409 minetest.after("5.0",function() autofly.autotp(tpname) end)
410 return end
415 autofly.register_transport('Fly',function(pos,name) autofly.goto_waypoint(name) end)
416 autofly.register_transport('wrp',function(pos,name) autofly.warp(name) end)
417 autofly.register_transport('atp',function(pos,name) autofly.autotp(name) end)
419 function autofly.axissnap()
420 if not minetest.settings:get_bool('afly_snap') then return end
421 if minetest.settings:get_bool("freecam") then return end
422 local y=minetest.localplayer:get_yaw()
423 local yy=nil
424 if ( y < 45 or y > 315 ) then
425 yy=0
426 elseif (y < 135) then
427 yy=90
428 elseif (y < 225 ) then
429 yy=180
430 elseif ( y < 315 ) then
431 yy=270
433 if yy ~= nil then
434 minetest.localplayer:set_yaw(yy)
438 minetest.register_on_death(function()
439 if minetest.localplayer then
440 local name = 'Death waypoint'
441 local pos = minetest.localplayer:get_pos()
442 autofly.last_coords = pos
443 autofly.last_name = name
444 autofly.set_waypoint(pos,name)
445 autofly.display(pos,name)
447 end)
449 local function get_dimension(pos)
450 if pos.y > -65 then return "overworld"
451 elseif pos.y > -8000 then return "void"
452 elseif pos.y > -27000 then return "end"
453 elseif pos.y >29000 then return "void"
454 elseif pos.y >31000 then return "nether"
455 else return "void"
459 function autofly.warp(name)
460 local pos=autofly.get_waypoint(name)
461 if pos then
462 if pos.y > -64 then
463 pos=vector.add(pos,{x=0,y=150,z=0})
465 if get_dimension(pos) == "void" then return false end
466 minetest.localplayer:set_pos(pos)
467 return true
470 function autofly.warpae(name)
471 local s, m = autofly.warp(name)
472 if s then
473 minetest.disconnect()
475 return true
478 function autofly.getwps()
479 local wp={}
480 for name, _ in pairs(storage:to_table().fields) do
481 if name:sub(1, string.len(stprefix)) == stprefix then
482 table.insert(wp, name:sub(string.len(stprefix)+1))
485 table.sort(wp)
486 return wp
489 function autofly.set_waypoint(pos, name)
490 pos = pos_to_string(pos)
491 if not pos then return end
492 storage:set_string(stprefix .. tostring(name), pos)
493 return true
496 function autofly.delete_waypoint(name)
497 storage:set_string(stprefix .. tostring(name), '')
500 function autofly.get_waypoint(name)
501 return string_to_pos(storage:get_string(stprefix .. tostring(name)))
504 function autofly.rename_waypoint(oldname, newname)
505 oldname, newname = tostring(oldname), tostring(newname)
506 local pos = autofly.get_waypoint(oldname)
507 if not pos or not autofly.set_waypoint(pos, newname) then return end
508 if oldname ~= newname then
509 autofly.delete_waypoint(oldname)
511 return true
514 minetest.after("5.0",function()
515 if autofly.get_waypoint('AUTOTP') ~= nil then autofly.autotp(nil) end
516 end)
519 math.randomseed(os.time())
521 local randflying = false
523 minetest.register_globalstep(function()
524 if randflying and not autofly.flying then
525 local x = math.random(-31000, 31000)
526 local y = math.random(2000, 31000)
527 local z = math.random(-31000, 31000)
529 autofly.goto({x = x, y = y, z = z})
531 end)
533 local function randfly()
534 if not randflying then
535 randflying = true
536 local lp = minetest.localplayer:get_pos()
537 autofly.goto(turtle.coord(lp.x, 6000, lp.z))
538 else
539 randflying = false
540 autofly.arrived()
544 local register_chatcommand_alias = ws.register_chatcommand_alias
547 minetest.register_chatcommand('waypoints', {
548 params = '',
549 description = 'Open the autofly GUI',
550 func = function(param) autofly.display_formspec() end
553 register_chatcommand_alias('waypoints','wp', 'wps', 'waypoint')
555 -- Add a waypoint
556 minetest.register_chatcommand('add_waypoint', {
557 params = '<pos / "here" / "there"> <name>',
558 description = 'Adds a waypoint.',
559 func = function(param)
560 local s, e = param:find(' ')
561 if not s or not e then
562 return false, 'Invalid syntax! See .help add_mrkr for more info.'
564 local pos = param:sub(1, s - 1)
565 local name = param:sub(e + 1)
567 -- Validate the position
568 if not pos then
569 return false, err
572 -- Validate the name
573 if not name or #name < 1 then
574 return false, 'Invalid name!'
577 -- Set the waypoint
578 return autofly.set_waypoint(pos, name), 'Done!'
581 register_chatcommand_alias('add_waypoint','wa', 'add_wp')
584 minetest.register_chatcommand('add_waypoint_here', {
585 params = 'name',
586 description = 'marks the current position',
587 func = function(param)
588 local name = os.date("%Y-%m-%d %H:%M:%S")
589 local pos = minetest.localplayer:get_pos()
590 return autofly.set_waypoint(pos, name), 'Done!'
593 register_chatcommand_alias('add_waypoint_here', 'wah', 'add_wph')
595 minetest.register_chatcommand('clear_waypoint', {
596 params = '',
597 description = 'Hides the displayed waypoint.',
598 func = function(param)
599 if autofly.flying then autofly.flying=false end
600 if hud_wp then
601 minetest.localplayer:hud_remove(hud_wp)
602 hud_wp = nil
603 return true, 'Hidden the currently displayed waypoint.'
604 elseif not minetest.localplayer.hud_add then
605 minetest.run_server_chatcommand('clrmrkr')
606 return
607 elseif not hud_wp then
608 return false, 'No waypoint is currently being displayed!'
610 for k,v in wps do
611 minetest.localplayer:hud_remove(v)
612 table.remove(k)
615 end,
617 register_chatcommand_alias('clear_waypoint', 'cwp','cls')
619 minetest.register_chatcommand('autotp', {
620 params = 'position',
621 description = 'autotp',
622 func = function(param)
623 autofly.autotp(minetest.string_to_pos(param))
626 register_chatcommand_alias('autotp', 'atp')
628 minetest.register_chatcommand('wpdisplay', {
629 params = 'position name',
630 description = 'display waypoint',
631 func = function(pos,name)
632 autofly.display(pos,name)
635 register_chatcommand_alias('wpdisplay', 'wpd')
639 minetest.register_chatcommand("randfly", {
640 description = "Randomly fly up high (toggle).",
641 func = randfly
645 minetest.register_cheat("Aim", "Autofly", "afly_autoaim")
646 minetest.register_cheat("AxisSnap", "Autofly", "afly_snap")
647 minetest.register_cheat("Cruise", "Autofly", "afly_cruise")
648 minetest.register_cheat("Sprint", "Autofly", "afly_sprint")
649 minetest.register_cheat("ShowNames", "Autofly", "afly_shownames")
650 minetest.register_cheat("Waypoints", "Autofly", autofly.display_formspec)