1
0
Fork 0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2025-02-17 14:40:31 +00:00

Throw options (#293)

* Initial Creation

* Initial attempt, no pummeling or actual throw directions implemented

* All throw directions + Throw Delay working

* Medium Delay

* Cleanup and warning fixing

* Menu grammar fix

* Menu Images

* Image Fix and Language Fix

* Renormalize line endings

* Fixed into_string() vs. as_str()

* Update README

* Update Version

* Update to 3.2.0

* Update Cargo.toml

Corrected version number
This commit is contained in:
GradualSyrup 2021-12-26 12:07:17 -06:00 committed by GitHub
parent f9522d2699
commit 6f6ce58a88
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 761 additions and 2 deletions

View file

@ -112,6 +112,9 @@ When multiple options are selected, one of the selected options will be chosen a
| SDI Strength | Relative strength of the smash directional influence inputs | Normal (8 frames between SDI inputs), Medium (6 frames), High (4 frames) |
| Shield Toggles | CPU Shield Behavior | None, Infinite (no shield damage or decay), Hold (no shield decay until the shield is hit for the first time), Constant (no shield decay) |
| Mirroring | Flips save states in the left-right direction across the stage center | None, Alternate, Random |
| Throw Options | Throw to be performed when a grab is landed | None, Forward Throw, Back Throw, Up Throw, Down Throw |
| Throw Delay | How many frames to delay the throw option | 0 to 150 frames (2.5 seconds) in increments of 5 frames |
| Pummel Delay | How many frames after a grab to wait before starting to pummel | 0 to 150 frames (2.5 seconds) in increments of 5 frames |
| Input Delay | Frames to delay player inputs by | 0 to 10 frames (0.167 seconds) |
| Save Damage | Should save states retain player/CPU damage | Yes, No |
| Hitbox Visualization | Should hitboxes be displayed, hiding other visual effects | Yes, No |
@ -157,6 +160,7 @@ SD Card Root
│ ├── mash_state.svg
│ ├── miss_tech_state.svg
│ ├── oos_offset.svg
│ ├── pummel_delay.svg
│ ├── reaction_time.svg
│ ├── save_damage.svg
│ ├── save_state_mirroring.svg
@ -165,7 +169,9 @@ SD Card Root
│ ├── shield_state.svg
│ ├── shield_tilt.svg
│ ├── stage_hazards.svg
│ └── tech_state.svg
│ ├── tech_state.svg
│ ├── throw_delay.svg
│ └── throw_state.svg
└── romfs
└── skyline
└── plugins

View file

@ -464,6 +464,44 @@ bitflags! {
}
}
// Throw Option
bitflags! {
pub struct ThrowOption : u32
{
const NONE = 0x1;
const FORWARD = 0x2;
const BACKWARD = 0x4;
const UP = 0x8;
const DOWN = 0x10;
}
}
impl ThrowOption {
pub fn into_cmd(self) -> Option<i32> {
Some(match self {
ThrowOption::NONE => 0,
ThrowOption::FORWARD => *FIGHTER_PAD_CMD_CAT2_FLAG_THROW_F,
ThrowOption::BACKWARD => *FIGHTER_PAD_CMD_CAT2_FLAG_THROW_B,
ThrowOption::UP => *FIGHTER_PAD_CMD_CAT2_FLAG_THROW_HI,
ThrowOption::DOWN => *FIGHTER_PAD_CMD_CAT2_FLAG_THROW_LW,
_ => return None,
})
}
pub fn as_str(self) -> Option<&'static str> {
Some(match self {
ThrowOption::NONE => "None",
ThrowOption::FORWARD => "Forward Throw",
ThrowOption::BACKWARD => "Back Throw",
ThrowOption::UP => "Up Throw",
ThrowOption::DOWN => "Down Throw",
_ => return None,
})
}
}
extra_bitflag_impls! {ThrowOption}
impl Delay {
pub fn as_str(self) -> Option<&'static str> {
Some(match self {
@ -509,6 +547,87 @@ impl Delay {
extra_bitflag_impls! {Delay}
bitflags! {
pub struct MedDelay : u32 {
const D0 = 0x1;
const D5 = 0x2;
const D10 = 0x4;
const D15 = 0x8;
const D20 = 0x10;
const D25 = 0x20;
const D30 = 0x40;
const D35 = 0x80;
const D40 = 0x100;
const D45 = 0x200;
const D50 = 0x400;
const D55 = 0x800;
const D60 = 0x1000;
const D65 = 0x2000;
const D70 = 0x4000;
const D75 = 0x8000;
const D80 = 0x10000;
const D85 = 0x20000;
const D90 = 0x40000;
const D95 = 0x80000;
const D100 = 0x0010_0000;
const D105 = 0x0020_0000;
const D110 = 0x0040_0000;
const D115 = 0x0080_0000;
const D120 = 0x0100_0000;
const D125 = 0x0200_0000;
const D130 = 0x0400_0000;
const D135 = 0x0800_0000;
const D140 = 0x1000_0000;
const D145 = 0x2000_0000;
const D150 = 0x4000_0000;
}
}
impl MedDelay {
pub fn as_str(self) -> Option<&'static str> {
Some(match self {
MedDelay::D0 => "0",
MedDelay::D5 => "5",
MedDelay::D10 => "10",
MedDelay::D15 => "15",
MedDelay::D20 => "20",
MedDelay::D25 => "25",
MedDelay::D30 => "30",
MedDelay::D35 => "35",
MedDelay::D40 => "40",
MedDelay::D45 => "45",
MedDelay::D50 => "50",
MedDelay::D55 => "55",
MedDelay::D60 => "60",
MedDelay::D65 => "65",
MedDelay::D70 => "70",
MedDelay::D75 => "75",
MedDelay::D80 => "80",
MedDelay::D85 => "85",
MedDelay::D90 => "90",
MedDelay::D95 => "95",
MedDelay::D100 => "100",
MedDelay::D105 => "105",
MedDelay::D110 => "110",
MedDelay::D115 => "115",
MedDelay::D120 => "120",
MedDelay::D125 => "125",
MedDelay::D130 => "130",
MedDelay::D135 => "135",
MedDelay::D140 => "140",
MedDelay::D145 => "145",
MedDelay::D150 => "150",
_ => return None,
})
}
pub fn into_meddelay(&self) -> u32 {
self.to_index() * 5
}
}
extra_bitflag_impls! {MedDelay}
bitflags! {
pub struct LongDelay : u32 {
const D0 = 0x1;
@ -714,6 +833,9 @@ url_params! {
pub save_state_mirroring: SaveStateMirroring,
pub frame_advantage: OnOff,
pub save_state_enable: OnOff,
pub throw_state: ThrowOption,
pub throw_delay: MedDelay,
pub pummel_delay: MedDelay,
}
}
@ -761,6 +883,9 @@ impl TrainingModpackMenu {
frame_advantage = OnOff::from_val(val),
save_state_mirroring = num::FromPrimitive::from_u32(val),
save_state_enable = OnOff::from_val(val),
throw_state = ThrowOption::from_bits(val),
throw_delay = MedDelay::from_bits(val),
pummel_delay = MedDelay::from_bits(val),
);
}
}

View file

@ -482,6 +482,27 @@ pub unsafe fn write_menu() {
SaveStateMirroring,
"Mirroring: Flips save states in the left-right direction across the stage center"
);
add_bitflag_submenu!(
overall_menu,
"Throw Options",
throw_state,
ThrowOption,
"Throw Options: Throw to be performed when a grab is landed"
);
add_bitflag_submenu!(
overall_menu,
"Throw Delay",
throw_delay,
MedDelay,
"Throw Delay: How many frames to delay the throw option"
);
add_bitflag_submenu!(
overall_menu,
"Pummel Delay",
pummel_delay,
MedDelay,
"Pummel Delay: How many frames after a grab to wait before starting to pummel"
);
// Slider menus
overall_menu.add_sub_menu(

View file

@ -39,6 +39,9 @@ pub static BASE_MENU: consts::TrainingModpackMenu = consts::TrainingModpackMenu
save_state_mirroring: SaveStateMirroring::None,
frame_advantage: OnOff::Off,
save_state_enable: OnOff::On,
throw_state: ThrowOption::NONE,
throw_delay: MedDelay::empty(),
pummel_delay: MedDelay::empty(),
};
pub static mut DEFAULT_MENU: TrainingModpackMenu = BASE_MENU;

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 27 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 42 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 45 KiB

View file

@ -10,6 +10,7 @@ pub mod combo;
pub mod directional_influence;
pub mod frame_counter;
pub mod ledge;
pub mod throw;
pub mod sdi;
pub mod shield;
pub mod tech;
@ -83,7 +84,9 @@ pub unsafe fn handle_get_command_flag_cat(
}
flag |= mash::get_command_flag_cat(module_accessor, category);
// Get throw directions
flag |= throw::get_command_flag_throw_direction(module_accessor);
once_per_frame_per_fighter(module_accessor, category);
flag
@ -355,5 +358,6 @@ pub fn training_mods() {
fast_fall::init();
mash::init();
ledge::init();
throw::init();
menu::init();
}

View file

@ -1,6 +1,7 @@
use crate::common::*;
use crate::training::frame_counter;
use crate::training::ledge;
use crate::training::throw;
use crate::training::mash;
use crate::training::sdi;
use crate::training::shield_tilt;
@ -43,5 +44,6 @@ pub fn on_reset() {
sdi::roll_direction();
frame_counter::reset_all();
ledge::reset_ledge_delay();
throw::reset_throw_delay();
shield_tilt::roll_direction();
}

154
src/training/throw.rs Normal file
View file

@ -0,0 +1,154 @@
use crate::common::consts::*;
use crate::common::*;
use crate::training::frame_counter;
use crate::training::mash;
use smash::app::{self, lua_bind::*};
use smash::lib::lua_const::*;
const NOT_SET: u32 = 9001;
static mut THROW_DELAY: u32 = NOT_SET;
static mut THROW_DELAY_COUNTER: usize = 0;
static mut THROW_CASE: ThrowOption = ThrowOption::empty();
static mut PUMMEL_DELAY: u32 = NOT_SET;
static mut PUMMEL_DELAY_COUNTER: usize = 0;
pub fn init() {
unsafe {
THROW_DELAY_COUNTER = frame_counter::register_counter();
PUMMEL_DELAY_COUNTER = frame_counter::register_counter();
}
}
// Rolling Throw Delays and Pummel Delays separately
pub fn reset_throw_delay() {
unsafe {
if THROW_DELAY != NOT_SET {
THROW_DELAY = NOT_SET;
frame_counter::full_reset(THROW_DELAY_COUNTER);
}
}
}
pub fn reset_pummel_delay() {
unsafe {
if PUMMEL_DELAY != NOT_SET {
PUMMEL_DELAY = NOT_SET;
frame_counter::full_reset(PUMMEL_DELAY_COUNTER);
}
}
}
pub fn reset_throw_case() {
unsafe {
if THROW_CASE != ThrowOption::empty() {
// Don't roll another throw option if one is already selected
THROW_CASE = ThrowOption::empty();
}
}
}
fn roll_throw_delay() {
unsafe {
if THROW_DELAY != NOT_SET {
// Don't roll another throw delay if one is already selected
return;
}
THROW_DELAY = MENU.throw_delay.get_random().into_meddelay();
}
}
fn roll_pummel_delay() {
unsafe {
if PUMMEL_DELAY != NOT_SET {
// Don't roll another pummel delay if one is already selected
return;
}
PUMMEL_DELAY = MENU.pummel_delay.get_random().into_meddelay();
}
}
fn roll_throw_case() {
unsafe {
// Don't re-roll if there is already a throw option selected
if THROW_CASE != ThrowOption::empty() {
return;
}
THROW_CASE = MENU.throw_state.get_random();
}
}
pub unsafe fn get_command_flag_throw_direction(
module_accessor: &mut app::BattleObjectModuleAccessor
) -> i32 {
if !is_operation_cpu(module_accessor) {
return 0;
}
if StatusModule::status_kind(module_accessor) as i32 != *FIGHTER_STATUS_KIND_CATCH_WAIT
&& StatusModule::status_kind(module_accessor) as i32 != *FIGHTER_STATUS_KIND_CATCH_PULL
&& StatusModule::status_kind(module_accessor) as i32 != *FIGHTER_STATUS_KIND_CATCH_ATTACK
{
// No longer holding character, so re-roll the throw case and reset the delay counter for next time
reset_throw_case();
reset_throw_delay();
reset_pummel_delay();
return 0;
}
if !WorkModule::is_enable_transition_term( // If you can't throw right now, don't bother
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_THROW_HI,
) {
return 0;
}
roll_throw_delay();
roll_throw_case();
roll_pummel_delay();
if THROW_CASE == ThrowOption::NONE {
// Do nothing, but don't reroll the throw case.
return 0;
}
if frame_counter::should_delay(THROW_DELAY, THROW_DELAY_COUNTER) {
// Not yet time to perform the throw action
if frame_counter::should_delay(PUMMEL_DELAY, PUMMEL_DELAY_COUNTER) {
// And not yet time to pummel either, so don't do anything
return 0;
}
// If no pummel delay is selected (default), then don't pummel
if MENU.pummel_delay == MedDelay::empty() {
return 0;
}
// (this conditional would need to be changed to speed up pummelling)
if StatusModule::status_kind(module_accessor) as i32 == *FIGHTER_STATUS_KIND_CATCH_WAIT {
let status = *FIGHTER_STATUS_KIND_CATCH_ATTACK;//.unwrap_or(0);
StatusModule::change_status_request_from_script(module_accessor, status, true);
}
return 0;
}
// If you can uthrow, then throw (since all throws should be possible at the same times)
if WorkModule::is_enable_transition_term(
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_THROW_HI,
) {
let cmd = THROW_CASE.into_cmd().unwrap_or(0);
mash::buffer_menu_mash();
return cmd;
}
return 0;
}