veloren_rtsim/data/
airship.rs

1use common::{
2    rtsim::{NpcId, SiteId},
3    util::Dir,
4};
5use std::cmp::Ordering;
6use vek::*;
7use world::{civ::airship_travel::Airships, index::Index, util::DHashMap};
8
9/// Data for airship operations. This is part of RTSimData and is NOT persisted.
10pub type AirshipRouteId = u32;
11#[derive(Clone, Default)]
12pub struct AirshipSim {
13    /// The pilot route assignments. The key is the pilot NpcId, the value is
14    /// the route id.
15    pub assigned_routes: DHashMap<NpcId, AirshipRouteId>,
16    /// The pilots assigned to a route. The value is a list of pilot NpcIds. The
17    /// key is the route id.
18    pub route_pilots: DHashMap<AirshipRouteId, Vec<NpcId>>,
19}
20
21const AIRSHIP_DEBUG: bool = false;
22
23macro_rules! debug_airships {
24    ($($arg:tt)*) => {
25        if AIRSHIP_DEBUG {
26            tracing::debug!($($arg)*);
27        }
28    }
29}
30
31impl AirshipSim {
32    /// Connect the airshp captain NpcId to an airship route using the given
33    /// docking position. This establishes the airship captain's route.
34    /// Returns the position where the airship should be placed.
35    pub fn register_airship_captain(
36        &mut self,
37        docking_pos: Vec3<f32>,
38        captain_id: NpcId,
39        airship_id: NpcId,
40        index: &Index,
41        airships: &Airships,
42    ) -> Option<Vec3<f32>> {
43        // Find the route where where either approach.dock_pos is equal (very close to)
44        // the given docking_pos.
45        if let Some((route_id, approach_index)) =
46            airships.airship_route_for_docking_pos(docking_pos)
47            && let Some(route) = airships.routes.get(&route_id)
48        {
49            let site0_name = index.sites.get(route.sites[0]).name().to_string();
50            let site1_name = index.sites.get(route.sites[1]).name().to_string();
51            debug_airships!(
52                "Registering airship {:?}/{:?} for docking position {:?}, site0:{}, site1:{}",
53                airship_id,
54                captain_id,
55                docking_pos,
56                site0_name,
57                site1_name
58            );
59
60            self.assigned_routes.insert(captain_id, route_id);
61            let approach = &route.approaches[approach_index];
62            let airship_wpos = approach
63                .approach_final_pos
64                .with_z(approach.airship_pos.z + approach.height);
65            debug_airships!(
66                "Airship {:?}/{:?}, approach index:{}, initial wpos:{:?}",
67                airship_id,
68                captain_id,
69                approach_index,
70                airship_wpos
71            );
72            Some(airship_wpos)
73        } else {
74            // It should be impossible to get here if
75            // should_spawn_airship_at_docking_position is working correctly.
76            tracing::warn!(
77                "Failed to register airship captain {:?} for docking position {:?}",
78                captain_id,
79                docking_pos
80            );
81            None
82        }
83    }
84
85    /// Collects the captain NPC ids for the airships flying each route (out and
86    /// back).
87    pub fn configure_route_pilots(&mut self, airships: &Airships) {
88        // for each route, get the docking position id, then for for each assigned
89        // route, get the pilot id and the routes the pilot is assigned to, then
90        // if the pilot is assigned to the route, add the pilot to the route's
91        // pilots
92        self.route_pilots
93            .extend(airships.routes.iter().map(|(route_id, _)| {
94                (
95                    *route_id,
96                    self.assigned_routes
97                        .iter()
98                        .filter(|(_, assigned_route_id)| **assigned_route_id == *route_id)
99                        .map(|(pilot_id, _)| *pilot_id)
100                        .collect(),
101                )
102            }));
103        debug_airships!("Route pilots: {:?}", self.route_pilots);
104    }
105}
106
107#[derive(Debug)]
108pub struct AirshipSpawningLocation {
109    pub pos: Vec3<f32>,
110    pub dir: Dir,
111    pub center: Vec2<i32>,
112    pub docking_pos: Vec3<i32>,
113    pub site_id: SiteId,
114    pub site_name: String,
115}
116
117impl PartialEq for AirshipSpawningLocation {
118    fn eq(&self, other: &Self) -> bool {
119        self.center == other.center
120            && self.docking_pos == other.docking_pos
121            && self.site_id == other.site_id
122    }
123}
124
125impl Eq for AirshipSpawningLocation {}
126
127impl Ord for AirshipSpawningLocation {
128    fn cmp(&self, other: &Self) -> Ordering {
129        self.site_id
130            .cmp(&other.site_id)
131            .then_with(|| self.docking_pos.cmp(&other.docking_pos))
132    }
133}
134
135impl PartialOrd for AirshipSpawningLocation {
136    fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
137}