1
0
Fork 0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2025-03-14 02:16:10 +00:00

Initial Save State Slots (#474)

This commit is contained in:
jugeeya 2023-02-10 22:02:56 -08:00 committed by GitHub
parent e10092b766
commit bf78f06f7d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 124 additions and 68 deletions

View file

@ -1 +1 @@
stable
nightly

View file

@ -33,6 +33,14 @@ 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)]
@ -40,6 +48,8 @@ pub enum ButtonCombo {
OpenMenu,
SaveState,
LoadState,
PrevSaveStateSlot,
NextSaveStateSlot
}
#[derive(Deserialize, Default)]
@ -53,6 +63,8 @@ struct BtnComboConfig {
open_menu: BtnList,
save_state: BtnList,
load_state: BtnList,
previous_save_state_slot: BtnList,
next_save_state_slot: BtnList
}
#[derive(Deserialize)]
@ -64,7 +76,8 @@ pub fn validate_config(data: &str) -> bool {
let conf: TopLevelBtnComboConfig =
toml::from_str(data).expect("Custom button config has invalid schema");
let conf = conf.button_config;
let configs = [conf.open_menu, conf.save_state, conf.load_state];
let configs = [conf.open_menu, conf.save_state, conf.load_state,
conf.previous_save_state_slot, conf.next_save_state_slot];
let bad_keys = configs
.iter()
.flat_map(|btn_list| {
@ -108,6 +121,14 @@ pub fn save_all_btn_config_from_defaults() {
hold: vec!["GRAB".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 {
@ -144,6 +165,14 @@ pub fn combo_passes(
&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,
),
};
hold.iter()
.map(|hold| *BUTTON_MAPPING.get(&*hold.to_uppercase()).unwrap())
@ -187,4 +216,12 @@ press=["DOWNTAUNT",]
[button_config.load_state]
hold=["GRAB",]
press=["UPTAUNT",]
[button_config.previous_save_state_slot]
hold=["GRAB",]
press=["LEFTTAUNT",]
[button_config.next_save_state_slot]
hold=["GRAB",]
press=["RIGHTTAUNT",]
"#;

View file

@ -10,7 +10,6 @@
clippy::missing_safety_doc,
clippy::wrong_self_convention,
clippy::option_map_unit_fn,
clippy::float_cmp,
clippy::fn_null_check,
// Look into why for this one
clippy::transmute_num_to_bytes
@ -80,10 +79,10 @@ pub fn main() {
info!("Initialized.");
unsafe {
EVENT_QUEUE.push(Event::smash_open());
notification("Training Modpack", "Welcome!", 60);
notification("Open Menu", "Special + Uptaunt", 120);
notification("Save State", "Grab + Downtaunt", 120);
notification("Load State", "Grab + Uptaunt", 120);
notification("Training Modpack".to_string(), "Welcome!".to_string(), 60);
notification("Open Menu".to_string(), "Special + Uptaunt".to_string(), 120);
notification("Save State".to_string(), "Grab + Downtaunt".to_string(), 120);
notification("Load State".to_string(), "Grab + Uptaunt".to_string(), 120);
}
hitbox_visualizer::hitbox_visualization();

View file

@ -5,7 +5,6 @@ use crate::common::*;
use crate::training::*;
pub static mut FRAME_ADVANTAGE: i32 = 0;
static mut FRAME_ADVANTAGE_STR: String = String::new();
static mut PLAYER_ACTIONABLE: bool = false;
static mut CPU_ACTIONABLE: bool = false;
static mut PLAYER_ACTIVE_FRAME: u32 = 0;
@ -50,13 +49,11 @@ unsafe fn is_actionable(module_accessor: *mut app::BattleObjectModuleAccessor) -
fn update_frame_advantage(new_frame_adv: i32) {
unsafe {
FRAME_ADVANTAGE = new_frame_adv;
FRAME_ADVANTAGE_STR = String::new();
FRAME_ADVANTAGE_STR.push_str(&format!("{FRAME_ADVANTAGE}"));
if MENU.frame_advantage == OnOff::On {
ui::notifications::clear_notifications("Frame Advantage");
ui::notifications::color_notification(
"Frame Advantage",
&FRAME_ADVANTAGE_STR,
"Frame Advantage".to_string(),
format!("{FRAME_ADVANTAGE}"),
60,
match FRAME_ADVANTAGE {
x if x < 0 => ResColor { r: 200, g: 8, b: 8, a: 255 },

View file

@ -12,19 +12,22 @@ use crate::training::character_specific::steve;
use crate::training::charge::{self, ChargeState};
use crate::training::items::apply_item;
use crate::training::reset;
use crate::{is_ptrainer, ITEM_MANAGER_ADDR};
use SaveState::*;
use smash::app::{self, lua_bind::*, Item};
use smash::hash40;
use smash::lib::lua_const::*;
use smash::phx::{Hash40, Vector3f};
use std::collections::HashMap;
use training_mod_consts::{CharacterItem, SaveDamage};
use crate::training::ui::notifications;
extern "C" {
#[link_name = "\u{1}_ZN3app14sv_information8stage_idEv"]
pub fn stage_id() -> i32;
}
#[derive(PartialEq)]
#[derive(PartialEq, Copy, Clone)]
enum SaveState {
Save,
NoAction,
@ -34,6 +37,7 @@ enum SaveState {
ApplyBuff,
}
#[derive(Copy, Clone)]
struct SavedState {
x: f32,
y: f32,
@ -85,21 +89,32 @@ macro_rules! default_save_state {
};
}
use crate::{is_ptrainer, ITEM_MANAGER_ADDR};
use SaveState::*;
// static mut SAVE_STATE_PLAYER: SavedState = default_save_state!();
// static mut SAVE_STATE_CPU: SavedState = default_save_state!();
const NUM_SAVE_STATE_SLOTS : usize = 5;
static mut SAVE_STATE_PLAYER : [SavedState; NUM_SAVE_STATE_SLOTS] = [default_save_state!(); NUM_SAVE_STATE_SLOTS];
static mut SAVE_STATE_CPU : [SavedState; NUM_SAVE_STATE_SLOTS] = [default_save_state!(); NUM_SAVE_STATE_SLOTS];
static mut SAVE_STATE_SLOT : usize = 0;
unsafe fn save_state_player() -> &'static mut SavedState {
&mut SAVE_STATE_PLAYER[SAVE_STATE_SLOT]
}
unsafe fn save_state_cpu() -> &'static mut SavedState {
&mut SAVE_STATE_CPU[SAVE_STATE_SLOT]
}
static mut SAVE_STATE_PLAYER: SavedState = default_save_state!();
static mut SAVE_STATE_CPU: SavedState = default_save_state!();
static mut MIRROR_STATE: f32 = 1.0;
// MIRROR_STATE == 1 -> Do not mirror
// MIRROR_STATE == -1 -> Do Mirror
static mut MIRROR_STATE: f32 = 1.0;
pub unsafe fn is_killing() -> bool {
SAVE_STATE_PLAYER.state == KillPlayer || SAVE_STATE_CPU.state == KillPlayer
save_state_player().state == KillPlayer || save_state_cpu().state == KillPlayer
}
pub unsafe fn is_loading() -> bool {
SAVE_STATE_PLAYER.state != NoAction || SAVE_STATE_CPU.state != NoAction
save_state_player().state != NoAction || save_state_cpu().state != NoAction
}
pub unsafe fn should_mirror() -> f32 {
@ -221,9 +236,9 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
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 {
&mut SAVE_STATE_CPU
save_state_cpu()
} else {
&mut SAVE_STATE_PLAYER
save_state_player()
};
let fighter_kind = app::utility::get_kind(module_accessor);
@ -240,6 +255,28 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
]
.contains(&fighter_kind);
if !is_operation_cpu(module_accessor) &&
button_config::combo_passes(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 !is_operation_cpu(module_accessor) &&
button_config::combo_passes(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;
}
// Grab + Dpad up: reset state
let autoload_reset = MENU.save_state_autoload == OnOff::On
&& save_state.state == NoAction
@ -251,8 +288,8 @@ 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;
save_state_player().state = KillPlayer;
save_state_cpu().state = KillPlayer;
}
MIRROR_STATE = should_mirror();
return;
@ -497,8 +534,8 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
if button_config::combo_passes(module_accessor, button_config::ButtonCombo::SaveState) {
// 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().state = Save;
save_state_cpu().state = Save;
}
if save_state.state == Save && !fighter_is_nana {

View file

@ -24,32 +24,30 @@ pub unsafe fn draw(root_pane: &mut Pane) {
let notification_idx = 0;
let queue = &mut ui::notifications::QUEUE;
let notification = queue.first_mut();
let notification = queue.first();
if let Some(parent) = root_pane.find_pane_by_name_recursive(display_parent_fmt!(notification_idx)) {
parent.set_visible(notification.is_some());
if notification.is_none() {
return;
}
root_pane.find_pane_by_name_recursive(display_parent_fmt!(notification_idx))
.unwrap().set_visible(notification.is_some());
if notification.is_none() {
return;
}
let notification = notification.unwrap();
let header_txt = notification.header();
let message = notification.message();
let color = notification.color();
let color = notification.color;
root_pane.find_pane_by_name_recursive(display_header_fmt!(notification_idx))
.unwrap()
.as_textbox().set_text_string(&notification.header);
let text = root_pane.find_pane_by_name_recursive(display_txt_fmt!(notification_idx))
.unwrap().as_textbox();
text.set_text_string(&notification.message);
text.set_default_material_colors();
text.set_color(color.r, color.g, color.b, color.a);
let notification = queue.first_mut().unwrap();
let has_completed = notification.tick();
if has_completed {
queue.remove(0);
}
if let Some(header) = root_pane.find_pane_by_name_recursive(display_header_fmt!(notification_idx)) {
header.as_textbox().set_text_string(header_txt);
}
if let Some(text) = root_pane.find_pane_by_name_recursive(display_txt_fmt!(notification_idx)) {
let text = text.as_textbox();
text.set_text_string(message);
text.set_default_material_colors();
text.set_color(color.r, color.g, color.b, color.a);
}
}

View file

@ -1,17 +1,17 @@
use skyline::nn::ui2d::ResColor;
pub static mut QUEUE: Vec<Notification<'static>> = vec![];
pub static mut QUEUE: Vec<Notification> = vec![];
#[derive(Copy, Clone)]
pub struct Notification<'a> {
header: &'a str,
message: &'a str,
#[derive(Clone)]
pub struct Notification {
pub header: String,
pub message: String,
length: u32,
color: ResColor
pub color: ResColor
}
impl<'a> Notification<'a> {
pub fn new(header: &'a str, message: &'a str, length: u32, color: ResColor) -> Notification<'a> {
impl Notification {
pub fn new(header: String, message: String, length: u32, color: ResColor) -> Notification {
Notification {
header,
message,
@ -28,21 +28,9 @@ impl<'a> Notification<'a> {
self.length -= 1;
false
}
pub fn header(self) -> &'a str {
self.header
}
pub fn message(self) -> &'a str {
self.message
}
pub fn color(self) -> ResColor {
self.color
}
}
pub fn notification(header: &'static str, message: &'static str, len: u32) {
pub fn notification(header: String, message: String, len: u32) {
unsafe {
let queue = &mut QUEUE;
queue.push(Notification::new(header, message, len, ResColor {
@ -54,7 +42,7 @@ pub fn notification(header: &'static str, message: &'static str, len: u32) {
}
}
pub fn color_notification(header: &'static str, message: &'static str, len: u32, color: ResColor) {
pub fn color_notification(header: String, message: String, len: u32, color: ResColor) {
unsafe {
let queue = &mut QUEUE;
queue.push(Notification::new(header, message, len, color));