class_name ReputationEvaluator extends RefCounted ## Evaluates player performance (PLAN.md: Reputation Meter). ## Scoring weights are data so they can be tuned per venue. const EventBus := preload("res://src/core/event_bus.gd") ## rating: float starting 50 (out of 100). Errors subtract, though marks add. var rating: float = 70.0 var _modifiers: Array[Dictionary] = [] var event_bus: EventBus = null func set_event_bus(bus: EventBus) -> void: event_bus = bus ## Apply a reputation change. ## category: "peaceful", "force", "false_report", "accuracy", "complaint", ## "security_failure", "property_damage", "access_judgment", "crowd" func apply(_category: String, delta: float, reason: String) -> void: # Clamp range: 0..100. var clamped := clampf(rating + delta, 0.0, 100.0) var applied: float = clamped - rating rating = clamped _modifiers.append({ "category": _category, "delta": applied, "reason": reason, "at_ms": Time.get_ticks_msec(), }) if event_bus: event_bus.reputation_changed.emit({ "rating": rating, "delta": applied, "reason": reason, "category": _category, }) static func grade_for(rating_value: float) -> String: if rating_value >= 90.0: return "A" if rating_value >= 75.0: return "B" if rating_value >= 60.0: return "C" if rating_value >= 40.0: return "D" return "F" func summary() -> Dictionary: return { "rating": rating, "grade": grade_for(rating), "modifiers": _modifiers.duplicate(true), } func snapshot() -> Dictionary: return {"rating": rating, "modifiers": _modifiers.duplicate(true)} func restore(data: Dictionary) -> void: rating = clampf(float(data.get("rating", 70.0)), 0.0, 100.0) _modifiers.clear() for modifier in data.get("modifiers", []): if modifier is Dictionary: _modifiers.append((modifier as Dictionary).duplicate(true))