diff --git a/src/app/screens/BalanceAnalyserModel.res b/src/app/screens/BalanceAnalyserModel.res index 0040b3b6..b933b249 100644 --- a/src/app/screens/BalanceAnalyserModel.res +++ b/src/app/screens/BalanceAnalyserModel.res @@ -33,6 +33,7 @@ type levelSummary = { levelWidth: int, difficultyScore: float, guardSpawnRate: float, + meanPatrolRadius: float, defenceDensity: float, alertThreshold: float, } @@ -147,6 +148,7 @@ let parseLevelSummary = (obj: Dict.t): levelSummary => { levelWidth: getInt(obj, "level_width"), difficultyScore: getFloat(obj, "difficulty_score"), guardSpawnRate: getFloat(obj, "guard_spawn_rate"), + meanPatrolRadius: getFloat(obj, "mean_patrol_radius"), defenceDensity: getFloat(obj, "defence_density"), alertThreshold: getFloat(obj, "alert_threshold"), } diff --git a/tools/balance-analyser.jl b/tools/balance-analyser.jl index 549f8e0a..3e86947f 100644 --- a/tools/balance-analyser.jl +++ b/tools/balance-analyser.jl @@ -34,6 +34,7 @@ struct LevelStats level_name::String guard_count::Int guard_spawn_rate::Float64 # guards per 1000 pixels of level width + mean_patrol_radius::Float64 # mean patrolRadius across all guards (pixels) alert_threshold::Float64 # normalised 0.0-1.0 (higher = harder to trigger) difficulty_score::Float64 # composite difficulty metric device_count::Int # total devices with custom defences @@ -285,6 +286,11 @@ function level_dict_to_stats(d::Dict{String,Any})::LevelStats # Guard spawn rate: guards per 1000px of level width guard_spawn_rate = guard_count > 0 ? (guard_count / max_x) * 1000.0 : 0.0 + # Mean patrol radius across all guards (pixels). The patrolRadius field + # carries the half-width of each guard's patrol range in LevelConfig.res. + mean_patrol_radius = guard_count > 0 ? + sum(Float64(get(g, "patrolRadius", 0.0)) for g in guards) / guard_count : 0.0 + # Defence density: average number of active flags per defended device defence_density = if device_count > 0 total_flags = sum(length(get(dd, "flags", [])) for dd in defences) @@ -323,6 +329,7 @@ function level_dict_to_stats(d::Dict{String,Any})::LevelStats get(d, "levelName", get(d, "missionId", "Unknown Level")), guard_count, guard_spawn_rate, + mean_patrol_radius, alert_threshold, difficulty_score, device_count, @@ -759,8 +766,8 @@ function generate_recommendations(stats::LevelStats, sim::SimulationResult)::Vec push!(recs, BalanceRecommendation( stats.level_id, "guard_patrol_radius", - stats.guard_spawn_rate, - stats.guard_spawn_rate * 0.85, + stats.mean_patrol_radius, + stats.mean_patrol_radius * 0.85, "$(round(guard_death_ratio*100; digits=0))% of deaths are from guards. " * "Consider widening patrol gaps or reducing guard detection radius.", "moderate", @@ -834,6 +841,7 @@ function export_report( "level_name" => s.level_name, "guard_count" => s.guard_count, "guard_spawn_rate" => round(s.guard_spawn_rate; digits=3), + "mean_patrol_radius" => round(s.mean_patrol_radius; digits=1), "alert_threshold" => round(s.alert_threshold; digits=3), "difficulty_score" => round(s.difficulty_score; digits=2), "device_count" => s.device_count,