use crate::{
base::Complex,
master::{
ERR_ALREADY_SET,
ERR_NOT_SET_CANNOT_RUN,
Master
},
play::Context,
sys::{
Button,
Key,
Music,
Sound
}
};
use super::{
ColorMode,
EditMode
};
const MID: &str = "AutomatonControl";
pub enum MControl {
Unset,
Set {
_mus_forest: Option<Music>,
snd_alchemlab: Option<Sound>,
snd_tick: Option<Sound>,
snd_tock: Option<Sound>,
snd_carbrakes: Option<Sound>,
snd_carstarts: Option<Sound>,
snd_glasscracks: Option<Sound>,
snd_glasshatt: Option<Sound>,
snd_kaleidoscope: Option<Sound>,
snd_lightson: Option<Sound>,
snd_lightsoff: Option<Sound>,
snd_seed: Option<Sound>,
snd_tearpage: Option<Sound>,
tick_tock: bool
}
}
impl MControl {
pub fn new() -> Box<Self> {
Box::new(Self::Unset)
}
}
impl Master for MControl {
fn id(&self) -> String {
String::from(MID)
}
fn start(&mut self, Context{sys, ..}: &mut Context) -> Result<(), String> {
match self {
Self::Unset => {
let _mus_forest = sys.load_music("Simon_the_Sorcerer_OST_Forest.ogg");
sys.play_music(_mus_forest.as_ref()).unwrap_or(());
let mut snd_alchemlab = sys.load_sound("alchemlab0.ogg");
sys.play_sound_ever(snd_alchemlab.as_mut()).unwrap_or(());
let snd_tick = sys.load_sound("tick0.ogg");
let snd_tock = sys.load_sound("tock0.ogg");
let snd_carbrakes = sys.load_sound("carbrakes0.ogg");
let snd_carstarts = sys.load_sound("carstarts0.ogg");
let snd_glasscracks = sys.load_sound("glasscracks0.ogg");
let snd_glasshatt = sys.load_sound("glasshatt0.ogg");
let snd_kaleidoscope = sys.load_sound("kaleidoscope0.ogg");
let snd_lightson = sys.load_sound("lightson0.ogg");
let snd_lightsoff = sys.load_sound("lightsoff0.ogg");
let snd_seed = sys.load_sound("seed0.ogg");
let snd_tearpage = sys.load_sound("tearpage0.ogg");
let tick_tock = false;
*self = Self::Set{
_mus_forest,
snd_alchemlab,
snd_tick,
snd_tock,
snd_carbrakes,
snd_carstarts,
snd_glasscracks,
snd_glasshatt,
snd_kaleidoscope,
snd_lightson,
snd_lightsoff,
snd_seed,
snd_tearpage,
tick_tock
};
Ok(())
},
Self::Set{..} => Err(format!("{} {}", MID, ERR_ALREADY_SET))
}
}
fn run(&mut self, Context{sys, state, ..}: &mut Context) -> Result<(), String> {
match self {
&mut Self::Set{
ref mut snd_alchemlab,
ref mut snd_tick, ref mut snd_tock,
ref mut snd_carbrakes, ref mut snd_carstarts,
ref mut snd_glasscracks, ref mut snd_glasshatt, ref mut snd_kaleidoscope,
ref mut snd_lightson, ref mut snd_lightsoff,
ref mut snd_seed,
ref mut snd_tearpage,
ref mut tick_tock, ..
} => {
match &mut state.automaton {
Some(state) => {
let shiftkeypress = sys.test_keys(&[Key::LShift, Key::RShift]);
let altkeypress = sys.test_keys(&[Key::LAlt, Key::RAlt]);
let ctrlkeypress = sys.test_keys(&[Key::LCtrl, Key::RCtrl]);
let (left_btn, middle_btn, right_btn) = (sys.poll_btn(Button::Left), sys.poll_btn(Button::Middle), sys.poll_btn(Button::Right));
let (mouse_dx, mouse_dy) = (sys.poll_mouse_dx(), sys.poll_mouse_dy());
let wheel_dw = sys.poll_mouse_dw();
if state.manual_step {
sys.pause_sound(snd_alchemlab.as_ref()).unwrap_or(());
}
if (!(state.manual_step)) || ((state.manual_step) && sys.poll_key(Key::Space)) {
state.field.update(& state.neighbourhood, state.amplification, state.noise, state.synchronicity, sys.irng()).unwrap_or(());
state.count_new_cycle(sys.now());
if state.manual_step { if *tick_tock {
sys.play_sound_once(snd_tick.as_mut()).unwrap_or(());
} else {
sys.play_sound_once(snd_tock.as_mut()).unwrap_or(());
}
*tick_tock = !(*tick_tock);
}
}
if sys.poll_key(Key::Tab) {
state.edit_mode = match state.edit_mode {
EditMode::Field => EditMode::Neighbourhood,
EditMode::Neighbourhood => EditMode::Field
};
}
if sys.poll_key(Key::Delete) || right_btn {
if ctrlkeypress {
state.neighbourhood.0.clear();
} else if altkeypress {
state.field.nullify_outside(
state.pointer_field_u as usize,
(state.pointer_field_y / state.cell_size) as usize,
(state.pointer_field_x / state.cell_size) as usize,
state.brush_radius as usize
);
} else if shiftkeypress {
state.field.nullify_all();
sys.play_sound_once(snd_glasshatt.as_mut()).unwrap_or(());
} else if state.edit_mode == EditMode::Field {
state.field.nullify(
state.pointer_field_u as usize,
(state.pointer_field_y / state.cell_size) as usize,
(state.pointer_field_x / state.cell_size) as usize,
state.brush_radius as usize
);
sys.play_sound_once(snd_glasscracks.as_mut()).unwrap_or(());
} else if state.edit_mode == EditMode::Neighbourhood {
let dv = (state.pointer_nbhood_y / state.nbhood_cell_size - state.nbhood_radius) as isize;
let dw = (state.pointer_nbhood_x / state.nbhood_cell_size - state.nbhood_radius) as isize;
let triple = (state.nbhood_du, dv, dw);
state.neighbourhood.0.remove(&triple);
}
}
if sys.poll_key(Key::Backspace) {
if ctrlkeypress {
state.neighbourhood.reset();
sys.play_sound_once(snd_tearpage.as_mut()).unwrap_or(());
} else if altkeypress {
state.field.fill(&state.brush);
} else if shiftkeypress {
state.field.deim();
} else {
state.field.reset_random(sys.irng());
sys.play_sound_once(snd_kaleidoscope.as_mut()).unwrap_or(());
}
}
if sys.poll_key(Key::Insert) || left_btn {
match state.edit_mode {
EditMode::Field => {
state.field.set(
state.pointer_field_u as usize,
(state.pointer_field_y / state.cell_size) as usize,
(state.pointer_field_x / state.cell_size) as usize,
state.brush_radius as usize,
& state.brush
);
sys.play_sound_once(snd_seed.as_mut()).unwrap_or(());
},
EditMode::Neighbourhood => {
let dv = (state.pointer_nbhood_y / state.nbhood_cell_size - state.nbhood_radius) as isize;
let dw = (state.pointer_nbhood_x / state.nbhood_cell_size - state.nbhood_radius) as isize;
let triple = (state.nbhood_du, dv, dw);
state.neighbourhood.0.insert(triple);
}
}
}
if sys.poll_key(Key::J) || middle_btn {
if state.edit_mode == EditMode::Field {
let pv = (state.pointer_field_y / state.cell_size) as usize;
let pw = (state.pointer_field_x / state.cell_size) as usize;
if let Ok(amph) = state.field.get(state.pointer_field_u as usize, pv, pw) {
state.brush = amph;
}
}
}
if sys.poll_key(Key::E) {
if state.edit_mode == EditMode::Field {
state.field.add_embryo(
state.pointer_field_u as usize,
(state.pointer_field_y / state.cell_size) as usize,
(state.pointer_field_x / state.cell_size) as usize,
state.amplification * state.neighbourhood.perpetuator()
);
}
}
if sys.poll_key(Key::O) {
state.brush = Complex::new_default();
}
if sys.poll_key(Key::G) {
state.brush_radius = state.maglass_radius;
}
if sys.poll_key(Key::C) {
state.color_mode = match state.color_mode {
ColorMode::HueLum => ColorMode::Lum,
ColorMode::Lum => ColorMode::Hue,
ColorMode::Hue => ColorMode::HueLum
};
}
if sys.poll_key(Key::Enter) {
state.manual_step = !(state.manual_step);
if state.manual_step {
sys.play_sound_once(snd_carbrakes.as_mut()).unwrap_or(());
} else {
sys.resume_sound(snd_alchemlab.as_ref()).unwrap_or(());
sys.play_sound_once(snd_carstarts.as_mut()).unwrap_or(());
}
}
state.amplification = state.amplification +
0.001f64 * match (sys.poll_key(Key::LeftBracket), sys.poll_key(Key::RightBracket)) {
(true, false) => -1.0,
(false, true) => 1.0,
_ => 0.0
} * match shiftkeypress {
false => 1.0,
true => 10.0
} * match altkeypress {
false => 1.0,
true => 10.0
} * match ctrlkeypress {
false => 1.0,
true => 10.0
};
state.noise = (state.noise +
0.001f64 * match (sys.poll_key(Key::Comma), sys.poll_key(Key::Period)) {
(true, false) => -1.0,
(false, true) => 1.0,
_ => 0.0
} * match shiftkeypress {
false => 1.0,
true => 10.0
} * match altkeypress {
false => 1.0,
true => 10.0
} * match ctrlkeypress {
false => 1.0,
true => 10.0
}).max(0.0);
state.synchronicity = (state.synchronicity +
0.001f64 * match (sys.poll_key(Key::Minus), sys.poll_key(Key::Equals)) {
(true, false) => -1.0,
(false, true) => 1.0,
_ => 0.0
} * match shiftkeypress {
false => 1.0,
true => 10.0
} * match altkeypress {
false => 1.0,
true => 10.0
} * match ctrlkeypress {
false => 1.0,
true => 10.0
}).max(0.0).min(1.0);
if sys.poll_key(Key::F) {
state.show_field = ! state.show_field;
}
if sys.poll_key(Key::N) {
state.show_nbhood = ! state.show_nbhood;
}
if sys.poll_key(Key::M) {
state.show_maglass = ! state.show_maglass;
}
if sys.poll_key(Key::P) {
state.show_palette = ! state.show_palette;
}
if sys.poll_key(Key::S) {
state.show_settings_stats = ! state.show_settings_stats;
}
if shiftkeypress && sys.poll_key(Key::Num9) {
if state.cell_size > 1 {
state.cell_size -= 1;
state.pointer_field_y = state.pointer_field_y * state.cell_size / (state.cell_size + 1);
state.pointer_field_x = state.pointer_field_x * state.cell_size / (state.cell_size + 1);
}
}
if shiftkeypress && sys.poll_key(Key::Num0) {
state.cell_size += 1;
state.pointer_field_y = state.pointer_field_y * state.cell_size / (state.cell_size - 1);
state.pointer_field_x = state.pointer_field_x * state.cell_size / (state.cell_size - 1);
}
if sys.poll_key(Key::L) {
state.scale_lum = ! state.scale_lum;
if state.scale_lum {
sys.play_sound_once(snd_lightson.as_mut()).unwrap_or(());
} else {
sys.play_sound_once(snd_lightsoff.as_mut()).unwrap_or(());
}
}
let p_dxy_mlt = if shiftkeypress {10} else {1};
if sys.poll_key(Key::Left) {
if ctrlkeypress {
} else if altkeypress {
} else if state.edit_mode == EditMode::Field {
state.pointer_field_x = (state.pointer_field_x - p_dxy_mlt * state.cell_size).max(0);
}
}
if sys.poll_key(Key::Right) {
if ctrlkeypress {
} else if altkeypress {
} else if state.edit_mode == EditMode::Field {
state.pointer_field_x = (state.pointer_field_x + p_dxy_mlt * state.cell_size).min((state.field.length() as i32) * state.cell_size - 1).min(sys.width() - 1);
}
}
if sys.poll_key(Key::Down) {
if ctrlkeypress {
state.nbhood_radius = (state.nbhood_radius - 1).max(0);
state.nbhood_cell_size = (((state.field.height() - 1 + state.field.width()) as i32) * state.cell_size / (2 * state.nbhood_radius + 1)).max(1);
} else if altkeypress {
state.maglass_radius = (state.maglass_radius - 1).max(0);
state.maglass_cell_size = ((sys.height() - ((state.field.height() - 1 + state.field.width()) as i32) * state.cell_size) / (2 * state.maglass_radius + 1)).max(1);
} else if state.edit_mode == EditMode::Field {
state.pointer_field_y = (state.pointer_field_y + p_dxy_mlt * state.cell_size).min((state.field.width() as i32) * state.cell_size - 1).min(sys.height() - 1);
}
}
if sys.poll_key(Key::Up) {
if ctrlkeypress {
state.nbhood_radius += 1;
state.nbhood_cell_size = (((state.field.height() - 1 + state.field.width()) as i32) * state.cell_size / (2 * state.nbhood_radius + 1)).max(1);
} else if altkeypress {
state.maglass_radius += 1;
state.maglass_cell_size = ((sys.height() - ((state.field.height() - 1 + state.field.width()) as i32) * state.cell_size) / (2 * state.maglass_radius + 1)).max(1);
} else if state.edit_mode == EditMode::Field {
state.pointer_field_y = (state.pointer_field_y - p_dxy_mlt * state.cell_size).max(0);
}
}
if sys.poll_key(Key::PageDown) {
state.brush_radius = (state.brush_radius - 1).max(0);
}
if sys.poll_key(Key::PageUp) {
state.brush_radius += 1;
}
if sys.poll_key(Key::D) {
println!("{:?}", & state.neighbourhood.0);
}
if ctrlkeypress && altkeypress {
state.brush.re = (state.brush.re + (mouse_dx as f64) / 512.0).max(-1.0).min(1.0);
state.brush.im = (state.brush.im - (mouse_dy as f64) / 512.0).max(-1.0).min(1.0);
} else if ctrlkeypress {
state.brush.re = (state.brush.re + (wheel_dw as f64) / 32.0).max(-1.0).min(1.0);
} else if altkeypress {
state.brush.im = (state.brush.im + (wheel_dw as f64) / 32.0).max(-1.0).min(1.0);
} else { if state.edit_mode == EditMode::Field {
state.pointer_field_y = (state.pointer_field_y + mouse_dy).max(0).min((state.field.width() as i32) * state.cell_size - 1).min(sys.height() - 1);
state.pointer_field_x = (state.pointer_field_x + mouse_dx).max(0).min((state.field.length() as i32) * state.cell_size - 1).min(sys.width() - 1);
state.pointer_field_u = (state.pointer_field_u - wheel_dw).max(0).min((state.field.height() - 1) as i32);
} else {
state.pointer_nbhood_y = (state.pointer_nbhood_y + mouse_dy).max(0).min((2 * state.nbhood_radius + 1) * state.nbhood_cell_size - 1);
state.pointer_nbhood_x = (state.pointer_nbhood_x + mouse_dx).max(0).min((2 * state.nbhood_radius + 1) * state.nbhood_cell_size - 1);
state.nbhood_du += wheel_dw as isize;
}
}
Ok(())
},
None => Err(String::from("automaton state is absent"))
}
},
Self::Unset => Err(format!("{} {}", MID, ERR_NOT_SET_CANNOT_RUN))
}
}
}