diff --git a/src/common/consts.rs b/src/common/consts.rs
index dde9710..890cb2d 100644
--- a/src/common/consts.rs
+++ b/src/common/consts.rs
@@ -277,3 +277,11 @@ pub struct TrainingModpackMenu {
     pub mash_in_neutral: MashInNeutral,
     pub fast_fall: FastFall,
 }
+
+// Fighter Ids
+#[repr(i32)]
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum FighterId {
+    Player = 0,
+    CPU = 1,
+}
diff --git a/src/training/combo.rs b/src/training/combo.rs
index c1c8e51..7ba0bf5 100644
--- a/src/training/combo.rs
+++ b/src/training/combo.rs
@@ -1,15 +1,23 @@
+use crate::common::consts::FighterId;
 use crate::common::FIGHTER_MANAGER_ADDR;
 use crate::common::*;
 use crate::training::*;
 
 pub static mut FRAME_ADVANTAGE: i32 = 0;
-static mut FRAME_COUNTER: u64 = 0;
 static mut PLAYER_ACTIONABLE: bool = false;
 static mut CPU_ACTIONABLE: bool = false;
-static mut PLAYER_ACTIVE_FRAME: u64 = 0;
-static mut CPU_ACTIVE_FRAME: u64 = 0;
+static mut PLAYER_ACTIVE_FRAME: u32 = 0;
+static mut CPU_ACTIVE_FRAME: u32 = 0;
 static mut FRAME_ADVANTAGE_CHECK: bool = false;
 
+static mut FRAME_COUNTER_INDEX: usize = 0;
+
+pub fn init() {
+    unsafe {
+        FRAME_COUNTER_INDEX = frame_counter::register_counter();
+    }
+}
+
 unsafe fn was_in_hitstun(module_accessor: *mut app::BattleObjectModuleAccessor) -> bool {
     let prev_status = StatusModule::prev_status_kind(module_accessor, 0);
     (*FIGHTER_STATUS_KIND_DAMAGE..=*FIGHTER_STATUS_KIND_DAMAGE_FALL).contains(&prev_status)
@@ -20,7 +28,8 @@ unsafe fn was_in_shieldstun(module_accessor: *mut app::BattleObjectModuleAccesso
     prev_status == FIGHTER_STATUS_KIND_GUARD_DAMAGE
 }
 
-unsafe fn get_module_accessor(entry_id_int: i32) -> *mut app::BattleObjectModuleAccessor {
+unsafe fn get_module_accessor(fighter_id: FighterId) -> *mut app::BattleObjectModuleAccessor {
+    let entry_id_int = fighter_id as i32;
     let entry_id = app::FighterEntryID(entry_id_int);
     let mgr = *(FIGHTER_MANAGER_ADDR as *mut *mut app::FighterManager);
     let fighter_entry = FighterManager::get_fighter_entry(mgr, entry_id) as *mut app::FighterEntry;
@@ -59,53 +68,49 @@ pub unsafe fn get_command_flag_cat(
     let entry_id_int =
         WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID) as i32;
     // do only once.
-    if entry_id_int == 0 {
-        let player_module_accessor = get_module_accessor(0);
-        let cpu_module_accessor = get_module_accessor(1);
+    if entry_id_int != (FighterId::Player as i32) {
+        return;
+    }
 
-        // Use to factor in that we should only update frame advantage if
-        // there's been a hit that connects
-        // if AttackModule::is_infliction(
-        //     player_module_accessor,
-        //     *COLLISION_KIND_MASK_HIT | *COLLISION_KIND_MASK_SHIELD) {
+    let player_module_accessor = get_module_accessor(FighterId::Player);
+    let cpu_module_accessor = get_module_accessor(FighterId::CPU);
 
-        // }
+    // Use to factor in that we should only update frame advantage if
+    // there's been a hit that connects
+    // if AttackModule::is_infliction(
+    //     player_module_accessor,
+    //     *COLLISION_KIND_MASK_HIT | *COLLISION_KIND_MASK_SHIELD) {
 
-        // the frame the fighter *becomes* actionable
-        if !CPU_ACTIONABLE && is_actionable(cpu_module_accessor) {
-            CPU_ACTIVE_FRAME = FRAME_COUNTER;
+    // the frame the fighter *becomes* actionable
+    if !CPU_ACTIONABLE && is_actionable(cpu_module_accessor) {
+        CPU_ACTIVE_FRAME = frame_counter::get_frame_count(FRAME_COUNTER_INDEX);
+    }
+
+    if !PLAYER_ACTIONABLE && is_actionable(player_module_accessor) {
+        PLAYER_ACTIVE_FRAME = frame_counter::get_frame_count(FRAME_COUNTER_INDEX);
+    }
+
+    CPU_ACTIONABLE = is_actionable(cpu_module_accessor);
+    PLAYER_ACTIONABLE = is_actionable(player_module_accessor);
+
+    // if neither are active
+    if !CPU_ACTIONABLE && !PLAYER_ACTIONABLE {
+        if !FRAME_ADVANTAGE_CHECK {
+            frame_counter::reset_frame_count(FRAME_COUNTER_INDEX);
+            frame_counter::start_counting(FRAME_COUNTER_INDEX);
         }
+        FRAME_ADVANTAGE_CHECK = true;
+    }
 
-        if !PLAYER_ACTIONABLE && is_actionable(player_module_accessor) {
-            PLAYER_ACTIVE_FRAME = FRAME_COUNTER;
-        }
-
-        CPU_ACTIONABLE = is_actionable(cpu_module_accessor);
-        PLAYER_ACTIONABLE = is_actionable(player_module_accessor);
-
-        // if neither are active
-        if !CPU_ACTIONABLE && !PLAYER_ACTIONABLE {
-            FRAME_ADVANTAGE_CHECK = true;
-        }
-
-        // if both are now active
-        if PLAYER_ACTIONABLE && CPU_ACTIONABLE {
-            if FRAME_ADVANTAGE_CHECK {
-                if was_in_hitstun(cpu_module_accessor) || was_in_shieldstun(cpu_module_accessor) {
-                    let frame_advantage: i64;
-                    if PLAYER_ACTIVE_FRAME > CPU_ACTIVE_FRAME {
-                        frame_advantage = (PLAYER_ACTIVE_FRAME - CPU_ACTIVE_FRAME) as i64 * -1;
-                    } else {
-                        frame_advantage = (CPU_ACTIVE_FRAME - PLAYER_ACTIVE_FRAME) as i64;
-                    }
-
-                    FRAME_ADVANTAGE = frame_advantage as i32;
-                }
-
-                FRAME_ADVANTAGE_CHECK = false;
+    // if both are now active
+    if PLAYER_ACTIONABLE && CPU_ACTIONABLE {
+        if FRAME_ADVANTAGE_CHECK {
+            if was_in_hitstun(cpu_module_accessor) || was_in_shieldstun(cpu_module_accessor) {
+                FRAME_ADVANTAGE = (CPU_ACTIVE_FRAME as i64 - PLAYER_ACTIVE_FRAME as i64) as i32;
             }
-        }
 
-        FRAME_COUNTER += 1;
+            frame_counter::stop_counting(FRAME_COUNTER_INDEX);
+            FRAME_ADVANTAGE_CHECK = false;
+        }
     }
 }
diff --git a/src/training/frame_counter.rs b/src/training/frame_counter.rs
new file mode 100644
index 0000000..f57efa6
--- /dev/null
+++ b/src/training/frame_counter.rs
@@ -0,0 +1,60 @@
+use crate::common::*;
+use crate::training::*;
+
+static mut SHOULD_COUNT: Vec<bool> = vec![];
+static mut COUNTERS: Vec<u32> = vec![];
+
+pub unsafe fn register_counter() -> usize {
+    let index = COUNTERS.len();
+
+    COUNTERS.push(0);
+    SHOULD_COUNT.push(false);
+
+    index
+}
+
+pub unsafe fn start_counting(index:usize) {
+    SHOULD_COUNT[index] = true;
+}
+
+pub unsafe fn stop_counting(index:usize) {
+    SHOULD_COUNT[index] =  false;
+}
+
+pub unsafe fn reset_frame_count(index:usize) {
+    COUNTERS[index] = 0;
+}
+
+pub unsafe fn get_frame_count(index:usize) -> u32 {
+    COUNTERS[index]
+}
+
+pub unsafe fn tick() {
+    for (index, _frame) in COUNTERS.iter().enumerate() {
+        if !SHOULD_COUNT[index]{
+            continue;
+        }
+        COUNTERS[index] += 1;
+    }
+}
+
+pub unsafe fn get_command_flag_cat(
+    module_accessor: &mut app::BattleObjectModuleAccessor,
+    category: i32,
+) {
+    if !is_training_mode() {
+        return;
+    }
+
+    // Only do once per frame
+    if category != 0 {
+        return;
+    }
+
+    if !is_operation_cpu(module_accessor) {
+        return;
+    }
+    //~
+
+    tick();
+}
diff --git a/src/training/mod.rs b/src/training/mod.rs
index dfe4308..a025318 100644
--- a/src/training/mod.rs
+++ b/src/training/mod.rs
@@ -10,6 +10,7 @@ pub mod tech;
 
 pub mod combo;
 mod fast_fall;
+mod frame_counter;
 mod ledge;
 mod left_stick;
 mod mash;
@@ -55,6 +56,7 @@ pub unsafe fn handle_get_command_flag_cat(
 
     let mut flag = original!()(module_accessor, category);
 
+    frame_counter::get_command_flag_cat(module_accessor, category);
     combo::get_command_flag_cat(module_accessor, category);
 
     // bool replace;
@@ -222,6 +224,8 @@ pub fn training_mods() {
         get_stick_y,
     );
 
+    combo::init();
+
     // // Input recorder
     // SaltySD_function_replace_sym(
     //     "_ZN3app8lua_bind31ControlModule__get_stick_x_implEPNS_26BattleObjectModuleAccessorE",