mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2025-04-25 15:09:18 +00:00
Initial
This commit is contained in:
parent
2b241dcb19
commit
ddd5f16b87
11 changed files with 248 additions and 313 deletions
3
ryujinx_build.ps1
vendored
3
ryujinx_build.ps1
vendored
|
@ -1,5 +1,8 @@
|
|||
$IP=(Test-Connection -ComputerName (hostname) -Count 1 | Select -ExpandProperty IPV4Address).IPAddressToString
|
||||
cargo skyline build --release --features layout_arc_from_file
|
||||
if (($lastexitcode -ne 0)) {
|
||||
exit $lastexitcode
|
||||
}
|
||||
|
||||
# Set up symlinks
|
||||
$RYUJINX_LAYOUT_ARC_PATH="C:\Users\Josh\AppData\Roaming\Ryujinx\sdcard\ultimate\TrainingModpack\layout.arc"
|
||||
|
|
|
@ -46,6 +46,113 @@ pub fn button_mapping(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn name_to_font_glyph(button: ButtonConfig, style: ControllerStyle) -> Option<u16> {
|
||||
let is_gcc = style == ControllerStyle::GCController;
|
||||
Some(match button {
|
||||
ButtonConfig::A => 0xE0E0,
|
||||
ButtonConfig::B => 0xE0E1,
|
||||
ButtonConfig::X => {
|
||||
if is_gcc {
|
||||
0xE206
|
||||
} else {
|
||||
0xE0E2
|
||||
}
|
||||
}
|
||||
ButtonConfig::Y => {
|
||||
if is_gcc {
|
||||
0xE207
|
||||
} else {
|
||||
0xE0E3
|
||||
}
|
||||
}
|
||||
ButtonConfig::L => {
|
||||
if is_gcc {
|
||||
return None;
|
||||
} else {
|
||||
0xE0E4
|
||||
}
|
||||
}
|
||||
ButtonConfig::R => {
|
||||
if is_gcc {
|
||||
0xE205
|
||||
} else {
|
||||
0xE0E5
|
||||
}
|
||||
}
|
||||
ButtonConfig::ZL => {
|
||||
if is_gcc {
|
||||
0xE204
|
||||
} else {
|
||||
0xE0E6
|
||||
}
|
||||
}
|
||||
ButtonConfig::ZR => {
|
||||
if is_gcc {
|
||||
0xE208
|
||||
} else {
|
||||
0xE0E7
|
||||
}
|
||||
}
|
||||
ButtonConfig::DPAD_UP => {
|
||||
if is_gcc {
|
||||
0xE209
|
||||
} else {
|
||||
0xE0EB
|
||||
}
|
||||
}
|
||||
ButtonConfig::DPAD_DOWN => {
|
||||
if is_gcc {
|
||||
0xE20A
|
||||
} else {
|
||||
0xE0EC
|
||||
}
|
||||
}
|
||||
ButtonConfig::DPAD_LEFT => {
|
||||
if is_gcc {
|
||||
0xE20B
|
||||
} else {
|
||||
0xE0ED
|
||||
}
|
||||
}
|
||||
ButtonConfig::DPAD_RIGHT => {
|
||||
if is_gcc {
|
||||
0xE20C
|
||||
} else {
|
||||
0xE0EE
|
||||
}
|
||||
}
|
||||
ButtonConfig::PLUS => {
|
||||
if is_gcc {
|
||||
0xE20D
|
||||
} else {
|
||||
0xE0EF
|
||||
}
|
||||
}
|
||||
ButtonConfig::MINUS => {
|
||||
if is_gcc {
|
||||
return None;
|
||||
} else {
|
||||
0xE0F0
|
||||
}
|
||||
}
|
||||
ButtonConfig::LSTICK => {
|
||||
if is_gcc {
|
||||
return None;
|
||||
} else {
|
||||
0xE104
|
||||
}
|
||||
}
|
||||
ButtonConfig::RSTICK => {
|
||||
if is_gcc {
|
||||
return None;
|
||||
} else {
|
||||
0xE105
|
||||
}
|
||||
}
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, EnumIter, PartialEq, Eq, Hash, Copy, Clone)]
|
||||
pub enum ButtonCombo {
|
||||
OpenMenu,
|
||||
|
|
|
@ -41,14 +41,25 @@ pub fn is_emulator() -> bool {
|
|||
}
|
||||
|
||||
pub fn get_module_accessor(fighter_id: FighterId) -> *mut app::BattleObjectModuleAccessor {
|
||||
try_get_module_accessor(fighter_id).unwrap()
|
||||
}
|
||||
|
||||
pub fn try_get_module_accessor(
|
||||
fighter_id: FighterId,
|
||||
) -> Option<*mut app::BattleObjectModuleAccessor> {
|
||||
let entry_id_int = fighter_id as i32;
|
||||
let entry_id = app::FighterEntryID(entry_id_int);
|
||||
unsafe {
|
||||
let mgr = *(FIGHTER_MANAGER_ADDR as *mut *mut app::FighterManager);
|
||||
let fighter_entry =
|
||||
FighterManager::get_fighter_entry(mgr, entry_id) as *mut app::FighterEntry;
|
||||
if fighter_entry.is_null() {
|
||||
return None;
|
||||
}
|
||||
let current_fighter_id = FighterEntry::current_fighter_id(fighter_entry);
|
||||
app::sv_battle_object::module_accessor(current_fighter_id as u32)
|
||||
Some(app::sv_battle_object::module_accessor(
|
||||
current_fighter_id as u32,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
23
src/training/input_log.rs
Normal file
23
src/training/input_log.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
use crate::common::input::*;
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref P1_INPUT_MAPPINGS: Mutex<VecDeque<MappedInputs>> = Mutex::new(VecDeque::new());
|
||||
}
|
||||
|
||||
// TODO: how many
|
||||
const NUM_INPUTS: usize = 120;
|
||||
|
||||
pub fn handle_final_input_mapping(player_idx: i32, out: *mut MappedInputs) {
|
||||
unsafe {
|
||||
if player_idx == 0 {
|
||||
let mut mappings = P1_INPUT_MAPPINGS.lock();
|
||||
|
||||
mappings.push_front(*out);
|
||||
mappings.truncate(NUM_INPUTS);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
use crate::common::button_config;
|
||||
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::common::{
|
||||
get_module_accessor, is_in_hitstun, is_in_shieldstun, try_get_module_accessor, MENU,
|
||||
};
|
||||
use crate::training::mash;
|
||||
use crate::training::ui::notifications::{clear_notifications, color_notification};
|
||||
use lazy_static::lazy_static;
|
||||
|
@ -434,7 +436,14 @@ unsafe fn set_cpu_controls(p_data: *mut *mut u8) {
|
|||
should_mash_playback();
|
||||
}
|
||||
|
||||
let cpu_module_accessor = get_module_accessor(FighterId::CPU);
|
||||
let cpu_module_accessor = try_get_module_accessor(FighterId::CPU);
|
||||
|
||||
// Sometimes we can try to grab their module accessor before they are valid?
|
||||
if cpu_module_accessor.is_none() {
|
||||
return;
|
||||
}
|
||||
let cpu_module_accessor = cpu_module_accessor.unwrap();
|
||||
|
||||
if INPUT_RECORD == Pause {
|
||||
match LOCKOUT_FRAME.cmp(&0) {
|
||||
Ordering::Greater => LOCKOUT_FRAME -= 1,
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
#[macro_use]
|
||||
pub mod structures;
|
|
@ -1,307 +0,0 @@
|
|||
#![allow(dead_code)] // TODO: Yeah don't do this
|
||||
use crate::common::events::smash_version;
|
||||
use crate::common::release::CURRENT_VERSION;
|
||||
use crate::training::save_states::SavedState;
|
||||
use bitflags::bitflags;
|
||||
use training_mod_consts::TrainingModpackMenu;
|
||||
|
||||
use crate::default_save_state;
|
||||
use crate::training::character_specific::steve;
|
||||
use crate::training::charge::ChargeState;
|
||||
use crate::training::save_states::SaveState::NoAction;
|
||||
|
||||
// Need to define necesary structures here. Probably should move to consts or something. Realistically, should be in skyline smash prob tho.
|
||||
|
||||
// Final final controls used for controlmodule
|
||||
// can I actually derive these?
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct ControlModuleInternal {
|
||||
pub vtable: *mut u8,
|
||||
pub controller_index: i32,
|
||||
pub buttons: Buttons,
|
||||
pub stick_x: f32,
|
||||
pub stick_y: f32,
|
||||
pub padding: [f32; 2],
|
||||
pub unk: [u32; 8],
|
||||
pub clamped_lstick_x: f32,
|
||||
pub clamped_lstick_y: f32,
|
||||
pub padding2: [f32; 2],
|
||||
pub clamped_rstick_x: f32,
|
||||
pub clamped_rstick_y: f32,
|
||||
}
|
||||
|
||||
impl ControlModuleInternal {
|
||||
pub fn _clear(&mut self) {
|
||||
// Try to nullify controls so we can't control player 1 during recording
|
||||
self.stick_x = 0.0;
|
||||
self.stick_y = 0.0;
|
||||
self.buttons = Buttons::empty();
|
||||
self.clamped_lstick_x = 0.0;
|
||||
self.clamped_lstick_y = 0.0;
|
||||
self.clamped_rstick_x = 0.0;
|
||||
self.clamped_rstick_y = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct ControlModuleStored {
|
||||
// Custom type for saving only necessary controls/not saving vtable
|
||||
pub buttons: Buttons,
|
||||
pub stick_x: f32,
|
||||
pub stick_y: f32,
|
||||
pub padding: [f32; 2],
|
||||
pub unk: [u32; 8],
|
||||
pub clamped_lstick_x: f32,
|
||||
pub clamped_lstick_y: f32,
|
||||
pub padding2: [f32; 2],
|
||||
pub clamped_rstick_x: f32,
|
||||
pub clamped_rstick_y: f32,
|
||||
}
|
||||
|
||||
// Re-ordered bitfield the game uses for buttons - TODO: Is this a problem? What's the original order?
|
||||
pub type ButtonBitfield = i32; // may need to actually implement? Not for now though
|
||||
|
||||
/// Controller style declaring what kind of controller is being used
|
||||
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
|
||||
#[repr(u32)]
|
||||
pub enum ControllerStyle {
|
||||
Handheld = 0x1,
|
||||
DualJoycon = 0x2,
|
||||
LeftJoycon = 0x3,
|
||||
RightJoycon = 0x4,
|
||||
ProController = 0x5,
|
||||
DebugPad = 0x6, // probably
|
||||
GCController = 0x7,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct AutorepeatInfo {
|
||||
field: [u8; 0x18],
|
||||
}
|
||||
|
||||
// Can map any of these over any button - what does this mean?
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum InputKind {
|
||||
Attack = 0x0,
|
||||
Special = 0x1,
|
||||
Jump = 0x2,
|
||||
Guard = 0x3,
|
||||
Grab = 0x4,
|
||||
SmashAttack = 0x5,
|
||||
AppealHi = 0xA,
|
||||
AppealS = 0xB,
|
||||
AppealLw = 0xC,
|
||||
Unset = 0xD,
|
||||
}
|
||||
|
||||
// 0x50 Byte struct containing the information for controller mappings
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct ControllerMapping {
|
||||
pub gc_l: InputKind,
|
||||
pub gc_r: InputKind,
|
||||
pub gc_z: InputKind,
|
||||
pub gc_dup: InputKind,
|
||||
pub gc_dlr: InputKind,
|
||||
pub gc_ddown: InputKind,
|
||||
pub gc_a: InputKind,
|
||||
pub gc_b: InputKind,
|
||||
pub gc_cstick: InputKind,
|
||||
pub gc_y: InputKind,
|
||||
pub gc_x: InputKind,
|
||||
pub gc_rumble: bool,
|
||||
pub gc_absmash: bool,
|
||||
pub gc_tapjump: bool,
|
||||
pub gc_sensitivity: u8,
|
||||
// 0xF
|
||||
pub pro_l: InputKind,
|
||||
pub pro_r: InputKind,
|
||||
pub pro_zl: InputKind,
|
||||
pub pro_zr: InputKind,
|
||||
pub pro_dup: InputKind,
|
||||
pub pro_dlr: InputKind,
|
||||
pub pro_ddown: InputKind,
|
||||
pub pro_a: InputKind,
|
||||
pub pro_b: InputKind,
|
||||
pub pro_cstick: InputKind,
|
||||
pub pro_x: InputKind,
|
||||
pub pro_y: InputKind,
|
||||
pub pro_rumble: bool,
|
||||
pub pro_absmash: bool,
|
||||
pub pro_tapjump: bool,
|
||||
pub pro_sensitivity: u8,
|
||||
// 0x1F
|
||||
pub joy_shoulder: InputKind,
|
||||
pub joy_zshoulder: InputKind,
|
||||
pub joy_sl: InputKind,
|
||||
pub joy_sr: InputKind,
|
||||
pub joy_up: InputKind,
|
||||
pub joy_right: InputKind,
|
||||
pub joy_left: InputKind,
|
||||
pub joy_down: InputKind,
|
||||
pub joy_rumble: bool,
|
||||
pub joy_absmash: bool,
|
||||
pub joy_tapjump: bool,
|
||||
pub joy_sensitivity: u8,
|
||||
// 0x2B
|
||||
pub _2b: u8,
|
||||
pub _2c: u8,
|
||||
pub _2d: u8,
|
||||
pub _2e: u8,
|
||||
pub _2f: u8,
|
||||
pub _30: u8,
|
||||
pub _31: u8,
|
||||
pub _32: u8,
|
||||
pub is_absmash: bool,
|
||||
pub _34: [u8; 0x1C],
|
||||
}
|
||||
|
||||
//type Buttons = u32; // may need to actually implement (like label and such)? Not for now though
|
||||
bitflags! {
|
||||
pub struct Buttons: u32 {
|
||||
const ATTACK = 0x1;
|
||||
const SPECIAL = 0x2;
|
||||
const JUMP = 0x4;
|
||||
const GUARD = 0x8;
|
||||
const CATCH = 0x10;
|
||||
const SMASH = 0x20;
|
||||
const JUMP_MINI = 0x40;
|
||||
const CSTICK_ON = 0x80;
|
||||
const STOCK_SHARE = 0x100;
|
||||
const ATTACK_RAW = 0x200;
|
||||
const APPEAL_HI = 0x400;
|
||||
const SPECIAL_RAW = 0x800;
|
||||
const APPEAL_LW = 0x1000;
|
||||
const APPEAL_SL = 0x2000;
|
||||
const APPEAL_SR = 0x4000;
|
||||
const FLICK_JUMP = 0x8000;
|
||||
const GUARD_HOLD = 0x10000;
|
||||
const SPECIAL_RAW2 = 0x20000;
|
||||
}
|
||||
}
|
||||
|
||||
// Controller class used internally by the game
|
||||
#[repr(C)]
|
||||
pub struct Controller {
|
||||
pub vtable: *const u64,
|
||||
pub current_buttons: ButtonBitfield,
|
||||
pub previous_buttons: ButtonBitfield,
|
||||
pub left_stick_x: f32,
|
||||
pub left_stick_y: f32,
|
||||
pub left_trigger: f32,
|
||||
pub _left_padding: u32,
|
||||
pub right_stick_x: f32,
|
||||
pub right_stick_y: f32,
|
||||
pub right_trigger: f32,
|
||||
pub _right_padding: u32,
|
||||
pub gyro: [f32; 4],
|
||||
pub button_timespan: AutorepeatInfo,
|
||||
pub lstick_timespan: AutorepeatInfo,
|
||||
pub rstick_timespan: AutorepeatInfo,
|
||||
pub just_down: ButtonBitfield,
|
||||
pub just_release: ButtonBitfield,
|
||||
pub autorepeat_keys: u32,
|
||||
pub autorepeat_threshold: u32,
|
||||
pub autorepeat_initial_press_threshold: u32,
|
||||
pub style: ControllerStyle,
|
||||
pub controller_id: u32,
|
||||
pub primary_controller_color1: u32,
|
||||
pub primary_controller_color2: u32,
|
||||
pub secondary_controller_color1: u32,
|
||||
pub secondary_controller_color2: u32,
|
||||
pub led_pattern: u8,
|
||||
pub button_autorepeat_initial_press: bool,
|
||||
pub lstick_autorepeat_initial_press: bool,
|
||||
pub rstick_autorepeat_initial_press: bool,
|
||||
pub is_valid_controller: bool,
|
||||
pub _x_b9: [u8; 2],
|
||||
pub is_connected: bool,
|
||||
pub is_left_connected: bool,
|
||||
pub is_right_connected: bool,
|
||||
pub is_wired: bool,
|
||||
pub is_left_wired: bool,
|
||||
pub is_right_wired: bool,
|
||||
pub _x_c1: [u8; 3],
|
||||
pub npad_number: u32,
|
||||
pub _x_c8: [u8; 8],
|
||||
}
|
||||
|
||||
// SomeControllerStruct used in hooked function - need to ask blujay what this is again
|
||||
#[repr(C)]
|
||||
pub struct SomeControllerStruct {
|
||||
padding: [u8; 0x10],
|
||||
controller: &'static mut Controller,
|
||||
}
|
||||
|
||||
// Define struct used for final controller inputs
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct MappedInputs {
|
||||
pub buttons: Buttons,
|
||||
pub lstick_x: i8,
|
||||
pub lstick_y: i8,
|
||||
pub rstick_x: i8,
|
||||
pub rstick_y: i8,
|
||||
}
|
||||
|
||||
impl MappedInputs {
|
||||
// pub needed?
|
||||
pub fn default() -> MappedInputs {
|
||||
MappedInputs {
|
||||
buttons: Buttons::empty(),
|
||||
lstick_x: 0,
|
||||
lstick_y: 0,
|
||||
rstick_x: 0,
|
||||
rstick_y: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Final Structure containing all input recording slots, menu options, and save states.
|
||||
// 5 Input Recording Slots should be fine for now for most mix up scenarios
|
||||
// When loading a "scenario", we want to load all menu options (with maybe overrides in the config?), load savestate(s), and load input recording slots.
|
||||
// If we have submenus for input recording slots, we need to get that info as well, and we want to apply saved damage from save states to the menu.
|
||||
// Damage range seems to be saved in menu for range of damage, so that's taken care of with menu.
|
||||
|
||||
#[derive(Clone)]
|
||||
#[repr(C)]
|
||||
pub struct Scenario {
|
||||
pub record_slots: Vec<Vec<MappedInputs>>,
|
||||
pub starting_statuses: Vec<i32>,
|
||||
pub menu: TrainingModpackMenu,
|
||||
pub save_states: Vec<SavedState>,
|
||||
pub player_char: i32, // fighter_kind
|
||||
pub cpu_char: i32, // fighter_kind
|
||||
pub stage: i32, // index of stage, but -1 = random
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub mod_version: String,
|
||||
pub smash_version: String,
|
||||
// depending on version, we need to modify newly added menu options, so that regardless of their defaults they reflect the previous version to minimize breakage of old scenarios
|
||||
// we may also add more scenario parts to the struct in the future etc.
|
||||
// pub screenshot: image????
|
||||
// datetime?
|
||||
// author?
|
||||
// mirroring?
|
||||
}
|
||||
|
||||
impl Scenario {
|
||||
pub fn default() -> Scenario {
|
||||
Scenario {
|
||||
record_slots: vec![vec![MappedInputs::default(); 600]; 5],
|
||||
starting_statuses: vec![0],
|
||||
menu: crate::common::consts::DEFAULTS_MENU,
|
||||
save_states: vec![default_save_state!(); 5],
|
||||
player_char: 0,
|
||||
cpu_char: 0,
|
||||
stage: -1, // index of stage, but -1 = random/any stage
|
||||
title: "Scenario Title".to_string(),
|
||||
description: "Description...".to_string(),
|
||||
mod_version: CURRENT_VERSION.to_string(),
|
||||
smash_version: smash_version(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@ mod character_specific;
|
|||
mod fast_fall;
|
||||
mod full_hop;
|
||||
pub mod input_delay;
|
||||
mod input_log;
|
||||
mod input_record;
|
||||
mod mash;
|
||||
mod reset;
|
||||
|
@ -712,15 +713,34 @@ unsafe fn handle_final_input_mapping(
|
|||
controller_struct: &mut SomeControllerStruct,
|
||||
arg: bool,
|
||||
) {
|
||||
// go through the original mapping function first
|
||||
// Order of hooks here REALLY matters. Tread lightly
|
||||
|
||||
// Go through the original mapping function first
|
||||
original!()(mappings, player_idx, out, controller_struct, arg);
|
||||
if !is_training_mode() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab button input requests from player
|
||||
// Non-mutable pull
|
||||
button_config::handle_final_input_mapping(player_idx, controller_struct);
|
||||
|
||||
// Grab menu inputs from player
|
||||
// Non-mutable pull
|
||||
menu::handle_final_input_mapping(player_idx, controller_struct, out);
|
||||
|
||||
// Check if we should apply hot reload configs
|
||||
// Non-mutable pull
|
||||
dev_config::handle_final_input_mapping(player_idx, controller_struct);
|
||||
|
||||
// Potentially apply input delay
|
||||
// MUTATES controller state
|
||||
input_delay::handle_final_input_mapping(player_idx, out);
|
||||
|
||||
input_log::handle_final_input_mapping(player_idx, out);
|
||||
|
||||
// Potentially apply input recording, thus with delay
|
||||
// MUTATES controller state
|
||||
input_record::handle_final_input_mapping(player_idx, out);
|
||||
}
|
||||
|
||||
|
|
69
src/training/ui/input_log.rs
Normal file
69
src/training/ui/input_log.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
use skyline::nn::ui2d::*;
|
||||
use smash::ui2d::{SmashPane, SmashTextBox};
|
||||
use training_mod_consts::ButtonConfig;
|
||||
|
||||
use crate::{
|
||||
common::{
|
||||
button_config::name_to_font_glyph,
|
||||
input::Buttons,
|
||||
menu::{P1_CONTROLLER_STYLE, QUICK_MENU_ACTIVE},
|
||||
},
|
||||
training::input_log::P1_INPUT_MAPPINGS,
|
||||
};
|
||||
|
||||
macro_rules! log_parent_fmt {
|
||||
($x:ident) => {
|
||||
format!("TrModInputLog{}", $x).as_str()
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn draw(root_pane: &Pane) {
|
||||
let log_number = 0;
|
||||
let log_pane = root_pane
|
||||
.find_pane_by_name_recursive(log_parent_fmt!(log_number))
|
||||
.unwrap();
|
||||
|
||||
// TODO: And menu option for input log is on
|
||||
log_pane.set_visible(!QUICK_MENU_ACTIVE);
|
||||
|
||||
let logs_ptr = P1_INPUT_MAPPINGS.data_ptr();
|
||||
if logs_ptr.is_null() {
|
||||
return;
|
||||
}
|
||||
let logs = &*logs_ptr;
|
||||
let first_log = logs.front();
|
||||
if first_log.is_none() {
|
||||
return;
|
||||
}
|
||||
let first_log = first_log.unwrap();
|
||||
|
||||
let p1_style_ptr = P1_CONTROLLER_STYLE.data_ptr();
|
||||
if p1_style_ptr.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
let input_pane = log_pane
|
||||
.find_pane_by_name_recursive("InputTxt")
|
||||
.unwrap()
|
||||
.as_textbox();
|
||||
|
||||
input_pane.set_text_string("NONE");
|
||||
|
||||
if first_log.buttons.contains(Buttons::ATTACK) {
|
||||
let potential_font_glyph = name_to_font_glyph(ButtonConfig::A, *p1_style_ptr);
|
||||
if let Some(font_glyph) = potential_font_glyph {
|
||||
input_pane.set_text_string("");
|
||||
|
||||
let it = input_pane.text_buf as *mut u16;
|
||||
input_pane.text_len = 1;
|
||||
*it = font_glyph;
|
||||
*(it.add(1)) = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
log_pane
|
||||
.find_pane_by_name_recursive("FrameTxt")
|
||||
.unwrap()
|
||||
.as_textbox()
|
||||
.set_text_string(format!("{}", logs.len()).as_str());
|
||||
}
|
|
@ -10,6 +10,7 @@ use crate::consts::LAYOUT_ARC_PATH;
|
|||
|
||||
mod damage;
|
||||
mod display;
|
||||
mod input_log;
|
||||
mod menu;
|
||||
pub mod notifications;
|
||||
|
||||
|
@ -38,6 +39,7 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
|
|||
damage::draw(root_pane, &layout_name);
|
||||
|
||||
if layout_name == "info_training" {
|
||||
input_log::draw(root_pane);
|
||||
display::draw(root_pane);
|
||||
menu::draw(root_pane);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue