# -*- coding: utf-8 -*- from core.kick_off_event import KickOffEvent class Step: """Represents a single replay step, potentially containing major events.""" def __init__(self, step_number=None, game_turn=None, team0_score=0, team1_score=0, active_team_id=None): self.step_number = step_number # Sequential replay step counter self.game_turn = game_turn # GameTurn value from replay self.team0_score = team0_score self.team1_score = team1_score self.active_team_id = active_team_id # 0 or 1, from PlayerStep self.turn_owner_team_id = None self.kick_off = None # KickOffEvent if one occurred in this step self.touchdown = None # Touchdown details if one occurred in this step self.weather = None # Weather snapshot after this step, if known self.roll_events = [] # All non-kickoff dice roll events found in this step self.explicit_turn_end = False # True when replay emitted EventEndTurn in this step self.end_turn_reason = None # Replay EventEndTurn.Reason self.end_turn_type = None # Replay EventEndTurn.FinishingTurnType self.next_active_team_id = None # Replay next active gamer, when explicit self.acting_player_id = None # Replay-resolved acting player for this step self.acting_player_name = None self.acting_player_team_id = None def has_kick_off(self): """Check if this step has a kickoff event.""" return self.kick_off is not None def set_kick_off(self, kick_off_event): """Set the kickoff event for this step.""" if isinstance(kick_off_event, KickOffEvent): self.kick_off = kick_off_event else: raise ValueError("kick_off_event must be a KickOffEvent instance") def has_touchdown(self): """Check if this step records a touchdown.""" return self.touchdown is not None def set_touchdown(self, player_id, player_name, team_id): """Store touchdown details for this step.""" self.touchdown = { 'player_id': player_id, 'player_name': player_name, 'team_id': team_id, } def set_weather(self, weather): """Store weather snapshot for this step.""" if isinstance(weather, dict) or weather is None: self.weather = weather else: raise ValueError("weather must be a dict or None") def add_roll_event(self, roll_event): """Add a parsed dice roll event for this step.""" if isinstance(roll_event, dict): self.roll_events.append(roll_event) else: raise ValueError("roll_event must be a dict") def set_turn_boundary(self, explicit_turn_end=False, end_turn_reason=None, end_turn_type=None, next_active_team_id=None): """Store explicit turn-boundary metadata extracted from replay events.""" self.explicit_turn_end = bool(explicit_turn_end) self.end_turn_reason = end_turn_reason self.end_turn_type = end_turn_type self.next_active_team_id = next_active_team_id def set_turn_owner(self, team_id): """Store canonical team-turn ownership for this step.""" self.turn_owner_team_id = team_id def set_acting_player(self, player_id=None, player_name=None, team_id=None): """Store replay-resolved acting player metadata for this step.""" self.acting_player_id = player_id self.acting_player_name = player_name self.acting_player_team_id = team_id def __repr__(self) -> str: kick_off_str = f", KickOff: {self.kick_off}" if self.kick_off else "" touchdown_str = f", Touchdown: {self.touchdown}" if self.touchdown else "" weather_str = f", Weather: {self.weather}" if self.weather else "" turn_end_str = "" if self.explicit_turn_end: turn_end_str = ( f", TurnEnd(reason={self.end_turn_reason}, type={self.end_turn_type}, " f"next={self.next_active_team_id})" ) return f"Step(#{self.step_number}, GameTurn={self.game_turn}, Team{self.active_team_id} active, Score {self.team0_score}-{self.team1_score}{kick_off_str}{touchdown_str}{weather_str}{turn_end_str})" def to_dict(self): return { 'step_number': self.step_number, 'game_turn': self.game_turn, 'team0_score': self.team0_score, 'team1_score': self.team1_score, 'active_team_id': self.active_team_id, 'turn_owner_team_id': self.turn_owner_team_id, 'kick_off': self.kick_off.to_dict() if self.kick_off else None, 'touchdown': self.touchdown, 'weather': self.weather, 'roll_events': self.roll_events, 'explicit_turn_end': self.explicit_turn_end, 'end_turn_reason': self.end_turn_reason, 'end_turn_type': self.end_turn_type, 'next_active_team_id': self.next_active_team_id, 'acting_player_id': self.acting_player_id, 'acting_player_name': self.acting_player_name, 'acting_player_team_id': self.acting_player_team_id, }