1
0
Fork 0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2024-11-20 00:46:34 +00:00

Add UI backing to text options in menu, always do new damage display (#451)

* A bunch of things

* Current progress

* Fix for ResAnimationContent

* Figure out Parts*

* Cleanup, just because

* New pane working!!!

* New null pane for hierarchy

* Success with parent pane

* Generate multiple panes

* Multiple panes, almost working text color

* MaterialColor test, but fails

* Forgot bitfield-struct

* Vtable for material. Fixes SetWhiteColor!

* Refactor color changing, change naming scheme

* Just Frame Advantage

* Merge

* Delete T_test.txt

* Delete set_txt_num_01.txt

* Delete libtraining_modpack.nro

* Format Rust code using rustfmt

* Ignore shell scripts in repo languages

* General refactor, add basis for quick menu

* Small refactor, fix ordering of submenu options

* Toggles, sliders

* Tons of progress...

* Correct dmg updater, remove old quick menu backend

* Fix damage percentage display

* Small QoL

* Format Rust code using rustfmt

* More edits. Use Quit Training button as Modpack Menu header

* Finish merge

* Format Rust code using rustfmt

* Use vanilla backgrounds for text options

* Format ui_hacks, also always do new percent display

* Fix merge

* That was the most awful merge ever

* Address clippy warnings

* Format Rust code using rustfmt

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
jugeeya 2022-12-30 11:33:17 -08:00 committed by GitHub
parent 52e3528292
commit ed425d78e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 411 additions and 341 deletions

View file

@ -6,8 +6,5 @@
"--workspace",
"--message-format=json",
"--all-features",
"--",
"-A",
"clippy::borrow_interior_mutable_const"
],
}

View file

@ -154,7 +154,7 @@ pub fn combo_passes(
}
}
pub const DEFAULT_BTN_CONFIG: &'static str = r#"[button_config]
pub const DEFAULT_BTN_CONFIG: &str = r#"[button_config]
# Available Options:
#
# ATTACK

View file

@ -41,7 +41,7 @@ impl Uuid {
pub fn to_str(&self) -> String {
self.data
.iter()
.map(|i| format!("{:02x}", i))
.map(|i| format!("{i:02x}"))
.collect::<String>()
}
}
@ -91,7 +91,7 @@ impl Event {
user_uid
.id
.iter()
.map(|i| format!("{:02x}", i))
.map(|i| format!("{i:02x}"))
.collect::<Vec<String>>()
.join(""),
)
@ -109,7 +109,7 @@ impl Event {
device_uuid
.data
.iter()
.map(|i| format!("{:02x}", i))
.map(|i| format!("{i:02x}"))
.collect::<Vec<String>>()
.join(""),
)
@ -137,7 +137,7 @@ impl Event {
session_id_hash
.hash
.iter()
.map(|i| format!("{:02x}", i))
.map(|i| format!("{i:02x}"))
.collect::<Vec<String>>()
.join(""),
)

View file

@ -54,8 +54,8 @@ pub unsafe fn write_menu() {
let program_id = get_program_id();
let htdocs_dir = "training_modpack";
let menu_html_path = Path::new("sd:/atmosphere/contents")
.join(&format!("{:016X}", program_id))
.join(&format!("manual_html/html-document/{}.htdocs/", htdocs_dir))
.join(format!("{program_id:016X}"))
.join(format!("manual_html/html-document/{htdocs_dir}.htdocs/"))
.join("training_menu.html");
let write_resp = fs::write(menu_html_path, data);
@ -94,11 +94,10 @@ pub unsafe fn set_menu_from_json(message: &str) {
skyline::error::show_error(
0x70,
"Could not parse the menu response!\nPlease send a screenshot of the details page to the developers.\n\0",
&*format!("{:#?}\0", message)
&format!("{message:#?}\0")
);
};
if MENU.quick_menu == OnOff::Off {
if is_emulator() {
if MENU.quick_menu == OnOff::Off && is_emulator() {
skyline::error::show_error(
0x69,
"Cannot use web menu on emulator.\n\0",
@ -106,7 +105,6 @@ pub unsafe fn set_menu_from_json(message: &str) {
);
MENU.quick_menu = OnOff::On;
}
}
EVENT_QUEUE.push(Event::menu_open(message.to_string()));
}
@ -151,14 +149,6 @@ pub struct ButtonPress {
}
impl ButtonPress {
pub fn default() -> ButtonPress {
ButtonPress {
prev_frame_is_pressed: false,
is_pressed: false,
lockout_frames: 0,
}
}
pub fn read_press(&mut self) -> bool {
let is_pressed = self.is_pressed;
if self.is_pressed {

View file

@ -26,7 +26,7 @@ extern "C" {
#[cfg(feature = "outside_training_mode")]
pub fn is_training_mode() -> bool {
return true;
true
}
pub fn get_category(module_accessor: &mut app::BattleObjectModuleAccessor) -> i32 {
@ -60,7 +60,7 @@ pub fn is_operation_cpu(module_accessor: &mut app::BattleObjectModuleAccessor) -
}
let entry_id_int =
WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID) as i32;
WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID);
if entry_id_int == 0 {
return false;
@ -76,13 +76,13 @@ pub fn is_operation_cpu(module_accessor: &mut app::BattleObjectModuleAccessor) -
}
pub fn is_grounded(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
let situation_kind = unsafe { StatusModule::situation_kind(module_accessor) as i32 };
let situation_kind = unsafe { StatusModule::situation_kind(module_accessor) };
situation_kind == SITUATION_KIND_GROUND
}
pub fn is_airborne(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
let situation_kind = unsafe { StatusModule::situation_kind(module_accessor) as i32 };
let situation_kind = unsafe { StatusModule::situation_kind(module_accessor) };
situation_kind == SITUATION_KIND_AIR
}
@ -105,7 +105,7 @@ pub fn is_in_footstool(module_accessor: &mut app::BattleObjectModuleAccessor) ->
}
pub fn is_shielding(module_accessor: *mut app::BattleObjectModuleAccessor) -> bool {
let status_kind = unsafe { StatusModule::status_kind(module_accessor) as i32 };
let status_kind = unsafe { StatusModule::status_kind(module_accessor) };
(*FIGHTER_STATUS_KIND_GUARD_ON..=*FIGHTER_STATUS_KIND_GUARD_DAMAGE).contains(&status_kind)
}
@ -130,7 +130,7 @@ pub unsafe fn is_ptrainer(module_accessor: &mut app::BattleObjectModuleAccessor)
}
pub unsafe fn is_dead(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
let status_kind = StatusModule::status_kind(module_accessor) as i32;
let status_kind = StatusModule::status_kind(module_accessor);
let prev_status_kind = StatusModule::prev_status_kind(module_accessor, 0);
// Pokemon trainer enters FIGHTER_STATUS_KIND_WAIT for one frame during their respawn animation
// And the previous status is FIGHTER_STATUS_NONE

View file

@ -168,11 +168,10 @@ fn print_char(
for segment_char in segment_str.chars() {
let mut index = segment_char as i32 - 'a' as i32;
let segment: [f32; 5];
if is_facing_left {
index = SEGMENT_REV[index as usize] as i32 - 'a' as i32;
}
segment = SEGMENT_DICT[index as usize];
let segment = SEGMENT_DICT[index as usize];
const SIZE_MULT: f32 = 0.5;

View file

@ -38,26 +38,23 @@ pub fn version_check() {
// Display dialog box on launch if changing versions
DialogOk::ok(
format!(
"Thank you for installing version {} of the Training Modpack.\n\n\
"Thank you for installing version {CURRENT_VERSION} of the Training Modpack.\n\n\
Due to a breaking change in this version, your menu selections and defaults must be reset once.\n\n\
Please refer to the Github page and the Discord server for a full list of recent features, bugfixes, and other changes.",
CURRENT_VERSION
Please refer to the Github page and the Discord server for a full list of recent features, bugfixes, and other changes."
)
);
// Remove old menu selections, silently ignoring errors (i.e. if the file doesn't exist)
fs::remove_file("sd:/TrainingModpack/training_modpack_menu.conf").unwrap_or({});
fs::remove_file("sd:/TrainingModpack/training_modpack_menu.json").unwrap_or({});
fs::remove_file("sd:/TrainingModpack/training_modpack_menu_defaults.conf")
.unwrap_or({});
fs::remove_file("sd:/TrainingModpack/training_modpack_menu.conf").unwrap();
fs::remove_file("sd:/TrainingModpack/training_modpack_menu.json").unwrap();
fs::remove_file("sd:/TrainingModpack/training_modpack_menu_defaults.conf").unwrap();
record_current_version(VERSION_FILE_PATH);
}
VersionCheck::NoFile => {
// Display dialog box on fresh installation
DialogOk::ok(
format!(
"Thank you for installing version {} of the Training Modpack.\n\n\
Please refer to the Github page and the Discord server for a full list of features and instructions on how to utilize the improved Training Mode.",
CURRENT_VERSION
"Thank you for installing version {CURRENT_VERSION} of the Training Modpack.\n\n\
Please refer to the Github page and the Discord server for a full list of features and instructions on how to utilize the improved Training Mode."
)
);
record_current_version(VERSION_FILE_PATH);

View file

@ -75,7 +75,7 @@ fn get_hazard_hook_address() -> usize {
}
}
flag_pos as usize
flag_pos
}
// 8.1.0 Defaults
@ -129,8 +129,7 @@ unsafe fn validate_hazards_addrs() -> std::result::Result<(), ()> {
pub fn hazard_manager() {
println!("[Training Modpack] Applying hazard control mods.");
unsafe {
match validate_hazards_addrs() {
Ok(()) => {
if let Ok(()) = validate_hazards_addrs() {
HAZARD_FLAG_ADDRESS = get_hazard_flag_address() as *mut u8;
LOAD_ADDRESS = get_hazard_hook_address();
A64InlineHook(
@ -138,7 +137,5 @@ pub fn hazard_manager() {
hazard_intercept as *const skyline::libc::c_void,
);
}
Err(()) => {}
}
}
}

View file

@ -161,7 +161,7 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModule
return;
}
let status_kind = StatusModule::status_kind(module_accessor) as i32;
let status_kind = StatusModule::status_kind(module_accessor);
if (*FIGHTER_STATUS_KIND_CATCH..=*FIGHTER_STATUS_KIND_CATCH_TURN).contains(&status_kind) {
return;
}
@ -231,11 +231,11 @@ unsafe fn mod_handle_attack(lua_state: u64) {
let mut hitbox_params: Vec<L2CValue> =
(0..36).map(|i| l2c_agent.pop_lua_stack(i + 1)).collect();
l2c_agent.clear_lua_stack();
for (i, mut x) in hitbox_params.iter_mut().enumerate().take(36) {
for (i, x) in hitbox_params.iter_mut().enumerate().take(36) {
if i == 20 {
l2c_agent.push_lua_stack(&mut L2CValue::new_num(-999.0));
} else {
l2c_agent.push_lua_stack(&mut x);
l2c_agent.push_lua_stack(x);
}
}
}
@ -335,7 +335,7 @@ unsafe fn mod_handle_catch(lua_state: u64) {
size.get_num(),
center,
capsule_center,
ID_COLORS[(id.get_int() + 3 % 8) as usize],
ID_COLORS[((id.get_int() + 3) % 8) as usize],
);
}

View file

@ -5,11 +5,15 @@
#![feature(c_variadic)]
#![allow(
clippy::borrow_interior_mutable_const,
clippy::declare_interior_mutable_const,
clippy::not_unsafe_ptr_arg_deref,
clippy::missing_safety_doc,
clippy::wrong_self_convention,
clippy::option_map_unit_fn,
clippy::float_cmp
clippy::float_cmp,
clippy::fn_null_check,
// Look into why for this one
clippy::transmute_num_to_bytes
)]
pub mod common;
@ -66,7 +70,7 @@ pub fn main() {
},
};
let err_msg = format!("thread has panicked at '{}', {}", msg, location);
let err_msg = format!("thread has panicked at '{msg}', {location}");
skyline::error::show_error(
69,
"Skyline plugin has panicked! Please open the details and send a screenshot to the developer, then close the game.\n",
@ -108,7 +112,7 @@ pub fn main() {
let menu_conf_path = "sd:/TrainingModpack/training_modpack_menu.json";
log!("Checking for previous menu in training_modpack_menu.json...");
if fs::metadata(menu_conf_path).is_ok() {
let menu_conf = fs::read_to_string(&menu_conf_path).unwrap();
let menu_conf = fs::read_to_string(menu_conf_path).unwrap();
if let Ok(menu_conf_json) = serde_json::from_str::<MenuJsonStruct>(&menu_conf) {
unsafe {
MENU = menu_conf_json.menu;
@ -130,7 +134,7 @@ pub fn main() {
log!("Checking for previous button combo settings in training_modpack.toml...");
if fs::metadata(combo_path).is_ok() {
log!("Previous button combo settings found. Loading...");
let combo_conf = fs::read_to_string(&combo_path).unwrap();
let combo_conf = fs::read_to_string(combo_path).unwrap();
if button_config::validate_config(&combo_conf) {
button_config::save_all_btn_config_from_toml(&combo_conf);
} else {
@ -161,7 +165,7 @@ pub fn main() {
event.event_name, event.device_id, event.event_time
);
let url = format!("{}{}", host, path);
let url = format!("{host}{path}");
minreq::post(url).with_json(&event).unwrap().send().ok();
}
}

View file

@ -519,14 +519,14 @@ pub unsafe fn handle_generate_article_for_target(
) -> u64 {
// unknown return value, gets cast to an (Article *)
let target_module_accessor = TARGET_PLAYER.unwrap_or(module_accessor);
let ori = original!()(
original!()(
article_module_accessor,
int_1,
target_module_accessor,
bool_1,
int_2,
);
return ori;
)
}
pub fn init() {

View file

@ -2,7 +2,7 @@ use smash::app::{self, lua_bind::*, ArticleOperationTarget, FighterFacial, Fight
use smash::lib::lua_const::*;
use smash::phx::{Hash40, Vector3f};
#[derive(Copy, Clone)]
#[derive(Default, Copy, Clone)]
pub struct ChargeState {
pub int_x: Option<i32>,
pub int_y: Option<i32>,
@ -44,19 +44,6 @@ impl ChargeState {
}
}
impl Default for ChargeState {
fn default() -> Self {
Self {
int_x: None,
int_y: None,
float_x: None,
float_y: None,
float_z: None,
has_charge: None,
}
}
}
pub unsafe fn get_charge(
module_accessor: &mut app::BattleObjectModuleAccessor,
fighter_kind: i32,
@ -282,12 +269,11 @@ pub unsafe fn handle_charge(
);
if shot_charge == 112 {
EffectModule::req_common(module_accessor, Hash40::new("charge_max"), 0.0);
let samus_cshot_hash;
if fighter_kind == FIGHTER_KIND_SAMUS {
samus_cshot_hash = Hash40::new("samus_cshot_max");
let samus_cshot_hash = if fighter_kind == FIGHTER_KIND_SAMUS {
Hash40::new("samus_cshot_max")
} else {
samus_cshot_hash = Hash40::new("samusd_cshot_max");
}
Hash40::new("samusd_cshot_max")
};
let joint_hash = Hash40::new("armr");
let pos = Vector3f {
x: 7.98004,

View file

@ -76,7 +76,7 @@ pub unsafe fn hook_start_clatter(
// Most of the time this is 8 frames, but could be less depending on
// the status (e.g. freeze is 4 frames / input)
if is_training_mode() && is_operation_cpu(module_accessor) {
CLATTER_STEP = manual_recovery_rate.clone();
CLATTER_STEP = manual_recovery_rate;
}
original!()(
module_accessor,

View file

@ -55,8 +55,7 @@ pub unsafe fn is_enable_transition_term(
transition_term: i32,
is: bool,
) {
let entry_id_int =
WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID) as i32;
let entry_id_int = WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID);
if entry_id_int != (FighterId::Player as i32) {
return;
@ -92,8 +91,7 @@ pub unsafe fn is_enable_transition_term(
}
pub unsafe fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModuleAccessor) {
let entry_id_int =
WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID) as i32;
let entry_id_int = WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID);
// do only once.
if entry_id_int != (FighterId::Player as i32) {
return;

View file

@ -73,7 +73,7 @@ pub fn should_reverse_angle(direction: &Direction) -> bool {
let player_module_accessor = get_module_accessor(FighterId::Player);
unsafe {
PostureModule::pos_x(player_module_accessor) > PostureModule::pos_x(cpu_module_accessor)
&& ![Direction::LEFT, Direction::RIGHT].contains(&direction)
&& ![Direction::LEFT, Direction::RIGHT].contains(direction)
}
}

View file

@ -61,7 +61,7 @@ unsafe fn should_return_none_in_check_button(
}
// Only need to hold during jump squat
let status_kind = StatusModule::status_kind(module_accessor) as i32;
let status_kind = StatusModule::status_kind(module_accessor);
if status_kind != FIGHTER_STATUS_KIND_JUMP_SQUAT {
return true;
}

View file

@ -24,8 +24,7 @@ pub unsafe fn p1_controller_id() -> u32 {
pub fn handle_get_npad_state(state: *mut NpadGcState, controller_id: *const u32) {
unsafe {
if crate::common::is_training_mode() {
if *controller_id == p1_controller_id() {
if crate::common::is_training_mode() && *controller_id == p1_controller_id() {
let mut delayed_states = P1_DELAYED_NPAD_STATES.lock();
let actual_state = *state;
@ -48,4 +47,3 @@ pub fn handle_get_npad_state(state: *mut NpadGcState, controller_id: *const u32)
}
}
}
}

View file

@ -23,8 +23,7 @@ pub enum InputRecordState {
use InputRecordState::*;
pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAccessor) {
let entry_id_int =
WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID) as i32;
let entry_id_int = WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID);
if entry_id_int == 0 {
// Attack + Dpad Right: Playback

View file

@ -58,7 +58,7 @@ fn roll_ledge_case() {
}
pub unsafe fn force_option(module_accessor: &mut app::BattleObjectModuleAccessor) {
if StatusModule::situation_kind(module_accessor) as i32 != *SITUATION_KIND_CLIFF {
if StatusModule::situation_kind(module_accessor) != *SITUATION_KIND_CLIFF {
// No longer on ledge, so re-roll the ledge case and reset the delay counter for next time
reset_ledge_case();
reset_ledge_delay();
@ -113,7 +113,7 @@ pub unsafe fn is_enable_transition_term(
return None;
}
// Only handle ledge scenarios from menu
if StatusModule::status_kind(_module_accessor) as i32 != *FIGHTER_STATUS_KIND_CLIFF_WAIT
if StatusModule::status_kind(_module_accessor) != *FIGHTER_STATUS_KIND_CLIFF_WAIT
|| MENU.ledge_state == LedgeOption::empty()
{
return None;

View file

@ -143,7 +143,7 @@ unsafe fn check_buffer(module_accessor: &mut app::BattleObjectModuleAccessor) {
unsafe fn should_buffer(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
let fighter_distance = get_fighter_distance();
if MENU.mash_triggers.contains(MashTrigger::ALWAYS)
MENU.mash_triggers.contains(MashTrigger::ALWAYS)
|| (MENU.mash_triggers.contains(MashTrigger::HIT) && is_in_hitstun(module_accessor))
// BLOCK handled in shield.rs
|| (MENU.mash_triggers.contains(MashTrigger::PARRY) && is_in_parry(module_accessor))
@ -158,13 +158,7 @@ unsafe fn should_buffer(module_accessor: &mut app::BattleObjectModuleAccessor) -
|| (MENU.mash_triggers.contains(MashTrigger::GROUNDED) && is_grounded(module_accessor))
|| (MENU.mash_triggers.contains(MashTrigger::AIRBORNE) && is_airborne(module_accessor))
|| (MENU.mash_triggers.contains(MashTrigger::DISTANCE_CLOSE) && fighter_distance < DISTANCE_CLOSE_THRESHOLD)
|| (MENU.mash_triggers.contains(MashTrigger::DISTANCE_MID) && fighter_distance < DISTANCE_MID_THRESHOLD)
|| (MENU.mash_triggers.contains(MashTrigger::DISTANCE_FAR) && fighter_distance < DISTANCE_FAR_THRESHOLD)
{
true
} else {
false
}
|| (MENU.mash_triggers.contains(MashTrigger::DISTANCE_MID) && fighter_distance < DISTANCE_MID_THRESHOLD) || (MENU.mash_triggers.contains(MashTrigger::DISTANCE_FAR) && fighter_distance < DISTANCE_FAR_THRESHOLD)
}
// Temp Translation

View file

@ -360,11 +360,9 @@ pub unsafe fn handle_check_doyle_summon_dispatch(
if !is_training_mode() {
return ori;
}
if ori == *FIGHTER_JACK_STATUS_KIND_SUMMON as u64 {
if buff::is_buffing(module_accessor) {
if ori == *FIGHTER_JACK_STATUS_KIND_SUMMON as u64 && buff::is_buffing(module_accessor) {
return 4294967295;
}
}
ori
}
@ -384,7 +382,7 @@ static STALE_MENU_OFFSET: usize = 0x013e88a0;
#[skyline::hook(offset=STALE_MENU_OFFSET, inline)]
unsafe fn stale_menu_handle(ctx: &mut InlineCtx) {
// Set the text pointer to where "mel_training_on" is located
let on_text_ptr = ((getRegionAddress(Region::Text) as u64) + (0x42b215e)) as u64;
let on_text_ptr = (getRegionAddress(Region::Text) as u64) + 0x42b215e;
let x1 = ctx.registers[1].x.as_mut();
*x1 = on_text_ptr;
}
@ -467,9 +465,9 @@ static CAN_FUTTOBI_BACK_OFFSET: usize = 0x0260f950; // can_futtobi_back, checks
pub unsafe fn handle_star_ko(my_long_ptr: &mut u64) -> bool {
let ori = original!()(my_long_ptr);
if !is_training_mode() {
return ori;
ori
} else {
return false;
false
}
}

View file

@ -127,11 +127,9 @@ pub unsafe fn get_param_int(
if param_hash == hash40("rebirth_move_frame") {
return Some(0);
}
if param_hash == hash40("rebirth_move_frame_trainer") {
if is_killing() {
if param_hash == hash40("rebirth_move_frame_trainer") && is_killing() {
return Some(0);
}
}
if param_hash == hash40("rebirth_wait_frame") {
return Some(0);
}
@ -142,13 +140,12 @@ pub unsafe fn get_param_int(
return Some(0);
}
}
if param_type == hash40("param_mball") {
if param_hash == hash40("change_fly_frame") {
if is_killing() {
if param_type == hash40("param_mball")
&& param_hash == hash40("change_fly_frame")
&& is_killing()
{
return Some(0);
}
}
}
None
}
@ -203,7 +200,7 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
return;
}
let status = StatusModule::status_kind(module_accessor) as i32;
let status = StatusModule::status_kind(module_accessor);
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 {
@ -318,7 +315,7 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
// move to correct pos
if save_state.state == PosMove || save_state.state == NanaPosMove {
let status_kind = StatusModule::status_kind(module_accessor) as i32;
let status_kind = StatusModule::status_kind(module_accessor);
if save_state.state == NanaPosMove
&& (!fighter_is_nana || (status_kind == FIGHTER_STATUS_KIND_STANDBY))
{

View file

@ -44,8 +44,8 @@ pub unsafe fn check_hit_stop_delay_command(
// If there is a non-neutral direction picked,
// modify the SDI angle Vector2f as a side-effect
// and return 1 so the CPU knows that an SDI input occurred
(*sdi_direction).x = (angle.cos() as f32).into();
(*sdi_direction).y = (angle.sin() as f32).into();
(*sdi_direction).x = angle.cos() as f32;
(*sdi_direction).y = angle.sin() as f32;
return 1;
}
}

View file

@ -70,9 +70,7 @@ unsafe fn handle_oos_offset(module_accessor: &mut app::BattleObjectModuleAccesso
SHIELD_DELAY = MENU.reaction_time.get_random().into_delay();
// Decrease offset once if needed
if MULTI_HIT_OFFSET > 0 {
MULTI_HIT_OFFSET -= 1;
}
MULTI_HIT_OFFSET = MULTI_HIT_OFFSET.saturating_sub(1);
// Mark that we were in shield stun, so we don't decrease again
WAS_IN_SHIELDSTUN = true;

View file

@ -199,7 +199,7 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModule
return;
}
let status = StatusModule::status_kind(module_accessor) as i32;
let status = StatusModule::status_kind(module_accessor);
let mut requested_status: i32 = 0;
if [
*FIGHTER_STATUS_KIND_DOWN_WAIT,

View file

@ -89,9 +89,9 @@ pub unsafe fn get_command_flag_throw_direction(
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
if StatusModule::status_kind(module_accessor) != *FIGHTER_STATUS_KIND_CATCH_WAIT
&& StatusModule::status_kind(module_accessor) != *FIGHTER_STATUS_KIND_CATCH_PULL
&& StatusModule::status_kind(module_accessor) != *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();
@ -132,7 +132,7 @@ pub unsafe fn get_command_flag_throw_direction(
}
// (this conditional would need to be changed to speed up pummelling)
if StatusModule::status_kind(module_accessor) as i32 == *FIGHTER_STATUS_KIND_CATCH_WAIT {
if StatusModule::status_kind(module_accessor) == *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);
}

View file

@ -55,8 +55,8 @@ pub struct AnimTransform {
impl AnimTransform {
pub unsafe fn parse_anim_transform(&mut self, layout_name: Option<&str>) {
let res_animation_block_data_start = (*self).res_animation_block as u64;
let res_animation_block = &*(*self).res_animation_block;
let res_animation_block_data_start = self.res_animation_block as u64;
let res_animation_block = &*self.res_animation_block;
let mut anim_cont_offsets = (res_animation_block_data_start
+ res_animation_block.anim_cont_offsets_offset as u64)
as *const u32;
@ -70,8 +70,8 @@ impl AnimTransform {
let anim_type = (*res_animation_cont).anim_content_type;
// AnimContentType 1 == MATERIAL
if layout_name.is_some() && name.starts_with("set_dmg_num") && anim_type == 1 {
let layout_name = layout_name.unwrap();
if name.starts_with("set_dmg_num") && anim_type == 1 {
if let Some(layout_name) = layout_name {
let (hundreds, tens, ones, dec) = get_player_dmg_digits(match layout_name {
"p1" => FighterId::Player,
"p2" => FighterId::CPU,
@ -91,6 +91,7 @@ impl AnimTransform {
self.frame = dec as f32;
}
}
}
anim_cont_offsets = anim_cont_offsets.add(1);
}
@ -224,6 +225,14 @@ impl Pane {
self.global_alpha = 0;
}
}
pub fn get_name(&self) -> String {
self.name
.iter()
.take_while(|b| **b != 0)
.map(|b| *b as char)
.collect::<String>()
}
}
#[repr(C)]
@ -410,12 +419,12 @@ pub enum MaterialColorType {
#[repr(C)]
#[derive(Debug, PartialEq)]
pub enum MaterialFlags {
FlagsUserAllocated,
FlagsTextureOnly,
FlagsThresholdingAlphaInterpolation,
FlagsBlackColorFloat,
FlagsWhiteColorFloat,
FlagsDynamicAllocatedColorData,
UserAllocated,
TextureOnly,
ThresholdingAlphaInterpolation,
BlackColorFloat,
WhiteColorFloat,
DynamicAllocatedColorData,
}
#[repr(C)]
@ -458,9 +467,9 @@ impl Material {
pub fn set_color(&mut self, color_type: MaterialColorType, r: f32, g: f32, b: f32, a: f32) {
let (is_float_flag, idx) = if color_type == MaterialColorType::BlackColor {
(MaterialFlags::FlagsBlackColorFloat as u8, 0)
(MaterialFlags::BlackColorFloat as u8, 0)
} else {
(MaterialFlags::FlagsWhiteColorFloat as u8, 1)
(MaterialFlags::WhiteColorFloat as u8, 1)
};
if self.m_flag & (0x1 << is_float_flag) != 0 {
self.set_color_float(idx, r, g, b, a);

View file

@ -118,13 +118,16 @@ impl ResPane {
self.size_y = size.y;
}
pub fn name_matches(&self, other: &str) -> bool {
pub fn get_name(&self) -> String {
self.name
.iter()
.take_while(|b| **b != 0)
.map(|b| *b as char)
.collect::<String>()
== other
}
pub fn name_matches(&self, other: &str) -> bool {
self.get_name() == other
}
}
@ -146,7 +149,7 @@ enum TextBoxFlag {
KeepingFontScaleEnabled,
PerCharacterTransformFixSpace,
PerCharacterTransformSplitByCharWidthInsertSpaceEnabled,
MaxTextBoxFlag,
Max,
}
#[repr(C)]

View file

@ -1,9 +1,8 @@
use crate::common::get_player_dmg_digits;
use crate::common::MENU;
use crate::consts::FighterId;
use crate::training::ui::*;
use crate::{common::menu::QUICK_MENU_ACTIVE, training::combo::FRAME_ADVANTAGE};
use training_mod_consts::{OnOff, SaveDamage};
use training_mod_consts::OnOff;
use training_mod_tui::gauge::GaugeState;
pub static NUM_DISPLAY_PANES: usize = 1;
@ -11,18 +10,60 @@ pub static NUM_MENU_TEXT_OPTIONS: usize = 27;
pub static NUM_MENU_TEXT_SLIDERS: usize = 4;
pub static NUM_MENU_TABS: usize = 3;
pub static mut HAS_SORTED_MENU_CHILDREN: bool = false;
// Sort all panes in under menu pane such that text and check options
// are last
pub unsafe fn all_menu_panes_sorted(root_pane: &Pane) -> Vec<&mut Pane> {
let mut panes = (0..NUM_MENU_TEXT_OPTIONS)
.flat_map(|idx| {
let x = idx % 3;
let y = idx / 3;
[
root_pane
.find_pane_by_name_recursive(format!("trMod_menu_opt_{x}_{y}").as_str())
.unwrap(),
root_pane
.find_pane_by_name_recursive(format!("trMod_menu_check_{x}_{y}").as_str())
.unwrap(),
root_pane
.find_pane_by_name_recursive(format!("trMod_menu_bg_left_{x}_{y}").as_str())
.unwrap(),
root_pane
.find_pane_by_name_recursive(format!("trMod_menu_bg_back_{x}_{y}").as_str())
.unwrap(),
]
})
.collect::<Vec<&mut Pane>>();
panes.append(
&mut (0..NUM_MENU_TEXT_SLIDERS)
.map(|idx| {
root_pane
.find_pane_by_name_recursive(format!("trMod_menu_slider_{idx}").as_str())
.unwrap()
})
.collect::<Vec<&mut Pane>>(),
);
panes.sort_by(|a, _| {
if a.get_name().contains("opt") || a.get_name().contains("check") {
std::cmp::Ordering::Greater
} else {
std::cmp::Ordering::Less
}
});
panes
}
#[skyline::hook(offset = 0x4b620)]
pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64) {
let layout_name = skyline::from_c_str((*layout).layout_name);
let root_pane = &*(*layout).root_pane;
// Update percentage display as soon as possible on death,
// only if we have random save state damage active
if crate::common::is_training_mode()
&& (MENU.save_damage_cpu == SaveDamage::RANDOM
|| MENU.save_damage_player == SaveDamage::RANDOM)
&& layout_name == "info_melee"
{
// Update percentage display as soon as possible on death
if crate::common::is_training_mode() && layout_name == "info_melee" {
for player_name in &["p1", "p2"] {
if let Some(parent) = root_pane.find_pane_by_name_recursive(player_name) {
let _p1_layout_name =
@ -111,13 +152,11 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
if let Some(text) = root_pane.find_pane_by_name_recursive("trMod_disp_0_txt") {
text.set_text_string(format!("{FRAME_ADVANTAGE}").as_str());
let text = text.as_textbox();
if FRAME_ADVANTAGE < 0 {
text.set_color(200, 8, 8, 255);
} else if FRAME_ADVANTAGE == 0 {
text.set_color(0, 0, 0, 255);
} else {
text.set_color(31, 198, 0, 255);
}
match FRAME_ADVANTAGE {
x if x < 0 => text.set_color(200, 8, 8, 255),
x if x == 0 => text.set_color(0, 0, 0, 255),
_ => text.set_color(31, 198, 0, 255),
};
}
// Update menu display
@ -144,6 +183,15 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
let menu_pane = root_pane.find_pane_by_name_recursive("trMod_menu").unwrap();
menu_pane.set_visible(QUICK_MENU_ACTIVE);
if !HAS_SORTED_MENU_CHILDREN {
let sorted_panes = all_menu_panes_sorted(root_pane);
// Place in sorted order such that backings are behind, etc.
sorted_panes.iter().for_each(|p| menu_pane.remove_child(p));
sorted_panes.iter().for_each(|p| menu_pane.append_child(p));
HAS_SORTED_MENU_CHILDREN = true;
}
// Make all invisible first
(0..NUM_MENU_TEXT_OPTIONS).for_each(|idx| {
let x = idx % 3;
@ -154,10 +202,16 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
root_pane
.find_pane_by_name_recursive(format!("trMod_menu_check_{x}_{y}").as_str())
.map(|text| text.set_visible(false));
root_pane
.find_pane_by_name_recursive(format!("trMod_menu_bg_left_{x}_{y}").as_str())
.map(|text| text.set_visible(false));
root_pane
.find_pane_by_name_recursive(format!("trMod_menu_bg_back_{x}_{y}").as_str())
.map(|text| text.set_visible(false));
});
(0..NUM_MENU_TEXT_SLIDERS).for_each(|idx| {
root_pane
.find_pane_by_name_recursive(&format!("trMod_menu_slider_{idx}").as_str())
.find_pane_by_name_recursive(format!("trMod_menu_slider_{idx}").as_str())
.map(|text| text.set_visible(false));
});
@ -194,12 +248,22 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
list_idx,
root_pane
.find_pane_by_name_recursive(
&format!("trMod_menu_opt_{list_section}_{list_idx}").to_owned(),
format!("trMod_menu_opt_{list_section}_{list_idx}").as_str(),
)
.unwrap(),
root_pane
.find_pane_by_name_recursive(
format!("trMod_menu_bg_left_{list_section}_{list_idx}").as_str(),
)
.unwrap(),
root_pane
.find_pane_by_name_recursive(
format!("trMod_menu_bg_back_{list_section}_{list_idx}").as_str(),
)
.unwrap(),
)
})
.for_each(|(list_section, list_idx, text)| {
.for_each(|(list_section, list_idx, text, bg_left, bg_back)| {
let list = &tab.lists[list_section];
let submenu = &list.items[list_idx];
let is_selected = list.state.selected().filter(|s| *s == list_idx).is_some();
@ -208,27 +272,28 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
let text = text.as_textbox();
if is_selected {
text.set_color(0x27, 0x4E, 0x13, 255);
if let Some(footer) = root_pane
.find_pane_by_name_recursive(&format!("trMod_menu_footer_txt").as_str())
if let Some(footer) =
root_pane.find_pane_by_name_recursive("trMod_menu_footer_txt")
{
footer.set_text_string(submenu.help_text);
}
} else {
text.set_color(0, 0, 0, 255);
text.set_color(255, 255, 255, 255);
}
bg_left.set_visible(true);
bg_back.set_visible(true);
});
} else {
if matches!(app.selected_sub_menu_slider.state, GaugeState::None) {
} else if matches!(app.selected_sub_menu_slider.state, GaugeState::None) {
let (_title, _help_text, mut sub_menu_str_lists) = app.sub_menu_strs_and_states();
for list_section in 0..sub_menu_str_lists.len() {
(0..sub_menu_str_lists.len()).for_each(|list_section| {
let sub_menu_str = sub_menu_str_lists[list_section].0.clone();
let sub_menu_state = &mut sub_menu_str_lists[list_section].1;
sub_menu_str
.iter()
.enumerate()
.for_each(|(idx, (checked, name))| {
let is_selected =
sub_menu_state.selected().filter(|s| *s == idx).is_some();
let is_selected = sub_menu_state.selected().filter(|s| *s == idx).is_some();
if let Some(text) = root_pane.find_pane_by_name_recursive(
format!("trMod_menu_opt_{list_section}_{idx}").as_str(),
) {
@ -237,11 +302,23 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
if is_selected {
text.set_color(0x27, 0x4E, 0x13, 255);
} else {
text.set_color(0, 0, 0, 255);
text.set_color(255, 255, 255, 255);
}
text.set_visible(true);
}
if let Some(bg_left) = root_pane.find_pane_by_name_recursive(
format!("trMod_menu_bg_left_{list_section}_{idx}").as_str(),
) {
bg_left.set_visible(true);
}
if let Some(bg_back) = root_pane.find_pane_by_name_recursive(
format!("trMod_menu_bg_back_{list_section}_{idx}").as_str(),
) {
bg_back.set_visible(true);
}
if let Some(check) = root_pane.find_pane_by_name_recursive(
format!("trMod_menu_check_{list_section}_{idx}").as_str(),
) {
@ -253,7 +330,7 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
}
}
});
}
});
} else {
let (_title, _help_text, gauge_vals) = app.sub_menu_strs_for_slider();
let abs_min = gauge_vals.abs_min;
@ -295,11 +372,14 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
}
}
}
}
original!()(layout, draw_info, cmd_buffer);
}
pub static mut MENU_PANE_PTR: u64 = 0;
pub static mut HAS_CREATED_OPT_BG: bool = false;
pub static mut HAS_CREATED_OPT_BG_BACK: bool = false;
#[skyline::hook(offset = 0x493a0)]
pub unsafe fn layout_build_parts_impl(
layout: *mut Layout,
@ -331,6 +411,72 @@ pub unsafe fn layout_build_parts_impl(
};
}
let root_pane = &*(*layout).root_pane;
let block = data as *mut ResPane;
let menu_pos = ResVec3::new(-360.0, 440.0, 0.0);
if layout_name == "info_training_btn0_00_item" {
if !HAS_CREATED_OPT_BG && (*block).name_matches("icn_bg_main") {
(0..NUM_MENU_TEXT_OPTIONS).for_each(|txt_idx| {
let x = txt_idx % 3;
let y = txt_idx / 3;
let x_offset = x as f32 * 500.0;
let y_offset = y as f32 * 85.0;
let block = block as *mut ResPictureWithTex<2>;
let mut pic_menu_block = *block;
pic_menu_block
.picture
.pane
.set_name(format!("trMod_menu_bg_left_{x}_{y}").as_str());
pic_menu_block.picture.pane.scale_x /= 1.5;
pic_menu_block.picture.pane.set_pos(ResVec3::new(
menu_pos.x - 400.0 - 195.0 + x_offset,
menu_pos.y - 50.0 - y_offset,
0.0,
));
let pic_menu_pane = build!(pic_menu_block, ResPictureWithTex<2>, kind, Picture);
pic_menu_pane.detach();
if MENU_PANE_PTR != 0 {
(*(MENU_PANE_PTR as *mut Pane)).append_child(pic_menu_pane);
HAS_CREATED_OPT_BG = true;
}
});
}
if !HAS_CREATED_OPT_BG_BACK && (*block).name_matches("btn_bg") {
(0..NUM_MENU_TEXT_OPTIONS).for_each(|txt_idx| {
let x = txt_idx % 3;
let y = txt_idx / 3;
let x_offset = x as f32 * 500.0;
let y_offset = y as f32 * 85.0;
let block = block as *mut ResWindowWithTexCoordsAndFrames<1, 4>;
let mut pic_menu_block = *block;
pic_menu_block
.window
.pane
.set_name(format!("trMod_menu_bg_back_{x}_{y}").as_str());
pic_menu_block.window.pane.scale_x /= 2.0;
pic_menu_block.window.pane.set_pos(ResVec3::new(
menu_pos.x - 400.0 + x_offset,
menu_pos.y - 50.0 - y_offset,
0.0,
));
let pic_menu_pane =
build!(pic_menu_block, ResWindowWithTexCoordsAndFrames<1,4>, kind, Window);
pic_menu_pane.pane.detach();
if MENU_PANE_PTR != 0 {
(*(MENU_PANE_PTR as *mut Pane)).append_child(&pic_menu_pane.pane);
HAS_CREATED_OPT_BG_BACK = true;
}
});
}
}
if layout_name != "info_training" {
return original!()(
layout,
@ -344,24 +490,8 @@ pub unsafe fn layout_build_parts_impl(
);
}
let root_pane = &*(*layout).root_pane;
let block = data as *mut ResPane;
let menu_pos = ResVec3::new(-360.0, 440.0, 0.0);
// Menu creation
if (*block).name_matches("pic_numbase_01") {
let block = block as *mut ResPictureWithTex<1>;
// For menu backing
let mut pic_menu_block = (*block).clone();
pic_menu_block.picture.pane.set_name("trMod_menu_base");
pic_menu_block.picture.pane.set_pos(menu_pos);
pic_menu_block
.picture
.pane
.set_size(ResVec2::new(1400.0, 1600.0));
let pic_menu_pane = build!(pic_menu_block, ResPictureWithTex<1>, kind, Picture);
pic_menu_pane.detach();
// pic is loaded first, we can create our parent pane here.
let menu_pane_kind = u32::from_le_bytes([b'p', b'a', b'n', b'1']);
let mut menu_pane_block = ResPane::new("trMod_menu");
@ -370,31 +500,9 @@ pub unsafe fn layout_build_parts_impl(
let menu_pane = build!(menu_pane_block, ResPane, menu_pane_kind, Pane);
menu_pane.detach();
root_pane.append_child(menu_pane);
menu_pane.append_child(pic_menu_pane);
if MENU_PANE_PTR == 0 {
MENU_PANE_PTR = menu_pane as *mut Pane as u64;
}
// Menu header
// TODO: Copy "Quit Training" window and text
if (*block).name_matches("set_txt_num_01") {
let menu_pane = root_pane.find_pane_by_name("trMod_menu", true).unwrap();
let block = data as *mut ResTextBox;
// Header
let mut text_block = (*block).clone();
text_block.pane.size_x = text_block.pane.size_x * 2.0;
text_block.pane.set_name("trMod_menu_header");
text_block
.pane
.set_pos(ResVec3::new(menu_pos.x - 525.0, menu_pos.y + 75.0, 0.0));
let text_pane = build!(text_block, ResTextBox, kind, TextBox);
text_pane.pane.set_text_string("Modpack Menu");
// Ensure Material Colors are not hardcoded so we can just use SetTextColor.
text_pane.set_default_material_colors();
text_pane.set_color(200, 8, 8, 255);
text_pane.detach();
menu_pane.append_child(text_pane);
}
// Menu footer background
@ -402,7 +510,7 @@ pub unsafe fn layout_build_parts_impl(
let menu_pane = root_pane.find_pane_by_name("trMod_menu", true).unwrap();
let block = block as *mut ResPictureWithTex<1>;
// For menu backing
let mut pic_menu_block = (*block).clone();
let mut pic_menu_block = *block;
pic_menu_block.picture.pane.set_name("trMod_menu_footer_bg");
let pic_menu_pane = build!(pic_menu_block, ResPictureWithTex<1>, kind, Picture);
pic_menu_pane.detach();
@ -415,13 +523,11 @@ pub unsafe fn layout_build_parts_impl(
let menu_pane = root_pane.find_pane_by_name("trMod_menu", true).unwrap();
let block = data as *mut ResTextBox;
let mut text_block = (*block).clone();
text_block
.pane
.set_name(format!("trMod_menu_footer_txt").as_str());
let mut text_block = *block;
text_block.pane.set_name("trMod_menu_footer_txt");
let text_pane = build!(text_block, ResTextBox, kind, TextBox);
text_pane.pane.set_text_string(format!("Footer!").as_str());
text_pane.pane.set_text_string("Footer!");
// Ensure Material Colors are not hardcoded so we can just use SetTextColor.
text_pane.set_default_material_colors();
text_pane.set_color(255, 255, 255, 255);
@ -434,7 +540,7 @@ pub unsafe fn layout_build_parts_impl(
let menu_pane = root_pane.find_pane_by_name("trMod_menu", true).unwrap();
let block = data as *mut ResTextBox;
let mut text_block = (*block).clone();
let mut text_block = *block;
text_block.enable_shadow();
text_block.text_alignment(TextAlignment::Center);
@ -466,7 +572,7 @@ pub unsafe fn layout_build_parts_impl(
text_pane.detach();
menu_pane.append_child(text_pane);
let mut help_block = (*block).clone();
let mut help_block = *block;
// Font Idx 2 = nintendo64 which contains nice symbols
help_block.font_idx = 2;
@ -482,7 +588,7 @@ pub unsafe fn layout_build_parts_impl(
0.0,
));
let help_pane = build!(help_block, ResTextBox, kind, TextBox);
help_pane.pane.set_text_string(format!("abcd").as_str());
help_pane.pane.set_text_string("abcd");
let it = help_pane.m_text_buf as *mut u16;
match txt_idx {
// Left Tab: ZL
@ -520,7 +626,7 @@ pub unsafe fn layout_build_parts_impl(
let menu_pane = root_pane.find_pane_by_name("trMod_menu", true).unwrap();
let block = data as *mut ResTextBox;
let mut text_block = (*block).clone();
let mut text_block = *block;
text_block.enable_shadow();
text_block.text_alignment(TextAlignment::Center);
@ -528,10 +634,10 @@ pub unsafe fn layout_build_parts_impl(
.pane
.set_name(format!("trMod_menu_opt_{x}_{y}").as_str());
let x_offset = x as f32 * 400.0;
let y_offset = y as f32 * 75.0;
let x_offset = x as f32 * 500.0;
let y_offset = y as f32 * 85.0;
text_block.pane.set_pos(ResVec3::new(
menu_pos.x - 450.0 + x_offset,
menu_pos.x - 480.0 + x_offset,
menu_pos.y - 50.0 - y_offset,
0.0,
));
@ -541,11 +647,11 @@ pub unsafe fn layout_build_parts_impl(
.set_text_string(format!("Opt {txt_idx}!").as_str());
// Ensure Material Colors are not hardcoded so we can just use SetTextColor.
text_pane.set_default_material_colors();
text_pane.set_color(0, 0, 0, 255);
text_pane.set_color(255, 255, 255, 255);
text_pane.detach();
menu_pane.append_child(text_pane);
let mut check_block = (*block).clone();
let mut check_block = *block;
// Font Idx 2 = nintendo64 which contains nice symbols
check_block.font_idx = 2;
@ -553,7 +659,7 @@ pub unsafe fn layout_build_parts_impl(
.pane
.set_name(format!("trMod_menu_check_{x}_{y}").as_str());
check_block.pane.set_pos(ResVec3::new(
menu_pos.x - 675.0 + x_offset,
menu_pos.x - 375.0 + x_offset,
menu_pos.y - 50.0 - y_offset,
0.0,
));
@ -575,7 +681,7 @@ pub unsafe fn layout_build_parts_impl(
let menu_pane = root_pane.find_pane_by_name("trMod_menu", true).unwrap();
let block = data as *mut ResTextBox;
let mut text_block = (*block).clone();
let mut text_block = *block;
text_block.enable_shadow();
text_block.text_alignment(TextAlignment::Center);
@ -611,7 +717,7 @@ pub unsafe fn layout_build_parts_impl(
if (*block).name_matches("pic_numbase_01") {
let block = block as *mut ResPictureWithTex<1>;
let mut pic_block = (*block).clone();
let mut pic_block = *block;
pic_block.picture.pane.set_name(pic_name.as_str());
pic_block.picture.pane.set_pos(ResVec3::default());
let pic_pane = build!(pic_block, ResPictureWithTex<1>, kind, Picture);
@ -633,7 +739,7 @@ pub unsafe fn layout_build_parts_impl(
.unwrap();
let block = data as *mut ResTextBox;
let mut text_block = (*block).clone();
let mut text_block = *block;
text_block.pane.set_name(txt_name.as_str());
text_block.pane.set_pos(ResVec3::new(-10.0, -25.0, 0.0));
let text_pane = build!(text_block, ResTextBox, kind, TextBox);
@ -652,7 +758,7 @@ pub unsafe fn layout_build_parts_impl(
.unwrap();
let block = data as *mut ResTextBox;
let mut header_block = (*block).clone();
let mut header_block = *block;
header_block.pane.set_name(header_name.as_str());
header_block.pane.set_pos(ResVec3::new(0.0, 25.0, 0.0));
let header_pane = build!(header_block, ResTextBox, kind, TextBox);