Laboratory
Overview
Core production building that can send output via Routes, earn money, and optionally convert excess production into Control or Loyalty based on mode and personality. Supports maintenance costs, pause, control-gain mode, upgrade level, and runtime save/load of key fields. Registers with LabGroupRegistrar and participates in the global tick as a Lab type.
Serialized Atoms
- FloatVariable
moneyPerUnit,currentMoney - FloatVariable
routeBaseCost,routeCostPerNode,routeRefund,routeCostMultiplier - FloatVariable
controlGainPerStar,loyalty,labMaintenanceCost - VoidEvent
monthlyTick— triggers maintenance. - BoolVariable
controlToLoyaltyMode - IntVariable
selectedPersonality
Production Settings
- float
baseProduction(default0.5) - float
bonusProduction(default0) - float
TotalProduction(read-only) = base + bonus
Runtime State
List<Route> routes(read-only in inspector)Region regionbool ProductionPaused— toggles visual pause on routesbool ControlGainMode— converts all production to Control whentrueint UpgradeLevel— derived frombaseProductionon load
Tick Logic
When not paused:
modified = baseProduction + bonusProduction- If not
ControlGainMode:- Send
modifiedthrough eachRoute.SendProduction(modified). - Earn money up to demand:
currentMoney += min(modified, region.LocalDemand) * moneyPerUnit. - If
modified > region.LocalDemand(excess):- If controlToLoyaltyMode == false:
- Personality switch on
selectedPersonality:- MOBSTER → add 50% of the excess as extra money.
- SUBTERFUGE → add Control by
excess * controlGainPerStar(clamped to 1).
- (Other personalities: no special excess handling.)
- Personality switch on
- Else (convert to Loyalty) → increase
loyaltybyexcess * controlGainPerStar(clamped to 1).
- If controlToLoyaltyMode == false:
- Send
- Else (ControlGainMode) → increase
region.Controlbymodified * controlGainPerStar(clamped to 1). UpdateSupply()setsregion.SupplyPerTick = modifiedandregion.Presence = true.
Routes
AddRoute(Route route)— adds and registers withLabGroupRegistrar.RemoveRoute(int index, bool refund=true)/RemoveRoute(Route r, bool refund=true)/RemoveLastRoute(bool refund)— remove and optionally refund using(routeBaseCost + routeCostPerNode * NodesTraversed) * routeCostMultiplier * routeRefund. Destroys theRouteGameObject.
Maintenance
- Subscribed in
Awake()→monthlyTick.Register(ApplyMaintenanceCost). ApplyMaintenanceCost()subtractslabMaintenanceCostfromcurrentMoneyon each monthly tick.
Save / Load
- OnSave:
- Header:
PrefabType="Laboratory",RegionId = region.name. - Body: two lines —
BaseProductionandBonusProduction.
- Header:
- OnLoad:
- Read header and re-parent under the Region by name.
- Parse
BaseProduction(also setsUpgradeLevel = floor(BaseProduction * 2)) andBonusProduction. - Call
region.AddLaboratory(this)to register with the Region.
TickBehavior
IsLab()returnstruesoGameManagerupdates Labs after Regions but before other systems.
Cleanup
OnDestroy()unregisters fromLabGroupRegistrarand unsubscribes from the monthly tick.