From 516c85ec3007dc19d889ab818a5095b908bba52d Mon Sep 17 00:00:00 2001
From: asimon-1 <40246417+asimon-1@users.noreply.github.com>
Date: Tue, 17 Aug 2021 19:43:01 -0400
Subject: [PATCH] Menu help text (#234)

* Add footer with help text

* Set help text strings

Co-authored-by: asimon-1 <asimon1@protonmail.com>
---
 src/common/menu.rs      | 86 ++++++++++++++++++++++-------------------
 src/templates/menu.html | 24 +++++++++---
 2 files changed, 66 insertions(+), 44 deletions(-)

diff --git a/src/common/menu.rs b/src/common/menu.rs
index 2cada26..78f172f 100644
--- a/src/common/menu.rs
+++ b/src/common/menu.rs
@@ -40,7 +40,8 @@ struct SubMenu<'a> {
     onoffselector: Vec<OnOffSelector<'a>>,
     index: usize,
     check_against: usize,
-    is_single_option: Option<bool>
+    is_single_option: Option<bool>,
+    help_text: &'a str,
 }
 
 impl<'a> SubMenu<'a> {
@@ -96,7 +97,7 @@ impl<'a> Menu<'a> {
             .unwrap_or(0)
     }
 
-    pub fn add_sub_menu(&mut self, title: &'a str, id: &'a str, check_against: usize, toggles: Vec<(&'a str, usize)>, sliders: Vec<(usize,usize,usize)>, defaults: usize) {
+    pub fn add_sub_menu(&mut self, title: &'a str, id: &'a str, check_against: usize, toggles: Vec<(&'a str, usize)>, sliders: Vec<(usize,usize,usize)>, defaults: usize, help_text: &'a str) {
         let mut sub_menu = SubMenu {
             title,
             id,
@@ -105,7 +106,8 @@ impl<'a> Menu<'a> {
             onoffselector: Vec::new(),
             index: self.max_idx() + 1,
             check_against,
-            is_single_option: Some(true)
+            is_single_option: Some(true),
+            help_text,
         };
 
         for toggle in toggles {
@@ -119,7 +121,7 @@ impl<'a> Menu<'a> {
         self.sub_menus.push(sub_menu);
     }
 
-    pub fn add_sub_menu_sep(&mut self, title: &'a str, id: &'a str, check_against: usize, strs: Vec<&'a str>, vals: Vec<usize>, defaults: usize) {
+    pub fn add_sub_menu_sep(&mut self, title: &'a str, id: &'a str, check_against: usize, strs: Vec<&'a str>, vals: Vec<usize>, defaults: usize, help_text: &'a str) {
         let mut sub_menu = SubMenu {
             title,
             id,
@@ -128,7 +130,8 @@ impl<'a> Menu<'a> {
             onoffselector: Vec::new(),
             index: self.max_idx() + 1,
             check_against,
-            is_single_option: None
+            is_single_option: None,
+            help_text,
         };
 
         for i in 0..strs.len() {
@@ -140,7 +143,7 @@ impl<'a> Menu<'a> {
         self.sub_menus.push(sub_menu);
     }
 
-    pub fn add_sub_menu_onoff(&mut self, title: &'a str, id: &'a str, check_against: usize, checked: bool, default: usize) {
+    pub fn add_sub_menu_onoff(&mut self, title: &'a str, id: &'a str, check_against: usize, checked: bool, default: usize, help_text: &'a str) {
         let mut sub_menu = SubMenu {
             title,
             id,
@@ -149,7 +152,8 @@ impl<'a> Menu<'a> {
             onoffselector: Vec::new(),
             index: self.max_idx() + 1,
             check_against,
-            is_single_option: None
+            is_single_option: None,
+            help_text,
         };
 
         sub_menu.add_onoffselector(title, checked, (default & OnOff::On as usize) != 0);
@@ -158,7 +162,7 @@ impl<'a> Menu<'a> {
 }
 
 macro_rules! add_bitflag_submenu {
-    ($menu:ident, $title:literal, $id:ident, $e:ty) => {
+    ($menu:ident, $title:literal, $id:ident, $e:ty, $help_text:literal) => {
         paste::paste!{
             let [<$id _strs>] = <$e>::to_toggle_strs();
             let [<$id _vals>] = <$e>::to_toggle_vals();
@@ -170,13 +174,14 @@ macro_rules! add_bitflag_submenu {
                 [<$id _strs>].iter().map(|i| i.as_str()).collect(),
                 [<$id _vals>],
                 DEFAULT_MENU.$id.bits() as usize,
+                stringify!($help_text),
             );
         }
     }
 }
 
 macro_rules! add_single_option_submenu {
-    ($menu:ident, $title:literal, $id:ident, $e:ty) => {
+    ($menu:ident, $title:literal, $id:ident, $e:ty, $help_text:literal) => {
         paste::paste!{
             let mut [<$id _toggles>] = Vec::new();
             for val in [<$e>]::iter() {
@@ -189,21 +194,23 @@ macro_rules! add_single_option_submenu {
                 MENU.$id as usize,
                 [<$id _toggles>].iter().map(|(x, y)| (x.as_str(), *y)).collect::<Vec<(&str, usize)>>(),
                 [].to_vec(),
-                DEFAULT_MENU.$id as usize
+                DEFAULT_MENU.$id as usize,
+                stringify!($help_text),
             );
         }
     }
 }
 
 macro_rules! add_onoff_submenu {
-    ($menu:ident, $title:literal, $id:ident) => {
+    ($menu:ident, $title:literal, $id:ident, $help_text:literal) => {
         paste::paste!{
             $menu.add_sub_menu_onoff(
                 $title, 
                 stringify!($id), 
                 MENU.$id as usize,
                 (MENU.$id as usize & OnOff::On as usize) != 0,
-                DEFAULT_MENU.$id as usize
+                DEFAULT_MENU.$id as usize,
+                stringify!($help_text),
             );
         }
     }
@@ -250,33 +257,33 @@ pub unsafe fn write_menu() {
     };
 
     // Toggle/bitflag menus
-    add_bitflag_submenu!(overall_menu, "Mash Toggles", mash_state, Action);
-    add_bitflag_submenu!(overall_menu, "Followup Toggles", follow_up, Action);
-    add_bitflag_submenu!(overall_menu, "Attack Angle", attack_angle, AttackAngle);
+    add_bitflag_submenu!(overall_menu, "Mash Toggles", mash_state, Action, "Mash Toggles: Actions to be performed as soon as possible");
+    add_bitflag_submenu!(overall_menu, "Followup Toggles", follow_up, Action, "Followup Toggles: Actions to be performed after the Mash option");
+    add_bitflag_submenu!(overall_menu, "Attack Angle", attack_angle, AttackAngle, "Attack Angle: For attacks that can be angled, such as some forward tilts");
 
-    add_bitflag_submenu!(overall_menu, "Ledge Options", ledge_state, LedgeOption);
-    add_bitflag_submenu!(overall_menu, "Ledge Delay", ledge_delay, LongDelay);
-    add_bitflag_submenu!(overall_menu, "Tech Options", tech_state, TechFlags);
-    add_bitflag_submenu!(overall_menu, "Miss Tech Options", miss_tech_state, MissTechFlags);
-    add_bitflag_submenu!(overall_menu, "Defensive Options", defensive_state, Defensive);
+    add_bitflag_submenu!(overall_menu, "Ledge Options", ledge_state, LedgeOption, "Ledge Options: Actions to be taken when on the ledge");
+    add_bitflag_submenu!(overall_menu, "Ledge Delay", ledge_delay, LongDelay, "Ledge Delay: How many frames to delay the ledge option");
+    add_bitflag_submenu!(overall_menu, "Tech Options", tech_state, TechFlags, "Tech Options: Actions to take when slammed into a hard surface");
+    add_bitflag_submenu!(overall_menu, "Miss Tech Options", miss_tech_state, MissTechFlags, "Miss Tech Options: Actions to take after missing a tech");
+    add_bitflag_submenu!(overall_menu, "Defensive Options", defensive_state, Defensive, "Defensive Options: Actions to take after a ledge option, tech option, or miss tech option");
 
-    add_bitflag_submenu!(overall_menu, "Aerial Delay", aerial_delay, Delay);
-    add_bitflag_submenu!(overall_menu, "OoS Offset", oos_offset, Delay);
-    add_bitflag_submenu!(overall_menu, "Reaction Time", reaction_time, Delay);
+    add_bitflag_submenu!(overall_menu, "Aerial Delay", aerial_delay, Delay, "Aerial Delay: How long to delay a Mash aerial attack");
+    add_bitflag_submenu!(overall_menu, "OoS Offset", oos_offset, Delay, "OoS Offset: How many times the CPU shield can be hit before performing a Mash option");
+    add_bitflag_submenu!(overall_menu, "Reaction Time", reaction_time, Delay, "Reaction Time: How many frames to delay before performing an option out of shield");
 
-    add_bitflag_submenu!(overall_menu, "Fast Fall", fast_fall, BoolFlag);
-    add_bitflag_submenu!(overall_menu, "Fast Fall Delay", fast_fall_delay, Delay);
-    add_bitflag_submenu!(overall_menu, "Falling Aerials", falling_aerials, BoolFlag);
-    add_bitflag_submenu!(overall_menu, "Full Hop", full_hop, BoolFlag);
+    add_bitflag_submenu!(overall_menu, "Fast Fall", fast_fall, BoolFlag, "Fast Fall: Should the CPU fastfall during a jump");
+    add_bitflag_submenu!(overall_menu, "Fast Fall Delay", fast_fall_delay, Delay, "Fast Fall Delay: How many frames the CPU should delay their fastfall");
+    add_bitflag_submenu!(overall_menu, "Falling Aerials", falling_aerials, BoolFlag, "Falling Aerials: Should aerials be performed when rising or when falling");
+    add_bitflag_submenu!(overall_menu, "Full Hop", full_hop, BoolFlag, "Full Hop: Should the CPU perform a full hop or a short hop");
 
-    add_bitflag_submenu!(overall_menu, "Shield Tilt", shield_tilt, Direction);
-    add_bitflag_submenu!(overall_menu, "DI Direction", di_state, Direction);
-    add_bitflag_submenu!(overall_menu, "SDI Direction", sdi_state, Direction);
-    add_bitflag_submenu!(overall_menu, "Airdodge Direction", air_dodge_dir, Direction);
+    add_bitflag_submenu!(overall_menu, "Shield Tilt", shield_tilt, Direction, "Shield Tilt: Direction to tilt the shield");
+    add_bitflag_submenu!(overall_menu, "DI Direction", di_state, Direction, "DI Direction: Direction to angle the directional influence during hitlag");
+    add_bitflag_submenu!(overall_menu, "SDI Direction", sdi_state, Direction, "SDI Direction: Direction to angle the smash directional influence during hitlag");
+    add_bitflag_submenu!(overall_menu, "Airdodge Direction", air_dodge_dir, Direction, "Airdodge Direction: Direction to angle airdodges");
 
-    add_single_option_submenu!(overall_menu, "SDI Strength", sdi_strength, SdiStrength);
-    add_single_option_submenu!(overall_menu, "Shield Toggles", shield_state, Shield);
-    add_single_option_submenu!(overall_menu, "Mirroring", save_state_mirroring, SaveStateMirroring);
+    add_single_option_submenu!(overall_menu, "SDI Strength", sdi_strength, SdiStrength, "SDI Strength: Relative strength of the smash directional influence inputs");
+    add_single_option_submenu!(overall_menu, "Shield Toggles", shield_state, Shield, "Shield Toggles: CPU Shield Behavior");
+    add_single_option_submenu!(overall_menu, "Mirroring", save_state_mirroring, SaveStateMirroring, "Mirroring: Flips save states in the left-right direction across the stage center");
 
 
     // Slider menus
@@ -288,13 +295,14 @@ pub unsafe fn write_menu() {
         [("0", 0),("1",1),("2",2),("3",3),("4",4),("5",5),("6",6),("7",7),("8",8),("9",9),("10",10)].to_vec(),
         [].to_vec(), //(0, 10, MENU.input_delay as usize)
         DEFAULT_MENU.input_delay as usize,
+        stringify!("Input Delay: Frames to delay player inputs by"),
     );
 
-    add_onoff_submenu!(overall_menu, "Save Damage", save_damage);
-    add_onoff_submenu!(overall_menu, "Hitbox Visualization", hitbox_vis);
-    add_onoff_submenu!(overall_menu, "Stage Hazards", stage_hazards);
-    add_onoff_submenu!(overall_menu, "Frame Advantage", frame_advantage);
-    add_onoff_submenu!(overall_menu, "Mash In Neutral", mash_in_neutral);
+    add_onoff_submenu!(overall_menu, "Save Damage", save_damage, "Save Damage: Should save states retain player/CPU damage");
+    add_onoff_submenu!(overall_menu, "Hitbox Visualization", hitbox_vis, "Hitbox Visualization: Should hitboxes be displayed, hiding other visual effects");
+    add_onoff_submenu!(overall_menu, "Stage Hazards", stage_hazards, "Stage Hazards: Should stage hazards be present");
+    add_onoff_submenu!(overall_menu, "Frame Advantage", frame_advantage, "Frame Advantage: Display the time difference between when the player is actionable and the CPU is actionable");
+    add_onoff_submenu!(overall_menu, "Mash In Neutral", mash_in_neutral, "Mash In Neutral: Should Mash options be performed repeatedly or only when the CPU is hit");
 
     let data = tpl.render(&overall_menu);
 
diff --git a/src/templates/menu.html b/src/templates/menu.html
index 7544d27..43d03d2 100644
--- a/src/templates/menu.html
+++ b/src/templates/menu.html
@@ -7,6 +7,7 @@
         <title>Document</title>
         <link rel="stylesheet" href="./help/css/common.css" />
         <link rel="stylesheet" href="./help/css/qa.css" />
+        <link rel="stylesheet" href="./help/css/top.css" />
         <link id="font-stylesheet" rel="stylesheet" href="./help/css/font.css">
         <link rel="stylesheet" href="./help/css/keyword.css">
         <link href="./nouislider.min.css" rel="stylesheet">
@@ -50,9 +51,9 @@
                 width: 100%;
             }
 
-            /* Overwrite margin on the last child to avoid overlap*/
+            /* Overwrite margin on the last child to avoid overlap with footer */
             .l-qa:last-child .qa {
-                margin-bottom: 0px;
+                margin-bottom: 75px;
             }
 
             .l-qa:last-child .qa.is-opened {
@@ -83,6 +84,12 @@
             .question::before {
                 width: 70px;
             }
+
+            /* Footer */
+            .footer {
+                position: fixed;
+                z-index: 10;
+            }
         </style>
     </head>
 
@@ -136,7 +143,7 @@
             {{#sub_menus}}
                 <div class="l-qa">
                     {{^onoffselector}}
-                        <a id="qa-{{id}}" class="qa" tabindex="{{index}}" href="javascript:void(0);" onfocus="focusQA(this)" onblur="defocusQA(this)" onclick="openAnswer(this)" nx-se-disabled="">
+                        <a id="qa-{{id}}" class="qa" tabindex="{{index}}" href="javascript:void(0);" onfocus="focusQA(this);setHelpText({{help_text}})" onblur="defocusQA(this)" onclick="openAnswer(this)" nx-se-disabled="">
                             <div class="question-outer">
                                 <div class="question-border">
                                     <div id="question-{{id}}" class="question scuffle-thema">
@@ -207,7 +214,7 @@
                         </a>
                     {{/onoffselector}}
                     {{#onoffselector}}
-                        <a id="qa-{{id}}" class="qa" tabindex="{{index}}" href="javascript:void(0);" onfocus="focusQA(this)" onblur="defocusQA(this)" onclick="clickToggle(this)" nx-se-disabled="">
+                        <a id="qa-{{id}}" class="qa" tabindex="{{index}}" href="javascript:void(0);" onfocus="focusQA(this);setHelpText({{help_text}})" onblur="defocusQA(this)" onclick="clickToggle(this)" nx-se-disabled="">
                             <div class="question-outer">
                                 <div class="question-border">
                                     <div id="question-{{id}}" class="question scuffle-thema">
@@ -225,7 +232,6 @@
                     {{/onoffselector}}
                 </div>
             {{/sub_menus}}
-
         </div>
         {{#sub_menus}}
             {{#sliders}}
@@ -241,6 +247,9 @@
                 </script>
             {{/sliders}}
         {{/sub_menus}}
+        <footer id="footer" class="footer l-footer f-u-bold">
+            <p id="help-text" class="header-desc"></p>
+        </footer>
         <script>
             if (isNx) {
                 window.nx.footer.setAssign('B', '', goBackHook, {
@@ -412,6 +421,11 @@
                     $("[default*='is-hidden']").addClass("is-hidden");
                 }
             }
+
+            function setHelpText(text) {
+                // Modify the help text in the footer
+                $("#help-text").text(text);
+            }
         </script>
         <script>
             window.onload = setSettings;