Compare commits

...

6 Commits

Author SHA1 Message Date
erion 04555fe363 Update from upstream. 2023-02-10 13:00:19 +01:00
Mohammad Shoaib Khan 7409959c99
Moved character customization patch to separate file 2023-02-10 11:17:50 +05:30
Katie Durden baedf69d80 Character creation text boxes announce content if set.
Causes text boxes to report their content instead of " text box" when text was already entered.
E.G. after entering a name, "Farmer's Name Text Box" becomes "Farmer's Name: <name>"
2023-02-09 20:50:36 -08:00
Katie Durden 4c336c36ed Enable access to the character appearance controls.
Added accessible buttons to rotate the farmer, change skin tone, hair style, shirt, pants style, and accessory choice.
Added new accessible slider controls to adjust hue, saturation and value for eye, hair and pants color.
    Up/Down to adjust 1%; PageUp/PageDown to adjust by 10%.
Changed spoken modifiable fields (such as current pet, current shirt) to only announce when relevant controls have focus.
    This includes Random Skin Button for appearance controls.
Added toggle key (LeftControl + Space) to show / hide the appearance controls; hidden by default.
Added announcement when entering customization menu to inform of toggle key.
2023-02-09 07:50:54 -08:00
Katie Durden fcf81004d3 Typo: `isCustomizingChrachter` should be `isCustomizingCharacter`. Updated all occurrences. 2023-02-09 07:42:27 -08:00
Katie Durden 5996fa09f2 Update harmony and Stardew.ModConfig; add newtonsoft.json as dependency. 2023-02-09 07:41:32 -08:00
6 changed files with 1458 additions and 26 deletions

View File

@ -48,7 +48,7 @@ namespace stardew_access
harmony.Patch(
original: AccessTools.Method(typeof(CharacterCustomization), nameof(CharacterCustomization.draw), new Type[] { typeof(SpriteBatch) }),
postfix: new HarmonyMethod(typeof(TitleMenuPatches), nameof(TitleMenuPatches.CharacterCustomizationMenuPatch))
postfix: new HarmonyMethod(typeof(TitleMenuPatches), nameof(CharacterCustomizationPatches.CharacterCustomizationMenuPatch))
);
harmony.Patch(

View File

@ -49,9 +49,14 @@ namespace stardew_access
#region Menu Keys
public KeybindList PrimaryInfoKey { get; set; } = KeybindList.Parse("C");
// Charachter Creatinon menu (new game menu) keys
// Character Creation menu (new game menu) keys
public KeybindList CharacterCreationMenuNextKey { get; set; } = KeybindList.Parse("Right");
public KeybindList CharacterCreationMenuPreviousKey { get; set; } = KeybindList.Parse("Left");
public KeybindList CharacterCreationMenuSliderIncreaseKey { get; set; } = KeybindList.Parse("Up");
public KeybindList CharacterCreationMenuSliderLargeIncreaseKey { get; set; } = KeybindList.Parse("PageUp");
public KeybindList CharacterCreationMenuSliderDecreaseKey { get; set; } = KeybindList.Parse("Down");
public KeybindList CharacterCreationMenuSliderLargeDecreaseKey { get; set; } = KeybindList.Parse("PageDown");
public KeybindList CharacterCreationMenuDesignToggleKey { get; set; } = KeybindList.Parse("LeftControl + Space");
// Bundle menu keys
public KeybindList BundleMenuIngredientsKey { get; set; } = KeybindList.Parse("I");

View File

@ -212,7 +212,7 @@ namespace stardew_access
#region Simulate left and right clicks
if (Game1.activeClickableMenu != null)
{
bool isCustomizingChrachter = Game1.activeClickableMenu is CharacterCustomization || (TitleMenu.subMenu != null && TitleMenu.subMenu is CharacterCustomization);
bool isCustomizingCharacter = Game1.activeClickableMenu is CharacterCustomization || (TitleMenu.subMenu != null && TitleMenu.subMenu is CharacterCustomization);
#region Mouse Click Simulation
// Main Keybinds
@ -226,11 +226,11 @@ namespace stardew_access
}
// Alternate Keybinds
if (!isCustomizingChrachter && Game1.activeClickableMenu is not AnimalQueryMenu && Config.LeftClickAlternateKey.JustPressed()) // Excluding the character creation menu
if (!isCustomizingCharacter && Game1.activeClickableMenu is not AnimalQueryMenu && Config.LeftClickAlternateKey.JustPressed()) // Excluding the character creation menu
{
Game1.activeClickableMenu.receiveLeftClick(Game1.getMouseX(true), Game1.getMouseY(true));
}
if (!isCustomizingChrachter && Game1.activeClickableMenu is not AnimalQueryMenu && Config.RightClickAlternateKey.JustPressed()) // Excluding the character creation menu
if (!isCustomizingCharacter && Game1.activeClickableMenu is not AnimalQueryMenu && Config.RightClickAlternateKey.JustPressed()) // Excluding the character creation menu
{
Game1.activeClickableMenu.receiveRightClick(Game1.getMouseX(true), Game1.getMouseY(true));
}
@ -239,7 +239,7 @@ namespace stardew_access
if (Game1.currentMinigame != null)
{
bool isCustomizingChrachter = Game1.activeClickableMenu is CharacterCustomization || (TitleMenu.subMenu != null && TitleMenu.subMenu is CharacterCustomization);
bool isCustomizingCharacter = Game1.activeClickableMenu is CharacterCustomization || (TitleMenu.subMenu != null && TitleMenu.subMenu is CharacterCustomization);
#region Mouse Click Simulation
// Main Keybinds

View File

@ -0,0 +1,829 @@
using StardewValley;
using StardewValley.Menus;
namespace stardew_access.Patches {
internal class CharacterCustomizationPatches {
private static bool isRunning = false;
private static int saveGameIndex = -1;
public static string characterCreationMenuQueryKey = " ";
public static string prevPants = " ";
public static string prevShirt = " ";
public static string prevHair = " ";
public static string prevAccessory = " ";
public static string prevSkin = " ";
public static string prevEyeColor = " ";
public static string prevEyeColorHue = " ";
public static string prevEyeColorSaturation = " ";
public static string prevEyeColorValue = " ";
public static string prevHairColor = " ";
public static string prevHairColorHue = " ";
public static string prevHairColorSaturation = " ";
public static string prevHairColorValue = " ";
public static string prevPantsColor = " ";
public static string prevPantsColorHue = " ";
public static string prevPantsColorSaturation = " ";
public static string prevPantsColorValue = " ";
public static string prevPetName = " ";
public static bool characterDesignToggle = false;
public static bool characterDesignToggleShouldSpeak = true;
public static ClickableComponent? currentComponent = null;
internal static void CharacterCustomizationMenuPatch(CharacterCustomization __instance, bool ___skipIntro,
ClickableComponent ___startingCabinsLabel, ClickableComponent ___difficultyModifierLabel, TextBox ___nameBox,
TextBox ___farmnameBox, TextBox ___favThingBox)
{
try
{
bool isEscPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Escape); // For escaping/unselecting from the animal name text box
string toSpeak = "";
if (characterDesignToggleShouldSpeak)
{
toSpeak = "Press left control + space to toggle character appearance controls";
characterDesignToggleShouldSpeak = false;
}
string itemsToSpeak = "";
string changesToSpeak = "";
if (___nameBox.Selected)
{
toSpeak = ___nameBox.Text;
if (isEscPressed)
{
___nameBox.Selected = false;
}
}
else if (___farmnameBox.Selected)
{
toSpeak = ___farmnameBox.Text;
if (isEscPressed)
{
___farmnameBox.Selected = false;
}
}
else if (___favThingBox.Selected)
{
toSpeak = ___favThingBox.Text;
if (isEscPressed)
{
___favThingBox.Selected = false;
}
}
else if (MainClass.Config.CharacterCreationMenuNextKey.JustPressed() && !isRunning)
{
isRunning = true;
itemsToSpeak =CycleThroughItems(true, __instance, ___skipIntro, ___startingCabinsLabel, ___difficultyModifierLabel, ___nameBox, ___farmnameBox, ___favThingBox);
if (itemsToSpeak != "")
toSpeak = $"{itemsToSpeak} \n {toSpeak}";
Task.Delay(200).ContinueWith(_ => { isRunning = false; });
}
else if (MainClass.Config.CharacterCreationMenuPreviousKey.JustPressed() && !isRunning)
{
isRunning = true;
toSpeak = CycleThroughItems(false, __instance, ___skipIntro, ___startingCabinsLabel, ___difficultyModifierLabel, ___nameBox, ___farmnameBox, ___favThingBox);
Task.Delay(200).ContinueWith(_ => { isRunning = false; });
}
else if (characterDesignToggle && MainClass.Config.CharacterCreationMenuSliderIncreaseKey.JustPressed() && !isRunning)
{
isRunning = true;
AdjustCurrentSlider(true, __instance);
Task.Delay(200).ContinueWith(_ => { isRunning = false; });
}
else if (characterDesignToggle && MainClass.Config.CharacterCreationMenuSliderLargeIncreaseKey.JustPressed() && !isRunning)
{
isRunning = true;
AdjustCurrentSlider(true, __instance, 10);
Task.Delay(200).ContinueWith(_ => { isRunning = false; });
}
else if (characterDesignToggle && MainClass.Config.CharacterCreationMenuSliderDecreaseKey.JustPressed() && !isRunning)
{
isRunning = true;
AdjustCurrentSlider(false, __instance);
Task.Delay(200).ContinueWith(_ => { isRunning = false; });
}
else if (characterDesignToggle && MainClass.Config.CharacterCreationMenuSliderLargeDecreaseKey.JustPressed() && !isRunning)
{
isRunning = true;
AdjustCurrentSlider(false, __instance, 10);
Task.Delay(200).ContinueWith(_ => { isRunning = false; });
}
else if (Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.LeftControl) && MainClass.Config.CharacterCreationMenuDesignToggleKey.JustPressed() && !isRunning)
{
string displayState = "";
characterDesignToggle = !characterDesignToggle;
saveGameIndex = Math.Min(saveGameIndex, 5); // move to random skin button if focus was beyond that point
if (characterDesignToggle)
{
displayState = "shown";
} else {
displayState = "hidden";
}
toSpeak = $"Character design controls {displayState}. \n {toSpeak}";
}
changesToSpeak = getChangesToSpeak(__instance);
if (changesToSpeak != "")
toSpeak = $"{toSpeak} \n {changesToSpeak}";
if (characterCreationMenuQueryKey != toSpeak && toSpeak.Trim() != "")
{
characterCreationMenuQueryKey = toSpeak;
MainClass.ScreenReader.Say(toSpeak, true);
}
}
catch (Exception e)
{
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
}
}
private static string getChangesToSpeak(CharacterCustomization __instance)
{
string toSpeak = "";
string currentPetName = getCurrentPetName();
string currentSkin = getCurrentSkin();
string currentHair = getCurrentHair();
string currentShirt = getCurrentShirt();
string currentPants = getCurrentPants();
string currentAccessory = getCurrentAccessory();
string currentEyeColor = getCurrentEyeColor();
string currentEyeColorHue = getCurrentEyeColorHue(__instance);
string currentEyeColorSaturation = getCurrentEyeColorSaturation(__instance);
string currentEyeColorValue = getCurrentEyeColorValue(__instance);
string currentHairColor = getCurrentHairColor();
string currentHairColorHue = getCurrentHairColorHue(__instance);
string currentHairColorSaturation = getCurrentHairColorSaturation(__instance);
string currentHairColorValue = getCurrentHairColorValue(__instance);
string currentPantsColor = getCurrentPantsColor();
string currentPantsColorHue = getCurrentPantsColorHue(__instance);
string currentPantsColorSaturation = getCurrentPantsColorSaturation(__instance);
string currentPantsColorValue = getCurrentPantsColorValue(__instance);
if (characterDesignToggle)
{
if (prevSkin != currentSkin)
{
prevSkin = currentSkin;
if (currentSkin != "")
toSpeak = $"{toSpeak} \n {currentSkin}";
}
if (prevHair != currentHair)
{
prevHair = currentHair;
if (currentHair != "")
toSpeak = $"{toSpeak} \n {currentHair}";
}
if (prevShirt != currentShirt)
{
prevShirt = currentShirt;
if (currentShirt != "")
toSpeak = $"{toSpeak} \n {currentShirt}";
}
if (prevPants != currentPants)
{
prevPants = currentPants;
if (currentPants != "")
toSpeak = $"{toSpeak} \n {currentPants}";
}
if (prevAccessory != currentAccessory)
{
prevAccessory = currentAccessory;
if (currentAccessory != "")
toSpeak = $"{toSpeak} \n {currentAccessory}";
}
if (prevEyeColorHue != currentEyeColorHue)
{
if (currentComponent != null && currentComponent.myID == 522)
{
prevEyeColorHue = currentEyeColorHue;
if (currentEyeColorHue != "")
toSpeak = $"{toSpeak} \n Hue: {currentEyeColorHue}";
} else {
prevEyeColorHue = "";
}
}
if (prevEyeColorSaturation != currentEyeColorSaturation)
{
if (currentComponent != null && currentComponent.myID == 523)
{
prevEyeColorSaturation = currentEyeColorSaturation;
if (currentEyeColorSaturation != "")
toSpeak = $"{toSpeak} \n Saturation: {currentEyeColorSaturation}";
} else {
prevEyeColorSaturation = "";
}
}
if (prevEyeColorValue != currentEyeColorValue)
{
if (currentComponent != null && currentComponent.myID == 524)
{
prevEyeColorValue = currentEyeColorValue;
if (currentEyeColorValue != "")
toSpeak = $"{toSpeak} \n Value: {currentEyeColorValue}";
} else {
prevEyeColorValue = "";
}
}
if (prevEyeColor != currentEyeColor)
{
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 522 || currentComponent.myID <= 524)))
{
prevEyeColor = currentEyeColor;
if (currentEyeColor != "")
toSpeak = $"{toSpeak} \n {currentEyeColor}";
}
}
if (prevHairColorHue != currentHairColorHue)
{
if (currentComponent != null && currentComponent.myID == 525)
{
prevHairColorHue = currentHairColorHue;
if (currentHairColorHue != "")
toSpeak = $"{toSpeak} \n Hue: {currentHairColorHue}";
} else {
prevHairColorHue = "";
}
}
if (prevHairColorSaturation != currentHairColorSaturation)
{
if (currentComponent != null && currentComponent.myID == 526)
{
prevHairColorSaturation = currentHairColorSaturation;
if (currentHairColorSaturation != "")
toSpeak = $"{toSpeak} \n Saturation: {currentHairColorSaturation}";
} else {
prevHairColorSaturation = "";
}
}
if (prevHairColorValue != currentHairColorValue)
{
if (currentComponent != null && currentComponent.myID == 527)
{
prevHairColorValue = currentHairColorValue;
if (currentHairColorValue != "")
toSpeak = $"{toSpeak} \n Value: {currentHairColorValue}";
} else {
prevHairColorValue = "";
}
}
if (prevHairColor != currentHairColor)
{
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 525 || currentComponent.myID <= 527)))
{
prevHairColor = currentHairColor;
if (currentHairColor != "")
toSpeak = $"{toSpeak} \n {currentHairColor}";
}
}
if (prevPantsColorHue != currentPantsColorHue)
{
if (currentComponent != null && currentComponent.myID == 528)
{
prevPantsColorHue = currentPantsColorHue;
if (currentPantsColorHue != "")
toSpeak = $"{toSpeak} \n Hue: {currentPantsColorHue}";
} else {
prevPantsColorHue = "";
}
}
if (prevPantsColorSaturation != currentPantsColorSaturation)
{
if (currentComponent != null && currentComponent.myID == 529)
{
prevPantsColorSaturation = currentPantsColorSaturation;
if (currentPantsColorSaturation != "")
toSpeak = $"{toSpeak} \n Saturation: {currentPantsColorSaturation}";
} else {
prevPantsColorSaturation = "";
}
}
if (prevPantsColorValue != currentPantsColorValue)
{
if (currentComponent != null && currentComponent.myID == 530)
{
prevPantsColorValue = currentPantsColorValue;
if (currentPantsColorValue != "")
toSpeak = $"{toSpeak} \n Value: {currentPantsColorValue}";
} else {
prevPantsColorValue = "";
}
}
if (prevPantsColor != currentPantsColor)
{
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 528 || currentComponent.myID <= 530)))
{
prevPantsColor = currentPantsColor;
if (currentPantsColor != "")
toSpeak = $"{toSpeak} \n {currentPantsColor}";
}
}
}
if (prevPetName != currentPetName)
{
prevPetName = currentPetName;
if (currentPetName != "")
toSpeak = $"{toSpeak} \n Current Pet: {currentPetName}";
}
return toSpeak.Trim();
}
private static string CycleThroughItems(bool increase, CharacterCustomization __instance, bool ___skipIntro,
ClickableComponent ___startingCabinsLabel, ClickableComponent ___difficultyModifierLabel, TextBox ___nameBox,
TextBox ___farmnameBox, TextBox ___favThingBox)
{
string toSpeak = " ";
int DesignControlsIndex = 0;
Dictionary<ClickableComponent, string> buttons = new();
#region Add buttons with their names IF they are available
#region Character related
string postText = "";
if (__instance.nameBoxCC != null && __instance.nameBoxCC.visible)
{
if (___nameBox.Text != "")
{
postText = $": {___nameBox.Text}";
} else {
postText = " Text Box";
}
buttons.Add(__instance.nameBoxCC, $"Farmer's Name{postText}");
}
if (__instance.farmnameBoxCC != null && __instance.farmnameBoxCC.visible)
{
if (___farmnameBox.Text != "")
{
postText = $": {___farmnameBox.Text}";
} else {
postText = " Text Box";
}
buttons.Add(__instance.farmnameBoxCC, $"Farm's Name{postText}");
}
if (__instance.favThingBoxCC != null && __instance.favThingBoxCC.visible)
{
if (___favThingBox.Text != "")
{
postText = $": {___favThingBox.Text}";
} else {
postText = " Text Box";
}
buttons.Add(__instance.favThingBoxCC, $"Favourite Thing{postText}");
}
if (__instance.petPortraitBox.HasValue) // Cannot get petButtons like with others
{
ClickableComponent petPrev = __instance.getComponentWithID(511);
buttons.Add(petPrev, "Previous pet button");
ClickableComponent petNext = __instance.getComponentWithID(510);
buttons.Add(petNext, "Next pet button");
}
if (__instance.randomButton != null && __instance.randomButton.visible)
buttons.Add(__instance.randomButton, "Random Skin Button");
// Controls to rotate the farmer (Potentially useful for low vision players) are first if they're available.
// They also appear above the gender buttons, so we handle them separately here.
if (characterDesignToggle && new[] {__instance.leftSelectionButtons.Count, __instance.rightSelectionButtons.Count }.All(c => c >= 0)) // both have Count > 0
{
if (new[] {__instance.leftSelectionButtons[DesignControlsIndex].visible, __instance.rightSelectionButtons[DesignControlsIndex].visible }.All(v => v == true) // both visible
&& new[] {__instance.leftSelectionButtons[DesignControlsIndex].name, __instance.rightSelectionButtons[DesignControlsIndex].name }.All(n => n == "Direction")) // both named "Direction"
{
buttons.Add(__instance.leftSelectionButtons[DesignControlsIndex], "Rotate Left Button");
buttons.Add(__instance.rightSelectionButtons[DesignControlsIndex], "Rotate Right Button");
++DesignControlsIndex;
}
}
if (__instance.genderButtons.Count > 0)
{
buttons.Add(__instance.genderButtons[0], ((Game1.player.IsMale) ? "Selected " : "") + "Gender: Male Button");
buttons.Add(__instance.genderButtons[1], ((!Game1.player.IsMale) ? "Selected " : "") + "Gender: Female Button");
}
if (characterDesignToggle&& new[] {__instance.leftSelectionButtons.Count, __instance.rightSelectionButtons.Count }.All(c => c >= DesignControlsIndex) && new[] {__instance.leftSelectionButtons[DesignControlsIndex].visible, __instance.rightSelectionButtons[DesignControlsIndex].visible }.All(v => v == true))
{
while(DesignControlsIndex < __instance.leftSelectionButtons.Count)
{
ClickableComponent left = __instance.leftSelectionButtons[DesignControlsIndex];
ClickableComponent right = __instance.rightSelectionButtons[DesignControlsIndex];
string name = left.name;
// minor cleanup on names to be slightly more descriptive
switch (name)
{
case "Skin":
name += " Tone";
break;
case "Hair":
name += " Style";
break;
case "Acc":
name = "Accessory";
break;
default:
break;
}
if (!buttons.ContainsKey(left) || !buttons.ContainsKey(right))
{
buttons.Add(left, $"Previous {name} button");
buttons.Add(right, $"Next {name} button");
}
//MainClass.ScreenReader.Say($"Left {DesignControlsIndex}: {__instance.leftSelectionButtons[DesignControlsIndex]} {__instance.leftSelectionButtons[DesignControlsIndex].name}\n", true);
//MainClass.ScreenReader.Say($"Right {DesignControlsIndex}: {__instance.rightSelectionButtons[DesignControlsIndex]} {__instance.rightSelectionButtons[DesignControlsIndex].name}\n", true);
++DesignControlsIndex;
}
ClickableComponent eyeColorHue = __instance.getComponentWithID(522);
if (eyeColorHue != null && eyeColorHue.visible)
buttons.Add(eyeColorHue, "eye color hue slider");
ClickableComponent eyeColorSaturation = __instance.getComponentWithID(523);
if (eyeColorSaturation != null && eyeColorSaturation.visible)
buttons.Add(eyeColorSaturation, "eye color saturation slider");
ClickableComponent eyeColorValue = __instance.getComponentWithID(524);
if (eyeColorValue != null && eyeColorValue.visible)
buttons.Add(eyeColorValue, "eye color Value slider");
ClickableComponent hairColorHue = __instance.getComponentWithID(525);
if (hairColorHue != null && hairColorHue.visible)
buttons.Add(hairColorHue, "hair color hue slider");
ClickableComponent hairColorSaturation = __instance.getComponentWithID(526);
if (hairColorSaturation != null && hairColorSaturation.visible)
buttons.Add(hairColorSaturation, "hair color saturation slider");
ClickableComponent hairColorValue = __instance.getComponentWithID(527);
if (hairColorValue != null && hairColorValue.visible)
buttons.Add(hairColorValue, "hair color Value slider");
ClickableComponent pantsColorHue = __instance.getComponentWithID(528);
if (pantsColorHue != null && pantsColorHue.visible)
buttons.Add(pantsColorHue, "pants color hue slider");
ClickableComponent pantsColorSaturation = __instance.getComponentWithID(529);
if (pantsColorSaturation != null && pantsColorSaturation.visible)
buttons.Add(pantsColorSaturation, "pants color saturation slider");
ClickableComponent pantsColorValue = __instance.getComponentWithID(530);
if (pantsColorValue != null && pantsColorValue.visible)
buttons.Add(pantsColorValue, "pants color Value slider");
}
#endregion
#region Farm layout related
if (__instance.farmTypeButtons.Count > 0)
{
for (int i = 0; i < __instance.farmTypeButtons.Count; i++)
{
buttons.Add(__instance.farmTypeButtons[i], ((i == Game1.whichFarm) ? "Selected " : "") + getFarmHoverText(__instance.farmTypeButtons[i]));
}
}
if (__instance.farmTypeNextPageButton != null && __instance.farmTypeNextPageButton.visible)
buttons.Add(__instance.farmTypeNextPageButton, "Next Farm Type Page Button");
if (__instance.farmTypePreviousPageButton != null && __instance.farmTypePreviousPageButton.visible)
buttons.Add(__instance.farmTypePreviousPageButton, "Previous Farm Type Page Button");
#endregion
#region Co-op related
if (__instance.source == CharacterCustomization.Source.HostNewFarm)
{
ClickableComponent cabinLeft = __instance.getComponentWithID(621);
if (Game1.startingCabins > 0)
buttons.Add(cabinLeft, "Decrease starting cabins button");
buttons.Add(___startingCabinsLabel, $"Starting cabins: {Game1.startingCabins}");
ClickableComponent cabinRight = __instance.getComponentWithID(622);
if (Game1.startingCabins < 3)
buttons.Add(cabinRight, "Increase starting cabins button");
if (Game1.startingCabins > 0)
{
buttons.Add(__instance.cabinLayoutButtons[0], "Cabin layout to nearby Button");
buttons.Add(__instance.cabinLayoutButtons[1], "Cabin layout to separate Button");
}
ClickableComponent difficultyLeft = __instance.getComponentWithID(627);
buttons.Add(difficultyLeft, "Increase profit margin button");
buttons.Add(___difficultyModifierLabel, "Profit Margin: " + (((Game1.player.difficultyModifier * 100) == 100f) ? "normal" : Game1.player.difficultyModifier.ToString()));
ClickableComponent difficultyRight = __instance.getComponentWithID(628);
buttons.Add(difficultyRight, "Decrease profit margin button");
ClickableComponent walletLeft = __instance.getComponentWithID(631);
buttons.Add(walletLeft, "Money style to " + ((!Game1.player.team.useSeparateWallets.Value) ? "separate wallets" : "shared wallets") + " button");
}
#endregion
if (__instance.skipIntroButton != null && __instance.skipIntroButton.visible)
buttons.Add(__instance.skipIntroButton, (___skipIntro ? "Enabled" : "Disabled") + " Skip Intro Button");
if (__instance.advancedOptionsButton != null && __instance.advancedOptionsButton.visible)
buttons.Add(__instance.advancedOptionsButton, "Advanced Options Button");
if (__instance.okButton != null && __instance.okButton.visible)
buttons.Add(__instance.okButton, "OK Button");
if (__instance.backButton != null && __instance.backButton.visible)
buttons.Add(__instance.backButton, "Back Button");
#endregion
int size = buttons.Count - 1;
if (increase)
{
saveGameIndex++;
if (saveGameIndex > size)
saveGameIndex = 0;
}
else
{
saveGameIndex--;
if (saveGameIndex < 0)
saveGameIndex = size;
}
currentComponent = buttons.ElementAt(saveGameIndex).Key;
currentComponent!.snapMouseCursor();
__instance.setCurrentlySnappedComponentTo(currentComponent!.myID);
toSpeak = buttons.ElementAt(saveGameIndex).Value;
return toSpeak.Trim();
}
private static string getFarmHoverText(ClickableTextureComponent farm)
{
string hoverTitle = " ", hoverText = " ";
if (!farm.name.Contains("Gray"))
{
if (farm.hoverText.Contains('_'))
{
hoverTitle = farm.hoverText.Split('_')[0];
hoverText = farm.hoverText.Split('_')[1];
}
else
{
hoverTitle = " ";
hoverText = farm.hoverText;
}
}
else
{
if (farm.name.Contains("Gray"))
{
hoverText = "Reach level 10 " + Game1.content.LoadString("Strings\\UI:Character_" + farm.name.Split('_')[1]) + " to unlock.";
}
}
return $"{hoverTitle}: {hoverText}";
}
private static SliderBar? getCurrentSliderBar(int id, CharacterCustomization __instance)
{
if (id >= 522 && id <= 530)
{
// Three ColorPickers with 3 SliderBars each.
// First group ids by ColorPicker.
// Maps 522-524 -> 0, 525-527 -> 1, 528-530 -> 2
int whichColorPicker = (int)Math.Floor(((float)id - 522f) / 3f);
// Next group ids by slider type.
// Maps [522,525,528] -> 0, [523,526,529] -> 1, [524,527,530] -> 2
int whichSliderBar = (int)Math.Floor((float)id % 3f);
ColorPicker cp;
switch (whichColorPicker)
{
default:
case 0:
// 522-524 == eye color
cp = __instance.eyeColorPicker;
break;
case 1:
// 525-527 == hair color
cp = __instance.hairColorPicker;
break;
case 2:
// 528-530 == pants color
cp = __instance.pantsColorPicker;
break;
}
SliderBar sb;
switch (whichSliderBar)
{
default:
case 0:
// 522, 525, 528 == hue slider
sb = cp.hueBar;
break;
case 1:
// 523, 526, 529 == saturation slider
sb = cp.saturationBar;
break;
case 2:
// 524, 527, 530 == value slider
sb = cp.valueBar;
break;
}
return sb;
} else {
return null;
}
}
private static void AdjustCurrentSlider(bool increase, CharacterCustomization __instance, int amount=1)
{
if (currentComponent != null && currentComponent.myID >= 522 && currentComponent.myID <= 530)
{
SliderBar sb = getCurrentSliderBar(currentComponent.myID, __instance) !;
if (sb != null)
{
double step = ((double)sb.bounds.Width / 100d); // size of 1% change in slider value
double value = (double)sb.value;
double x = 0d;
int y = currentComponent.bounds.Center.Y;
if (increase)
{
value = Math.Min(value + amount, 99d);
x = Math.Min(Math.Ceiling((value * step)), (double)sb.bounds.Width);
} else {
value = Math.Max(value - amount, 0d);
x = Math.Max(Math.Ceiling((value * step)), 0d);
}
x += (double)currentComponent.bounds.Left;
Game1.setMousePosition((int)x, y);
Game1.activeClickableMenu.receiveLeftClick((int)x, y);
}
}
}
// Most values (exception noted below) are 0 indexed internally but visually start from 1. Thus we increment before returning.
private static string getCurrentSkin()
{
if (currentComponent != null && (currentComponent.myID == 507 || currentComponent.name == "Skin"))
return $"Skin tone: {Game1.player.skin.Value + 1}";
return "";
}
private static string getCurrentHair()
{
if (currentComponent != null && (currentComponent.myID == 507 || currentComponent.name == "Hair"))
return $"hair style: {Game1.player.hair.Value + 1}";
return "";
}
private static string getCurrentShirt()
{
if (currentComponent != null && (currentComponent.myID == 507 || currentComponent.name == "Shirt"))
return $"Shirt: {Game1.player.shirt.Value + 1}";
return "";
}
private static string getCurrentPants()
{
if (currentComponent != null && (currentComponent.myID == 507 || currentComponent.name == "Pants Style"))
return $"Pants: {Game1.player.pants.Value + 1}";
return "";
}
private static string getCurrentAccessory()
{
// Internally accessory starts from -1 while displaying +1 on screen.
if (currentComponent != null && (currentComponent.myID == 507 || currentComponent.name == "Acc"))
return $"accessory: {Game1.player.accessory.Value + 2}";
return "";
}
private static string getCurrentEyeColor()
{
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 522 && currentComponent.myID <= 524)))
return $"Eye color: {Game1.player.newEyeColor.R}, {Game1.player.newEyeColor.G}, {Game1.player.newEyeColor.B}";
return "";
}
private static string getCurrentEyeColorHue(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(522, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 522 && currentComponent.myID <= 524)))
return sb.value!.ToString();
return "";
}
private static string getCurrentEyeColorSaturation(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(523, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 522 && currentComponent.myID <= 524)))
return sb.value!.ToString();
return "";
}
private static string getCurrentEyeColorValue(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(524, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 522 && currentComponent.myID <= 524)))
return sb.value!.ToString();
return "";
}
private static string getCurrentHairColor()
{
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 525 && currentComponent.myID <= 527)))
return $"Hair color: {Game1.player.hairstyleColor.R}, {Game1.player.hairstyleColor.G}, {Game1.player.hairstyleColor.B}";
return "";
}
private static string getCurrentHairColorHue(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(525, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 525 && currentComponent.myID <= 527)))
return sb.value!.ToString();
return "";
}
private static string getCurrentHairColorSaturation(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(526, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 525 && currentComponent.myID <= 527)))
return sb.value!.ToString();
return "";
}
private static string getCurrentHairColorValue(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(527, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 525 && currentComponent.myID <= 527)))
return sb.value!.ToString();
return "";
}
private static string getCurrentPantsColor()
{
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 528 && currentComponent.myID <= 530)))
return $"Pants color: {Game1.player.pantsColor.R}, {Game1.player.pantsColor.G}, {Game1.player.pantsColor.B}";
return "";
}
private static string getCurrentPantsColorHue(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(528, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 528 && currentComponent.myID <= 530)))
return sb.value!.ToString();
return "";
}
private static string getCurrentPantsColorSaturation(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(529, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 528 && currentComponent.myID <= 530)))
return sb.value!.ToString();
return "";
}
private static string getCurrentPantsColorValue(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(530, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 528 && currentComponent.myID <= 530)))
return sb.value!.ToString();
return "";
}
private static string getCurrentPetName()
{
if (currentComponent != null && currentComponent.name == "Pet")
{
return ((Game1.player.catPerson) ? "Cat" : "Dog") + " Breed: " + Game1.player.whichPetBreed;
} else {
return "";
}
}
}
}

View File

@ -1,5 +1,4 @@
using StardewValley;
using StardewValley.Characters;
using StardewValley.Menus;
using static StardewValley.Menus.CharacterCustomization;
using static StardewValley.Menus.LoadGameMenu;
@ -12,7 +11,27 @@ namespace stardew_access.Patches
private static bool isRunning = false;
public static string characterCreationMenuQueryKey = " ";
public static string advancedGameOptionsQueryKey = " ";
public static string prevPants = " ";
public static string prevShirt = " ";
public static string prevHair = " ";
public static string prevAccessory = " ";
public static string prevSkin = " ";
public static string prevEyeColor = " ";
public static string prevEyeColorHue = " ";
public static string prevEyeColorSaturation = " ";
public static string prevEyeColorValue = " ";
public static string prevHairColor = " ";
public static string prevHairColorHue = " ";
public static string prevHairColorSaturation = " ";
public static string prevHairColorValue = " ";
public static string prevPantsColor = " ";
public static string prevPantsColorHue = " ";
public static string prevPantsColorSaturation = " ";
public static string prevPantsColorValue = " ";
public static string prevPetName = " ";
public static bool characterDesignToggle = false;
public static bool characterDesignToggleShouldSpeak = true;
public static ClickableComponent? currentComponent = null;
internal static void AdvancedGameOptionsPatch(AdvancedGameOptions __instance)
{
@ -248,8 +267,14 @@ namespace stardew_access.Patches
try
{
bool isEscPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Escape); // For escaping/unselecting from the animal name text box
string toSpeak = " ";
string currentPetName = getCurrentPetName();
string toSpeak = "";
if (characterDesignToggleShouldSpeak)
{
toSpeak = "Press left control + space to toggle character appearance controls";
characterDesignToggleShouldSpeak = false;
}
string itemsToSpeak = "";
string changesToSpeak = "";
if (___nameBox.Selected)
{
@ -281,23 +306,65 @@ namespace stardew_access.Patches
else if (MainClass.Config.CharacterCreationMenuNextKey.JustPressed() && !isRunning)
{
isRunning = true;
CycleThroughItems(true, __instance, ___skipIntro, ___startingCabinsLabel, ___difficultyModifierLabel);
itemsToSpeak =CycleThroughItems(true, __instance, ___skipIntro, ___startingCabinsLabel, ___difficultyModifierLabel, ___nameBox, ___farmnameBox, ___favThingBox);
if (itemsToSpeak != "")
toSpeak = $"{itemsToSpeak} \n {toSpeak}";
Task.Delay(200).ContinueWith(_ => { isRunning = false; });
}
else if (MainClass.Config.CharacterCreationMenuPreviousKey.JustPressed() && !isRunning)
{
isRunning = true;
CycleThroughItems(false, __instance, ___skipIntro, ___startingCabinsLabel, ___difficultyModifierLabel);
toSpeak = CycleThroughItems(false, __instance, ___skipIntro, ___startingCabinsLabel, ___difficultyModifierLabel, ___nameBox, ___farmnameBox, ___favThingBox);
Task.Delay(200).ContinueWith(_ => { isRunning = false; });
}
if (prevPetName != currentPetName)
else if (characterDesignToggle && MainClass.Config.CharacterCreationMenuSliderIncreaseKey.JustPressed() && !isRunning)
{
prevPetName = currentPetName;
toSpeak = $"Current Pet: {currentPetName} \n {toSpeak}";
isRunning = true;
AdjustCurrentSlider(true, __instance);
Task.Delay(200).ContinueWith(_ => { isRunning = false; });
}
if (characterCreationMenuQueryKey != toSpeak && toSpeak != " ")
else if (characterDesignToggle && MainClass.Config.CharacterCreationMenuSliderLargeIncreaseKey.JustPressed() && !isRunning)
{
isRunning = true;
AdjustCurrentSlider(true, __instance, 10);
Task.Delay(200).ContinueWith(_ => { isRunning = false; });
}
else if (characterDesignToggle && MainClass.Config.CharacterCreationMenuSliderDecreaseKey.JustPressed() && !isRunning)
{
isRunning = true;
AdjustCurrentSlider(false, __instance);
Task.Delay(200).ContinueWith(_ => { isRunning = false; });
}
else if (characterDesignToggle && MainClass.Config.CharacterCreationMenuSliderLargeDecreaseKey.JustPressed() && !isRunning)
{
isRunning = true;
AdjustCurrentSlider(false, __instance, 10);
Task.Delay(200).ContinueWith(_ => { isRunning = false; });
}
else if (Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.LeftControl) && MainClass.Config.CharacterCreationMenuDesignToggleKey.JustPressed() && !isRunning)
{
string displayState = "";
characterDesignToggle = !characterDesignToggle;
saveGameIndex = Math.Min(saveGameIndex, 5); // move to random skin button if focus was beyond that point
if (characterDesignToggle)
{
displayState = "shown";
} else {
displayState = "hidden";
}
toSpeak = $"Character design controls {displayState}. \n {toSpeak}";
}
changesToSpeak = getChangesToSpeak(__instance);
if (changesToSpeak != "")
toSpeak = $"{toSpeak} \n {changesToSpeak}";
if (characterCreationMenuQueryKey != toSpeak && toSpeak.Trim() != "")
{
characterCreationMenuQueryKey = toSpeak;
MainClass.ScreenReader.Say(toSpeak, true);
@ -309,23 +376,258 @@ namespace stardew_access.Patches
}
}
private static void CycleThroughItems(bool increase, CharacterCustomization __instance, bool ___skipIntro,
ClickableComponent ___startingCabinsLabel, ClickableComponent ___difficultyModifierLabel)
private static string getChangesToSpeak(CharacterCustomization __instance)
{
string toSpeak = "";
string currentPetName = getCurrentPetName();
string currentSkin = getCurrentSkin();
string currentHair = getCurrentHair();
string currentShirt = getCurrentShirt();
string currentPants = getCurrentPants();
string currentAccessory = getCurrentAccessory();
string currentEyeColor = getCurrentEyeColor();
string currentEyeColorHue = getCurrentEyeColorHue(__instance);
string currentEyeColorSaturation = getCurrentEyeColorSaturation(__instance);
string currentEyeColorValue = getCurrentEyeColorValue(__instance);
string currentHairColor = getCurrentHairColor();
string currentHairColorHue = getCurrentHairColorHue(__instance);
string currentHairColorSaturation = getCurrentHairColorSaturation(__instance);
string currentHairColorValue = getCurrentHairColorValue(__instance);
string currentPantsColor = getCurrentPantsColor();
string currentPantsColorHue = getCurrentPantsColorHue(__instance);
string currentPantsColorSaturation = getCurrentPantsColorSaturation(__instance);
string currentPantsColorValue = getCurrentPantsColorValue(__instance);
if (characterDesignToggle)
{
if (prevSkin != currentSkin)
{
prevSkin = currentSkin;
if (currentSkin != "")
toSpeak = $"{toSpeak} \n {currentSkin}";
}
if (prevHair != currentHair)
{
prevHair = currentHair;
if (currentHair != "")
toSpeak = $"{toSpeak} \n {currentHair}";
}
if (prevShirt != currentShirt)
{
prevShirt = currentShirt;
if (currentShirt != "")
toSpeak = $"{toSpeak} \n {currentShirt}";
}
if (prevPants != currentPants)
{
prevPants = currentPants;
if (currentPants != "")
toSpeak = $"{toSpeak} \n {currentPants}";
}
if (prevAccessory != currentAccessory)
{
prevAccessory = currentAccessory;
if (currentAccessory != "")
toSpeak = $"{toSpeak} \n {currentAccessory}";
}
if (prevEyeColorHue != currentEyeColorHue)
{
if (currentComponent != null && currentComponent.myID == 522)
{
prevEyeColorHue = currentEyeColorHue;
if (currentEyeColorHue != "")
toSpeak = $"{toSpeak} \n Hue: {currentEyeColorHue}";
} else {
prevEyeColorHue = "";
}
}
if (prevEyeColorSaturation != currentEyeColorSaturation)
{
if (currentComponent != null && currentComponent.myID == 523)
{
prevEyeColorSaturation = currentEyeColorSaturation;
if (currentEyeColorSaturation != "")
toSpeak = $"{toSpeak} \n Saturation: {currentEyeColorSaturation}";
} else {
prevEyeColorSaturation = "";
}
}
if (prevEyeColorValue != currentEyeColorValue)
{
if (currentComponent != null && currentComponent.myID == 524)
{
prevEyeColorValue = currentEyeColorValue;
if (currentEyeColorValue != "")
toSpeak = $"{toSpeak} \n Value: {currentEyeColorValue}";
} else {
prevEyeColorValue = "";
}
}
if (prevEyeColor != currentEyeColor)
{
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 522 || currentComponent.myID <= 524)))
{
prevEyeColor = currentEyeColor;
if (currentEyeColor != "")
toSpeak = $"{toSpeak} \n {currentEyeColor}";
}
}
if (prevHairColorHue != currentHairColorHue)
{
if (currentComponent != null && currentComponent.myID == 525)
{
prevHairColorHue = currentHairColorHue;
if (currentHairColorHue != "")
toSpeak = $"{toSpeak} \n Hue: {currentHairColorHue}";
} else {
prevHairColorHue = "";
}
}
if (prevHairColorSaturation != currentHairColorSaturation)
{
if (currentComponent != null && currentComponent.myID == 526)
{
prevHairColorSaturation = currentHairColorSaturation;
if (currentHairColorSaturation != "")
toSpeak = $"{toSpeak} \n Saturation: {currentHairColorSaturation}";
} else {
prevHairColorSaturation = "";
}
}
if (prevHairColorValue != currentHairColorValue)
{
if (currentComponent != null && currentComponent.myID == 527)
{
prevHairColorValue = currentHairColorValue;
if (currentHairColorValue != "")
toSpeak = $"{toSpeak} \n Value: {currentHairColorValue}";
} else {
prevHairColorValue = "";
}
}
if (prevHairColor != currentHairColor)
{
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 525 || currentComponent.myID <= 527)))
{
prevHairColor = currentHairColor;
if (currentHairColor != "")
toSpeak = $"{toSpeak} \n {currentHairColor}";
}
}
if (prevPantsColorHue != currentPantsColorHue)
{
if (currentComponent != null && currentComponent.myID == 528)
{
prevPantsColorHue = currentPantsColorHue;
if (currentPantsColorHue != "")
toSpeak = $"{toSpeak} \n Hue: {currentPantsColorHue}";
} else {
prevPantsColorHue = "";
}
}
if (prevPantsColorSaturation != currentPantsColorSaturation)
{
if (currentComponent != null && currentComponent.myID == 529)
{
prevPantsColorSaturation = currentPantsColorSaturation;
if (currentPantsColorSaturation != "")
toSpeak = $"{toSpeak} \n Saturation: {currentPantsColorSaturation}";
} else {
prevPantsColorSaturation = "";
}
}
if (prevPantsColorValue != currentPantsColorValue)
{
if (currentComponent != null && currentComponent.myID == 530)
{
prevPantsColorValue = currentPantsColorValue;
if (currentPantsColorValue != "")
toSpeak = $"{toSpeak} \n Value: {currentPantsColorValue}";
} else {
prevPantsColorValue = "";
}
}
if (prevPantsColor != currentPantsColor)
{
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 528 || currentComponent.myID <= 530)))
{
prevPantsColor = currentPantsColor;
if (currentPantsColor != "")
toSpeak = $"{toSpeak} \n {currentPantsColor}";
}
}
}
if (prevPetName != currentPetName)
{
prevPetName = currentPetName;
if (currentPetName != "")
toSpeak = $"{toSpeak} \n Current Pet: {currentPetName}";
}
return toSpeak.Trim();
}
private static string CycleThroughItems(bool increase, CharacterCustomization __instance, bool ___skipIntro,
ClickableComponent ___startingCabinsLabel, ClickableComponent ___difficultyModifierLabel, TextBox ___nameBox,
TextBox ___farmnameBox, TextBox ___favThingBox)
{
string toSpeak = " ";
int DesignControlsIndex = 0;
Dictionary<ClickableComponent, string> buttons = new();
#region Add buttons with their names IF they are available
#region Character related
string postText = "";
if (__instance.nameBoxCC != null && __instance.nameBoxCC.visible)
buttons.Add(__instance.nameBoxCC, "Farmer's Name Text box");
{
if (___nameBox.Text != "")
{
postText = $": {___nameBox.Text}";
} else {
postText = " Text Box";
}
buttons.Add(__instance.nameBoxCC, $"Farmer's Name{postText}");
}
if (__instance.farmnameBoxCC != null && __instance.farmnameBoxCC.visible)
buttons.Add(__instance.farmnameBoxCC, "Farm's Name Text box");
{
if (___farmnameBox.Text != "")
{
postText = $": {___farmnameBox.Text}";
} else {
postText = " Text Box";
}
buttons.Add(__instance.farmnameBoxCC, $"Farm's Name{postText}");
}
if (__instance.favThingBoxCC != null && __instance.favThingBoxCC.visible)
buttons.Add(__instance.favThingBoxCC, "Favourite Thing Text box");
{
if (___favThingBox.Text != "")
{
postText = $": {___favThingBox.Text}";
} else {
postText = " Text Box";
}
buttons.Add(__instance.favThingBoxCC, $"Favourite Thing{postText}");
}
if (__instance.petPortraitBox.HasValue) // Cannot get petButtons like with others
{
@ -339,11 +641,94 @@ namespace stardew_access.Patches
if (__instance.randomButton != null && __instance.randomButton.visible)
buttons.Add(__instance.randomButton, "Random Skin Button");
// Controls to rotate the farmer (Potentially useful for low vision players) are first if they're available.
// They also appear above the gender buttons, so we handle them separately here.
if (characterDesignToggle && new[] {__instance.leftSelectionButtons.Count, __instance.rightSelectionButtons.Count }.All(c => c >= 0)) // both have Count > 0
{
if (new[] {__instance.leftSelectionButtons[DesignControlsIndex].visible, __instance.rightSelectionButtons[DesignControlsIndex].visible }.All(v => v == true) // both visible
&& new[] {__instance.leftSelectionButtons[DesignControlsIndex].name, __instance.rightSelectionButtons[DesignControlsIndex].name }.All(n => n == "Direction")) // both named "Direction"
{
buttons.Add(__instance.leftSelectionButtons[DesignControlsIndex], "Rotate Left Button");
buttons.Add(__instance.rightSelectionButtons[DesignControlsIndex], "Rotate Right Button");
++DesignControlsIndex;
}
}
if (__instance.genderButtons.Count > 0)
{
buttons.Add(__instance.genderButtons[0], ((Game1.player.IsMale) ? "Selected " : "") + "Gender: Male Button");
buttons.Add(__instance.genderButtons[1], ((!Game1.player.IsMale) ? "Selected " : "") + "Gender: Female Button");
}
if (characterDesignToggle&& new[] {__instance.leftSelectionButtons.Count, __instance.rightSelectionButtons.Count }.All(c => c >= DesignControlsIndex) && new[] {__instance.leftSelectionButtons[DesignControlsIndex].visible, __instance.rightSelectionButtons[DesignControlsIndex].visible }.All(v => v == true))
{
while(DesignControlsIndex < __instance.leftSelectionButtons.Count)
{
ClickableComponent left = __instance.leftSelectionButtons[DesignControlsIndex];
ClickableComponent right = __instance.rightSelectionButtons[DesignControlsIndex];
string name = left.name;
// minor cleanup on names to be slightly more descriptive
switch (name)
{
case "Skin":
name += " Tone";
break;
case "Hair":
name += " Style";
break;
case "Acc":
name = "Accessory";
break;
default:
break;
}
if (!buttons.ContainsKey(left) || !buttons.ContainsKey(right))
{
buttons.Add(left, $"Previous {name} button");
buttons.Add(right, $"Next {name} button");
}
//MainClass.ScreenReader.Say($"Left {DesignControlsIndex}: {__instance.leftSelectionButtons[DesignControlsIndex]} {__instance.leftSelectionButtons[DesignControlsIndex].name}\n", true);
//MainClass.ScreenReader.Say($"Right {DesignControlsIndex}: {__instance.rightSelectionButtons[DesignControlsIndex]} {__instance.rightSelectionButtons[DesignControlsIndex].name}\n", true);
++DesignControlsIndex;
}
ClickableComponent eyeColorHue = __instance.getComponentWithID(522);
if (eyeColorHue != null && eyeColorHue.visible)
buttons.Add(eyeColorHue, "eye color hue slider");
ClickableComponent eyeColorSaturation = __instance.getComponentWithID(523);
if (eyeColorSaturation != null && eyeColorSaturation.visible)
buttons.Add(eyeColorSaturation, "eye color saturation slider");
ClickableComponent eyeColorValue = __instance.getComponentWithID(524);
if (eyeColorValue != null && eyeColorValue.visible)
buttons.Add(eyeColorValue, "eye color Value slider");
ClickableComponent hairColorHue = __instance.getComponentWithID(525);
if (hairColorHue != null && hairColorHue.visible)
buttons.Add(hairColorHue, "hair color hue slider");
ClickableComponent hairColorSaturation = __instance.getComponentWithID(526);
if (hairColorSaturation != null && hairColorSaturation.visible)
buttons.Add(hairColorSaturation, "hair color saturation slider");
ClickableComponent hairColorValue = __instance.getComponentWithID(527);
if (hairColorValue != null && hairColorValue.visible)
buttons.Add(hairColorValue, "hair color Value slider");
ClickableComponent pantsColorHue = __instance.getComponentWithID(528);
if (pantsColorHue != null && pantsColorHue.visible)
buttons.Add(pantsColorHue, "pants color hue slider");
ClickableComponent pantsColorSaturation = __instance.getComponentWithID(529);
if (pantsColorSaturation != null && pantsColorSaturation.visible)
buttons.Add(pantsColorSaturation, "pants color saturation slider");
ClickableComponent pantsColorValue = __instance.getComponentWithID(530);
if (pantsColorValue != null && pantsColorValue.visible)
buttons.Add(pantsColorValue, "pants color Value slider");
}
#endregion
#region Farm layout related
@ -420,18 +805,230 @@ namespace stardew_access.Patches
saveGameIndex = size;
}
buttons.ElementAt(saveGameIndex).Key.snapMouseCursor();
currentComponent = buttons.ElementAt(saveGameIndex).Key;
currentComponent!.snapMouseCursor();
__instance.setCurrentlySnappedComponentTo(currentComponent!.myID);
toSpeak = buttons.ElementAt(saveGameIndex).Value;
if (toSpeak != " ")
return toSpeak.Trim();
}
private static SliderBar? getCurrentSliderBar(int id, CharacterCustomization __instance)
{
if (id >= 522 && id <= 530)
{
MainClass.ScreenReader.Say(toSpeak, true);
// Three ColorPickers with 3 SliderBars each.
// First group ids by ColorPicker.
// Maps 522-524 -> 0, 525-527 -> 1, 528-530 -> 2
int whichColorPicker = (int)Math.Floor(((float)id - 522f) / 3f);
// Next group ids by slider type.
// Maps [522,525,528] -> 0, [523,526,529] -> 1, [524,527,530] -> 2
int whichSliderBar = (int)Math.Floor((float)id % 3f);
ColorPicker cp;
switch (whichColorPicker)
{
default:
case 0:
// 522-524 == eye color
cp = __instance.eyeColorPicker;
break;
case 1:
// 525-527 == hair color
cp = __instance.hairColorPicker;
break;
case 2:
// 528-530 == pants color
cp = __instance.pantsColorPicker;
break;
}
SliderBar sb;
switch (whichSliderBar)
{
default:
case 0:
// 522, 525, 528 == hue slider
sb = cp.hueBar;
break;
case 1:
// 523, 526, 529 == saturation slider
sb = cp.saturationBar;
break;
case 2:
// 524, 527, 530 == value slider
sb = cp.valueBar;
break;
}
return sb;
} else {
return null;
}
}
private static void AdjustCurrentSlider(bool increase, CharacterCustomization __instance, int amount=1)
{
if (currentComponent != null && currentComponent.myID >= 522 && currentComponent.myID <= 530)
{
SliderBar sb = getCurrentSliderBar(currentComponent.myID, __instance) !;
if (sb != null)
{
double step = ((double)sb.bounds.Width / 100d); // size of 1% change in slider value
double value = (double)sb.value;
double x = 0d;
int y = currentComponent.bounds.Center.Y;
if (increase)
{
value = Math.Min(value + amount, 99d);
x = Math.Min(Math.Ceiling((value * step)), (double)sb.bounds.Width);
} else {
value = Math.Max(value - amount, 0d);
x = Math.Max(Math.Ceiling((value * step)), 0d);
}
x += (double)currentComponent.bounds.Left;
Game1.setMousePosition((int)x, y);
Game1.activeClickableMenu.receiveLeftClick((int)x, y);
}
}
}
// Most values (exception noted below) are 0 indexed internally but visually start from 1. Thus we increment before returning.
private static string getCurrentSkin()
{
if (currentComponent != null && (currentComponent.myID == 507 || currentComponent.name == "Skin"))
return $"Skin tone: {Game1.player.skin.Value + 1}";
return "";
}
private static string getCurrentHair()
{
if (currentComponent != null && (currentComponent.myID == 507 || currentComponent.name == "Hair"))
return $"hair style: {Game1.player.hair.Value + 1}";
return "";
}
private static string getCurrentShirt()
{
if (currentComponent != null && (currentComponent.myID == 507 || currentComponent.name == "Shirt"))
return $"Shirt: {Game1.player.shirt.Value + 1}";
return "";
}
private static string getCurrentPants()
{
if (currentComponent != null && (currentComponent.myID == 507 || currentComponent.name == "Pants Style"))
return $"Pants: {Game1.player.pants.Value + 1}";
return "";
}
private static string getCurrentAccessory()
{
// Internally accessory starts from -1 while displaying +1 on screen.
if (currentComponent != null && (currentComponent.myID == 507 || currentComponent.name == "Acc"))
return $"accessory: {Game1.player.accessory.Value + 2}";
return "";
}
private static string getCurrentEyeColor()
{
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 522 && currentComponent.myID <= 524)))
return $"Eye color: {Game1.player.newEyeColor.R}, {Game1.player.newEyeColor.G}, {Game1.player.newEyeColor.B}";
return "";
}
private static string getCurrentEyeColorHue(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(522, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 522 && currentComponent.myID <= 524)))
return sb.value!.ToString();
return "";
}
private static string getCurrentEyeColorSaturation(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(523, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 522 && currentComponent.myID <= 524)))
return sb.value!.ToString();
return "";
}
private static string getCurrentEyeColorValue(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(524, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 522 && currentComponent.myID <= 524)))
return sb.value!.ToString();
return "";
}
private static string getCurrentHairColor()
{
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 525 && currentComponent.myID <= 527)))
return $"Hair color: {Game1.player.hairstyleColor.R}, {Game1.player.hairstyleColor.G}, {Game1.player.hairstyleColor.B}";
return "";
}
private static string getCurrentHairColorHue(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(525, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 525 && currentComponent.myID <= 527)))
return sb.value!.ToString();
return "";
}
private static string getCurrentHairColorSaturation(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(526, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 525 && currentComponent.myID <= 527)))
return sb.value!.ToString();
return "";
}
private static string getCurrentHairColorValue(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(527, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 525 && currentComponent.myID <= 527)))
return sb.value!.ToString();
return "";
}
private static string getCurrentPantsColor()
{
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 528 && currentComponent.myID <= 530)))
return $"Pants color: {Game1.player.pantsColor.R}, {Game1.player.pantsColor.G}, {Game1.player.pantsColor.B}";
return "";
}
private static string getCurrentPantsColorHue(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(528, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 528 && currentComponent.myID <= 530)))
return sb.value!.ToString();
return "";
}
private static string getCurrentPantsColorSaturation(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(529, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 528 && currentComponent.myID <= 530)))
return sb.value!.ToString();
return "";
}
private static string getCurrentPantsColorValue(CharacterCustomization __instance)
{
SliderBar sb = getCurrentSliderBar(530, __instance)!;
if (currentComponent != null && (currentComponent.myID == 507 || (currentComponent.myID >= 528 && currentComponent.myID <= 530)))
return sb.value!.ToString();
return "";
}
private static string getCurrentPetName()
{
return ((Game1.player.catPerson) ? "Cat" : "Dog") + " Breed: " + Game1.player.whichPetBreed;
if (currentComponent != null && currentComponent.name == "Pet")
{
return ((Game1.player.catPerson) ? "Cat" : "Dog") + " Breed: " + Game1.player.whichPetBreed;
} else {
return "";
}
}
private static string getFarmHoverText(ClickableTextureComponent farm)

View File

@ -12,8 +12,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Lib.Harmony" Version="2.2.0" />
<PackageReference Include="Pathoschild.Stardew.ModBuildConfig" Version="4.0.0" />
<PackageReference Include="Lib.Harmony" Version="2.2.2" />
<PackageReference Include="newtonsoft.json" Version="13.0.2" />
<PackageReference Include="Pathoschild.Stardew.ModBuildConfig" Version="4.1.0" />
<Reference Include="./TolkDotNet.dll" />
</ItemGroup>