mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2024-11-20 00:46:34 +00:00
Ledge Recording Fixes (#585)
* Add reusable print_fighter_info() * rustfmt * Clippy * Standby fix, ngu fix, beginning posY fix, debugging ledge delay * Fighter specific ledge adjustments * Fix ledge delay * Remove debug, fmt * Fix Savestate Record * fmt * clippy
This commit is contained in:
parent
00268b3d72
commit
a76808c838
8 changed files with 124 additions and 35 deletions
|
@ -97,7 +97,7 @@ pub fn is_idle(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
|||
|
||||
pub fn is_in_hitstun(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||
let status_kind = unsafe { StatusModule::status_kind(module_accessor) };
|
||||
// TODO: Need to add EWGF'd out of shield to this?
|
||||
// TODO: Need to add lightly hit off of ledge to this?
|
||||
(*FIGHTER_STATUS_KIND_DAMAGE..*FIGHTER_STATUS_KIND_DAMAGE_FALL).contains(&status_kind)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::common::button_config;
|
||||
use crate::common::consts::{FighterId, HitstunPlayback, OnOff};
|
||||
use crate::common::consts::{FighterId, HitstunPlayback, OnOff, RecordTrigger};
|
||||
use crate::common::input::*;
|
||||
use crate::common::{get_module_accessor, is_in_hitstun, is_in_shieldstun, MENU};
|
||||
use crate::training::mash;
|
||||
|
@ -182,7 +182,7 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAcces
|
|||
if entry_id_int == 0 && !fighter_is_nana {
|
||||
if button_config::combo_passes_exclusive(button_config::ButtonCombo::InputPlayback) {
|
||||
playback(MENU.playback_button_combination.get_random().into_idx());
|
||||
} else if MENU.record_trigger == OnOff::On
|
||||
} else if MENU.record_trigger.contains(RecordTrigger::COMMAND)
|
||||
&& button_config::combo_passes_exclusive(button_config::ButtonCombo::InputRecord)
|
||||
{
|
||||
lockout_record();
|
||||
|
@ -331,7 +331,7 @@ pub unsafe fn playback_ledge(slot: Option<usize>) {
|
|||
// drop down from ledge can't be buffered on the same frame as jump/attack/roll/ngu so we have to do this
|
||||
// Need to buffer 1 less frame for non-lassos
|
||||
let cpu_module_accessor = get_module_accessor(FighterId::CPU);
|
||||
let status_kind = StatusModule::status_kind(cpu_module_accessor) as i32;
|
||||
let status_kind = StatusModule::status_kind(cpu_module_accessor);
|
||||
if status_kind == *FIGHTER_STATUS_KIND_CLIFF_CATCH {
|
||||
BUFFER_FRAME -= 1;
|
||||
}
|
||||
|
@ -391,6 +391,10 @@ pub unsafe fn handle_final_input_mapping(player_idx: i32, out: *mut MappedInputs
|
|||
*out = MappedInputs::empty(); // don't control player while recording
|
||||
println!("Stored Player Input! Frame: {}", INPUT_RECORD_FRAME);
|
||||
}
|
||||
// Don't allow for player input during Lockout
|
||||
if POSSESSION == Lockout {
|
||||
*out = MappedInputs::empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -408,6 +412,7 @@ unsafe fn set_cpu_controls(p_data: *mut *mut u8) {
|
|||
should_mash_playback();
|
||||
}
|
||||
|
||||
let cpu_module_accessor = get_module_accessor(FighterId::CPU);
|
||||
if INPUT_RECORD == Pause {
|
||||
match LOCKOUT_FRAME.cmp(&0) {
|
||||
Ordering::Greater => LOCKOUT_FRAME -= 1,
|
||||
|
@ -422,7 +427,6 @@ unsafe fn set_cpu_controls(p_data: *mut *mut u8) {
|
|||
if INPUT_RECORD == Record || INPUT_RECORD == Playback {
|
||||
let mut x_input_multiplier = RECORDED_LR * CURRENT_LR; // if we aren't facing the way we were when we initially recorded, we reverse horizontal inputs
|
||||
// Don't flip Shulk's dial inputs
|
||||
let cpu_module_accessor = get_module_accessor(FighterId::CPU);
|
||||
let fighter_kind = utility::get_kind(&mut *cpu_module_accessor);
|
||||
if fighter_kind == *FIGHTER_KIND_SHULK {
|
||||
let circle_menu_flag = WorkModule::is_flag(
|
||||
|
@ -436,6 +440,22 @@ unsafe fn set_cpu_controls(p_data: *mut *mut u8) {
|
|||
// If we have issues with the frame after the dial comes out, change condition to
|
||||
// circle_menu_flag && FIGHTER_SHULK_INSTANCE_WORK_ID_INT_SPECIAL_N_DECIDE_INTERVAL_FRAME > 1
|
||||
}
|
||||
|
||||
// Prevent us from falling off of the ledge in standby
|
||||
if StatusModule::status_kind(cpu_module_accessor) == *FIGHTER_STATUS_KIND_CLIFF_WAIT
|
||||
&& is_standby()
|
||||
&& WorkModule::get_int(
|
||||
cpu_module_accessor,
|
||||
*FIGHTER_STATUS_CLIFF_WORK_INT_CATCH_REST_TIME,
|
||||
) < 50
|
||||
{
|
||||
WorkModule::set_int(
|
||||
cpu_module_accessor,
|
||||
200,
|
||||
*FIGHTER_STATUS_CLIFF_WORK_INT_CATCH_REST_TIME,
|
||||
);
|
||||
}
|
||||
|
||||
println!("Overriding Cpu Player: {}, Frame: {}, BUFFER_FRAME: {}, STARTING_STATUS: {}, INPUT_RECORD: {:#?}, POSSESSION: {:#?}", controller_no, INPUT_RECORD_FRAME, BUFFER_FRAME, STARTING_STATUS, INPUT_RECORD, POSSESSION);
|
||||
|
||||
let mut saved_mapped_inputs = P1_FINAL_MAPPING.lock()[if INPUT_RECORD == Record {
|
||||
|
|
|
@ -102,7 +102,6 @@ pub unsafe fn force_option(module_accessor: &mut app::BattleObjectModuleAccessor
|
|||
reset_ledge_delay();
|
||||
return;
|
||||
}
|
||||
|
||||
// Need to roll ledge delay so we know if getup needs to be buffered
|
||||
roll_ledge_delay();
|
||||
roll_ledge_case();
|
||||
|
@ -161,7 +160,6 @@ pub unsafe fn force_option(module_accessor: &mut app::BattleObjectModuleAccessor
|
|||
}
|
||||
|
||||
let status = LEDGE_CASE.into_status().unwrap_or(0);
|
||||
|
||||
if LEDGE_CASE.is_playback() {
|
||||
input_record::playback(LEDGE_CASE.playback_slot());
|
||||
} else {
|
||||
|
@ -188,10 +186,11 @@ pub unsafe fn is_enable_transition_term(
|
|||
return None;
|
||||
}
|
||||
|
||||
// Disallow the default cliff-climb if we are waiting or we wait as part of a recording
|
||||
if (LEDGE_CASE == LedgeOption::WAIT
|
||||
|| frame_counter::get_frame_count(LEDGE_DELAY_COUNTER) < LEDGE_DELAY)
|
||||
&& term == *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_CLIFF_CLIMB
|
||||
// Disallow the default cliff-climb if we are waiting or we didn't get up during a recording
|
||||
if term == *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_CLIFF_CLIMB
|
||||
&& ((LEDGE_CASE == LedgeOption::WAIT
|
||||
|| frame_counter::get_frame_count(LEDGE_DELAY_COUNTER) < LEDGE_DELAY)
|
||||
|| (LEDGE_CASE.is_playback() && !input_record::is_playback()))
|
||||
{
|
||||
return Some(false);
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ pub fn buffer_action(action: Action) {
|
|||
//println!("Stopping mash playback for menu option!");
|
||||
// if we don't want to leave playback on mash actions, then don't perform the mash
|
||||
if input_record::is_playback() {
|
||||
input_record::stop_playback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
use skyline::hooks::{getRegionAddress, InlineCtx, Region};
|
||||
use skyline::nn::ro::LookupSymbol;
|
||||
use smash::app::{self, enSEType, lua_bind::*, utility};
|
||||
use smash::lib::lua_const::*;
|
||||
use smash::params::*;
|
||||
use smash::phx::{Hash40, Vector3f};
|
||||
|
||||
use crate::common::{
|
||||
consts::BuffOption, consts::FighterId, consts::MENU, dev_config, get_module_accessor,
|
||||
is_training_mode, menu, FIGHTER_MANAGER_ADDR, ITEM_MANAGER_ADDR, STAGE_MANAGER_ADDR,
|
||||
|
@ -13,6 +6,12 @@ use crate::hitbox_visualizer;
|
|||
use crate::input::*;
|
||||
use crate::logging::*;
|
||||
use crate::training::character_specific::items;
|
||||
use skyline::hooks::{getRegionAddress, InlineCtx, Region};
|
||||
use skyline::nn::ro::LookupSymbol;
|
||||
use smash::app::{self, enSEType, lua_bind::*, utility};
|
||||
use smash::lib::lua_const::*;
|
||||
use smash::params::*;
|
||||
use smash::phx::{Hash40, Vector3f};
|
||||
|
||||
pub mod buff;
|
||||
pub mod charge;
|
||||
|
|
|
@ -17,6 +17,8 @@ use crate::common::consts::get_random_float;
|
|||
use crate::common::consts::get_random_int;
|
||||
use crate::common::consts::FighterId;
|
||||
use crate::common::consts::OnOff;
|
||||
use crate::common::consts::PlaybackSlot;
|
||||
use crate::common::consts::RecordTrigger;
|
||||
use crate::common::consts::SaveStateMirroring;
|
||||
//TODO: Cleanup above
|
||||
use crate::common::consts::SAVE_STATES_TOML_PATH;
|
||||
|
@ -470,7 +472,7 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
|||
ControlModule::stop_rumble(module_accessor, false);
|
||||
KineticModule::clear_speed_all(module_accessor);
|
||||
|
||||
let pos = if MIRROR_STATE == -1.0 {
|
||||
let mut pos = if MIRROR_STATE == -1.0 {
|
||||
Vector3f {
|
||||
x: MIRROR_STATE * (save_state.x - get_stage_offset(stage_id())),
|
||||
y: save_state.y,
|
||||
|
@ -484,6 +486,8 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
|||
}
|
||||
};
|
||||
|
||||
// Adjust fighter y position if they won't grab ledge when they should
|
||||
adjust_ledge_pos(&mut pos, save_state.fighter_kind, save_state.situation_kind);
|
||||
let lr = MIRROR_STATE * save_state.lr;
|
||||
PostureModule::set_pos(module_accessor, &pos);
|
||||
PostureModule::set_lr(module_accessor, lr);
|
||||
|
@ -510,12 +514,13 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
|||
save_state.state = NoAction;
|
||||
}
|
||||
} else if save_state.situation_kind == SITUATION_KIND_CLIFF {
|
||||
if status != FIGHTER_STATUS_KIND_CLIFF_CATCH_MOVE
|
||||
if status != FIGHTER_STATUS_KIND_FALL
|
||||
&& status != FIGHTER_STATUS_KIND_CLIFF_CATCH_MOVE
|
||||
&& status != FIGHTER_STATUS_KIND_CLIFF_CATCH
|
||||
{
|
||||
StatusModule::change_status_request(
|
||||
module_accessor,
|
||||
*FIGHTER_STATUS_KIND_CLIFF_CATCH_MOVE,
|
||||
*FIGHTER_STATUS_KIND_FALL,
|
||||
false,
|
||||
);
|
||||
} else {
|
||||
|
@ -605,8 +610,18 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
|||
if prev_status_kind == FIGHTER_STATUS_KIND_REBIRTH && fighter_is_popo {
|
||||
save_state.state = NanaPosMove;
|
||||
}
|
||||
|
||||
// if we're recording on state load, record
|
||||
if MENU.record_trigger.contains(RecordTrigger::SAVESTATE) {
|
||||
input_record::lockout_record();
|
||||
return;
|
||||
}
|
||||
// otherwise, begin input recording playback if selected
|
||||
else if !MENU.save_state_playback.is_empty() {
|
||||
// for ledge, don't do this - if you want playback on a ledge, you have to set it as a ledge option,
|
||||
// otherwise there too many edge cases here
|
||||
else if MENU.save_state_playback.get_random() != PlaybackSlot::empty()
|
||||
&& save_state.situation_kind != SITUATION_KIND_CLIFF
|
||||
{
|
||||
input_record::playback(MENU.save_state_playback.get_random().into_idx());
|
||||
}
|
||||
|
||||
|
@ -640,17 +655,12 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
|||
if save_state.state == Save && !fighter_is_nana {
|
||||
// Don't save states with Nana. Should already be fine, just a safety.
|
||||
save_state.state = NoAction;
|
||||
|
||||
save_state.x = PostureModule::pos_x(module_accessor);
|
||||
save_state.y = PostureModule::pos_y(module_accessor);
|
||||
save_state.lr = PostureModule::lr(module_accessor);
|
||||
save_state.percent = DamageModule::damage(module_accessor, 0);
|
||||
save_state.situation_kind =
|
||||
if StatusModule::situation_kind(module_accessor) == *SITUATION_KIND_CLIFF {
|
||||
*SITUATION_KIND_AIR
|
||||
} else {
|
||||
StatusModule::situation_kind(module_accessor)
|
||||
};
|
||||
save_state.situation_kind = StatusModule::situation_kind(module_accessor);
|
||||
|
||||
// Always store fighter kind so that charges are handled properly
|
||||
save_state.fighter_kind = app::utility::get_kind(module_accessor);
|
||||
save_state.charge = charge::get_charge(module_accessor, fighter_kind);
|
||||
|
@ -688,3 +698,41 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn adjust_ledge_pos(pos: &mut Vector3f, fighter_kind: i32, situation_kind: i32) {
|
||||
// Adjusts save states for fighters who have grabbed the ledge
|
||||
if situation_kind != SITUATION_KIND_CLIFF {
|
||||
return;
|
||||
}
|
||||
|
||||
let fighter_needs_ledge_adjust_far = [
|
||||
*FIGHTER_KIND_DONKEY,
|
||||
*FIGHTER_KIND_DEDEDE,
|
||||
*FIGHTER_KIND_KROOL,
|
||||
]
|
||||
.contains(&fighter_kind);
|
||||
|
||||
let fighter_needs_ledge_adjust_medium = [
|
||||
*FIGHTER_KIND_SAMUS,
|
||||
*FIGHTER_KIND_SAMUSD,
|
||||
*FIGHTER_KIND_MEWTWO,
|
||||
*FIGHTER_KIND_DOLLY,
|
||||
]
|
||||
.contains(&fighter_kind);
|
||||
|
||||
let fighter_needs_ledge_adjust_slight = [
|
||||
*FIGHTER_KIND_KOOPA,
|
||||
*FIGHTER_KIND_ELIGHT,
|
||||
*FIGHTER_KIND_SNAKE,
|
||||
]
|
||||
.contains(&fighter_kind);
|
||||
|
||||
if fighter_needs_ledge_adjust_far {
|
||||
pos.y += 6.0;
|
||||
} else if fighter_needs_ledge_adjust_medium {
|
||||
pos.y += 4.0;
|
||||
}
|
||||
if fighter_needs_ledge_adjust_slight {
|
||||
pos.y += 2.0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ pub struct TrainingModpackMenu {
|
|||
pub landing_override: Action,
|
||||
pub trump_override: Action,
|
||||
pub recording_slot: RecordSlot,
|
||||
pub record_trigger: OnOff,
|
||||
pub record_trigger: RecordTrigger,
|
||||
pub recording_frames: RecordingFrames,
|
||||
pub playback_button_combination: PlaybackSlot,
|
||||
pub hitstun_playback: HitstunPlayback,
|
||||
|
@ -178,7 +178,7 @@ pub static DEFAULTS_MENU: TrainingModpackMenu = TrainingModpackMenu {
|
|||
trump_override: Action::empty(),
|
||||
recording_slot: RecordSlot::S1,
|
||||
recording_frames: RecordingFrames::F150,
|
||||
record_trigger: OnOff::On,
|
||||
record_trigger: RecordTrigger::COMMAND,
|
||||
playback_button_combination: PlaybackSlot::S1,
|
||||
hitstun_playback: HitstunPlayback::Hitstun,
|
||||
playback_mash: OnOff::On,
|
||||
|
@ -772,12 +772,12 @@ pub unsafe fn ui_menu(menu: TrainingModpackMenu) -> UiMenu<'static> {
|
|||
true,
|
||||
&(menu.recording_slot as u32),
|
||||
);
|
||||
input_tab.add_submenu_with_toggles::<OnOff>(
|
||||
input_tab.add_submenu_with_toggles::<RecordTrigger>(
|
||||
"Recording Trigger",
|
||||
"record_trigger",
|
||||
"Recording Trigger: Whether to begin recording via button combination (Default: Attack+Left Taunt)",
|
||||
true,
|
||||
&(menu.record_trigger as u32),
|
||||
"Recording Trigger: Whether to begin recording via button combination (Default: Attack+Left Taunt) or upon loading a Save State",
|
||||
false,
|
||||
&(menu.record_trigger.bits() as u32),
|
||||
);
|
||||
input_tab.add_submenu_with_toggles::<RecordingFrames>(
|
||||
"Recording Frames",
|
||||
|
|
|
@ -1373,6 +1373,28 @@ impl ToggleTrait for HitstunPlayback {
|
|||
}
|
||||
}
|
||||
|
||||
// Input Recording Trigger Type
|
||||
bitflags! {
|
||||
pub struct RecordTrigger : u32
|
||||
{
|
||||
const COMMAND = 0x1;
|
||||
const SAVESTATE = 0x2;
|
||||
}
|
||||
}
|
||||
|
||||
impl RecordTrigger {
|
||||
pub fn as_str(self) -> Option<&'static str> {
|
||||
Some(match self {
|
||||
RecordTrigger::COMMAND => "Button Combination",
|
||||
RecordTrigger::SAVESTATE => "Save State Load",
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
extra_bitflag_impls! {RecordTrigger}
|
||||
impl_serde_for_bitflags!(RecordTrigger);
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, FromPrimitive, EnumIter, Serialize_repr, Deserialize_repr,
|
||||
|
|
Loading…
Reference in a new issue