wasplib: fix bug
[waspsaliva.git] / clientmods / autofly / init.lua
blob1d39ab6b9e38bc15d19461a0adfa7ace77e639be
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
76 function autofly.get2ddst(pos1,pos2)
77 return vector.distance({x=pos1.x,y=0,z=pos1.z},{x=pos2.x,y=0,z=pos2.z})
78 end
80 local last_sprint = false
82 minetest.register_globalstep(function()
83 if not minetest.localplayer then return end
84 autofly.axissnap()
85 if minetest.settings:get_bool("autosprint") or (minetest.settings:get_bool("continuous_forward") and minetest.settings:get_bool("autofsprint")) then
86 core.set_keypress("special1", true)
87 last_sprint = true
88 elseif last_sprint then
89 core.set_keypress("special1", false)
90 last_sprint = false
91 end
92 if not autofly.flying then autofly.set_hud_info("")
93 else
94 autofly.set_hud_info("")
95 local pos = autofly.last_coords
96 if pos then
97 local dst = vector.distance(pos,minetest.localplayer:get_pos())
98 local etatime=-1
99 if not (speed == 0) then etatime = ws.round2(dst / speed / 60,2) end
100 autofly.etatime=etatime
101 autofly.set_hud_info(autofly.last_name .. "\n" .. pos_to_string(pos) .. "\n" .. "ETA" .. etatime .. " mins")
102 local hdst=autofly.get2ddst(pos,minetest.localplayer:get_pos())
103 if autofly.flying and hdst < landing_distance then
104 autofly.arrived()
109 if not minetest.settings:get_bool("freecam") and autofly.flying and (minetest.settings:get_bool('afly_autoaim')) then
110 autofly.aim(autofly.last_coords)
113 if ( os.time() < ltime + 1 ) then return end
114 ltime=os.time()
115 if lpos then
116 local dst=vector.distance(minetest.localplayer:get_pos(),lpos)
117 speed=ws.round2(dst,1)
118 autofly.speed=speed
120 lpos=minetest.localplayer:get_pos()
121 autofly.cruise()
122 end)
125 function autofly.set_hud_wp(pos, title)
126 if hud_wp then
127 minetest.localplayer:hud_remove(hud_wp)
129 pos = string_to_pos(pos)
130 hud_wp=nil
131 if not pos then return end
132 if not title then
133 title = pos.x .. ', ' .. pos.y .. ', ' .. pos.z
135 autofly.last_name=title
136 if hud_wp then
137 minetest.localplayer:hud_change(hud_wp, 'name', title)
138 minetest.localplayer:hud_change(hud_wp, 'world_pos', pos)
139 else
140 hud_wp = minetest.localplayer:hud_add({
141 hud_elem_type = 'waypoint',
142 name = title,
143 text = 'm',
144 number = 0x00ff00,
145 world_pos = pos
148 return true
151 local hud_info
152 function autofly.get_quad()
153 local lp=minetest.localplayer:get_pos()
154 local quad=""
156 if lp.z < 0 then quad="Q: South"
157 else quad="Q: North" end
159 if lp.x < 0 then quad=quad.."-west"
160 else quad=quad.."-east" end
162 return quad
165 function autofly.get_local_name()
166 local ww=autofly.getwps()
167 local lp=minetest.localplayer:get_pos()
168 local odst=500;
169 local rt=false
170 for k,v in pairs(ww) do
171 local lwp=autofly.get_waypoint(v)
172 if type(lwp) == 'table' then
173 local dst=vector.distance(lp,lwp)
174 if dst < 500 then
175 if dst < odst then
176 odst=dst
177 rt=v
182 if not rt then rt=autofly.get_quad() end
183 return rt
187 function autofly.set_hud_info(text)
188 if not minetest.localplayer then return end
189 if type(text) ~= "string" then return end
190 local lp=minetest.localplayer
191 local vspeed=lp:get_velocity()
192 local ttext=text.."\nSpeed: "..speed.."n/s\n"
193 ..ws.round2(vspeed.x,2) ..','
194 ..ws.round2(vspeed.y,2) ..','
195 ..ws.round2(vspeed.z,2) .."\n"
196 .."Yaw:"..ws.round2(lp:get_yaw(),2).."° Pitch:" ..ws.round2(lp:get_pitch(),2).."° "
197 if turtle then ttext=ttext..turtle.getdir() end
198 if minetest.settings:get_bool('afly_shownames') then
199 ttext=ttext.."\n"..autofly.get_local_name()
201 if hud_info then
202 minetest.localplayer:hud_change(hud_info,'text',ttext)
203 else
204 hud_info = minetest.localplayer:hud_add({
205 hud_elem_type = 'text',
206 name = "Flight Info",
207 text = ttext,
208 number = 0x00ff00,
209 direction = 0,
210 position = {x=0,y=0.8},
211 alignment ={x=1,y=1},
212 offset = {x=0, y=0}
215 return true
218 function autofly.display(pos,name)
219 if name == nil then name=pos_to_string(pos) end
220 local pos=string_to_pos(pos)
221 autofly.set_hud_wp(pos, name)
222 return true
226 function autofly.display_waypoint(name)
227 local pos=name
228 if type(name) ~= 'table' then pos=autofly.get_waypoint(name) end
229 autofly.last_name = name
230 --autofly.last_coords = pos
231 autofly.set_hud_info(name)
232 autofly.aim(autofly.last_coords)
233 autofly.display(pos,name)
234 return true
237 function autofly.goto_waypoint(name)
238 local wp=autofly.get_waypoint(name)
239 autofly.goto(wp)
240 autofly.last_name=name
241 autofly.display_waypoint(autofly.last_name)
242 return true
245 function autofly.goto(pos)
246 oldpm=minetest.settings:get_bool("pitch_move")
247 minetest.settings:set_bool("pitch_move",true)
248 minetest.settings:set_bool("free_move",true)
249 minetest.settings:set_bool("continuous_forward",true)
250 if minetest.settings:get_bool("afly_sprint") then
251 minetest.settings:set_bool("autofsprint",true)
252 minetest.settings:set_bool("autoeat_timed",true)
254 minetest.settings:set_bool("afly_autoaim",true)
255 autofly.last_coords = pos
256 autofly.last_name = minetest.pos_to_string(pos)
257 autofly.aim(autofly.last_coords)
258 autofly.flying=true
259 autofly.set_hud_wp(autofly.last_coords, autofly.last_name)
260 return true
263 function autofly.arrived()
264 if not autofly.flying then return end
265 minetest.settings:set("continuous_forward", "false")
266 minetest.settings:set_bool("autofsprint",false)
267 minetest.settings:set_bool("pitch_move",oldpm)
268 minetest.settings:set_bool("afly_autoaim",false)
269 minetest.settings:set_bool("autoeat_timed",false)
270 autofly.set_hud_info("Arrived!")
271 autofly.flying = false
272 minetest.sound_play({name = "default_alert", gain = 1.0})
275 local cruise_wason=false
276 local nfctr=0
279 function autofly.cruise()
280 if not minetest.settings:get_bool('afly_cruise') then
281 if cruise_wason then
282 cruise_wason=false
283 core.set_keypress("jump",false)
284 core.set_keypress("sneak",false)
286 return end
288 local lp=minetest.localplayer:get_pos()
289 local pos1 = vector.add(lp,{x=16,y=100,z=16})
290 local pos2 = vector.add(lp,{x=-16,y=-100,z=-16})
291 local nds=minetest.find_nodes_in_area_under_air(pos1, pos2, nlist.get_mclnodes())
292 local y=0
293 local found=false
296 for k,v in ipairs(nds) do
297 local nd = minetest.get_node_or_nil(v)
298 if nd ~= nil and nd.name ~= "air" then
299 if v.y > y then
300 y=v.y
301 found=true
305 if (autofly.cruiseheight ~= nil) then y=y+autofly.cruiseheight end
306 local diff = math.ceil(lp.y - y)
308 if not cruise_wason then --initially set the cruiseheight to the current value above ground
309 -- if not found then return end --wait with activation til a ground node has been found.
310 local clr,nnd=minetest.line_of_sight(lp,vector.add(lp,{x=1,y=-200,z=1}))
311 if not clr then diff = math.ceil(lp.y - nnd.y)
312 elseif not found then return end
313 if diff < 1 then autofly.cruiseheight = 20
314 else autofly.cruiseheight = diff end
316 cruise_wason=true
317 minetest.display_chat_message("cruise mode activated. target height set to " .. diff .. " nodes above ground.")
320 if not found then
321 if nfctr<20 then nfctr = nfctr + 1 return end
322 --minetest.display_chat_message("no nodes found for 20 iterations. lowering altitude.")
323 nfctr=0
324 minetest.settings:set_bool("free_move",false)
325 core.set_keypress("jump",false)
326 core.set_keypress("sneak",false)
327 return
330 local tolerance = 1
331 if diff < -tolerance then
332 minetest.settings:set_bool("free_move",true)
333 core.set_keypress("jump",true)
334 core.set_keypress("sneak",false)
335 --minetest.display_chat_message("too low: " .. y)
336 elseif diff > tolerance * 10 then
337 core.set_keypress("jump",false)
338 core.set_keypress("sneak",true)
339 minetest.settings:set_bool("free_move",false)
340 --minetest.display_chat_message("too high: " .. y)
341 elseif diff > tolerance then
342 core.set_keypress("jump",false)
343 core.set_keypress("sneak",true)
344 else
345 minetest.settings:set_bool("free_move",true)
346 core.set_keypress("jump",false)
347 core.set_keypress("sneak",false)
348 --minetest.display_chat_message("target height reached: " .. y)
354 function autofly.aim(tpos)
355 local ppos=minetest.localplayer:get_pos()
356 --local dir=tpos
357 local dir=vector.direction(ppos,tpos)
358 local yyaw=0;
359 local pitch=0;
360 if dir.x < 0 then
361 yyaw = math.atan2(-dir.x, dir.z) + (math.pi * 2)
362 else
363 yyaw = math.atan2(-dir.x, dir.z)
365 yyaw = ws.round2(math.deg(yyaw),2)
366 pitch = ws.round2(math.deg(math.asin(-dir.y) * 1),2);
367 minetest.localplayer:set_yaw(yyaw)
368 minetest.localplayer:set_pitch(pitch)
372 function autofly.autotp(tpname)
373 if minetest.localplayer == nil then autofly.autotp(tpname) end
374 local tpos=nil
375 if tpname == nil then
376 tpos = autofly.get_waypoint('AUTOTP')
377 elseif type(tpname) == "table" then
378 tpos = tpname
379 else
380 tpos=autofly.get_waypoint(tpname)
382 if tpos == nil then return end
383 local lp=minetest.localplayer
384 local dst=vector.distance(lp:get_pos(),tpos)
385 if (dst < 300) then
386 minetest.sound_play({name = "default_alert", gain = 3.0})
387 autofly.delete_waypoint('AUTOTP')
388 return true
390 autofly.set_waypoint(tpos,'AUTOTP')
391 local boat_found=false
392 for k, v in ipairs(lp.get_nearby_objects(4)) do
393 local txt = v:get_item_textures()
394 if ( txt:find('mcl_boats_texture')) then
395 boat_found=true
396 minetest.display_chat_message("boat found. entering and tping to "..minetest.pos_to_string(autofly.get_waypoint('AUTOTP')))
397 autofly.aim(vector.add(v:get_pos(),{x=0,y=-1.5,z=0}))
398 minetest.after("0.2",function()
399 minetest.interact("place") end)
400 minetest.after("1.5",function()
401 autofly.warpae('AUTOTP')
402 end)
403 return true
406 if not boat_found then
407 minetest.display_chat_message("no boat found. trying again in 5.")
408 minetest.after("5.0",function() autofly.autotp(tpname) end)
409 return end
414 autofly.register_transport('Fly',function(pos,name) autofly.goto_waypoint(name) end)
415 autofly.register_transport('wrp',function(pos,name) autofly.warp(name) end)
416 autofly.register_transport('atp',function(pos,name) autofly.autotp(name) end)
418 function autofly.axissnap()
419 if not minetest.settings:get_bool('afly_snap') then return end
420 if minetest.settings:get_bool("freecam") then return end
421 local y=minetest.localplayer:get_yaw()
422 local yy=nil
423 if ( y < 45 or y > 315 ) then
424 yy=0
425 elseif (y < 135) then
426 yy=90
427 elseif (y < 225 ) then
428 yy=180
429 elseif ( y < 315 ) then
430 yy=270
432 if yy ~= nil then
433 minetest.localplayer:set_yaw(yy)
437 minetest.register_on_death(function()
438 if minetest.localplayer then
439 local name = 'Death waypoint'
440 local pos = minetest.localplayer:get_pos()
441 autofly.last_coords = pos
442 autofly.last_name = name
443 autofly.set_waypoint(pos,name)
444 autofly.display(pos,name)
446 end)
448 local function get_dimension(pos)
449 if pos.y > -65 then return "overworld"
450 elseif pos.y > -8000 then return "void"
451 elseif pos.y > -27000 then return "end"
452 elseif pos.y >29000 then return "void"
453 elseif pos.y >31000 then return "nether"
454 else return "void"
458 function autofly.warp(name)
459 local pos=autofly.get_waypoint(name)
460 if pos then
461 if pos.y > -64 then
462 pos=vector.add(pos,{x=0,y=150,z=0})
464 if get_dimension(pos) == "void" then return false end
465 minetest.localplayer:set_pos(pos)
466 return true
469 function autofly.warpae(name)
470 local s, m = autofly.warp(name)
471 if s then
472 minetest.disconnect()
474 return true
477 function autofly.getwps()
478 local wp={}
479 for name, _ in pairs(storage:to_table().fields) do
480 if name:sub(1, string.len(stprefix)) == stprefix then
481 table.insert(wp, name:sub(string.len(stprefix)+1))
484 table.sort(wp)
485 return wp
488 function autofly.set_waypoint(pos, name)
489 pos = pos_to_string(pos)
490 if not pos then return end
491 storage:set_string(stprefix .. tostring(name), pos)
492 return true
495 function autofly.delete_waypoint(name)
496 storage:set_string(stprefix .. tostring(name), '')
499 function autofly.get_waypoint(name)
500 return string_to_pos(storage:get_string(stprefix .. tostring(name)))
503 function autofly.rename_waypoint(oldname, newname)
504 oldname, newname = tostring(oldname), tostring(newname)
505 local pos = autofly.get_waypoint(oldname)
506 if not pos or not autofly.set_waypoint(pos, newname) then return end
507 if oldname ~= newname then
508 autofly.delete_waypoint(oldname)
510 return true
513 minetest.after("5.0",function()
514 if autofly.get_waypoint('AUTOTP') ~= nil then autofly.autotp(nil) end
515 end)
518 math.randomseed(os.time())
520 local randflying = false
522 minetest.register_globalstep(function()
523 if randflying and not autofly.flying then
524 local x = math.random(-31000, 31000)
525 local y = math.random(2000, 31000)
526 local z = math.random(-31000, 31000)
528 autofly.goto({x = x, y = y, z = z})
530 end)
532 local function randfly()
533 if not randflying then
534 randflying = true
535 local lp = minetest.localplayer:get_pos()
536 autofly.goto(turtle.coord(lp.x, 6000, lp.z))
537 else
538 randflying = false
539 autofly.arrived()
545 minetest.register_chatcommand('waypoints', {
546 params = '',
547 description = 'Open the autofly GUI',
548 func = function(param) autofly.display_formspec() end
551 ws.register_chatcommand_alias('waypoints','wp', 'wps', 'waypoint')
553 -- Add a waypoint
554 minetest.register_chatcommand('add_waypoint', {
555 params = '<pos / "here" / "there"> <name>',
556 description = 'Adds a waypoint.',
557 func = function(param)
558 local s, e = param:find(' ')
559 if not s or not e then
560 return false, 'Invalid syntax! See .help add_mrkr for more info.'
562 local pos = param:sub(1, s - 1)
563 local name = param:sub(e + 1)
565 -- Validate the position
566 if not pos then
567 return false, err
570 -- Validate the name
571 if not name or #name < 1 then
572 return false, 'Invalid name!'
575 -- Set the waypoint
576 return autofly.set_waypoint(pos, name), 'Done!'
579 ws.register_chatcommand_alias('add_waypoint','wa', 'add_wp')
582 minetest.register_chatcommand('add_waypoint_here', {
583 params = 'name',
584 description = 'marks the current position',
585 func = function(param)
586 local name = os.date("%Y-%m-%d %H:%M:%S")
587 local pos = minetest.localplayer:get_pos()
588 return autofly.set_waypoint(pos, name), 'Done!'
591 ws.register_chatcommand_alias('add_waypoint_here', 'wah', 'add_wph')
593 minetest.register_chatcommand('clear_waypoint', {
594 params = '',
595 description = 'Hides the displayed waypoint.',
596 func = function(param)
597 if autofly.flying then autofly.flying=false end
598 if hud_wp then
599 minetest.localplayer:hud_remove(hud_wp)
600 hud_wp = nil
601 return true, 'Hidden the currently displayed waypoint.'
602 elseif not minetest.localplayer.hud_add then
603 minetest.run_server_chatcommand('clrmrkr')
604 return
605 elseif not hud_wp then
606 return false, 'No waypoint is currently being displayed!'
608 for k,v in wps do
609 minetest.localplayer:hud_remove(v)
610 table.remove(k)
613 end,
615 ws.register_chatcommand_alias('clear_waypoint', 'cwp','cls')
617 minetest.register_chatcommand('autotp', {
618 params = 'position',
619 description = 'autotp',
620 func = function(param)
621 autofly.autotp(minetest.string_to_pos(param))
624 ws.register_chatcommand_alias('autotp', 'atp')
626 minetest.register_chatcommand('wpdisplay', {
627 params = 'position name',
628 description = 'display waypoint',
629 func = function(pos,name)
630 autofly.display(pos,name)
633 ws.register_chatcommand_alias('wpdisplay', 'wpd')
637 minetest.register_chatcommand("randfly", {
638 description = "Randomly fly up high (toggle).",
639 func = randfly
643 minetest.register_cheat("Aim", "Autofly", "afly_autoaim")
644 minetest.register_cheat("AxisSnap", "Autofly", "afly_snap")
645 minetest.register_cheat("Cruise", "Autofly", "afly_cruise")
646 minetest.register_cheat("Sprint", "Autofly", "afly_sprint")
647 minetest.register_cheat("ShowNames", "Autofly", "afly_shownames")
648 minetest.register_cheat("Waypoints", "Autofly", autofly.display_formspec)