mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2024-11-27 20:34:03 +00:00
Save State Slots as Menu Option (#520)
* Initial * Clippy + Format * Update save_states.rs * selected vs random * fix * Formats * Format * Format * Updated copy, 2 randomize_slots, 2 save_slot_state * Update to 5.1, fix random logic --------- Co-authored-by: Matthew Edell <edell.matthew@gmail.com>
This commit is contained in:
parent
188e7decad
commit
1ce2850af3
7 changed files with 95 additions and 114 deletions
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "training_modpack"
|
||||
version = "5.0.0"
|
||||
version = "5.1.0"
|
||||
authors = ["jugeeya <jugeeya@live.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
|
|
@ -156,6 +156,8 @@ The timing of the CPU option can be influenced by the following settings:
|
|||
| Save Damage (Player) | What to use for player's damage on save state load | Default, Save State, Random |
|
||||
| Damage Range (Player) | Random percentage for save state load for player | 0 to 150 % |
|
||||
| Enable Save States | Should save states be enabled or disabled | Yes, No |
|
||||
| Save State Slot | Save and load states from different slots | 1, 2, 3, 4, 5 |
|
||||
| Save State Random Slot | Load from a random slot | Yes, No |
|
||||
| Character Item | The item to give to the player's fighter when loading a save state | None, Player item (#1 - #8), CPU item (#1 - #8) |
|
||||
| Buff Options | Buff(s) to be applied to respective character when loading save states | Accelerate, Oomph, Psyche Up, Bounce, Arsene, Deep Breathing, Limit, K.O. Punch, Wing |
|
||||
|
||||
|
@ -165,7 +167,7 @@ The timing of the CPU option can be influenced by the following settings:
|
|||
|
||||
At any time in Training Mode, you can press `Shield + Down Taunt` to save the state of training mode. This will save the position, state, and damage of each fighter, which can then be reverted to at any time with `Shield + Up Taunt`. With the mirroring setting, loading the save state will flip the positions, allowing you to practice your skills facing both directions. Use this instead of the built-in training mode reset!
|
||||
|
||||
You can switch Save State slots by using `Grab + Left Taunt` to switch to a previous slot and `Grab + Right Taunt` to switch to the next. There are 5 slots you can save, and they are persisted between loads of the game!
|
||||
You can switch Save State slots by using the associated toggle! There are 5 slots you can save, and they are persisted between loads of the game!
|
||||
|
||||
The following attributes are saved in the save states:
|
||||
|
||||
|
|
|
@ -40,14 +40,6 @@ static mut BUTTON_COMBO_CONFIG: BtnComboConfig = BtnComboConfig {
|
|||
hold: vec![],
|
||||
press: vec![],
|
||||
},
|
||||
previous_save_state_slot: BtnList {
|
||||
hold: vec![],
|
||||
press: vec![],
|
||||
},
|
||||
next_save_state_slot: BtnList {
|
||||
hold: vec![],
|
||||
press: vec![],
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, EnumIter, PartialEq)]
|
||||
|
@ -55,8 +47,6 @@ pub enum ButtonCombo {
|
|||
OpenMenu,
|
||||
SaveState,
|
||||
LoadState,
|
||||
PrevSaveStateSlot,
|
||||
NextSaveStateSlot,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
|
@ -70,8 +60,6 @@ struct BtnComboConfig {
|
|||
open_menu: BtnList,
|
||||
save_state: BtnList,
|
||||
load_state: BtnList,
|
||||
previous_save_state_slot: BtnList,
|
||||
next_save_state_slot: BtnList,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -118,14 +106,6 @@ fn save_all_btn_config_from_defaults() {
|
|||
hold: vec!["SHIELD".to_string()],
|
||||
press: vec!["UPTAUNT".to_string()],
|
||||
},
|
||||
previous_save_state_slot: BtnList {
|
||||
hold: vec!["GRAB".to_string()],
|
||||
press: vec!["LEFTTAUNT".to_string()],
|
||||
},
|
||||
next_save_state_slot: BtnList {
|
||||
hold: vec!["GRAB".to_string()],
|
||||
press: vec!["RIGHTTAUNT".to_string()],
|
||||
},
|
||||
},
|
||||
};
|
||||
unsafe {
|
||||
|
@ -146,13 +126,7 @@ fn save_all_btn_config_from_toml(data: &str) {
|
|||
|
||||
fn validate_config(conf: TopLevelBtnComboConfig) -> bool {
|
||||
let conf = conf.button_config;
|
||||
let configs = [
|
||||
conf.open_menu,
|
||||
conf.save_state,
|
||||
conf.load_state,
|
||||
conf.previous_save_state_slot,
|
||||
conf.next_save_state_slot,
|
||||
];
|
||||
let configs = [conf.open_menu, conf.save_state, conf.load_state];
|
||||
let bad_keys = configs
|
||||
.iter()
|
||||
.flat_map(|btn_list| {
|
||||
|
@ -196,14 +170,6 @@ unsafe fn get_combo_keys(combo: ButtonCombo) -> (&'static Vec<String>, &'static
|
|||
&BUTTON_COMBO_CONFIG.load_state.hold,
|
||||
&BUTTON_COMBO_CONFIG.load_state.press,
|
||||
),
|
||||
ButtonCombo::PrevSaveStateSlot => (
|
||||
&BUTTON_COMBO_CONFIG.previous_save_state_slot.hold,
|
||||
&BUTTON_COMBO_CONFIG.previous_save_state_slot.press,
|
||||
),
|
||||
ButtonCombo::NextSaveStateSlot => (
|
||||
&BUTTON_COMBO_CONFIG.next_save_state_slot.hold,
|
||||
&BUTTON_COMBO_CONFIG.next_save_state_slot.press,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,12 +234,4 @@ press=["DOWNTAUNT",]
|
|||
[button_config.load_state]
|
||||
hold=["SHIELD",]
|
||||
press=["UPTAUNT",]
|
||||
|
||||
[button_config.previous_save_state_slot]
|
||||
hold=["GRAB",]
|
||||
press=["LEFTTAUNT",]
|
||||
|
||||
[button_config.next_save_state_slot]
|
||||
hold=["GRAB",]
|
||||
press=["RIGHTTAUNT",]
|
||||
"#;
|
||||
|
|
Binary file not shown.
|
@ -108,7 +108,6 @@ const NUM_SAVE_STATE_SLOTS: usize = 5;
|
|||
lazy_static::lazy_static! {
|
||||
static ref SAVE_STATE_SLOTS : Mutex<SaveStateSlots> = Mutex::new(load_from_file());
|
||||
}
|
||||
static mut SAVE_STATE_SLOT: usize = 0;
|
||||
|
||||
pub fn load_from_file() -> SaveStateSlots {
|
||||
let defaults = SaveStateSlots {
|
||||
|
@ -139,25 +138,32 @@ pub unsafe fn save_to_file() {
|
|||
.expect("Could not write save state information to file");
|
||||
}
|
||||
|
||||
unsafe fn save_state_player() -> &'static mut SavedState {
|
||||
&mut (*SAVE_STATE_SLOTS.data_ptr()).player[SAVE_STATE_SLOT]
|
||||
unsafe fn save_state_player(slot: usize) -> &'static mut SavedState {
|
||||
&mut (*SAVE_STATE_SLOTS.data_ptr()).player[slot]
|
||||
}
|
||||
|
||||
unsafe fn save_state_cpu() -> &'static mut SavedState {
|
||||
&mut (*SAVE_STATE_SLOTS.data_ptr()).cpu[SAVE_STATE_SLOT]
|
||||
unsafe fn save_state_cpu(slot: usize) -> &'static mut SavedState {
|
||||
&mut (*SAVE_STATE_SLOTS.data_ptr()).cpu[slot]
|
||||
}
|
||||
|
||||
// MIRROR_STATE == 1 -> Do not mirror
|
||||
// MIRROR_STATE == -1 -> Do Mirror
|
||||
static mut MIRROR_STATE: f32 = 1.0;
|
||||
|
||||
static mut RANDOM_SLOT: usize = 0;
|
||||
|
||||
pub unsafe fn is_killing() -> bool {
|
||||
(save_state_player().state == KillPlayer || save_state_player().state == WaitForAlive)
|
||||
|| (save_state_cpu().state == KillPlayer || save_state_cpu().state == WaitForAlive)
|
||||
let selected_slot = MENU.save_state_slot as u32 as usize;
|
||||
(save_state_player(selected_slot).state == KillPlayer
|
||||
|| save_state_player(selected_slot).state == WaitForAlive)
|
||||
|| (save_state_cpu(selected_slot).state == KillPlayer
|
||||
|| save_state_cpu(selected_slot).state == WaitForAlive)
|
||||
}
|
||||
|
||||
pub unsafe fn is_loading() -> bool {
|
||||
save_state_player().state != NoAction || save_state_cpu().state != NoAction
|
||||
let selected_slot = MENU.save_state_slot as u32 as usize;
|
||||
save_state_player(selected_slot).state != NoAction
|
||||
|| save_state_cpu(selected_slot).state != NoAction
|
||||
}
|
||||
|
||||
pub unsafe fn should_mirror() -> f32 {
|
||||
|
@ -331,13 +337,19 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
|||
return;
|
||||
}
|
||||
|
||||
let selected_slot = if MENU.randomize_slots == OnOff::On {
|
||||
RANDOM_SLOT
|
||||
} else {
|
||||
MENU.save_state_slot as u32 as usize
|
||||
};
|
||||
|
||||
let status = StatusModule::status_kind(module_accessor);
|
||||
let is_cpu = WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID)
|
||||
== FighterId::CPU as i32;
|
||||
let save_state = if is_cpu {
|
||||
save_state_cpu()
|
||||
save_state_cpu(selected_slot)
|
||||
} else {
|
||||
save_state_player()
|
||||
save_state_player(selected_slot)
|
||||
};
|
||||
|
||||
let fighter_kind = app::utility::get_kind(module_accessor);
|
||||
|
@ -354,46 +366,6 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
|||
]
|
||||
.contains(&fighter_kind);
|
||||
|
||||
if MENU.save_state_slot_enable == OnOff::On
|
||||
&& !is_operation_cpu(module_accessor)
|
||||
&& button_config::combo_passes_exclusive(
|
||||
module_accessor,
|
||||
button_config::ButtonCombo::PrevSaveStateSlot,
|
||||
)
|
||||
{
|
||||
SAVE_STATE_SLOT = if SAVE_STATE_SLOT == 0 {
|
||||
NUM_SAVE_STATE_SLOTS - 1
|
||||
} else {
|
||||
SAVE_STATE_SLOT - 1
|
||||
};
|
||||
notifications::clear_notifications("Save State");
|
||||
notifications::notification(
|
||||
"Save State".to_string(),
|
||||
format!("Switched to Slot {SAVE_STATE_SLOT}"),
|
||||
120,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if MENU.save_state_slot_enable == OnOff::On
|
||||
&& !is_operation_cpu(module_accessor)
|
||||
&& button_config::combo_passes_exclusive(
|
||||
module_accessor,
|
||||
button_config::ButtonCombo::NextSaveStateSlot,
|
||||
)
|
||||
{
|
||||
SAVE_STATE_SLOT = (SAVE_STATE_SLOT + 1) % NUM_SAVE_STATE_SLOTS;
|
||||
notifications::clear_notifications("Save State");
|
||||
notifications::notification(
|
||||
"Save State".to_string(),
|
||||
format!("Switched to Slot {SAVE_STATE_SLOT}"),
|
||||
120,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset state
|
||||
let autoload_reset = MENU.save_state_autoload == OnOff::On
|
||||
&& save_state.state == NoAction
|
||||
|
@ -407,8 +379,15 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
|||
}
|
||||
if (autoload_reset || triggered_reset) && !fighter_is_nana {
|
||||
if save_state.state == NoAction {
|
||||
save_state_player().state = KillPlayer;
|
||||
save_state_cpu().state = KillPlayer;
|
||||
let slot = if MENU.randomize_slots == OnOff::On {
|
||||
RANDOM_SLOT = get_random_int(NUM_SAVE_STATE_SLOTS as i32) as usize;
|
||||
RANDOM_SLOT
|
||||
} else {
|
||||
selected_slot
|
||||
};
|
||||
|
||||
save_state_player(slot).state = KillPlayer;
|
||||
save_state_cpu(slot).state = KillPlayer;
|
||||
}
|
||||
MIRROR_STATE = should_mirror();
|
||||
return;
|
||||
|
@ -612,12 +591,12 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
|||
{
|
||||
// Don't begin saving state if Nana's delayed input is captured
|
||||
MIRROR_STATE = 1.0;
|
||||
save_state_player().state = Save;
|
||||
save_state_cpu().state = Save;
|
||||
save_state_player(MENU.save_state_slot as u32 as usize).state = Save;
|
||||
save_state_cpu(MENU.save_state_slot as u32 as usize).state = Save;
|
||||
notifications::clear_notifications("Save State");
|
||||
notifications::notification(
|
||||
"Save State".to_string(),
|
||||
format!("Saved Slot {SAVE_STATE_SLOT}"),
|
||||
format!("Saved Slot {}", MENU.save_state_slot.as_str().unwrap()),
|
||||
120,
|
||||
);
|
||||
}
|
||||
|
@ -666,7 +645,9 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
|||
);
|
||||
|
||||
// If both chars finished saving by now
|
||||
if save_state_player().state != Save && save_state_cpu().state != Save {
|
||||
if save_state_player(selected_slot).state != Save
|
||||
&& save_state_cpu(selected_slot).state != Save
|
||||
{
|
||||
save_to_file();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,8 @@ pub struct TrainingModpackMenu {
|
|||
pub save_damage_limits_player: DamagePercent,
|
||||
pub save_state_autoload: OnOff,
|
||||
pub save_state_enable: OnOff,
|
||||
pub save_state_slot_enable: OnOff,
|
||||
pub save_state_slot: SaveStateSlot,
|
||||
pub randomize_slots: OnOff,
|
||||
pub save_state_mirroring: SaveStateMirroring,
|
||||
pub sdi_state: Direction,
|
||||
pub sdi_strength: SdiFrequency,
|
||||
|
@ -124,7 +125,8 @@ pub static DEFAULTS_MENU: TrainingModpackMenu = TrainingModpackMenu {
|
|||
save_damage_limits_player: DamagePercent::default(),
|
||||
save_state_autoload: OnOff::Off,
|
||||
save_state_enable: OnOff::On,
|
||||
save_state_slot_enable: OnOff::On,
|
||||
save_state_slot: SaveStateSlot::One,
|
||||
randomize_slots: OnOff::Off,
|
||||
save_state_mirroring: SaveStateMirroring::None,
|
||||
sdi_state: Direction::empty(),
|
||||
sdi_strength: SdiFrequency::None,
|
||||
|
@ -529,18 +531,19 @@ pub unsafe fn ui_menu(menu: TrainingModpackMenu) -> UiMenu<'static> {
|
|||
true,
|
||||
&(menu.save_state_enable as u32),
|
||||
);
|
||||
save_state_tab.add_submenu_with_toggles::<OnOff>(
|
||||
|
||||
"Enable Slots",
|
||||
|
||||
"save_state_slot_enable",
|
||||
|
||||
"Save State Slots: Enable save state slots. Switch to a different slot with Grab+Left or Right Taunt.",
|
||||
|
||||
save_state_tab.add_submenu_with_toggles::<SaveStateSlot>(
|
||||
"Save State Slot",
|
||||
"save_state_slot",
|
||||
"Save State Slot: Save and load states from different slots.",
|
||||
true,
|
||||
|
||||
&(menu.save_state_enable as u32),
|
||||
|
||||
&(menu.save_state_slot as u32),
|
||||
);
|
||||
save_state_tab.add_submenu_with_toggles::<OnOff>(
|
||||
"Randomize Slots",
|
||||
"randomize_slots",
|
||||
"Randomize Slots: Randomize slot when loading save state.",
|
||||
true,
|
||||
&(menu.randomize_slots as u32),
|
||||
);
|
||||
save_state_tab.add_submenu_with_toggles::<CharacterItem>(
|
||||
"Character Item",
|
||||
|
|
|
@ -1105,3 +1105,40 @@ impl SaveDamage {
|
|||
|
||||
extra_bitflag_impls! {SaveDamage}
|
||||
impl_serde_for_bitflags!(SaveDamage);
|
||||
|
||||
/// Save State Slots
|
||||
#[repr(i32)]
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, FromPrimitive, EnumIter, Serialize_repr, Deserialize_repr,
|
||||
)]
|
||||
pub enum SaveStateSlot {
|
||||
One = 0,
|
||||
Two = 1,
|
||||
Three = 2,
|
||||
Four = 3,
|
||||
Five = 4,
|
||||
}
|
||||
|
||||
impl SaveStateSlot {
|
||||
pub fn as_str(self) -> Option<&'static str> {
|
||||
Some(match self {
|
||||
SaveStateSlot::One => "1",
|
||||
SaveStateSlot::Two => "2",
|
||||
SaveStateSlot::Three => "3",
|
||||
SaveStateSlot::Four => "4",
|
||||
SaveStateSlot::Five => "5",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToggleTrait for SaveStateSlot {
|
||||
fn to_toggle_strs() -> Vec<&'static str> {
|
||||
SaveStateSlot::iter()
|
||||
.map(|i| i.as_str().unwrap_or(""))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn to_toggle_vals() -> Vec<u32> {
|
||||
SaveStateSlot::iter().map(|i| i as u32).collect()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue