manage stats and achievements

This commit is contained in:
2026-07-07 10:03:12 +02:00
parent b87be91521
commit 6da7021a58
6 changed files with 68 additions and 32 deletions

View File

@@ -1,6 +1,5 @@
extends Path3D extends Path3D
const STEAM_DISTANCE_STAT: String = "stat_distance_km"
const DISTANCE_KM_PER_UNIT: float = 0.01 const DISTANCE_KM_PER_UNIT: float = 0.01
const STATION_STOP_GROUP: StringName = &"railway_station" const STATION_STOP_GROUP: StringName = &"railway_station"
const TRACK_ZERO_SPACING_FIX_DISTANCE: float = 45.0 const TRACK_ZERO_SPACING_FIX_DISTANCE: float = 45.0
@@ -102,7 +101,6 @@ var is_restarting: bool = false
var tween_restart: Tween var tween_restart: Tween
var wagon_instances: Array[Node3D] = [] var wagon_instances: Array[Node3D] = []
var wagon_progress_offsets: Array[float] = [] var wagon_progress_offsets: Array[float] = []
var _pending_steam_distance_km: float = 0.0
var _initial_is_inmotion: bool = true var _initial_is_inmotion: bool = true
var _is_photo_mode_active: bool = false var _is_photo_mode_active: bool = false
@@ -493,28 +491,7 @@ func _track_steam_distance(distance_units: float) -> void:
# Always track the global distance in our save file (for UI and persistency) # Always track the global distance in our save file (for UI and persistency)
GameState.save_data.total_distance_km += distance_units * DISTANCE_KM_PER_UNIT GameState.save_data.total_distance_km += distance_units * DISTANCE_KM_PER_UNIT
StatsManager.add_distance_km(distance_units * DISTANCE_KM_PER_UNIT)
# Steam specific logic
if not SteamManager.is_on_steam:
return
_pending_steam_distance_km += distance_units * DISTANCE_KM_PER_UNIT
var whole_km: int = int(floor(_pending_steam_distance_km))
if whole_km <= 0:
return
_pending_steam_distance_km -= float(whole_km)
var total_distance_km: int = StatsManager.get_int(STEAM_DISTANCE_STAT) + whole_km
StatsManager.set_int(STEAM_DISTANCE_STAT, total_distance_km)
_check_distance_achievements(total_distance_km)
StatsManager.store()
#Check achievements
func _check_distance_achievements(total_distance_km: int) -> void:
if total_distance_km >= 100:
AchievementManager.unlock("ACH_DISTANCE_100")
if total_distance_km >= 200:
AchievementManager.unlock("ACH_DISTANCE_200")
func _execute_stop(go_forward: bool = true) -> void: func _execute_stop(go_forward: bool = true) -> void:
if not _find_next_valid_stop(go_forward): if not _find_next_valid_stop(go_forward):
@@ -525,6 +502,8 @@ func _execute_stop(go_forward: bool = true) -> void:
stop_multiply = 0.0 stop_multiply = 0.0
var current_stop_index = next_stop_index var current_stop_index = next_stop_index
StatsManager.add_int("stat_stop_number", 1)
StatsManager.store()
_advance_next_stop_index(go_forward) _advance_next_stop_index(go_forward)

View File

@@ -40,6 +40,7 @@ func _on_color_selected(selected_color_picker: TrainColorPicker, material_index:
for i in range(color_pickers.size()): for i in range(color_pickers.size()):
if color_pickers[i] == selected_color_picker: if color_pickers[i] == selected_color_picker:
_set_selected_color(i, material_index) _set_selected_color(i, material_index)
AchievementManager.unlock("ACH_CHANGE_TRAIN_COLOR")
break break
func _apply_train_color(color: Color, material_index: int, color_index: int = 0) -> void: func _apply_train_color(color: Color, material_index: int, color_index: int = 0) -> void:

View File

@@ -113,6 +113,7 @@ func _on_time_of_day_row_on_option_changed(data: String) -> void:
pass pass
func _on_weather_row_on_option_changed(data: String) -> void: func _on_weather_row_on_option_changed(data: String) -> void:
var weather_changed: bool = true
match data: match data:
"Snow": "Snow":
_snow = !_snow _snow = !_snow
@@ -129,9 +130,10 @@ func _on_weather_row_on_option_changed(data: String) -> void:
"Random": "Random":
pick_random_weather() pick_random_weather()
_: _:
pass weather_changed = false
AchievementManager.is_unlocked("ACH_CHANGE_METEO") if weather_changed:
AchievementManager.unlock("ACH_CHANGE_METEO")
func pick_random_weather() -> void: func pick_random_weather() -> void:
var valid_buttons = [] var valid_buttons = []
@@ -214,7 +216,6 @@ func _on_photo_taken_finished() -> void:
func _on_choo_choo_button_pressed() -> void: func _on_choo_choo_button_pressed() -> void:
UIEvents.toot_toot.emit(true) UIEvents.toot_toot.emit(true)
AchievementManager.is_unlocked("ACH_CHANGE_TRAIN_COLOR")
func _set_buttons_mouse_filter(ignore: bool) -> void: func _set_buttons_mouse_filter(ignore: bool) -> void:
var filter = Control.MOUSE_FILTER_IGNORE if ignore else Control.MOUSE_FILTER_STOP var filter = Control.MOUSE_FILTER_IGNORE if ignore else Control.MOUSE_FILTER_STOP

View File

@@ -6,6 +6,11 @@ extends Node
const KNOWN := [ const KNOWN := [
"ACH_CHANGE_METEO", "ACH_CHANGE_METEO",
"ACH_CHANGE_TRAIN_COLOR", "ACH_CHANGE_TRAIN_COLOR",
"ACH_DISTANCE_100",
"ACH_DISTANCE_200",
"ACH_10_PHOTOS",
"ACH_10_TOOTTOOT",
"ACH_DISTANCE_1000"
] ]
#how it works: #how it works:

View File

@@ -13,6 +13,13 @@ const KNOWN := [
"stat_photo_number", "stat_photo_number",
"stat_toottoot_number", "stat_toottoot_number",
] ]
const TIME_PLAYED_STAT: String = "stat_time_played"
const DISTANCE_KM_STAT: String = "stat_distance_km"
const STATS_STORE_INTERVAL_SECONDS: int = 60
var _pending_time_played_seconds: float = 0.0
var _pending_distance_km: float = 0.0
var _stats_store_timer: float = 0.0
#how it works: #how it works:
#func _on_match_finished(score: int) -> void: #func _on_match_finished(score: int) -> void:
@@ -25,10 +32,20 @@ const KNOWN := [
func _ready() -> void: func _ready() -> void:
if not SteamManager.is_on_steam: if not SteamManager.is_on_steam:
set_process(false)
return return
Steam.user_stats_stored.connect(_on_stats_stored) Steam.user_stats_stored.connect(_on_stats_stored)
func _process(delta: float) -> void:
_pending_time_played_seconds += delta
_stats_store_timer += delta
if _stats_store_timer >= STATS_STORE_INTERVAL_SECONDS:
_flush_periodic_stats(false)
func _exit_tree() -> void:
_flush_periodic_stats(true)
func get_int(stat: String) -> int: func get_int(stat: String) -> int:
if not SteamManager.is_on_steam: if not SteamManager.is_on_steam:
return 0 return 0
@@ -62,6 +79,14 @@ func add_int(stat: String, amount: int = 1) -> void:
return return
set_int(stat, get_int(stat) + amount) set_int(stat, get_int(stat) + amount)
func add_distance_km(distance_km: float) -> void:
if not SteamManager.is_on_steam:
return
if distance_km <= 0.0:
return
_pending_distance_km += distance_km
func update_avg_rate(stat: String, count_this_session: float, session_length: float) -> void: func update_avg_rate(stat: String, count_this_session: float, session_length: float) -> void:
if not SteamManager.is_on_steam: if not SteamManager.is_on_steam:
return return
@@ -74,6 +99,32 @@ func store() -> void:
if not Steam.storeStats(): if not Steam.storeStats():
push_error("storeStats failed; data saved locally") push_error("storeStats failed; data saved locally")
#periodic stats incrementation; store data every 60 secs
func _flush_periodic_stats(force_store: bool) -> void:
if not SteamManager.is_on_steam:
_pending_time_played_seconds = 0.0
_pending_distance_km = 0.0
_stats_store_timer = 0.0
return
var has_changes: bool = false
var whole_seconds: int = int(floor(_pending_time_played_seconds))
if whole_seconds > 0:
_pending_time_played_seconds -= float(whole_seconds)
add_int(TIME_PLAYED_STAT, whole_seconds)
has_changes = true
var whole_km: int = int(floor(_pending_distance_km))
if whole_km > 0:
_pending_distance_km -= float(whole_km)
add_int(DISTANCE_KM_STAT, whole_km)
has_changes = true
_stats_store_timer = 0.0
if has_changes and (force_store or whole_seconds > 0 or whole_km > 0):
store()
#Development only: reset stats #Development only: reset stats
func reset_all(include_achievements: bool = false) -> void: func reset_all(include_achievements: bool = false) -> void:
if not SteamManager.is_on_steam: if not SteamManager.is_on_steam:

View File

@@ -250,7 +250,6 @@ wagon_count = 5
wagon_gap = 0.8 wagon_gap = 0.8
wagon_spacing_scale = 0.9 wagon_spacing_scale = 0.9
cameras = NodePath("../cameras") cameras = NodePath("../cameras")
train_start_mode = 2
sleepers_model = ExtResource("46_lbmv2") sleepers_model = ExtResource("46_lbmv2")
fireworks_scene = ExtResource("47_q7p65") fireworks_scene = ExtResource("47_q7p65")