diff --git a/data/system/assets/tools/uphill.svg b/data/system/assets/tools/uphill.svg new file mode 100644 index 0000000000..6ef9200c99 --- /dev/null +++ b/data/system/assets/tools/uphill.svg @@ -0,0 +1,4 @@ + + + + diff --git a/game/src/challenges/prebake.rs b/game/src/challenges/prebake.rs index 8803bb68d6..ddab1139b9 100644 --- a/game/src/challenges/prebake.rs +++ b/game/src/challenges/prebake.rs @@ -131,7 +131,7 @@ fn prebake( } PrebakeSummary { map: scenario.map_name.describe(), - scenario: scenario.scenario_name.clone(), + scenario: scenario.scenario_name, finished_trips, cancelled_trips, total_trip_duration_seconds, diff --git a/game/src/info/building.rs b/game/src/info/building.rs index 5de55c2fb7..ded741dff5 100644 --- a/game/src/info/building.rs +++ b/game/src/info/building.rs @@ -306,6 +306,7 @@ pub fn draw_occupants(details: &mut Details, app: &App, id: BuildingID, focus: O pos, facing: Angle::degrees(90.0), waiting_for_turn: None, + intent: None, preparing_bike: false, // Both hands and feet! waiting_for_bus: true, diff --git a/geom/src/distance.rs b/geom/src/distance.rs index 16d299ebb5..109aeea01d 100644 --- a/geom/src/distance.rs +++ b/geom/src/distance.rs @@ -125,16 +125,14 @@ impl Distance { Distance::feet(10.0 * (ft / 10.0).ceil()) } else if miles < 0.1 { Distance::feet(100.0 * (ft / 100.0).ceil()) + } else if miles <= 1.0 { + Distance::miles((miles * 10.0).ceil() / 10.0) + } else if miles <= 10.0 { + Distance::miles(miles.ceil()) + } else if miles <= 100.0 { + Distance::miles(10.0 * (miles / 10.0).ceil()) } else { - if miles <= 1.0 { - Distance::miles((miles * 10.0).ceil() / 10.0) - } else if miles <= 10.0 { - Distance::miles(miles.ceil()) - } else if miles <= 100.0 { - Distance::miles(10.0 * (miles / 10.0).ceil()) - } else { - self - } + self } } } diff --git a/map_gui/src/render/bike.rs b/map_gui/src/render/bike.rs index 4be6e527bf..40cbff8f4f 100644 --- a/map_gui/src/render/bike.rs +++ b/map_gui/src/render/bike.rs @@ -1,6 +1,6 @@ use geom::{ArrowCap, Circle, Distance, Line, PolyLine, Polygon, Pt2D}; use map_model::{Map, SIDEWALK_THICKNESS}; -use sim::{CarID, DrawCarInput, Sim}; +use sim::{CarID, DrawCarInput, Intent, Sim}; use widgetry::{Drawable, GeomBatch, GfxCtx, Prerender}; use crate::colors::ColorScheme; @@ -99,6 +99,25 @@ impl DrawBike { ); } + if input.intent == Some(Intent::SteepUphill) { + let bubble_z = -0.0001; + let mut bubble_batch = + GeomBatch::load_svg(prerender, "system/assets/map/thought_bubble.svg") + .scale(0.05) + .centered_on(input.body.middle()) + .translate(2.0, -3.5) + .set_z_offset(bubble_z); + bubble_batch.append( + GeomBatch::load_svg(prerender, "system/assets/tools/uphill.svg") + .scale(0.05) + .centered_on(input.body.middle()) + .translate(2.2, -4.2) + .set_z_offset(bubble_z), + ); + + draw_default.append(bubble_batch); + } + let zorder = input .partly_on .into_iter() diff --git a/map_gui/src/render/car.rs b/map_gui/src/render/car.rs index d0116a7544..9b19c23bc2 100644 --- a/map_gui/src/render/car.rs +++ b/map_gui/src/render/car.rs @@ -1,6 +1,6 @@ use geom::{Angle, ArrowCap, Distance, PolyLine, Polygon, Pt2D, Ring}; use map_model::{Map, TurnType}; -use sim::{CarID, CarStatus, DrawCarInput, Sim, VehicleType}; +use sim::{CarID, CarStatus, DrawCarInput, Intent, Sim, VehicleType}; use widgetry::{Color, Drawable, GeomBatch, GfxCtx, Line, Prerender, Text}; use crate::colors::ColorScheme; @@ -90,7 +90,7 @@ impl DrawCar { ); } - if input.show_parking_intent { + if input.intent == Some(Intent::Parking) { // draw intent bubble let bubble_z = -0.0001; let mut bubble_batch = diff --git a/map_gui/src/render/pedestrian.rs b/map_gui/src/render/pedestrian.rs index 1a55336859..28df9b5287 100644 --- a/map_gui/src/render/pedestrian.rs +++ b/map_gui/src/render/pedestrian.rs @@ -1,6 +1,6 @@ use geom::{ArrowCap, Circle, Distance, PolyLine, Polygon, Pt2D}; use map_model::{DrivingSide, Map, SIDEWALK_THICKNESS}; -use sim::{DrawPedCrowdInput, DrawPedestrianInput, PedCrowdLocation, PedestrianID, Sim}; +use sim::{DrawPedCrowdInput, DrawPedestrianInput, Intent, PedCrowdLocation, PedestrianID, Sim}; use widgetry::{Color, Drawable, GeomBatch, GfxCtx, Line, Prerender, Text}; use crate::colors::ColorScheme; @@ -43,6 +43,25 @@ impl DrawPedestrian { ); } + if input.intent == Some(Intent::SteepUphill) { + let bubble_z = -0.0001; + let mut bubble_batch = + GeomBatch::load_svg(prerender, "system/assets/map/thought_bubble.svg") + .scale(0.05) + .centered_on(input.pos) + .translate(2.0, -3.5) + .set_z_offset(bubble_z); + bubble_batch.append( + GeomBatch::load_svg(prerender, "system/assets/tools/uphill.svg") + .scale(0.05) + .centered_on(input.pos) + .translate(2.2, -4.2) + .set_z_offset(bubble_z), + ); + + draw_default.append(bubble_batch); + } + DrawPedestrian { id: input.id, body_circle, diff --git a/map_model/src/pathfind/vehicles.rs b/map_model/src/pathfind/vehicles.rs index 6dd04271a5..a7d06de5e0 100644 --- a/map_model/src/pathfind/vehicles.rs +++ b/map_model/src/pathfind/vehicles.rs @@ -260,7 +260,7 @@ pub fn vehicle_cost( PathConstraints::Pedestrian => unreachable!(), }; let t1 = map.get_r(dr.id).center_pts.length() - / Traversable::max_speed_along_road(dr, max_speed, constraints, map); + / Traversable::max_speed_along_road(dr, max_speed, constraints, map).0; let t2 = mvmnt_length / Traversable::max_speed_along_movement(mvmnt, max_speed, constraints, map); diff --git a/map_model/src/traversable.rs b/map_model/src/traversable.rs index 6b2f08a093..8c22091cf2 100644 --- a/map_model/src/traversable.rs +++ b/map_model/src/traversable.rs @@ -202,6 +202,18 @@ impl Traversable { constraints: PathConstraints, map: &Map, ) -> Speed { + self.max_speed_and_incline_along(max_speed_on_flat_ground, constraints, map) + .0 + } + + /// The single definitive place to determine how fast somebody could go along a single road or + /// turn. This should be used for pathfinding and simulation. Returns (speed, percent incline). + pub fn max_speed_and_incline_along( + &self, + max_speed_on_flat_ground: Option, + constraints: PathConstraints, + map: &Map, + ) -> (Speed, f64) { match self { Traversable::Lane(l) => Traversable::max_speed_along_road( map.get_l(*l).get_directed_parent(), @@ -209,23 +221,26 @@ impl Traversable { constraints, map, ), - Traversable::Turn(t) => Traversable::max_speed_along_movement( - t.to_movement(map), - max_speed_on_flat_ground, - constraints, - map, + Traversable::Turn(t) => ( + Traversable::max_speed_along_movement( + t.to_movement(map), + max_speed_on_flat_ground, + constraints, + map, + ), + 0.0, ), } } /// The single definitive place to determine how fast somebody could go along a single road. - /// This should be used for pathfinding and simulation. - pub fn max_speed_along_road( + /// This should be used for pathfinding and simulation. Returns (speed, percent incline). + pub(crate) fn max_speed_along_road( dr: DirectedRoadID, max_speed_on_flat_ground: Option, constraints: PathConstraints, map: &Map, - ) -> Speed { + ) -> (Speed, f64) { let road = map.get_r(dr.id); let percent_incline = if dr.dir == Direction::Fwd { road.percent_incline @@ -245,16 +260,17 @@ impl Traversable { road.speed_limit }; - if let Some(s) = max_speed_on_flat_ground { + let speed = if let Some(s) = max_speed_on_flat_ground { base.min(s) } else { base - } + }; + (speed, percent_incline) } /// The single definitive place to determine how fast somebody could go along a single - /// movement. This should be used for pathfinding and simulation. - pub fn max_speed_along_movement( + /// movement. This should be used for pathfinding and simulation. Ignores elevation. + pub(crate) fn max_speed_along_movement( mvmnt: MovementID, max_speed_on_flat_ground: Option, _: PathConstraints, diff --git a/sim/src/lib.rs b/sim/src/lib.rs index 4076cb75cc..e184b6c6dc 100644 --- a/sim/src/lib.rs +++ b/sim/src/lib.rs @@ -29,7 +29,7 @@ use map_model::{ }; pub use crate::render::{ - CarStatus, DrawCarInput, DrawPedCrowdInput, DrawPedestrianInput, PedCrowdLocation, + CarStatus, DrawCarInput, DrawPedCrowdInput, DrawPedestrianInput, Intent, PedCrowdLocation, UnzoomedAgent, }; diff --git a/sim/src/mechanics/car.rs b/sim/src/mechanics/car.rs index d961d33915..8fbf42cef8 100644 --- a/sim/src/mechanics/car.rs +++ b/sim/src/mechanics/car.rs @@ -6,8 +6,8 @@ use geom::{Distance, Duration, PolyLine, Time, EPSILON_DIST}; use map_model::{Direction, LaneID, Map, Traversable}; use crate::{ - CarID, CarStatus, DistanceInterval, DrawCarInput, ParkingSpot, PersonID, Router, TimeInterval, - TransitSimState, TripID, Vehicle, VehicleType, + CarID, CarStatus, DistanceInterval, DrawCarInput, Intent, ParkingSpot, PersonID, Router, + TimeInterval, TransitSimState, TripID, Vehicle, VehicleType, }; /// Represents a single vehicle. Note "car" is a misnomer; it could also be a bus or bike. @@ -51,13 +51,17 @@ impl Car { start_time: Time, map: &Map, ) -> CarState { - let speed = self.router.head().max_speed_along( + let (speed, percent_incline) = self.router.head().max_speed_and_incline_along( self.vehicle.max_speed, self.vehicle.vehicle_type.to_constraints(), map, ); let dt = (dist_int.end - dist_int.start) / speed; - CarState::Crossing(TimeInterval::new(start_time, start_time + dt), dist_int) + CarState::Crossing { + time_int: TimeInterval::new(start_time, start_time + dt), + dist_int, + steep_uphill: percent_incline >= 0.08, + } } pub fn get_draw_car( @@ -262,17 +266,23 @@ impl Car { status: match self.state { CarState::Queued { .. } => CarStatus::Moving, CarState::WaitingToAdvance { .. } => CarStatus::Moving, - CarState::Crossing(_, _) => CarStatus::Moving, + CarState::Crossing { .. } => CarStatus::Moving, CarState::ChangingLanes { .. } => CarStatus::Moving, CarState::Unparking { .. } => CarStatus::Moving, CarState::Parking(_, _, _) => CarStatus::Moving, // Changing color for idling buses is helpful CarState::IdlingAtStop(_, _) => CarStatus::Parked, }, - show_parking_intent: matches!( - (self.is_parking(), &self.state), - (true, _) | (_, CarState::Unparking { .. }) - ), + intent: if self.is_parking() || matches!(self.state, CarState::Unparking { .. }) { + Some(Intent::Parking) + } else { + match self.state { + CarState::Crossing { steep_uphill, .. } if steep_uphill => { + Some(Intent::SteepUphill) + } + _ => None, + } + }, on: self.router.head(), partly_on, label: if self.vehicle.vehicle_type == VehicleType::Bus @@ -303,7 +313,11 @@ impl Car { /// state machine encoded here. #[derive(Debug, Serialize, Deserialize, Clone)] pub(crate) enum CarState { - Crossing(TimeInterval, DistanceInterval), + Crossing { + time_int: TimeInterval, + dist_int: DistanceInterval, + steep_uphill: bool, + }, ChangingLanes { from: LaneID, to: LaneID, @@ -334,7 +348,7 @@ pub(crate) enum CarState { impl CarState { pub fn get_end_time(&self) -> Time { match self { - CarState::Crossing(ref time_int, _) => time_int.end, + CarState::Crossing { ref time_int, .. } => time_int.end, CarState::Queued { .. } => unreachable!(), CarState::WaitingToAdvance { .. } => unreachable!(), // Note this state lasts for lc_time, NOT for new_time. diff --git a/sim/src/mechanics/driving.rs b/sim/src/mechanics/driving.rs index 3fc15fbb7e..14de95d271 100644 --- a/sim/src/mechanics/driving.rs +++ b/sim/src/mechanics/driving.rs @@ -368,7 +368,7 @@ impl DrivingSimState { transit: &mut TransitSimState, ) -> bool { match car.state { - CarState::Crossing(_, _) => { + CarState::Crossing { .. } => { car.state = CarState::Queued { blocked_since: now, want_to_change_lanes: None, @@ -554,7 +554,11 @@ impl DrivingSimState { } => { // The car is already in the target queue. Just set them in the crossing state; we // already calculated the intervals for it. - car.state = CarState::Crossing(new_time, new_dist); + car.state = CarState::Crossing { + time_int: new_time, + dist_int: new_dist, + steep_uphill: false, + }; ctx.scheduler .push(car.state.get_end_time(), Command::UpdateCar(car.vehicle.id)); @@ -595,7 +599,7 @@ impl DrivingSimState { let our_dist = dists[idx].front; match car.state { - CarState::Crossing(_, _) + CarState::Crossing { .. } | CarState::Unparking { .. } | CarState::WaitingToAdvance { .. } | CarState::ChangingLanes { .. } => unreachable!(), @@ -709,7 +713,7 @@ impl DrivingSimState { /* // If this car wasn't blocked at all, when would it reach its goal? let ideal_end_time = match car.crossing_state(our_dist, now, map) { - CarState::Crossing(time_int, _) => time_int.end, + CarState::Crossing { time_int, .. } => time_int.end, _ => unreachable!(), }; if ideal_end_time == now { @@ -876,7 +880,7 @@ impl DrivingSimState { Command::UpdateCar(follower_id), ); } - CarState::Crossing(_, _) => { + CarState::Crossing { .. } => { // If the follower was still Crossing, they might not've been blocked by the // leader yet. But recalculating their Crossing state isn't necessarily a no-op // -- this could prevent them from suddenly warping past a blockage. @@ -901,7 +905,9 @@ impl DrivingSimState { now, ctx.map, ) { - CarState::Crossing(time, dist) => (time, dist), + CarState::Crossing { + time_int, dist_int, .. + } => (time_int, dist_int), _ => unreachable!(), }; assert!(new_time.end >= lc_time.end); @@ -1051,7 +1057,7 @@ impl DrivingSimState { CarState::WaitingToAdvance { .. } => unreachable!(), // They weren't blocked. Note that there's no way the Crossing state could // jump forwards here; the leader vanished from the end of the traversable. - CarState::Crossing(_, _) + CarState::Crossing { .. } | CarState::ChangingLanes { .. } | CarState::Unparking { .. } | CarState::Parking(_, _, _) @@ -1151,7 +1157,9 @@ impl DrivingSimState { now, ctx.map, ) { - CarState::Crossing(time, dist) => (time, dist), + CarState::Crossing { + time_int, dist_int, .. + } => (time_int, dist_int), _ => unreachable!(), }; @@ -1366,7 +1374,7 @@ impl DrivingSimState { id: cause, waiting_for_turn: None, status: CarStatus::Parked, - show_parking_intent: false, + intent: None, on, partly_on: Vec::new(), label: Some("block".to_string()), @@ -1383,7 +1391,7 @@ impl DrivingSimState { id: cause, waiting_for_turn: None, status: CarStatus::Parked, - show_parking_intent: false, + intent: None, on, partly_on: Vec::new(), label: Some("block".to_string()), diff --git a/sim/src/mechanics/parking.rs b/sim/src/mechanics/parking.rs index 1b27376936..1aec4312b2 100644 --- a/sim/src/mechanics/parking.rs +++ b/sim/src/mechanics/parking.rs @@ -370,7 +370,7 @@ impl ParkingSim for NormalParkingSimState { id: p.vehicle.id, waiting_for_turn: None, status: CarStatus::Parked, - show_parking_intent: false, + intent: None, on: Traversable::Lane(lane), partly_on: Vec::new(), label: None, @@ -392,7 +392,7 @@ impl ParkingSim for NormalParkingSimState { id: p.vehicle.id, waiting_for_turn: None, status: CarStatus::Parked, - show_parking_intent: false, + intent: None, // Just used for z-order on: Traversable::Lane(pl.driving_pos.lane()), partly_on: Vec::new(), diff --git a/sim/src/mechanics/queue.rs b/sim/src/mechanics/queue.rs index c67870bebd..b58db8b319 100644 --- a/sim/src/mechanics/queue.rs +++ b/sim/src/mechanics/queue.rs @@ -228,7 +228,11 @@ impl Queue { } self.geom_len } - CarState::Crossing(ref time_int, ref dist_int) => { + CarState::Crossing { + ref time_int, + ref dist_int, + .. + } => { // TODO Why percent_clamp_end? We process car updates in any order, so we might // calculate this before moving this car from Crossing to another state. dist_int.lerp(time_int.percent_clamp_end(now)).min(bound) @@ -575,7 +579,11 @@ fn dump_cars(dists: &[QueueEntry], cars: &FixedMap, id: Traversable, println!("- {:?} @ {}..{}", entry.member, entry.front, entry.back); match entry.member { Queued::Vehicle(id) => match cars[&id].state { - CarState::Crossing(ref time_int, ref dist_int) => { + CarState::Crossing { + ref time_int, + ref dist_int, + .. + } => { println!( " Going {} .. {} during {} .. {}", dist_int.start, dist_int.end, time_int.start, time_int.end diff --git a/sim/src/mechanics/walking.rs b/sim/src/mechanics/walking.rs index 420b4be865..0713bbfe30 100644 --- a/sim/src/mechanics/walking.rs +++ b/sim/src/mechanics/walking.rs @@ -12,9 +12,9 @@ use map_model::{ use crate::sim::Ctx; use crate::{ AgentID, AgentProperties, Command, CommutersVehiclesCounts, CreatePedestrian, DistanceInterval, - DrawPedCrowdInput, DrawPedestrianInput, Event, IntersectionSimState, ParkedCar, ParkingSpot, - PedCrowdLocation, PedestrianID, PersonID, Scheduler, SidewalkPOI, SidewalkSpot, TimeInterval, - TransitSimState, TripID, TripManager, UnzoomedAgent, + DrawPedCrowdInput, DrawPedestrianInput, Event, Intent, IntersectionSimState, ParkedCar, + ParkingSpot, PedCrowdLocation, PedestrianID, PersonID, Scheduler, SidewalkPOI, SidewalkSpot, + TimeInterval, TransitSimState, TripID, TripManager, UnzoomedAgent, }; const TIME_TO_START_BIKING: Duration = Duration::const_seconds(30.0); @@ -60,13 +60,14 @@ impl WalkingSimState { let mut ped = Pedestrian { id: params.id, // Temporary bogus thing - state: PedState::Crossing( - DistanceInterval::new_walking(Distance::ZERO, Distance::meters(1.0)), - TimeInterval::new( + state: PedState::Crossing { + dist_int: DistanceInterval::new_walking(Distance::ZERO, Distance::meters(1.0)), + time_int: TimeInterval::new( Time::START_OF_DAY, Time::START_OF_DAY + Duration::seconds(1.0), ), - ), + steep_uphill: false, + }, speed: params.speed, total_blocked_time: Duration::ZERO, started_at: now, @@ -129,7 +130,7 @@ impl WalkingSimState { ) { let mut ped = self.peds.get_mut(&id).unwrap(); match ped.state { - PedState::Crossing(ref dist_int, _) => { + PedState::Crossing { ref dist_int, .. } => { if ped.path.is_last_step() { match ped.goal.connection { SidewalkPOI::ParkingSpot(spot) => { @@ -371,9 +372,11 @@ impl WalkingSimState { }*/ let current_state_dist = match p.state { - PedState::Crossing(ref dist_int, ref time_int) => { - time_int.percent(now) * dist_int.length() - } + PedState::Crossing { + ref dist_int, + ref time_int, + .. + } => time_int.percent(now) * dist_int.length(), // We're at the beginning of our trip and are only walking along a driveway or biking // connection PedState::LeavingBuilding(_, _) @@ -448,7 +451,7 @@ impl WalkingSimState { let dist = ped.get_dist_along(now, map); match ped.state { - PedState::Crossing(ref dist_int, _) => { + PedState::Crossing { ref dist_int, .. } => { if dist_int.start < dist_int.end { forwards.push((*id, dist)); } else { @@ -628,18 +631,26 @@ impl Pedestrian { } }; let dist_int = DistanceInterval::new_walking(start_dist, end_dist); - let speed = self.path.current_step().as_traversable().max_speed_along( - Some(self.speed), - PathConstraints::Pedestrian, - map, - ); + let (speed, percent_incline) = self + .path + .current_step() + .as_traversable() + .max_speed_and_incline_along(Some(self.speed), PathConstraints::Pedestrian, map); let time_int = TimeInterval::new(start_time, start_time + dist_int.length() / speed); - PedState::Crossing(dist_int, time_int) + PedState::Crossing { + dist_int, + time_int, + steep_uphill: percent_incline >= 0.08, + } } fn get_dist_along(&self, now: Time, map: &Map) -> Distance { match self.state { - PedState::Crossing(ref dist_int, ref time_int) => dist_int.lerp(time_int.percent(now)), + PedState::Crossing { + ref dist_int, + ref time_int, + .. + } => dist_int.lerp(time_int.percent(now)), PedState::WaitingToTurn(dist, _) => dist, PedState::LeavingBuilding(b, _) | PedState::EnteringBuilding(b, _) => { map.get_b(b).sidewalk_pos.dist_along() @@ -661,8 +672,13 @@ impl Pedestrian { } else { 270.0 }; + let mut intent = None; let (pos, facing) = match self.state { - PedState::Crossing(ref dist_int, ref time_int) => { + PedState::Crossing { + ref dist_int, + ref time_int, + steep_uphill, + } => { let percent = if now > time_int.end { 1.0 } else { @@ -677,6 +693,9 @@ impl Pedestrian { } else { orig_angle.opposite() }; + if steep_uphill { + intent = Some(Intent::SteepUphill); + } ( pos.project_away(SIDEWALK_THICKNESS / 4.0, facing.rotate_degs(angle_offset)), facing, @@ -758,6 +777,7 @@ impl Pedestrian { PedState::WaitingToTurn(_, _) => Some(self.path.next_step().as_turn()), _ => None, }, + intent, preparing_bike: matches!( self.state, PedState::StartingToBike(_, _, _) | PedState::FinishingBiking(_, _, _) @@ -817,7 +837,11 @@ impl Pedestrian { #[derive(Serialize, Deserialize, Debug, Clone)] enum PedState { - Crossing(DistanceInterval, TimeInterval), + Crossing { + dist_int: DistanceInterval, + time_int: TimeInterval, + steep_uphill: bool, + }, /// The Distance is either 0 or the current traversable's length. The Time is blocked_since. WaitingToTurn(Distance, Time), LeavingBuilding(BuildingID, TimeInterval), @@ -832,7 +856,7 @@ enum PedState { impl PedState { fn get_end_time(&self) -> Time { match self { - PedState::Crossing(_, ref time_int) => time_int.end, + PedState::Crossing { ref time_int, .. } => time_int.end, PedState::WaitingToTurn(_, _) => unreachable!(), PedState::LeavingBuilding(_, ref time_int) => time_int.end, PedState::EnteringBuilding(_, ref time_int) => time_int.end, diff --git a/sim/src/render.rs b/sim/src/render.rs index 13776274a1..a3e860db65 100644 --- a/sim/src/render.rs +++ b/sim/src/render.rs @@ -11,6 +11,7 @@ pub struct DrawPedestrianInput { pub pos: Pt2D, pub facing: Angle, pub waiting_for_turn: Option, + pub intent: Option, pub preparing_bike: bool, pub waiting_for_bus: bool, pub on: Traversable, @@ -37,7 +38,7 @@ pub struct DrawCarInput { pub id: CarID, pub waiting_for_turn: Option, pub status: CarStatus, - pub show_parking_intent: bool, + pub intent: Option, /// Front of the car pub on: Traversable, /// Possibly the rest @@ -56,6 +57,13 @@ pub enum CarStatus { Parked, } +/// Shows an agent's current inner intention or thoughts. +#[derive(Clone, PartialEq)] +pub enum Intent { + Parking, + SteepUphill, +} + pub struct UnzoomedAgent { pub id: AgentID, pub pos: Pt2D,