100 lines
2.7 KiB
Rust
100 lines
2.7 KiB
Rust
use std::sync::Arc;
|
|
|
|
use anyhow::Result;
|
|
use druid::Data;
|
|
|
|
use crate::{GameState, Notes};
|
|
use crate::notes::{Area, Step};
|
|
|
|
#[derive(Clone, Data)]
|
|
pub struct NotesState {
|
|
pub notes: Arc<Notes>,
|
|
last_stage: u16,
|
|
last_location: u32,
|
|
|
|
pub step_idx: Option<usize>,
|
|
pub area_idx: usize,
|
|
|
|
current_step: Step,
|
|
}
|
|
|
|
impl NotesState {
|
|
pub fn new(notes: Notes, game: &mut GameState) -> Result<Self> {
|
|
game.refresh()?;
|
|
// find first step with a matching story stage
|
|
let steps = notes.steps
|
|
.iter()
|
|
.take_while(|step| step.stage <= game.stage)
|
|
.count();
|
|
let (step, step_idx) = if steps == 0 {
|
|
// nothing previous
|
|
(notes.steps[0].clone(), None)
|
|
} else {
|
|
// in progress
|
|
(notes.steps[steps - 1].clone(), Some(steps - 1))
|
|
};
|
|
// find first area that matches
|
|
let area_idx = step.areas
|
|
.iter()
|
|
.position(|area| area.area == 0 || area.area == game.location)
|
|
.unwrap_or(0);
|
|
|
|
Ok(Self {
|
|
notes: Arc::new(notes),
|
|
last_stage: 0,
|
|
last_location: 0,
|
|
step_idx,
|
|
area_idx,
|
|
current_step: step,
|
|
})
|
|
}
|
|
|
|
pub fn tick(&mut self, game: &mut GameState) -> Result<bool> {
|
|
self.last_stage = game.stage;
|
|
self.last_location = game.location;
|
|
game.refresh()?;
|
|
|
|
let stage_changed = self.last_stage != game.stage;
|
|
let location_changed = self.last_location != game.location;
|
|
|
|
let step_advanced = stage_changed && self.change_step(game);
|
|
let mut highlight_changed = step_advanced;
|
|
let area = match self.next_area() {
|
|
Some(area) => area.clone(),
|
|
None => return Ok(highlight_changed),
|
|
};
|
|
|
|
if !step_advanced && location_changed && (game.location == area.area || area.area == 0) {
|
|
self.area_idx += 1;
|
|
highlight_changed = true;
|
|
}
|
|
|
|
Ok(highlight_changed)
|
|
}
|
|
|
|
fn area(&self) -> Option<&Area> {
|
|
self.current_step.areas.get(self.area_idx)
|
|
}
|
|
|
|
fn next_area(&self) -> Option<&Area> {
|
|
self.current_step.areas.get(self.area_idx + 1)
|
|
}
|
|
|
|
fn change_step(&mut self, game: &mut GameState) -> bool {
|
|
let idx = self.step_idx.map(|x| x + 1).unwrap_or(0);
|
|
let next = match self.notes.steps.get(idx) {
|
|
Some(step) => step,
|
|
None => return false,
|
|
};
|
|
|
|
if next.stage == game.stage {
|
|
self.current_step = next.clone();
|
|
self.step_idx = Some(idx);
|
|
self.area_idx = 0;
|
|
return true;
|
|
}
|
|
|
|
false
|
|
}
|
|
}
|