Specific activable component condition (for conditional components conditions and area victory conditions)

Feature: Specific Activable component condition for Conditional Components and Area Victory Conditions

Plan d'implémentation généré (pas encore relu): 471.zip

Summary

Add a new detection mode DETECTION_SPECIFIC_ACTIVABLE_COMPONENT to both conditional blocks (IDetectionComponent) and area victory conditions. This condition mirrors the active/inactive state of another component within the same area.

UI

When this mode is selected (in ComponentConditionsMenuInventory or AreaConditionsMenuInventory — same layout for both), instead of the usual range (min/max) controls, 4 items are displayed:

  • A button to open a shortcut bar for selecting the target component (similar to the solidifier's sender selection shortcut bar; texture: TO CREATE, use COMPONENT_MENU_CONDITIONS_OPEN_MENU as placeholder).
  • A non-clickable label (texture: same as COMPONENT_MENU_CONDITIONS_OPEN_MENU).
  • A checkbox: if checked → activated when target is activated; if unchecked → activated when target is NOT activated.
  • A teleport button (texture: same as SOLIDIFIER_TARGET_SENDERS_TELEPORT).

Constraints

  • Storage: New database fields required for both ComponentEntity and AreaEntity. Do not reuse existing fields.
  • Same area: The target must belong to the same area.
  • Not self: A component cannot target itself.
  • Target must be activable: Must implement a future IActivableComponent interface (see below).
  • Loop detection: Circular references (A → B → … → A) must be detected and rejected at selection time. Requires graph cycle detection (transitive walk).
  • Lifecycle ordering: A 0–1 tick delay between source and dependent activation is expected (or N ticks for chained conditions). Out of scope for now.

Edge cases

  • Targeted component is deleted → clean up the reference (reset mode or clear target). Note: LaserSolidifier has the same bug today (dangling targetSenderIds when a sender is deleted) — fix both.
  • User switches to another detection mode → clear the stored target.

Schematics

Component IDs change during paste, so target references become dangling. This is the same unsolved problem as LaserSolidifier.targetSenderIds (IDs are not remapped today). Fix solidifier schematic remapping in the same scope.

Activable components

A new IActivableComponent interface with boolean isActivated() is needed. Many components have an active/inactive state but use different method names today.

Eligible components

Component Current method State semantics
LaserSender isActivated() (via IDetectionComponent) Active per its own DetectionMode
WinnerBlock isActivated() (via IDetectionComponent) Active when receiver count ∈ [min, max]
AppearingWinnerBlock isActivated() (via IDetectionComponent) Active → block appears
DisappearingWinnerBlock isActivated() (via IDetectionComponent) Active → block disappears
Elevator isActivated() (via IDetectionComponent) Active → can move
MusicBlock isActivated() (via IDetectionComponent) Active → plays music
LaserSolidifier isActivated() (via IDetectionComponent) Active → places glass blocks
LaserReceiver isActivated() Activated by a laser of the correct color
RedstoneSensor isPowered() Powered by redstone
Lock isOpened() Opened (global state, set when any player with all keys clicks it)
BurnableBlock !isMelted() Active while visible (!melted); inactive once melted (invisible, not destroyed — reset on area reactivation)
Bonus via BonusRegistry Active if at least 1 player has obtained it during the current run

Excluded

  • Concentrator: active state is implicit (side-effect of laser movement each tick, not stored). Too complex for v1.

Technical concerns

  1. Schematic ID remapping: Must be solved generically for both LaserSolidifier.targetSenderIds and the new target component reference. During paste, old component IDs must be mapped to newly created IDs.

  2. Bonus per-player state: Bonus has no global boolean. Definition for this mode: activated if ≥1 player has obtained it this run (query BonusRegistry).

  3. Cascade update ordering: ComponentCounterUpdateService.updateDetectionComponents() iterates in unspecified order. With chains (A → B → C), delay can compound to N ticks. Acknowledged as out of scope.

Edited by Benjamin