""" Ride-Specific Statistics Models This module contains specialized statistics models for different ride categories: - WaterRideStats: For water rides (WR) - DarkRideStats: For dark rides (DR) - FlatRideStats: For flat rides (FR) These complement the existing RollerCoasterStats model in rides.py. """ import pghistory from django.db import models from apps.core.history import TrackedModel # Wetness Level Choices for Water Rides WETNESS_LEVELS = [ ("DRY", "Dry - No water contact"), ("MILD", "Mild - Light misting"), ("MODERATE", "Moderate - Some splashing"), ("SOAKING", "Soaking - Prepare to get drenched"), ] # Motion Type Choices for Flat Rides MOTION_TYPES = [ ("SPINNING", "Spinning"), ("SWINGING", "Swinging"), ("BOUNCING", "Bouncing"), ("ROTATING", "Rotating"), ("DROPPING", "Dropping"), ("MIXED", "Mixed Motion"), ] @pghistory.track() class WaterRideStats(TrackedModel): """ Statistics specific to water rides (category=WR). Tracks water-related attributes like wetness level and splash characteristics. """ ride = models.OneToOneField( "rides.Ride", on_delete=models.CASCADE, related_name="water_stats", help_text="Ride these water statistics belong to", ) wetness_level = models.CharField( max_length=10, choices=WETNESS_LEVELS, default="MODERATE", help_text="How wet riders typically get", ) splash_height_ft = models.DecimalField( max_digits=5, decimal_places=2, null=True, blank=True, help_text="Maximum splash height in feet", ) has_splash_zone = models.BooleanField( default=False, help_text="Whether there is a designated splash zone for spectators", ) boat_capacity = models.PositiveIntegerField( null=True, blank=True, help_text="Number of riders per boat/raft", ) uses_flume = models.BooleanField( default=False, help_text="Whether the ride uses a flume/log system", ) rapids_sections = models.PositiveIntegerField( default=0, help_text="Number of rapids/whitewater sections", ) class Meta(TrackedModel.Meta): verbose_name = "Water Ride Statistics" verbose_name_plural = "Water Ride Statistics" ordering = ["ride"] def __str__(self) -> str: return f"Water Stats for {self.ride.name}" @pghistory.track() class DarkRideStats(TrackedModel): """ Statistics specific to dark rides (category=DR). Tracks theming elements like scenes, animatronics, and technology. """ ride = models.OneToOneField( "rides.Ride", on_delete=models.CASCADE, related_name="dark_stats", help_text="Ride these dark ride statistics belong to", ) scene_count = models.PositiveIntegerField( default=0, help_text="Number of themed scenes", ) animatronic_count = models.PositiveIntegerField( default=0, help_text="Number of animatronic figures", ) has_projection_technology = models.BooleanField( default=False, help_text="Whether the ride uses projection mapping or screens", ) is_interactive = models.BooleanField( default=False, help_text="Whether riders can interact with elements (shooting, etc.)", ) ride_system = models.CharField( max_length=100, blank=True, help_text="Type of ride system (Omnimover, Trackless, Classic Track, etc.)", ) uses_practical_effects = models.BooleanField( default=True, help_text="Whether the ride uses practical/physical effects", ) uses_motion_base = models.BooleanField( default=False, help_text="Whether vehicles have motion simulation capability", ) class Meta(TrackedModel.Meta): verbose_name = "Dark Ride Statistics" verbose_name_plural = "Dark Ride Statistics" ordering = ["ride"] def __str__(self) -> str: return f"Dark Ride Stats for {self.ride.name}" @pghistory.track() class FlatRideStats(TrackedModel): """ Statistics specific to flat rides (category=FR). Tracks motion characteristics like rotation, swing angles, and height. """ ride = models.OneToOneField( "rides.Ride", on_delete=models.CASCADE, related_name="flat_stats", help_text="Ride these flat ride statistics belong to", ) max_height_ft = models.DecimalField( max_digits=6, decimal_places=2, null=True, blank=True, help_text="Maximum ride height in feet", ) rotation_speed_rpm = models.DecimalField( max_digits=5, decimal_places=2, null=True, blank=True, help_text="Maximum rotation speed in RPM", ) swing_angle_degrees = models.PositiveIntegerField( null=True, blank=True, help_text="Maximum swing angle in degrees (for swinging rides)", ) motion_type = models.CharField( max_length=20, choices=MOTION_TYPES, default="SPINNING", help_text="Primary type of motion", ) arm_count = models.PositiveIntegerField( null=True, blank=True, help_text="Number of arms/gondolas", ) seats_per_gondola = models.PositiveIntegerField( null=True, blank=True, help_text="Number of seats per gondola/arm", ) max_g_force = models.DecimalField( max_digits=4, decimal_places=2, null=True, blank=True, help_text="Maximum G-force experienced", ) class Meta(TrackedModel.Meta): verbose_name = "Flat Ride Statistics" verbose_name_plural = "Flat Ride Statistics" ordering = ["ride"] def __str__(self) -> str: return f"Flat Ride Stats for {self.ride.name}" # Transport Type Choices for Transportation Rides TRANSPORT_TYPES = [ ("TRAIN", "Train"), ("MONORAIL", "Monorail"), ("SKYLIFT", "Skylift / Chairlift"), ("FERRY", "Ferry / Boat"), ("PEOPLEMOVER", "PeopleMover"), ("CABLE_CAR", "Cable Car"), ("TRAM", "Tram"), ] @pghistory.track() class KiddieRideStats(TrackedModel): """ Statistics specific to kiddie rides (category=KR). Tracks age-appropriate ride characteristics and theming. """ ride = models.OneToOneField( "rides.Ride", on_delete=models.CASCADE, related_name="kiddie_stats", help_text="Ride these kiddie ride statistics belong to", ) min_age = models.PositiveIntegerField( null=True, blank=True, help_text="Minimum recommended age in years", ) max_age = models.PositiveIntegerField( null=True, blank=True, help_text="Maximum recommended age in years", ) educational_theme = models.CharField( max_length=200, blank=True, help_text="Educational theme if applicable (e.g., 'Dinosaurs', 'Space')", ) character_theme = models.CharField( max_length=200, blank=True, help_text="Character theme if applicable (e.g., 'Paw Patrol', 'Peppa Pig')", ) guardian_required = models.BooleanField( default=False, help_text="Whether a guardian must be present during the ride", ) adult_ride_along = models.BooleanField( default=True, help_text="Whether adults can ride along with children", ) seats_per_vehicle = models.PositiveIntegerField( null=True, blank=True, help_text="Number of seats per ride vehicle", ) class Meta(TrackedModel.Meta): verbose_name = "Kiddie Ride Statistics" verbose_name_plural = "Kiddie Ride Statistics" ordering = ["ride"] def __str__(self) -> str: return f"Kiddie Ride Stats for {self.ride.name}" @pghistory.track() class TransportationStats(TrackedModel): """ Statistics specific to transportation rides (category=TR). Tracks route, capacity, and vehicle information. """ ride = models.OneToOneField( "rides.Ride", on_delete=models.CASCADE, related_name="transport_stats", help_text="Ride these transportation statistics belong to", ) transport_type = models.CharField( max_length=20, choices=TRANSPORT_TYPES, default="TRAIN", help_text="Type of transportation", ) route_length_ft = models.DecimalField( max_digits=8, decimal_places=2, null=True, blank=True, help_text="Total route length in feet", ) stations_count = models.PositiveIntegerField( null=True, blank=True, help_text="Number of stations/stops on the route", ) vehicle_capacity = models.PositiveIntegerField( null=True, blank=True, help_text="Passenger capacity per vehicle", ) vehicles_count = models.PositiveIntegerField( null=True, blank=True, help_text="Total number of vehicles in operation", ) round_trip_duration_minutes = models.PositiveIntegerField( null=True, blank=True, help_text="Duration of a complete round trip in minutes", ) scenic_highlights = models.TextField( blank=True, help_text="Notable scenic views or attractions along the route", ) is_one_way = models.BooleanField( default=False, help_text="Whether this is a one-way transportation (vs round-trip)", ) class Meta(TrackedModel.Meta): verbose_name = "Transportation Statistics" verbose_name_plural = "Transportation Statistics" ordering = ["ride"] def __str__(self) -> str: return f"Transportation Stats for {self.ride.name}"