Door / Airlock atmosphere gating, and the ForceFieldDoor mod¶
Whether a door-type Structure lets the room atmosphere on one side mix with the other is decided by the CanAirPass property, evaluated by the atmospherics/room system. This page records the exact gating for the vanilla Door / Airlock family and for the third-party ForceFieldDoor mod, because an IC10 airlock controller that drives a door with the wrong LogicType (e.g. On instead of Open) will not actually open or seal the barrier it thinks it is controlling.
Vanilla Structure.CanAirPass and NeverAirPass¶
Structure (the base of Door) ties air passage to the current build state:
public virtual bool CanAirPass
{
get
{
if (CurrentBuildStateIndex >= 0)
return !CurrentBuildState.BlockAir;
return true;
}
}
protected bool NeverAirPass
{
get
{
if (CurrentBuildStateIndex >= 0)
return CurrentBuildState.AlwaysBlockAir;
return false;
}
}
A fully built solid wall has a build state with BlockAir == true, so CanAirPass == false (air is held). AlwaysBlockAir is the stronger flag a Door uses for the "even when open this never passes air" case (not used by normal doors).
Door.CanAirPass: gated on IsOpen¶
Door overrides CanAirPass so that an OPEN door passes air and a CLOSED door defers to the base (build-state) value:
public override bool CanAirPass
{
get
{
if (!IsOpen || base.NeverAirPass)
return base.CanAirPass; // closed door (or AlwaysBlockAir): seals per build state
return true; // open door: air passes
}
}
So for a Blast Door (and any normal Door/Airlock): air is held only when the door is CLOSED (IsOpen == false). The thing that opens/closes the door over logic is LogicType.Open, not LogicType.On. On (OnOff) is the power switch and does not move the door leaf.
IsOpen itself (lines 299228-299259) reflects the door's animator open-state integer (Interactable.OpenState == 1); writing LogicType.Open flips that state. Confirmed by the logic comparison path: case LogicType.Open: IsTrue = RelativeTruth(Device.IsOpen == ((int)Value == 1)); (vs case LogicType.Power: ... Device.OnOff ...). Open and On/Power are distinct logic values backed by distinct fields.
A Blast Door is documented community-side as a powered Portal with no pressure-differential limit (it can hold any pressure delta when closed). The atmosphere gate is still IsOpen: a closed blast door seals, an open one passes air, regardless of OnOff.
ForceFieldDoor (third-party mod) CanAirPass¶
ForceFieldDoor is from the third-party ForceFieldDoorMod (prefab hash 696254815, code name not vanilla). It derives from Airlock and overrides CanAirPass:
public override bool CanAirPass
{
get
{
if (_open || !((Thing)this).Powered)
return true; // air passes when OPEN or when UNPOWERED
return false; // air held only when CLOSED *and* POWERED
}
}
_open tracks the door's open state, set from IsOpen:
public void PoweredChanged()
{
if (!((Thing)this).Powered)
_open = true;
_open = ((Thing)this).IsOpen; // note: the unconditional reassignment makes the Powered branch above dead
}
Consequences:
- A force field door does hold atmosphere, but only while it is BOTH closed (
_open == false, i.e.IsOpen == false) AND powered. Lose power and it passes air (CanAirPassreturns true). This is unlike a blast door, which seals onIsOpen == falseregardless of power. - The thing that "raises/lowers the field" for atmosphere purposes is therefore still the Open state (driving
IsOpen/_open), plus power. An IC10 script that toggles onlyLogicType.On(OnOff) is toggling power, which is one of the two conditions, but it is not the same as opening/closing the leaf. Driving the field viaOnis fragile:On 0cuts power, which forcesCanAirPass = true(field down, air passes) and also stops theOnAtmosphericTickpower model;On 1restores power but leaves the actual barrier state dependent onIsOpen. WhetherOnalone produces a clean "field up / field down" depends on how the mod couples OnOff to IsOpen, which is NOT established here (see Open questions). - It is indestructible:
InitializeDamageStatesetsThingHealth = float.MaxValueand anIndestructableDamageState.
ForceFieldDoor power model (OnAtmosphericTick)¶
Power draw scales with the pressure differential the field is holding:
public override void OnAtmosphericTick()
{
((Device)this).OnAtmosphericTick();
if (_open)
{
((Device)this).UsedPower = 10f; // open: 10 W idle
return;
}
float x = 0f;
if (GridController.CanContainAtmos(_facingGrid) && GridController.CanContainAtmos(_rearGrid))
{
Atmosphere val = AtmosphericsController.SampleGlobalAtmosphere(_facingGrid);
Atmosphere obj = AtmosphericsController.SampleGlobalAtmosphere(_rearGrid);
float num = val.PressureGassesAndLiquidsInPa / 1000f;
float num2 = obj.PressureGassesAndLiquidsInPa / 1000f;
x = MathF.Abs(num - num2); // |facing kPa - rear kPa|
}
x = MathF.Floor(x);
if (FLUCTUATES && x >= 5f) { /* adds up to +5 random jitter */ }
float x2 = POWERUSAGE_BASE + x * POWERUSAGE_RATE; // 100 + delta*10
x2 = MathF.Max(x2, POWERUSAGE_BASE); // floor 100 W
x2 = MathF.Min(x2, POWERUSAGE_MAX); // cap 100000 W
UsedPower = x2;
}
Field constants: POWERUSAGE_BASE = 100, POWERUSAGE_MAX = 100000, POWERUSAGE_RATE = 10, FLUCTUATES = true. _facingGrid/_rearGrid are the two world grids 0.1 units in front of / behind the door, set in OnRegistered. So a closed, powered force field separating vacuum from 1 atm (~101 kPa delta) draws on the order of 100 + 101*10 ≈ 1110 W plus jitter; the harder the pressure delta, the more power, capped at 100 kW.
This confirms the design intent: the force field is meant to hold a pressure differential with blast doors open, at a power cost proportional to the delta. It is a real atmosphere barrier (while closed and powered), not a cosmetic effect.
How On and Open control the force field (resolved)¶
CanAirPass = _open || !Powered (verbatim above). There is no OnOff/On term. The field blocks air only when the leaf is CLOSED (_open == false) AND the door is electrically Powered.
Two facts decide how to control it over logic:
_opentracksIsOpen, andIsOpenis driven byLogicType.Open.ForceFieldDoor.OnInteractableUpdatedcallsPoweredChanged(), which does_open = IsOpen(the leadingif (!Powered) _open = true;is dead, immediately overwritten). So every interaction re-syncs_opento the current leaf state.Powered(Powered => PoweredValue >= 1, decompile line 299193) is the ELECTRICAL-network powered state.PoweredValue(299195-299226) reads thePoweredinteractable / animatorPoweredState, which the power system sets from the cable network (e.g.OnServer.Interact(InteractableType.Powered, network.PoweredValue), line 188443). It is independent ofLogicType.On/OnOff — confirmed by the pervasiveOnOff && Poweredchecks across the codebase (e.g.PoweredVent.OnAtmosphericTick:if (!OnOff || !Powered)), which are only non-redundant because(OnOff == false, Powered == true)is a real, reachable state.
Therefore LogicType.On/OnOff does NOT change CanAirPass. Writing On 0 / On 1 to a force field door does not raise or lower the field. The seal is controlled only by:
LogicType.Open:Open 1->IsOpen/_opentrue -> field DOWN (air passes);Open 0-> leaf closed -> field UP if the door is powered.- cable power: unpowered ->
!Powered-> field DOWN regardless of the leaf (the intended fail-open on power loss).
Trap for an On-based controller: _open initializes to true (field down). The FIRST On write of either value triggers PoweredChanged -> _open = IsOpen, flipping _open from its initial true to the closed-leaf false, which on a powered door SEALS the field. So an On 0 written meaning "field off" can actually seal a powered, closed force-field door (the opposite of the intent), and subsequent On writes then do nothing to the seal. The correct logic control is Open (plus ensuring the door has cable power whenever the field must hold).
Verification history¶
- 2026-05-31: Page created while adversarially reviewing an IC10 airlock+forcefield script that drives the force field door with
LogicType.On. ReadStructure.CanAirPass/NeverAirPass,Door.CanAirPass/IsOpen, and theLogicType.OpenvsLogicType.Powercomparison path from Assembly-CSharp v0.2.6228.27061. ReadForceFieldDoorMod.ForceFieldDoor(CanAirPass / OnAtmosphericTick / PoweredChanged / OnRegistered) from the third-party mod decompile at .work/decomp/0.2.6228.27061/ForceFieldDoorMod.decompiled.cs. Additive page; no prior Door/Airlock page existed, nothing contradicted. - 2026-05-31: Resolved both Open Questions after a full read of
ForceFieldDoorMod.decompiled.cs.OnInteractableUpdatedoverrides to call baseDoor.OnInteractableUpdatedthenPoweredChanged(), andPoweredChangedsets_open = IsOpenunconditionally (theif (!Powered) _open = true;first line is dead). So anOn/OnOff logic write re-syncs_opentoIsOpen: with the leaf closed (IsOpen == false),CanAirPassreduces to!Powered, soOnalone gates atmosphere (works, but fragile:_opendefaultstrueuntil the first interaction, and an opened leaf cannot be re-sealed withOnalone). The!Poweredterm inCanAirPassindependently carries the unpowered case. Updated "IC10 implication" section accordingly; no contradiction of prior content (the page previously flagged these as untraced). - 2026-05-31: CORRECTION of the entry immediately above. That entry wrongly concluded
Oncontrols the seal while the leaf stays closed (On 1seals,On 0drops via!Powered); it conflatedOn 0with!Powered. Verified viaDevice.PoweredValue(decompile 299193-299226):Poweredreads thePoweredinteractable/animator state set by the cable network (OnServer.Interact(InteractableType.Powered, network.PoweredValue), line 188443) and is INDEPENDENT ofLogicType.On/OnOff (the pervasive, non-redundantOnOff && Poweredchecks confirm(OnOff == false, Powered == true)is reachable).On/OnOff is absent fromCanAirPass = _open || !Powered, soOnwrites do NOT raise/lower the field; onlyOpen(viaIsOpen/_open) and cable power do. Section rewritten to "HowOnandOpencontrol the force field". The earlier entry is retained per the append-only VH convention but is superseded by this one.
Open questions¶
- None. Both prior questions (the
On-vs-Open/IsOpencoupling, and whether the!Poweredterm carries the unpowered case given the deadif (!Powered) _open = true;line) were resolved 2026-05-31; see "HowOnandOpencontrol the force field". Net:On/OnOff does not affect the seal at all (it is absent fromCanAirPass, andPoweredis OnOff-independent); the field is controlled byOpen(leaf) and cable power.