use crate::game::GameState;
use crate::social::AudioCue;
pub fn ui_overlay_signature(state: &GameState) -> u64 {
let mut s = 0u64;
macro_rules! bit {
($n:expr, $cond:expr) => {
if $cond {
s |= 1u64 << $n;
}
};
}
bit!(0, state.show_stats);
bit!(1, state.show_inventory_menu);
bit!(2, state.show_craft_menu);
bit!(3, state.show_plot_build_menu);
bit!(4, state.show_shop_menu);
bit!(5, state.bank_panel.is_some());
bit!(6, state.storage_panel.is_some());
bit!(7, state.market_panel.is_some());
bit!(8, state.show_npc_verb_menu);
bit!(9, state.show_npc_chat);
bit!(10, state.player_verbs.open);
bit!(11, state.trade_ui.panel.is_some());
bit!(12, state.whisper_pouch_ui.open);
bit!(13, state.social_chat.input_focused);
bit!(14, state.social_chat.picking_stone);
bit!(15, state.show_move_picker);
bit!(16, state.show_grant_picker);
bit!(17, state.show_destroy_picker);
bit!(18, state.show_rename_prompt);
bit!(19, state.show_worker_rename);
bit!(20, state.show_loadout_menu);
bit!(21, state.show_keychain_menu);
bit!(22, state.show_rotation_editor);
bit!(23, state.show_quest_offer);
bit!(24, state.show_quest_menu);
bit!(25, state.show_workers_menu);
bit!(26, state.show_worker_give_picker);
bit!(27, state.show_worker_give_target_picker);
bit!(28, state.show_worker_take_picker);
bit!(29, state.show_worker_teach_picker);
bit!(30, state.worker_route_editor.is_some());
bit!(31, state.show_plant_menu);
bit!(32, state.show_farm_access);
bit!(33, state.show_equip_menu);
bit!(34, state.claim_mode.is_some());
bit!(35, state.relocate_mode.is_some());
s
}
const UI_BIT_SHOP: u64 = 1 << 4;
const UI_BIT_STORAGE: u64 = 1 << 6;
const UI_BIT_NPC: u64 = (1 << 8) | (1 << 9);
fn cue_for_ui_open(opened: u64) -> Option<AudioCue> {
if opened == 0 {
return None;
}
if opened & UI_BIT_SHOP != 0 {
return Some(AudioCue::ShopOpen);
}
if opened & UI_BIT_STORAGE != 0 {
return Some(AudioCue::ChestOpen);
}
if opened & UI_BIT_NPC != 0 {
return Some(AudioCue::NpcGreet);
}
Some(AudioCue::UiOpen)
}
pub fn sync_ui_audio(state: &mut GameState) {
let sig = ui_overlay_signature(state);
let audio = &mut state.social_chat;
if !audio.audio_ui_bootstrapped {
audio.audio_ui_sig = sig;
audio.audio_ui_bootstrapped = true;
return;
}
let prev = audio.audio_ui_sig;
if sig == prev {
return;
}
let opened = sig & !prev;
let closed = prev & !sig;
if let Some(cue) = cue_for_ui_open(opened) {
audio.push_cue(cue);
}
if closed != 0 {
audio.push_cue(AudioCue::UiClose);
}
audio.audio_ui_sig = sig;
}
pub fn sync_world_audio(state: &mut GameState) {
let inside = state.effective_inside_building();
let audio = &mut state.social_chat;
if !audio.audio_world_bootstrapped {
audio.audio_inside_building = inside.clone();
for door in &state.doors {
audio.audio_door_open.insert(door.id.clone(), door.open);
audio.audio_door_locked.insert(door.id.clone(), door.locked);
}
for chest in &state.placed_containers {
audio
.audio_chest_locked
.insert(chest.id.clone(), chest.locked);
}
audio.audio_world_bootstrapped = true;
return;
}
match (&audio.audio_inside_building, &inside) {
(None, Some(_)) => audio.push_cue(AudioCue::BuildingEnter),
(Some(_), None) => audio.push_cue(AudioCue::BuildingExit),
_ => {}
}
audio.audio_inside_building = inside;
for door in &state.doors {
let id = &door.id;
if let Some(was_open) = audio.audio_door_open.get(id).copied() {
if !was_open && door.open {
audio.push_cue(AudioCue::DoorOpen);
} else if was_open && !door.open {
audio.push_cue(AudioCue::DoorClose);
}
}
if let Some(was_locked) = audio.audio_door_locked.get(id).copied() {
if !was_locked && door.locked {
audio.push_cue(AudioCue::DoorLock);
} else if was_locked && !door.locked {
audio.push_cue(AudioCue::DoorUnlock);
}
}
audio.audio_door_open.insert(id.clone(), door.open);
audio.audio_door_locked.insert(id.clone(), door.locked);
}
audio
.audio_door_open
.retain(|id, _| state.doors.iter().any(|d| &d.id == id));
audio
.audio_door_locked
.retain(|id, _| state.doors.iter().any(|d| &d.id == id));
for chest in &state.placed_containers {
let id = &chest.id;
if let Some(was_locked) = audio.audio_chest_locked.get(id).copied() {
if !was_locked && chest.locked {
audio.push_cue(AudioCue::ChestLock);
} else if was_locked && !chest.locked {
audio.push_cue(AudioCue::ChestUnlock);
}
}
audio.audio_chest_locked.insert(id.clone(), chest.locked);
}
audio
.audio_chest_locked
.retain(|id, _| state.placed_containers.iter().any(|c| &c.id == id));
}
pub fn sync_frame_audio(state: &mut GameState) {
sync_ui_audio(state);
sync_world_audio(state);
}