1
0
Fork 0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2024-11-28 04:44:06 +00:00

Add Miss Tech Options; Save States Control bug

This commit is contained in:
jugeeya 2020-08-29 11:03:33 -07:00
parent 4753258874
commit 02f4095c37
9 changed files with 185 additions and 115 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "training_modpack" name = "training_modpack"
version = "2.5.0" version = "2.5.3"
authors = ["jugeeya <jugeeya@live.com>"] authors = ["jugeeya <jugeeya@live.com>"]
edition = "2018" edition = "2018"

View file

@ -38,7 +38,7 @@ include $(DEVKITPRO)/libnx/switch_rules
# NACP building is skipped as well. # NACP building is skipped as well.
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
APP_TITLE := Training Modpack APP_TITLE := Training Modpack
APP_VERSION := 2.5.2Beta APP_VERSION := 2.5.3Beta
TARGET := ovlTrainingModpack TARGET := ovlTrainingModpack
BUILD := build BUILD := build

View file

@ -0,0 +1,61 @@
#include <tesla.hpp>
static const char* SYSTEM_SETTINGS_FILE = "/atmosphere/config/system_settings.ini";
static tsl::hlp::ini::IniData readSettings()
{
/* Open Sd card filesystem. */
FsFileSystem fsSdmc;
if(R_FAILED(fsOpenSdCardFileSystem(&fsSdmc))) return {};
tsl::hlp::ScopeGuard fsGuard([&] { fsFsClose(&fsSdmc); });
/* Open config file. */
FsFile fileConfig;
if(R_FAILED(fsFsOpenFile(&fsSdmc, SYSTEM_SETTINGS_FILE, FsOpenMode_Read, &fileConfig))) return {};
tsl::hlp::ScopeGuard fileGuard([&] { fsFileClose(&fileConfig); });
/* Get config file size. */
s64 configFileSize;
if(R_FAILED(fsFileGetSize(&fileConfig, &configFileSize))) return {};
/* Read and parse config file. */
std::string configFileData(configFileSize, '\0');
u64 readSize;
Result rc = fsFileRead(&fileConfig, 0, configFileData.data(), configFileSize, FsReadOption_None, &readSize);
if(R_FAILED(rc) || readSize != static_cast<u64>(configFileSize)) return {};
return tsl::hlp::ini::parseIni(configFileData);
}
static void writeSettings(tsl::hlp::ini::IniData const& iniData)
{
/* Open Sd card filesystem. */
FsFileSystem fsSdmc;
if(R_FAILED(fsOpenSdCardFileSystem(&fsSdmc))) return;
tsl::hlp::ScopeGuard fsGuard([&] { fsFsClose(&fsSdmc); });
std::string iniString = tsl::hlp::ini::unparseIni(iniData);
fsFsDeleteFile(&fsSdmc, SYSTEM_SETTINGS_FILE);
fsFsCreateFile(&fsSdmc, SYSTEM_SETTINGS_FILE, iniString.length(), 0);
/* Open config file. */
FsFile fileConfig;
if(R_FAILED(fsFsOpenFile(&fsSdmc, SYSTEM_SETTINGS_FILE, FsOpenMode_Write, &fileConfig))) return;
tsl::hlp::ScopeGuard fileGuard([&] { fsFileClose(&fileConfig); });
fsFileWrite(&fileConfig, 0, iniString.c_str(), iniString.length(), FsWriteOption_Flush);
}
static void updateSettings(tsl::hlp::ini::IniData const& changes)
{
tsl::hlp::ini::IniData iniData = readSettings();
for(auto& section : changes)
{
for(auto& keyValue : section.second)
{
iniData[section.first][keyValue.first] = keyValue.second;
}
}
writeSettings(iniData);
}

View file

@ -114,6 +114,26 @@ options.
CPUs will also perform a defensive CPUs will also perform a defensive
option after getting up.)""""; option after getting up.)"""";
// Missed Tech Option
// clang-format off
#define ENUM_CLASS_MissTechFlag(type,x) \
x(type,Getup,"Normal Getup") \
x(type,Attack,"Getup Attack") \
x(type,RollF,"RollF") \
x(type,RollB,"RollB")
// clang-format on
DEFINE_ENUM_CLASS(MissTechFlag);
constexpr const char* const miss_tech_help = R""""(
CPUs will perform a random
option after missing a tech
among the selected options.
CPUs will also perform a defensive
option after getting up.)"""";
// Defensive States // Defensive States
// clang-format off // clang-format off
@ -200,7 +220,7 @@ are saved:
- Position - Position
- Facing direction)""""; - Facing direction)"""";
const std::string reset_menu_help = R""""( const std::string reset_menu_help = R""""(
Reset menu to default Reset menu to default
configuration. Please also configuration. Please also
use on the first boot after use on the first boot after
@ -243,7 +263,7 @@ in frames.
Used to delay OOS Options.)""""; Used to delay OOS Options.)"""";
const std::string shield_tilt_help = R""""( const std::string shield_tilt_help = R""""(
Shield Tilt Direction Shield Tilt Direction
)""""; )"""";

View file

@ -5,6 +5,7 @@
#include "overlay_frame_with_help.hpp" #include "overlay_frame_with_help.hpp"
#include "value_list_item.hpp" #include "value_list_item.hpp"
#include "clickable_list_item.hpp" #include "clickable_list_item.hpp"
#include "ini_settings.hpp"
#include "taunt_toggles.hpp" #include "taunt_toggles.hpp"
static struct TrainingModpackMenu static struct TrainingModpackMenu
@ -18,6 +19,7 @@ static struct TrainingModpackMenu
LedgeFlags LEDGE_STATE = LedgeFlags::All; LedgeFlags LEDGE_STATE = LedgeFlags::All;
DelayFlags LEDGE_DELAY = DelayFlags::All; DelayFlags LEDGE_DELAY = DelayFlags::All;
TechFlags TECH_STATE = TechFlags::All; TechFlags TECH_STATE = TechFlags::All;
MissTechFlags MISS_TECH_STATE = MissTechFlags::All;
int SHIELD_STATE = NONE; int SHIELD_STATE = NONE;
DefensiveFlags DEFENSIVE_STATE = DefensiveFlags::All; DefensiveFlags DEFENSIVE_STATE = DefensiveFlags::All;
DelayFlags OOS_OFFSET = DelayFlags::None; DelayFlags OOS_OFFSET = DelayFlags::None;
@ -36,69 +38,10 @@ static struct TrainingModpackMenu defaultMenu = menu;
static int FRAME_ADVANTAGE = 0; static int FRAME_ADVANTAGE = 0;
u64 pidSmash = 0; u64 pidSmash = 0;
static const char* SYSTEM_SETTINGS_FILE = "/atmosphere/config/system_settings.ini";
static const char* TRAINING_MOD_LOG = "/TrainingModpack/training_modpack.log"; static const char* TRAINING_MOD_LOG = "/TrainingModpack/training_modpack.log";
static const char* TRAINING_MOD_FRAME_ADV_LOG = "/TrainingModpack/training_modpack_frame_adv.log"; static const char* TRAINING_MOD_FRAME_ADV_LOG = "/TrainingModpack/training_modpack_frame_adv.log";
static const char* TRAINING_MOD_CONF = "/TrainingModpack/training_modpack_menu.conf"; static const char* TRAINING_MOD_CONF = "/TrainingModpack/training_modpack_menu.conf";
static tsl::hlp::ini::IniData readSettings()
{
/* Open Sd card filesystem. */
FsFileSystem fsSdmc;
if(R_FAILED(fsOpenSdCardFileSystem(&fsSdmc))) return {};
tsl::hlp::ScopeGuard fsGuard([&] { fsFsClose(&fsSdmc); });
/* Open config file. */
FsFile fileConfig;
if(R_FAILED(fsFsOpenFile(&fsSdmc, SYSTEM_SETTINGS_FILE, FsOpenMode_Read, &fileConfig))) return {};
tsl::hlp::ScopeGuard fileGuard([&] { fsFileClose(&fileConfig); });
/* Get config file size. */
s64 configFileSize;
if(R_FAILED(fsFileGetSize(&fileConfig, &configFileSize))) return {};
/* Read and parse config file. */
std::string configFileData(configFileSize, '\0');
u64 readSize;
Result rc = fsFileRead(&fileConfig, 0, configFileData.data(), configFileSize, FsReadOption_None, &readSize);
if(R_FAILED(rc) || readSize != static_cast<u64>(configFileSize)) return {};
return tsl::hlp::ini::parseIni(configFileData);
}
static void writeSettings(tsl::hlp::ini::IniData const& iniData)
{
/* Open Sd card filesystem. */
FsFileSystem fsSdmc;
if(R_FAILED(fsOpenSdCardFileSystem(&fsSdmc))) return;
tsl::hlp::ScopeGuard fsGuard([&] { fsFsClose(&fsSdmc); });
std::string iniString = tsl::hlp::ini::unparseIni(iniData);
fsFsDeleteFile(&fsSdmc, SYSTEM_SETTINGS_FILE);
fsFsCreateFile(&fsSdmc, SYSTEM_SETTINGS_FILE, iniString.length(), 0);
/* Open config file. */
FsFile fileConfig;
if(R_FAILED(fsFsOpenFile(&fsSdmc, SYSTEM_SETTINGS_FILE, FsOpenMode_Write, &fileConfig))) return;
tsl::hlp::ScopeGuard fileGuard([&] { fsFileClose(&fileConfig); });
fsFileWrite(&fileConfig, 0, iniString.c_str(), iniString.length(), FsWriteOption_Flush);
}
static void updateSettings(tsl::hlp::ini::IniData const& changes)
{
tsl::hlp::ini::IniData iniData = readSettings();
for(auto& section : changes)
{
for(auto& keyValue : section.second)
{
iniData[section.first][keyValue.first] = keyValue.second;
}
}
writeSettings(iniData);
}
GuiMain::GuiMain() GuiMain::GuiMain()
{ {
smInitialize(); smInitialize();
@ -424,6 +367,7 @@ tsl::elm::Element* GuiMain::createUI()
list->addItem(createBitFlagOption(&menu.LEDGE_STATE, "Ledge Options", ledge_help, this)); list->addItem(createBitFlagOption(&menu.LEDGE_STATE, "Ledge Options", ledge_help, this));
list->addItem(createBitFlagOption(&menu.LEDGE_DELAY, "Ledge Delay", ledge_delay_help, this)); list->addItem(createBitFlagOption(&menu.LEDGE_DELAY, "Ledge Delay", ledge_delay_help, this));
list->addItem(createBitFlagOption(&menu.TECH_STATE, "Tech Options", tech_help, this)); list->addItem(createBitFlagOption(&menu.TECH_STATE, "Tech Options", tech_help, this));
list->addItem(createBitFlagOption(&menu.MISS_TECH_STATE, "Missed Tech Options", miss_tech_help, this));
list->addItem(createBitFlagOption(&menu.DEFENSIVE_STATE, "Defensive Options", defensive_help, this)); list->addItem(createBitFlagOption(&menu.DEFENSIVE_STATE, "Defensive Options", defensive_help, this));
list->addItem(new tsl::elm::CategoryHeader("Aerials", true)); list->addItem(new tsl::elm::CategoryHeader("Aerials", true));

View file

@ -35,7 +35,7 @@ macro_rules! to_index_impl {
return self.bits.trailing_zeros(); return self.bits.trailing_zeros();
} }
} };
} }
pub fn random_option<T>(arg: &Vec<T>) -> &T { pub fn random_option<T>(arg: &Vec<T>) -> &T {
@ -152,6 +152,21 @@ impl TechFlags {
get_random_impl! {TechFlags} get_random_impl! {TechFlags}
} }
// Missed Tech Options
bitflags! {
pub struct MissTechFlags : u32 {
const GETUP = 0x1;
const ATTACK = 0x2;
const ROLL_F = 0x4;
const ROLL_B = 0x8;
}
}
impl MissTechFlags {
to_vec_impl! {MissTechFlags}
get_random_impl! {MissTechFlags}
}
/// Shield States /// Shield States
#[repr(i32)] #[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
@ -287,7 +302,7 @@ impl BoolFlag {
return match *self { return match *self {
BoolFlag::TRUE => true, BoolFlag::TRUE => true,
_ => false, _ => false,
} };
} }
} }
@ -302,6 +317,7 @@ pub struct TrainingModpackMenu {
pub ledge_state: LedgeOption, pub ledge_state: LedgeOption,
pub ledge_delay: Delay, pub ledge_delay: Delay,
pub tech_state: TechFlags, pub tech_state: TechFlags,
pub miss_tech_state: MissTechFlags,
pub shield_state: Shield, pub shield_state: Shield,
pub defensive_state: Defensive, pub defensive_state: Defensive,
pub oos_offset: Delay, pub oos_offset: Delay,
@ -317,7 +333,7 @@ pub struct TrainingModpackMenu {
// Fighter Ids // Fighter Ids
#[repr(i32)] #[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FighterId { pub enum FighterId {
Player = 0, Player = 0,
CPU = 1, CPU = 1,

View file

@ -15,6 +15,7 @@ pub static mut MENU_STRUCT: consts::TrainingModpackMenu = consts::TrainingModpac
ledge_state: LedgeOption::all(), ledge_state: LedgeOption::all(),
ledge_delay: Delay::empty(), ledge_delay: Delay::empty(),
tech_state: TechFlags::all(), tech_state: TechFlags::all(),
miss_tech_state: MissTechFlags::all(),
shield_state: Shield::None, shield_state: Shield::None,
defensive_state: Defensive::all(), defensive_state: Defensive::all(),
oos_offset: Delay::empty(), oos_offset: Delay::empty(),

View file

@ -1,4 +1,4 @@
use crate::common::*; use crate::common::consts::FighterId;
use crate::training::reset; use crate::training::reset;
use smash::app::{self, lua_bind::*}; use smash::app::{self, lua_bind::*};
use smash::hash40; use smash::hash40;
@ -19,7 +19,7 @@ struct SavedState {
percent: f32, percent: f32,
lr: f32, lr: f32,
situation_kind: i32, situation_kind: i32,
state: SaveState state: SaveState,
} }
macro_rules! default_save_state { macro_rules! default_save_state {
@ -30,9 +30,9 @@ macro_rules! default_save_state {
percent: 0.0, percent: 0.0,
lr: 1.0, lr: 1.0,
situation_kind: 0, situation_kind: 0,
state: NoAction state: NoAction,
} }
} };
} }
use SaveState::*; use SaveState::*;
@ -69,7 +69,9 @@ pub unsafe fn get_param_int(
pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor) { pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor) {
let status = StatusModule::status_kind(module_accessor) as i32; let status = StatusModule::status_kind(module_accessor) as i32;
let save_state: &mut SavedState; let save_state: &mut SavedState;
if is_operation_cpu(module_accessor) { if WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID)
== FighterId::CPU as i32
{
save_state = &mut SAVE_STATE_CPU; save_state = &mut SAVE_STATE_CPU;
} else { } else {
save_state = &mut SAVE_STATE_PLAYER; save_state = &mut SAVE_STATE_PLAYER;
@ -107,7 +109,11 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
ControlModule::stop_rumble(module_accessor, true); ControlModule::stop_rumble(module_accessor, true);
SoundModule::stop_all_sound(module_accessor); SoundModule::stop_all_sound(module_accessor);
StatusModule::change_status_request(module_accessor, *FIGHTER_STATUS_KIND_DEAD, false); StatusModule::change_status_request(
module_accessor,
*FIGHTER_STATUS_KIND_DEAD,
false,
);
} }
} }
@ -142,12 +148,18 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
} }
} else if save_state.situation_kind == SITUATION_KIND_AIR { } else if save_state.situation_kind == SITUATION_KIND_AIR {
if status != FIGHTER_STATUS_KIND_FALL { if status != FIGHTER_STATUS_KIND_FALL {
StatusModule::change_status_request(module_accessor, *FIGHTER_STATUS_KIND_FALL, false); StatusModule::change_status_request(
module_accessor,
*FIGHTER_STATUS_KIND_FALL,
false,
);
} else { } else {
save_state.state = NoAction; save_state.state = NoAction;
} }
} else if save_state.situation_kind == SITUATION_KIND_CLIFF { } else if save_state.situation_kind == SITUATION_KIND_CLIFF {
if status != FIGHTER_STATUS_KIND_CLIFF_CATCH_MOVE && status != FIGHTER_STATUS_KIND_CLIFF_CATCH { if status != FIGHTER_STATUS_KIND_CLIFF_CATCH_MOVE
&& status != FIGHTER_STATUS_KIND_CLIFF_CATCH
{
StatusModule::change_status_request( StatusModule::change_status_request(
module_accessor, module_accessor,
*FIGHTER_STATUS_KIND_CLIFF_CATCH_MOVE, *FIGHTER_STATUS_KIND_CLIFF_CATCH_MOVE,

View file

@ -8,7 +8,8 @@ use smash::lib::lua_const::*;
use smash::lib::L2CValue; use smash::lib::L2CValue;
use smash::lua2cpp::L2CFighterBase; use smash::lua2cpp::L2CFighterBase;
static mut ROLL_DIRECTION: Direction = Direction::empty(); static mut TECH_ROLL_DIRECTION: Direction = Direction::empty();
static mut MISS_TECH_ROLL_DIRECTION: Direction = Direction::empty();
#[skyline::hook(replace = smash::lua2cpp::L2CFighterBase_change_status)] #[skyline::hook(replace = smash::lua2cpp::L2CFighterBase_change_status)]
pub unsafe fn handle_change_status( pub unsafe fn handle_change_status(
@ -45,32 +46,42 @@ unsafe fn mod_handle_change_status(
{ {
let state: TechFlags = MENU.tech_state.get_random(); let state: TechFlags = MENU.tech_state.get_random();
match state { if WorkModule::is_enable_transition_term(
TechFlags::IN_PLACE => { module_accessor,
*status_kind = FIGHTER_STATUS_KIND_PASSIVE.as_lua_int(); *FIGHTER_STATUS_TRANSITION_TERM_ID_PASSIVE,
*unk = LUA_TRUE; ) {
match state {
TechFlags::IN_PLACE => {
*status_kind = FIGHTER_STATUS_KIND_PASSIVE.as_lua_int();
*unk = LUA_TRUE;
mash::perform_defensive_option();
}
TechFlags::ROLL_F => {
*status_kind = FIGHTER_STATUS_KIND_PASSIVE_FB.as_lua_int();
*unk = LUA_TRUE;
TECH_ROLL_DIRECTION = Direction::IN; // = In
mash::perform_defensive_option();
}
TechFlags::ROLL_B => {
*status_kind = FIGHTER_STATUS_KIND_PASSIVE_FB.as_lua_int();
*unk = LUA_TRUE;
TECH_ROLL_DIRECTION = Direction::OUT; // = Away
mash::perform_defensive_option();
}
_ => (),
} }
TechFlags::ROLL_F => {
*status_kind = FIGHTER_STATUS_KIND_PASSIVE_FB.as_lua_int();
*unk = LUA_TRUE;
ROLL_DIRECTION = Direction::IN; // = In
}
TechFlags::ROLL_B => {
*status_kind = FIGHTER_STATUS_KIND_PASSIVE_FB.as_lua_int();
*unk = LUA_TRUE;
ROLL_DIRECTION = Direction::OUT; // = Away
}
_ => (),
} }
mash::perform_defensive_option();
return; return;
} }
// Wall Tech // Wall Tech
if status_kind_int == *FIGHTER_STATUS_KIND_STOP_WALL if (status_kind_int == *FIGHTER_STATUS_KIND_STOP_WALL
|| status_kind_int == *FIGHTER_STATUS_KIND_DAMAGE_FLY_REFLECT_LR || status_kind_int == *FIGHTER_STATUS_KIND_DAMAGE_FLY_REFLECT_LR)
&& WorkModule::is_enable_transition_term(
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_PASSIVE_CEIL,
)
{ {
*status_kind = FIGHTER_STATUS_KIND_PASSIVE_WALL.as_lua_int(); *status_kind = FIGHTER_STATUS_KIND_PASSIVE_WALL.as_lua_int();
*unk = LUA_TRUE; *unk = LUA_TRUE;
@ -78,8 +89,12 @@ unsafe fn mod_handle_change_status(
} }
// Ceiling Tech // Ceiling Tech
if status_kind_int == *FIGHTER_STATUS_KIND_STOP_CEIL if (status_kind_int == *FIGHTER_STATUS_KIND_STOP_CEIL
|| status_kind_int == *FIGHTER_STATUS_KIND_DAMAGE_FLY_REFLECT_U || status_kind_int == *FIGHTER_STATUS_KIND_DAMAGE_FLY_REFLECT_U)
&& WorkModule::is_enable_transition_term(
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_PASSIVE_WALL,
)
{ {
*status_kind = FIGHTER_STATUS_KIND_PASSIVE_CEIL.as_lua_int(); *status_kind = FIGHTER_STATUS_KIND_PASSIVE_CEIL.as_lua_int();
*unk = LUA_TRUE; *unk = LUA_TRUE;
@ -87,9 +102,7 @@ unsafe fn mod_handle_change_status(
} }
} }
pub unsafe fn get_command_flag_cat( pub unsafe fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModuleAccessor) {
module_accessor: &mut app::BattleObjectModuleAccessor,
) {
if !is_operation_cpu(module_accessor) { if !is_operation_cpu(module_accessor) {
return; return;
} }
@ -106,18 +119,23 @@ pub unsafe fn get_command_flag_cat(
] ]
.contains(&status) .contains(&status)
{ {
let random_statuses = vec![ let status = match MENU.miss_tech_state.get_random() {
*FIGHTER_STATUS_KIND_DOWN_STAND, // Normal Getup MissTechFlags::GETUP => *FIGHTER_STATUS_KIND_DOWN_STAND,
*FIGHTER_STATUS_KIND_DOWN_STAND_FB, // Getup Roll MissTechFlags::ATTACK => *FIGHTER_STATUS_KIND_DOWN_STAND_ATTACK,
*FIGHTER_STATUS_KIND_DOWN_STAND_ATTACK, // Getup Attack MissTechFlags::ROLL_F => {
]; MISS_TECH_ROLL_DIRECTION = Direction::IN; // = In
*FIGHTER_STATUS_KIND_DOWN_STAND_FB
}
MissTechFlags::ROLL_B => {
MISS_TECH_ROLL_DIRECTION = Direction::OUT; // = Away
*FIGHTER_STATUS_KIND_DOWN_STAND_FB
}
_ => *FIGHTER_STATUS_KIND_DOWN_STAND,
};
let random_status_index = get_random_int(random_statuses.len() as i32) as usize; StatusModule::change_status_request_from_script(module_accessor, status, false);
StatusModule::change_status_request_from_script(
module_accessor, mash::perform_defensive_option();
random_statuses[random_status_index],
false,
);
return; return;
} }
} }
@ -134,22 +152,20 @@ pub unsafe fn change_motion(
return None; return None;
} }
let random_roll = get_random_int(2);
if [hash40("passive_stand_f"), hash40("passive_stand_b")].contains(&motion_kind) { if [hash40("passive_stand_f"), hash40("passive_stand_b")].contains(&motion_kind) {
if ROLL_DIRECTION == Direction::IN { if TECH_ROLL_DIRECTION == Direction::IN {
return Some(hash40("passive_stand_f")); return Some(hash40("passive_stand_f"));
} else { } else {
return Some(hash40("passive_stand_b")); return Some(hash40("passive_stand_b"));
} }
} else if [hash40("down_forward_u"), hash40("down_back_u")].contains(&motion_kind) { } else if [hash40("down_forward_u"), hash40("down_back_u")].contains(&motion_kind) {
if random_roll != 0 { if MISS_TECH_ROLL_DIRECTION == Direction::IN {
return Some(hash40("down_forward_u")); return Some(hash40("down_forward_u"));
} else { } else {
return Some(hash40("down_back_u")); return Some(hash40("down_back_u"));
} }
} else if [hash40("down_forward_d"), hash40("down_back_d")].contains(&motion_kind) { } else if [hash40("down_forward_d"), hash40("down_back_d")].contains(&motion_kind) {
if random_roll != 0 { if MISS_TECH_ROLL_DIRECTION == Direction::IN {
return Some(hash40("down_forward_d")); return Some(hash40("down_forward_d"));
} else { } else {
return Some(hash40("down_back_d")); return Some(hash40("down_back_d"));