Table of Contents

Class InteractiveBehaviour

Namespace
GrindFest
Assembly
GrindFest.dll
[DisallowMultipleComponent]
[DefaultExecutionOrder(1)]
public class InteractiveBehaviour : MonoBehaviour
Inheritance
object
InteractiveBehaviour
Derived

Fields

AlwaysShowTooltips
Burnable
CanBeAttacked
CanBeDragged

When false, a drag never starts on this object: OnPlayerDrag(HeroController) returns before anything is touched. Gold, arrows and cursed coins are picked up by hovering and must not be carried around.

Why a flag and not just OnDrag = null, which is what those three components used to do: OnDrag is a plain delegate field, GoldBehaviour.OnEnable cleared it, and ItemBehaviour.Start() subscribes to it again - and Start runs after OnEnable. So a pile that was created fresh and never recycled ended up draggable while one that had been through LeanPool did not (measured 2026-09-23: all 7 live gold piles had OnDrag set, one from the pool had it null; arrows and coins never cleared it at runtime at all, only in OnValidate, which is editor-only and writes no serialized state). One gate that the drag path reads cannot be undone by callback order.

CanInteractDelegate
Character
Combat
ComparedNameplate
CraftingStation
CursorTexture
CustomNameProvider
DoubleClickEnabled
HighlightColor
HighlightMaterial
Highlightable
IsDisabled
IsDragged
IsHovered
Item
KeepUprightWhenCarried
LiquidContainer
Monster
Nameplate
NameplateColor
NameplateText
OnDisplayTooltip

Event handler for displaying tooltips with priority ordering.

OnDrag
OnHover
Priority
Renderers
ShowNameplate
UnityClick

Methods

AddDoubleClickHandler(int, string, Func<HeroController, bool>)
Awake()
CanInteract(HeroController)
CreateNameplate(HeroController, InteractiveBehaviour)
OnDisable()
OnEnable()
OnHear(SpeechBehaviour, string)
OnPlayerClick(HeroController)
OnPlayerClicking(HeroController)
OnPlayerDoubleClick(HeroController)
OnPlayerDrag(HeroController)
OnPlayerDropOn(HeroController, InteractiveBehaviour)
OnPlayerDroppedOnGround(HeroController)

On player drop on ground

OnPlayerHover(HeroController)
OnPlayerHoverEnd(HeroController)
OnValidate()
RefreshNameplateScreenPosition()

Projects this label to screen space and places its compare half. Called once per frame from TooltipManager's render callback, NOT from Update.

Why the render callback: Cinemachine moves the camera in LateUpdate, so a WorldToScreenPoint done during Update uses the previous frame's camera - the label trails the object it points at by exactly one frame of camera motion. Measured 2026-09-23 while the hero was running: 0.06 units of drift per frame from Update, 0.0000 over 8 of 8 frames from a render-time hook.

This is also the ONLY place the comparison half is placed, and it has to be driven from HERE (the item being compared) rather than from the half itself: the half carries the OTHER item's InteractiveBehaviour, whose own label does not exist while simply holding Ctrl - driving it through that item did nothing at all, so the half kept a stale position and the two halves of one comparison ended up far apart (measured 2026-09-23 with Ctrl+Alt on a Stick: the comparison sat on the item and the Stick's own label was pushed 189 px away, which reads as "the comparison stopped working").

SetRenderers()
UpdateRenderers()

Events

Click
Hear
OnDoubleClick

Subscribe a default-priority (7) handler. For handlers that need to consume the event or need a specific priority, use AddDoubleClickHandler(int, string, Func<HeroController, bool>).

OnDrop
OnDropOn
OnReceiveDrop

Operators

implicit operator InteractiveBehaviour(InteractiveBehaviour)

Implicit conversion from InteractiveBehaviour to simplified Isolated.InteractiveBehaviour for serialization across isolation boundary.

implicit operator InteractiveBehaviour(InteractiveBehaviour)

Implicit conversion from Isolated.InteractiveBehaviour to full InteractiveBehaviour by EntityId hash lookup.