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:
parent
f9522d2699
commit
6f6ce58a88
10 changed files with 761 additions and 2 deletions
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
116
src/templates/pummel_delay.svg
Normal file
116
src/templates/pummel_delay.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 27 KiB |
127
src/templates/throw_delay.svg
Normal file
127
src/templates/throw_delay.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 42 KiB |
201
src/templates/throw_state.svg
Normal file
201
src/templates/throw_state.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 45 KiB |
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
154
src/training/throw.rs
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue