diff --git a/mods/lzr_solutions/init.lua b/mods/lzr_solutions/init.lua index e3d34e51..315bf391 100644 --- a/mods/lzr_solutions/init.lua +++ b/mods/lzr_solutions/init.lua @@ -7,6 +7,12 @@ local state = "idle" -- true if recording should automatically stop when reaching LEVEL_COMPLETE state -- and trigger a file save local autostop = false + +-- true if running a full solution test of the core levels +local full_test = false +-- level number of currently tested core level +local full_test_level = 0 + local current_replay_time = 0 local current_action local current_solution @@ -52,9 +58,78 @@ action: { ]] +local test_next_core_solution_callback = function() + local level_data = lzr_levels.get_core_level_data() + if not level_data.solutions_path then + -- No solutions path. Nothing to test! + minetest.log("error", "[lzr_solutions] No solutions path") + return false + end + + local level_id = full_test_level + + local level = level_data[level_id] + if not level then + -- Level does not exist + minetest.log("error", "[lzr_solutions] Core level "..tostring(level_id).." does not exist") + return false + end + + if not level.filename_solution then + -- No solution in level. Skip test. + minetest.log("error", "[lzr_solutions] Core level "..tostring(level_id).." doesn't have solution") + return false + end + + local full_path = level_data.solutions_path.."/"..level.filename_solution + local solution_file = io.open(full_path, "r") + if solution_file then + local csv = solution_file:read("*a") + local solution = lzr_solutions.csv_to_solution(csv) + if solution then + lzr_solutions.replay_solution(solution) + minetest.log("action", "[lzr_solutions] Playing solution for core level "..level_id) + return true + else + minetest.log("error", "[lzr_solutions] Error in solution CSV file for core level "..level_id) + return false + end + else + minetest.log("error", "[lzr_solutions] Error while loading solution CSV file for core level "..level_id) + return false + end +end + +local test_next_core_solution = function() + full_test_level = full_test_level + 1 + if full_test_level > lzr_levels.LAST_LEVEL then + return false + end + if full_test_level == 1 then + minetest.log("verbose", "[lzr_solutions] Loading core level "..full_test_level.." ...") + lzr_levels.start_level(full_test_level) + end + return true +end +lzr_levels.register_on_level_start(function() + minetest.log("verbose", "[lzr_solutions] on_level_start event") + if full_test then + test_next_core_solution_callback() + end +end) + +lzr_solutions.test_core_solutions = function() + full_test = true + full_test_level = 0 + local ok = test_next_core_solution() + if not ok then + full_test = false + end +end + local record_action = function(solution, action) local new_action = table.copy(action) - local time = math.floor(minetest.get_us_time()/1000) + local time = math.floor(minetest.get_us_time()/5000) new_action.time = time - current_solution_start_time table.insert(solution.actions, new_action) end @@ -67,7 +142,7 @@ local replay_action = function(player, action) -- Check if node is the expected node local node = minetest.get_node(action.pos) if node.name ~= action.node.name or node.param2 ~= action.node.param2 then - minetest.log("error", "[lzr_solutions] Tried to dig node '"..action.node.name.."' (param2="..action.node.param2..") but found '"..node.name.."' (param2="..node.param2..")") + minetest.log("error", "[lzr_solutions] Expected to dig node '"..action.node.name.."' (param2="..action.node.param2..") but found '"..node.name.."' (param2="..node.param2..")") return false end minetest.node_dig(action.pos, action.node, player) @@ -351,12 +426,16 @@ minetest.register_globalstep(function(dtime) if not current_solution then minetest.log("error", "[lzr_solutions] In 'playing' state but current_solution is nil!") state = "idle" + full_test = false return end if current_action > #current_solution.actions then - -- Replay is finished, go back to idle state - current_solution = nil - state = "idle" + -- Replay is finished + if not full_test then + -- Go back to idle state + current_solution = nil + state = "idle" + end return end local action = current_solution.actions[current_action] @@ -370,6 +449,7 @@ minetest.register_globalstep(function(dtime) -- Abort replay if replay_action returns false (in case of error) current_solution = nil state = "idle" + full_test = false end current_action = current_action + 1 end @@ -461,11 +541,21 @@ lzr_gamestate.register_on_enter_state(function(new_state) lzr_solutions.stop_recording_solution() minetest.chat_send_player("singleplayer", S("Recording cancelled.")) end + elseif state == "playing" and full_test then + -- If level was completed during full test, continue with next level + if new_state == lzr_gamestate.LEVEL_COMPLETE then + local ok = test_next_core_solution() + if not ok then + full_test = false + current_solution = nil + state = "idle" + end + end end end) minetest.register_chatcommand("replay_solution", { - privs = { debug = true }, + privs = { debug = true, server = true }, params = "", description = S("Replay saved solution for current level, if one exists"), func = function(name, param) @@ -504,3 +594,18 @@ minetest.register_chatcommand("replay_solution", { end end, }) + +minetest.register_chatcommand("test_core_solutions", { + privs = { debug = true, server = true }, + params = "", + description = S("Test the solution of all core levels"), + func = function(name, param) + if state == "playing" then + return false, S("Already replaying a solution!") + elseif state == "recording" then + return false, S("Already recording!") + end + lzr_solutions.test_core_solutions() + return true + end, +}) diff --git a/mods/lzr_solutions/mod.conf b/mods/lzr_solutions/mod.conf index 6e4fa786..03a83186 100644 --- a/mods/lzr_solutions/mod.conf +++ b/mods/lzr_solutions/mod.conf @@ -1,2 +1,2 @@ name = lzr_solutions -depends = lzr_hook, lzr_laser, lzr_treasure, lzr_csv, lzr_world +depends = lzr_hook, lzr_laser, lzr_treasure, lzr_csv, lzr_world, lzr_levels