minecart/recording.lua

199 lines
5.4 KiB
Lua

--[[
Minecart
========
Copyright (C) 2019-2021 Joachim Stolberg
MIT
See license.txt for more information
]]--
-- for lazy programmers
local M = minetest.get_meta
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
local P2H = minetest.hash_node_position
local H2P = minetest.get_position_from_hash
local S = minecart.S
local function dashboard_destroy(self)
if self.driver and self.hud_id then
local player = minetest.get_player_by_name(self.driver)
if player then
player:hud_remove(self.hud_id)
self.hud_id = nil
end
end
end
local function dashboard_create(self)
if self.driver then
local player = minetest.get_player_by_name(self.driver)
if player then
dashboard_destroy(self)
self.hud_id = player:hud_add({
name = "minecart",
hud_elem_type = "text",
position = {x = 0.4, y = 0.25},
scale = {x=100, y=100},
text = "Recording:",
number = 0xFFFFFF,
size = {x = 1},
})
end
end
end
local function dashboard_update(self)
if self.driver and self.hud_id then
local player = minetest.get_player_by_name(self.driver)
if player then
local time = self.runtime or 0
local dir = (self.ctrl and self.ctrl.left and S("left")) or
(self.ctrl and self.ctrl.right and S("right")) or S("straight")
local speed = math.floor((self.curr_speed or 0) + 0.5)
local s = string.format(S("Recording") ..
" | " .. S("speed") ..
": %.1f | " .. S("next junction") ..
": %-8s | " .. S("Travel time") .. ": %.1f s",
speed, dir, time)
player:hud_change(self.hud_id, "text", s)
end
end
end
local function check_waypoint(self, pos)
-- If next waypoint already reached but not handled
-- determine next waypoint
if vector.equals(pos, self.waypoint.pos) then
local rot = self.object:get_rotation()
local dir = minetest.yaw_to_dir(rot.y)
dir.y = math.floor((rot.x / (math.pi/4)) + 0.5)
local facedir = minetest.dir_to_facedir(dir)
local waypoint = minecart.get_waypoint(pos, facedir, self.ctrl or {}, false)
if waypoint then
return waypoint.pos
end
end
return self.waypoint.pos
end
--
-- Route recording
--
function minecart.start_recording(self, pos)
--print("start_recording")
if self.driver then
self.start_pos = minecart.get_buffer_pos(pos, self.driver)
if self.start_pos then
self.checkpoints = {} -- {cart_pos, next_waypoint_pos, speed, dot}
self.junctions = {}
self.is_recording = true
self.rec_time = self.timebase
self.hud_time = self.timebase
self.runtime = 0
self.num_sections = 0
self.sum_speed = 0
self.ctrl = {}
dashboard_create(self)
dashboard_update(self, 0)
end
end
end
function minecart.stop_recording(self, pos, force_exit)
--print("stop_recording")
if self.driver and self.is_recording then
local dest_pos = minecart.get_buffer_pos(pos, self.driver)
local player = minetest.get_player_by_name(self.driver)
if force_exit then
minetest.chat_send_player(self.driver, S("[minecart] Recording canceled!"))
elseif dest_pos and player and #self.checkpoints > 3 then
-- Remove last checkpoint, because it is potentially too close to the dest_pos
table.remove(self.checkpoints)
if self.start_pos then
local route = {
dest_pos = dest_pos,
checkpoints = self.checkpoints,
junctions = self.junctions,
}
minecart.store_route(self.start_pos, route)
minetest.chat_send_player(self.driver, S("[minecart] Route stored!"))
local speed = self.sum_speed / #self.checkpoints
local length = speed * self.runtime
local fmt = S("[minecart] Speed = %u m/s, Time = %u s, Route length = %u m")
minetest.chat_send_player(self.driver, string.format(fmt, speed, self.runtime, length))
minecart.update_buffer_infotext(self.start_pos)
end
elseif #self.checkpoints <= 3 then
minetest.chat_send_player(self.driver, S("[minecart] Your route is too short to record!"))
end
dashboard_destroy(self)
end
self.is_recording = false
self.checkpoints = nil
self.waypoints = nil
self.junctions = nil
end
function minecart.recording_waypoints(self)
local pos = vector.round(self.object:get_pos())
-- pos correction on slopes
if not minecart.is_rail(pos) then
pos.y = pos.y - 1
end
-- hier müsste überprüfung dest_pos rein
self.sum_speed = self.sum_speed + self.curr_speed
local wp_pos = check_waypoint(self, pos)
self.checkpoints[#self.checkpoints+1] = {
-- cart_pos, next_waypoint_pos, speed, dot
P2H(pos),
P2H(wp_pos),
math.floor(self.curr_speed + 0.5),
self.waypoint.dot
}
end
function minecart.recording_junctions(self)
local player = minetest.get_player_by_name(self.driver)
if player then
local ctrl = player:get_player_control()
if ctrl.left then
self.ctrl = {left = true}
elseif ctrl.right then
self.ctrl = {right = true}
elseif ctrl.up or ctrl.down then
self.ctrl = nil
elseif ctrl.jump then
return true
end
end
if self.hud_time <= self.timebase then
dashboard_update(self)
self.hud_time = self.timebase + 0.5
self.runtime = self.runtime + 0.5
end
end
function minecart.set_junctions(self, wayp_pos)
if self.ctrl then
self.junctions[P2H(wayp_pos)] = self.ctrl
end
end
function minecart.player_ctrl(self)
local player = minetest.get_player_by_name(self.driver)
if player then
local ctrl = player:get_player_control()
if ctrl.left then
self.ctrl = {left = true}
elseif ctrl.right then
self.ctrl = {right = true}
elseif ctrl.jump then
return true
end
end
end