Skip to content

Commit 841d015

Browse files
committed
Release 1.1.7
1 parent 6a0a0b1 commit 841d015

22 files changed

Lines changed: 785 additions & 196 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ ipch/
118118
*.vspx
119119
*.sap
120120

121+
# GMCM build artifact created by mod build config.
122+
StarControl.Gmcm/*Undefined*StarControl/
123+
121124
# Visual Studio Trace Files
122125
*.e2e
123126

CHANGELOG.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,27 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7-
## [1.1.7-experimental.5] - 2025-12-23
7+
## [1.1.7] - 2025-12-23
88

99
### Added
1010

1111
- PlayStation button icon set and selector (Controls tab).
12-
- New UI sprite variants: `UI.Xbox.png` and `UI.PlayStation.png`.
13-
- Button icon set config option with a restart notice.
12+
- Instant Actions menu item in the mod wheel with visibility toggle.
13+
- PlayStation button spritemap and sprite sheet variants.
1414

1515
### Changed
1616

17-
- Button icon selection now swaps and reloads the UI sprite sheet in-game.
18-
- Updated attributions for PlayStation button icons.
19-
- Tooltip popups removed from the Defaults/Cancel/Save buttons to prevent overlap.
17+
- Button icon selector moved to the Controls tab.
18+
- Button icon switching now reloads UI sprites in-game (close and reopen the menu if needed).
19+
- Control prompts and mod-menu keybind editor respect the selected icon set.
20+
- Quick action menu slot content scaled up while keeping the menu size the same.
21+
- Instant Actions (remapping) menu layout adjusted to better fit smaller screens; middle list now scrolls with a visible scrollbar.
2022

2123
### Fixed
2224

23-
- Button icon swaps now invalidate all UI sprites so switching back works reliably.
25+
- Button icon switching now reliably toggles back and forth.
26+
- Controls tab button mapping labels wrap cleanly.
27+
- Defaults/Cancel/Save tooltips removed to avoid overlap on smaller screens.
2428

2529
---
2630

StarControl/Config/ItemsConfiguration.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,30 @@ public class ItemsConfiguration : IConfigEquatable<ItemsConfiguration>
5454
/// </remarks>
5555
public bool ShowSettingsItem { get; set; } = true;
5656

57+
/// <summary>
58+
/// Whether to display the Instant Actions item on page
59+
/// <see cref="InstantActionsItemPageIndex"/> and at position
60+
/// <see cref="InstantActionsItemPositionIndex"/>.
61+
/// </summary>
62+
/// <remarks>
63+
/// The Instant Actions item always exists and always has a specific location, but can be
64+
/// suppressed from the Mod Menu during gameplay. It will still appear in the configuration
65+
/// menu when editing the menu items.
66+
/// </remarks>
67+
public bool ShowInstantActionsItem { get; set; } = true;
68+
5769
/// <summary>
5870
/// The zero-based page number on which to show the Star Control Settings item, which brings up
5971
/// the configuration menu.
6072
/// </summary>
6173
public int SettingsItemPageIndex { get; set; }
6274

75+
/// <summary>
76+
/// The zero-based page number on which to show the Instant Actions item, which brings up the
77+
/// remapping (instant actions) menu.
78+
/// </summary>
79+
public int InstantActionsItemPageIndex { get; set; }
80+
6381
/// <summary>
6482
/// The zero-based position within the specific Mod Menu Page identified by
6583
/// <see cref="SettingsItemPageIndex"/> where the Star Control Settings item should be shown.
@@ -70,6 +88,16 @@ public class ItemsConfiguration : IConfigEquatable<ItemsConfiguration>
7088
/// </remarks>
7189
public int SettingsItemPositionIndex { get; set; }
7290

91+
/// <summary>
92+
/// The zero-based position within the specific Mod Menu Page identified by
93+
/// <see cref="InstantActionsItemPageIndex"/> where the Instant Actions item should be shown.
94+
/// </summary>
95+
/// <remarks>
96+
/// The item will be inserted <em>before</em> the specified index, so an index of <c>0</c> means
97+
/// it will be the first item on that page.
98+
/// </remarks>
99+
public int InstantActionsItemPositionIndex { get; set; }
100+
73101
/// <summary>
74102
/// Map of all quick-slot buttons to the corresponding quick slot item (if any).
75103
/// </summary>
@@ -164,8 +192,11 @@ public bool Equals(ItemsConfiguration? other)
164192
(page1, page2) => page1.SequenceEqual(page2, (item1, item2) => item1.Equals(item2))
165193
)
166194
&& ShowSettingsItem == other.ShowSettingsItem
195+
&& ShowInstantActionsItem == other.ShowInstantActionsItem
167196
&& SettingsItemPageIndex == other.SettingsItemPageIndex
197+
&& InstantActionsItemPageIndex == other.InstantActionsItemPageIndex
168198
&& SettingsItemPositionIndex == other.SettingsItemPositionIndex
199+
&& InstantActionsItemPositionIndex == other.InstantActionsItemPositionIndex
169200
&& QuickSlots.Count == other.QuickSlots.Count
170201
&& QuickSlots.IsEquivalentTo(other.QuickSlots, (slot1, slot2) => slot1.Equals(slot2));
171202
}

StarControl/Graphics/Sprites.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,19 @@ public static class Sprites
99
/// Asset path for the mod's own UI tile sheet.
1010
/// </summary>
1111
public const string UI_TEXTURE_PATH = "Mods/focustense.StarControl/Sprites/UI";
12+
public const string UI_PLAYSTATION_TEXTURE_PATH =
13+
"Mods/focustense.StarControl/Sprites/UI.PlayStation";
1214

1315
/// <summary>
1416
/// Sprite of a book, used for the built-in journal item.
1517
/// </summary>
1618
public static Sprite? Book() => Sprite.TryLoad(UI_TEXTURE_PATH, new(32, 64, 15, 16));
1719

20+
/// <summary>
21+
/// Sprite of a gamepad, used for the Instant Actions menu item.
22+
/// </summary>
23+
public static Sprite? Gamepad() => Sprite.TryLoad(UI_TEXTURE_PATH, new(0, 0, 16, 16));
24+
1825
/// <summary>
1926
/// Gets the default error item sprite used for missing items.
2027
/// </summary>
@@ -25,6 +32,11 @@ public static class Sprites
2532
/// </summary>
2633
public static Sprite? Hammer() => Sprite.TryLoad(UI_TEXTURE_PATH, new(0, 64, 16, 16));
2734

35+
/// <summary>
36+
/// Sprite of a bug net, used for the Instant Actions menu item.
37+
/// </summary>
38+
public static Sprite? BugNet() => Sprite.TryLoad(UI_TEXTURE_PATH, new(64, 0, 16, 16));
39+
2840
/// <summary>
2941
/// Sprite of a letter (envelope), used for the built-in mailbox item.
3042
/// </summary>

StarControl/Menus/ModMenu.cs

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ internal class ModMenu(
1111
IMenuToggle toggle,
1212
ModConfig config,
1313
ModMenuItem settingsItem,
14+
ModMenuItem instantActionsItem,
1415
Action<ModMenuItemConfiguration> shortcutActivator,
1516
IInvalidatableList<IRadialMenuPage> additionalPages,
1617
Func<int> userPageIndexSelector,
@@ -98,16 +99,23 @@ private IReadOnlyList<IRadialMenuPage> GetCombinedPages()
9899
pageConfig,
99100
standaloneItems,
100101
shortcutActivator,
101-
config.Items.ShowSettingsItem && pageIndex == config.Items.SettingsItemPageIndex
102-
? InsertSettingsItem
102+
pageIndex == config.Items.SettingsItemPageIndex && config.Items.ShowSettingsItem
103+
|| pageIndex == config.Items.InstantActionsItemPageIndex
104+
&& config.Items.ShowInstantActionsItem
105+
? items => InsertBuiltInItems(items, pageIndex)
103106
: null
104107
)
105108
);
106109
pageIndex++;
107110
}
108-
if (userPages.Count == 0 && config.Items.ShowSettingsItem)
111+
if (
112+
userPages.Count == 0
113+
&& (config.Items.ShowSettingsItem || config.Items.ShowInstantActionsItem)
114+
)
109115
{
110-
userPages.Add(new MenuPage<IRadialMenuItem>([settingsItem], _ => false));
116+
var pageItems = new List<IRadialMenuItem>();
117+
InsertBuiltInItems(pageItems, pageIndex: 0);
118+
userPages.Add(new MenuPage<IRadialMenuItem>(pageItems, _ => false));
111119
}
112120
var pages = new List<IRadialMenuPage>(additionalPages);
113121
pages.InsertRange(userPageIndexSelector(), userPages);
@@ -118,14 +126,39 @@ private IReadOnlyList<IRadialMenuPage> GetCombinedPages()
118126
);
119127
return pages;
120128

121-
void InsertSettingsItem(List<IRadialMenuItem> items)
129+
void InsertBuiltInItems(List<IRadialMenuItem> items, int pageIndex)
122130
{
123-
var index = Math.Clamp(config.Items.SettingsItemPositionIndex, 0, items.Count - 1);
124-
items.Insert(index, settingsItem);
125-
Logger.Log(
126-
LogCategory.Menus,
127-
$"Inserted built-in Mod Settings item at position {index}."
128-
);
131+
var inserts = new List<(int Index, IRadialMenuItem Item, string LogName)>();
132+
if (config.Items.ShowSettingsItem && pageIndex == config.Items.SettingsItemPageIndex)
133+
{
134+
inserts.Add((config.Items.SettingsItemPositionIndex, settingsItem, "Mod Settings"));
135+
}
136+
if (
137+
config.Items.ShowInstantActionsItem
138+
&& pageIndex == config.Items.InstantActionsItemPageIndex
139+
)
140+
{
141+
inserts.Add(
142+
(
143+
config.Items.InstantActionsItemPositionIndex,
144+
instantActionsItem,
145+
"Instant Actions"
146+
)
147+
);
148+
}
149+
if (inserts.Count == 0)
150+
{
151+
return;
152+
}
153+
foreach (var insert in inserts.OrderBy(entry => entry.Index))
154+
{
155+
var index = Math.Clamp(insert.Index, 0, items.Count);
156+
items.Insert(index, insert.Item);
157+
Logger.Log(
158+
LogCategory.Menus,
159+
$"Inserted built-in {insert.LogName} item at position {index}."
160+
);
161+
}
129162
}
130163
}
131164
}

StarControl/Menus/QuickSlotRenderer.cs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace StarControl.Menus;
88
internal class QuickSlotRenderer(GraphicsDevice graphicsDevice, ModConfig config)
99
{
1010
private const float MENU_SCALE = 0.7f; // scales the entire quick action menu
11+
private const float SLOT_CONTENT_SCALE = 1.2f; // scales slot visuals without moving the menu
1112

1213
private record ButtonFlash(FlashType Type, float DurationMs, float ElapsedMs = 0);
1314

@@ -53,7 +54,6 @@ private enum PromptPosition
5354
private readonly Dictionary<SButton, ButtonFlash> flashes = [];
5455
private readonly HashSet<SButton> enabledSlots = [];
5556
private readonly Dictionary<SButton, Sprite> slotSprites = [];
56-
private readonly Texture2D uiTexture = Game1.content.Load<Texture2D>(Sprites.UI_TEXTURE_PATH);
5757
private readonly GraphicsDevice graphicsDevice = graphicsDevice;
5858

5959
private Color disabledBackgroundColor = Color.Transparent;
@@ -62,6 +62,8 @@ private enum PromptPosition
6262
private float quickSlotScale = 1f;
6363
private Texture2D outerBackground = null!;
6464
private Texture2D slotBackground = null!;
65+
private Texture2D? uiTexture;
66+
private ButtonIconSet? uiTextureIconSet;
6567

6668
public void Draw(SpriteBatch b, Rectangle viewport)
6769
{
@@ -277,7 +279,7 @@ private void DrawSlot(
277279
}
278280

279281
var isEnabled = enabledSlots.Contains(button);
280-
var backgroundRect = GetCircleRect(origin, Scale(SLOT_SIZE / 2f));
282+
var backgroundRect = GetCircleRect(origin, Scale(SLOT_SIZE * SLOT_CONTENT_SCALE / 2f));
281283
if (darken)
282284
{
283285
var darkenRect = backgroundRect;
@@ -291,7 +293,10 @@ private void DrawSlot(
291293

292294
if (isAssigned)
293295
{
294-
var spriteRect = GetCircleRect(origin, Scale(IMAGE_SIZE * 1f * MENU_SCALE / 2f));
296+
var spriteRect = GetCircleRect(
297+
origin,
298+
Scale(IMAGE_SIZE * MENU_SCALE * SLOT_CONTENT_SCALE / 2f)
299+
);
295300
if (SlotItems.TryGetValue(button, out var item) && item.Texture is not null)
296301
{
297302
ItemRenderer.Draw(
@@ -315,7 +320,7 @@ private void DrawSlot(
315320

316321
if (GetPromptSprite(button) is { } promptSprite)
317322
{
318-
var promptOffset = Scale(PROMPT_OFFSET);
323+
var promptOffset = Scale(PROMPT_OFFSET * SLOT_CONTENT_SCALE);
319324
var promptOrigin = promptPosition switch
320325
{
321326
PromptPosition.Above => origin.AddY(-promptOffset),
@@ -327,7 +332,10 @@ private void DrawSlot(
327332
nameof(promptPosition)
328333
),
329334
};
330-
var promptRect = GetCircleRect(promptOrigin, Scale(PROMPT_SIZE / 2f));
335+
var promptRect = GetCircleRect(
336+
promptOrigin,
337+
Scale(PROMPT_SIZE * SLOT_CONTENT_SCALE / 2f)
338+
);
331339
b.Draw(
332340
promptSprite.Texture,
333341
promptRect,
@@ -404,7 +412,23 @@ private static Sprite GetIconSprite(IconConfig icon)
404412
{
405413
return null;
406414
}
407-
return new(uiTexture, new(columnIndex * 16, rowIndex * 16, 16, 16));
415+
var texture = GetUiTexture();
416+
return new(texture, new(columnIndex * 16, rowIndex * 16, 16, 16));
417+
}
418+
419+
private Texture2D GetUiTexture()
420+
{
421+
var desiredSet = config.Style.ButtonIconSet;
422+
if (uiTexture is null || uiTextureIconSet != desiredSet)
423+
{
424+
var assetPath =
425+
desiredSet == ButtonIconSet.PlayStation
426+
? Sprites.UI_PLAYSTATION_TEXTURE_PATH
427+
: Sprites.UI_TEXTURE_PATH;
428+
uiTexture = Game1.content.Load<Texture2D>(assetPath);
429+
uiTextureIconSet = desiredSet;
430+
}
431+
return uiTexture;
408432
}
409433

410434
private Sprite? GetSlotSprite(IItemLookup itemLookup)

StarControl/Menus/RadialMenuController.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,15 @@ public void Update(TimeSpan elapsed)
164164
activeMenu = menu;
165165
if (previousActiveMenu is null && activeMenu is not null)
166166
{
167+
InputPatches.RightStickCursorDeadZone = Math.Clamp(
168+
config.Input.ThumbstickDeadZone + 0.05f,
169+
0.1f,
170+
0.6f
171+
);
167172
InputPatches.AwaitRightStickMoveForCursor();
168173
InputPatches.ForceHideCursor = true;
169174
ResetMouseToPlayer();
175+
InputPatches.NotifyMousePositionReset();
170176
AnimateMenuOpen(elapsed); // Skip "zero" frame
171177
}
172178
}
@@ -352,6 +358,8 @@ private void Reset(bool fromActivation = false)
352358
ResetMouseToPlayer();
353359
InputPatches.SuppressRightStickFor(InputPatches.RightStickSuppressionDuration);
354360
}
361+
InputPatches.AwaitRightStickMoveForCursor();
362+
InputPatches.NotifyMousePositionReset();
355363
usedRightStickInMenu = false;
356364
if (fromActivation)
357365
{

0 commit comments

Comments
 (0)