Skip to content

Add a setting that starts new stands out of shift use, and mark a stand while its buttons are hovered - #28

Merged
beverage merged 2 commits into
mainfrom
feature/new-stand-setting
Oct 29, 2026
Merged

beverage merged 2 commits into
mainfrom
feature/new-stand-setting

Conversation

@beverage

@beverage beverage commented Oct 29, 2026 •

Copy link
Copy Markdown
Owner

Every outfit stand starts in service. It reads its room, holds "Allow removing items" off and keeps its contents out of trade, whether or not the room gives it anything to dress for. A player with about 30 stands asked on the Workshop page for a way to stop new stands becoming shift stands, because the only way out was opening each stand's settings in turn. This branch adds a mod setting for that, and corrects the description of Unassigned stands are shared, which promised more than the setting does.

The same request raised a second problem. With several stands selected, each stand shows its own switch and Set owner button, and nothing on a pair says which stand it belongs to. Hovering either button now marks its stand on the map.

The setting

New stands are used for shift changes, on by default and first in the mod settings. Turned off, a new stand starts as "Not used for shift changes", which leaves it vanilla: the removal toggle is the player's and the contents can be traded.

It is read in CompShiftStand.PostPostMake, which only ThingMaker.MakeThing reaches (through ThingWithComps.PostMake). A finished frame makes its building that way, in Frame.CompleteConstruction. A load builds the comp in ThingWithComps.ExposeData instead and reads excluded back from the save, and a stand boxed and set down again is the same object (MinifyUtility.MakeMinified keeps it as the InnerThing). So flipping the setting changes no stand that already exists. A stand bought from a trader takes the setting as it was when the trader's stock was generated.

DebugTools_Fixtures.Spawn now puts every stand it makes in service, so the harness and the media stages do not depend on the profile they run in.

The pooling description

With Unassigned stands are shared off, the description said every unassigned stand "behaves exactly like vanilla furniture". Such a stand dresses nobody, but it is still declared in service, and the removal-toggle lock and trade withholding key on that declaration (Patch_AllowRemovingToggle, CompShiftStand.BlocksTrade), not on whether the stand has an owner. The setting's behaviour is unchanged. The keyed string, the code comment, the README and DESIGN.md now say what it does, and point at "Not used for shift changes" for a stand that should be ordinary furniture.

The hover mark

Both buttons set Command_Action.onHover, which MapGizmoUtility.MapUIUpdate calls every frame the button is hovered, from the map interface's update. It calls CompShiftStand.PointAt, which draws two vanilla marks:

  • The arrow from TargetHighlighter.Highlight, which a storage link's button also shows on hover. Within nine cells of the screen centre it sits just below the stand and points up at it. Further out it is drawn seven cells from the centre and only gives a direction.
  • GenDraw.DrawTargetHighlight, the pulsing square a targeter puts on the thing under the cursor, drawn above the building layer. It marks the stand wherever it is on screen.

The highlighter can also draw a circle, but it is drawn at the building's own altitude with a radius of half the footprint, and in lab captures the stand's sprite and the selection brackets covered nearly all of it. The Set owner button is the base comp's gizmo, so its hover is chained: anything another mod put there still runs, then ours.

Testing

HarnessTriggers.NewStandSettingDecidesOnlyNewStands makes stands through ThingMaker.MakeThing. With the setting on, the new stand is automatic. With it off, the new stand is excluded and stays excluded once spawned. Spawned with "Allow removing items" on, it keeps it on, where a stand in service would force it off, and its contents can be traded. The fixture's own stand, made before the flip, stays in service.

The save round trip (DebugTools_SaveRoundTrip.RoundTrip) now loads its save with the setting off and asserts the loaded stand still comes back in service.

HarnessGizmos.HoveredButtonsMarkTheirOwnStand spawns a second stand and calls onHover on all four buttons. It reads the arrow from TargetHighlighter's private arrow list, and the square from GenDraw.CurTargetingMat, whose getter rewrites the material's colour each time: a colour set beforehand changes only if the square was drawn. Each button has to mark its own stand and not the other. Then the second stand is destroyed and a switch taken from it beforehand is hovered, which has to mark nothing, since vanilla keeps calling the last hovered button while another main tab is open.

Three mutants were run against it, and in each this case was the only one to fail. With the square removed from PointAt, the five lines that need it fail, each still reporting one arrow. With the map guard removed, only the destroyed-stand line fails, because the square is drawn for a stand that is gone. With the Set owner hover removed, both Set owner buttons fail their "has a hover action" line.

Game Mod list Result
1.7.4990 rev1069 Harmony, Core, Odyssey, Shift Change 128 passed, 0 failed, 7 known gaps
1.6.4871 not run

Six of the gaps are mods not on the list: Outfit Stands Plus, Complex Jobs, Common Sense, Pick Up And Haul, and Rimatomics twice. The seventh is the recolor case, since only Odyssey is active. The run was on this branch's head. check-invariants.py passes, and check-shipped-dll.py passes on the Release build the runner leaves behind and on the committed dll.

Not covered

The setting's case has not been run against main, so it has not been seen failing. No stand has been built from a frame in play with the setting off: the case calls ThingMaker.MakeThing directly, which is the call the frame makes.

The two marks have been seen only in lab captures on 1.7 at 1920×1080 with 30 stands selected, hovering one stand's switch near the screen centre and another stand's Set owner button far from it. Those captures predate the review changes, which reworded comments, chained the Set owner hover and extended the case, and changed nothing that is drawn. The chained hover runs no other mod's code here, since no mod on the list adds a hover to the Set owner button.

Left out on purpose

The dll is not in this branch; it is built and committed at the release merge. For translators, two English keys are new (ShiftChange.SettingNewStandsInService and ShiftChange.SettingNewStandsInServiceDesc) and one is reworded (ShiftChange.SettingPoolUnassignedDesc); the hover mark adds none. Editing several selected stands at once, the other half of the same Workshop request, is a separate change.

🤖 Generated with Claude Code

beverage and others added 2 commits October 29, 2026 02:08
…say what the pooling setting leaves on

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@beverage beverage changed the title Add a setting that starts newly built stands out of shift use Add a setting that starts new stands out of shift use, and mark a stand while its buttons are hovered Oct 29, 2026
@beverage
beverage merged commit 11b9c7b into main Oct 29, 2026
2 checks passed
@beverage
beverage deleted the feature/new-stand-setting branch October 29, 2026 13:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant