2025-03-15 19:34:29 -04:00
|
|
|
use physis::{
|
2025-03-15 21:41:39 -04:00
|
|
|
common::{Language, Platform},
|
2025-03-15 19:34:29 -04:00
|
|
|
gamedata::GameData,
|
|
|
|
layer::{
|
|
|
|
ExitRangeInstanceObject, InstanceObject, LayerEntryData, LayerGroup, PopRangeInstanceObject,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2025-03-15 20:36:39 -04:00
|
|
|
use crate::config::get_config;
|
2025-03-15 19:34:29 -04:00
|
|
|
|
|
|
|
/// Represents a loaded zone
|
|
|
|
pub struct Zone {
|
2025-03-15 20:49:07 -04:00
|
|
|
pub id: u16,
|
2025-03-15 19:34:29 -04:00
|
|
|
layer_group: LayerGroup,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Zone {
|
|
|
|
pub fn load(id: u16) -> Self {
|
|
|
|
let config = get_config();
|
|
|
|
|
|
|
|
let mut game_data =
|
|
|
|
GameData::from_existing(Platform::Win32, &config.game_location).unwrap();
|
2025-03-15 21:41:39 -04:00
|
|
|
|
|
|
|
let exh = game_data.read_excel_sheet_header("TerritoryType").unwrap();
|
|
|
|
let exd = game_data.read_excel_sheet("TerritoryType", &exh, Language::None, 0).unwrap();
|
|
|
|
|
|
|
|
let territory_type_row = &exd.read_row(&exh, id as u32).unwrap()[0];
|
|
|
|
|
|
|
|
// e.g. ffxiv/fst_f1/fld/f1f3/level/f1f3
|
|
|
|
let physis::exd::ColumnData::String(bg_path) = &territory_type_row.data[1] else {
|
|
|
|
panic!("Unexpected type!");
|
|
|
|
};
|
|
|
|
|
|
|
|
let path = format!("bg/{}/level/planmap.lgb", &bg_path[..bg_path.find("/level/").unwrap()]);
|
|
|
|
let lgb = game_data.extract(&path).unwrap();
|
|
|
|
let layer_group = LayerGroup::from_existing(&lgb).unwrap();
|
2025-03-15 19:34:29 -04:00
|
|
|
Self { id, layer_group }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Search for an exit box matching an id.
|
|
|
|
pub fn find_exit_box(
|
|
|
|
&self,
|
|
|
|
instance_id: u32,
|
|
|
|
) -> Option<(&InstanceObject, &ExitRangeInstanceObject)> {
|
|
|
|
// TODO: also check position!
|
|
|
|
for group in &self.layer_group.layers {
|
|
|
|
for object in &group.objects {
|
|
|
|
if let LayerEntryData::ExitRange(exit_range) = &object.data {
|
|
|
|
if object.instance_id == instance_id {
|
|
|
|
return Some((object, exit_range));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn find_pop_range(
|
|
|
|
&self,
|
|
|
|
instance_id: u32,
|
|
|
|
) -> Option<(&InstanceObject, &PopRangeInstanceObject)> {
|
|
|
|
// TODO: also check position!
|
|
|
|
for group in &self.layer_group.layers {
|
|
|
|
for object in &group.objects {
|
|
|
|
if let LayerEntryData::PopRange(pop_range) = &object.data {
|
|
|
|
if object.instance_id == instance_id {
|
|
|
|
return Some((object, pop_range));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|