API for Modders

Shared libraries you can build against. ← Back to mods

IFZModAPI · IFZModPanels · IFZModDialog

IFZModAPI v1.9.1

Shared API for Infection Free Zone BepInEx mods — provides controller caches, time-of-day helpers, VFX utilities, reflection helpers, and mod-coordination hooks.

Referencing this API

Load order (BepInDependency): [BepInDependency("com.ifzmod.api")]

Build reference (HintPath):

<Reference Include="IFZModAPI"><HintPath>..\\IFZModAPI\\bin\\Release\\netstandard2.1\\IFZModAPI.dll</HintPath></Reference>

Additive-only API. Do not version-pin the BepInDependency unless you require a specific minimum.

Plugin class

BepInEx plugin entry point. Binds config entries for Bloom and Sickness, patches all Harmony targets, and initializes the custom production API at load.

MemberParamsReturnsRemarks
public const string Guid = "com.ifzmod.api" The plugin GUID string Used by consumer mods in [BepInDependency] for explicit load ordering.
public static ManualLogSource Log BepInEx's logger, set in Awake() All IFZModAPI log output goes through this.
public static ConfigEntry<bool> BloomEnabled Config: boost bloom at night (default true) Off = vanilla bloom.
public static ConfigEntry<float> BloomNightIntensity Config: peak Bloom intensity at full night (default 8f) Vanilla is ~low single digits.
public static ConfigEntry<float> BloomThreshold Config: brightness threshold for bloom (default 1.1f) High = only bright emissive sources bloom.
public static ConfigEntry<float> BloomSoftKnee Config: Bloom knee (0 hard, 1 soft) (default 0.5f)
public static ConfigEntry<float> BloomTransitionHours Config: fade width around sunset/sunrise (default 1.5f) Match DarkerNights for sync.
public static ConfigEntry<float> SicknessMaxNewSickPerDayFraction Config: max fraction of population newly infected per day (default 0.10f) Vanilla infections are separate and uncapped.
public static ConfigEntry<SicknessCoordinator.Combine> SicknessCombineMode Config: how multiple mods' infect chances merge (Max or SumClamped)
public static ConfigEntry<bool> SicknessRollEnabled Config: master switch for coordinated daily sickness roll (default true)
public static ConfigEntry<bool> SicknessDebugLog Config: log each day's coordinated roll (default false)
public static ConfigEntry<bool> SicknessRequireTreatmentBuilding Config: sickness stays OFF until player owns a treatment building (default true) Off = sickness can roll from day one.
public static ConfigEntry<int> SicknessOnsetGraceDays Config: days after treatment first available before sickness rolls (default 2)
public static ConfigEntry<int> SicknessOnsetRampDays Config: days over which sickness ramps 0..1 (default 15) 0 = full strength immediately after grace.

Cache static class

Controller refs filled by Harmony postfixes. Consumers read e.g. IFZAPI.Cache.Buildings; null until the game has constructed each controller.

MemberParamsReturnsRemarks
public static BuildingsController Buildings The game's BuildingsController, null until constructed
public static GroupsController Groups The game's GroupsController
public static SquadsController Squads The game's SquadsController
public static StockroomsController Stockrooms The game's StockroomsController
public static WorkController Work The game's WorkController (WorkSystem)
public static ColorSwitcher ColorSwitcher The game's ColorSwitcher (PPv2 profile holder)
public static WeatherController Weather The game's WeatherController
public static LightController Light The game's LightController
public static HideoutsController Hideouts The game's HideoutsController
public static Zenject.DiContainer Container The current session's Zenject container Set by ContainerCapturePatch on each session install.
public static T TryResolve<T>() where T : class T: The singleton type to resolve T, or null if no active session or type unbound Re-resolve at point of use — never cache across loads.

Hooks / events

HookSignatureWhenRemarks
Cache.ContainerReady public static event System.Action<Zenject.DiContainer> ContainerReady Fires after the game (re)installs its scene bindings — i.e. on a fresh game / save load. The scene DiContainer is rebuilt across loads; subscribe to reset per-session state. Sole patcher of the installer is IFZModAPI; consumer mods must NOT patch it themselves.
Cache.HideoutsReady public static event System.Action<HideoutsController> HideoutsReady Fires when the game (re)builds the HideoutsController — i.e. on a fresh game / save load. Sole patcher of the ctor is IFZModAPI — consumer mods must NOT patch the HideoutsController ctor themselves.
Cache.Exploded public static event System.Action<Explosion, Vector3> Exploded Fires after every Explosion.Explode, with the explosion and its world position. Sole patcher of Explosion.Explode is IFZModAPI — consumer mods must NOT patch Explode themselves.
Cache.RegisterMaxGroupCountAdjuster public static void RegisterMaxGroupCountAdjuster(MaxGroupCountAdjuster a) Registers a callback that adjusts the max member count for a group (raise only). Called by all registered adjusters. Used by SquadMerge / VehicleSquadSize mods.
Cache.RegisterOrderInterceptor public static void RegisterOrderInterceptor(OrderInterceptor h) Intercepts an OrdersQueue.GiveOrder call. Return true if the order was consumed (the original GiveOrder is then skipped). First interceptor that returns true wins. Used by SquadMerge / VehicleSquadSize mods.
Cache.DefenceModuleAdded public static event System.Action<Gameplay.Rebuilding.Towers.StructureDefenceModule> DefenceModuleAdded Fires when a defence module is spawned (Awake patch). Main-thread only.
Cache.DefenceModuleRemoved public static event System.Action<Gameplay.Rebuilding.Towers.StructureDefenceModule> DefenceModuleRemoved Fires when a defence module is destroyed (OnDestroy patch). Main-thread only.
Cache.AntennaAdded public static event System.Action<Gameplay.Rebuilding.Towers.Antenna> AntennaAdded Fires when an antenna is spawned (Awake patch). Main-thread only.
Cache.AntennaRemoved public static event System.Action<Gameplay.Rebuilding.Towers.Antenna> AntennaRemoved Fires when an antenna is destroyed (OnDestroy patch). Main-thread only.
Cache.CharacterDied public static event System.Action<Gameplay.Units.Characters.Character> CharacterDied Fires when a character dies, from a Prefix on Character.OnCharacterDeath — i.e. BEFORE the game's DestroyCharacter teardown, so LastAttackedBy / Health.KilledByEnemy are still valid for kill attribution. Sole patcher of OnCharacterDeath (cross-mod: BlitzHund detonation + SquadTraits veterancy both subscribe here rather than double-patching).
Cache.WeaponFired public static event System.Action<GunFireEffect, Gameplay.GameResources.ResourceID> WeaponFired Fires once per shot from a Postfix on GunFireEffect.StartAnimation. Sole patcher of that method (cross-mod: GunfireLights muzzle flashes + Radiosity bounce-lights both subscribe here rather than double-patching).

Time static class

Time-of-day helpers. Hour / Sunrise / Sunset / IsNight / NightBlend(transitionHours). Fires once per in-game day at sunset/sunrise.

MemberParamsReturnsRemarks
public static float Hour The current game hour (0..24)
public static float Sunrise The game's configured sunrise hour
public static float Sunset The game's configured sunset hour
public static bool IsPaused True when the game clock is paused (TimeController.SpeedMultiplier == 0) IFZ pauses by setting SpeedMultiplier to 0, never touches UnityEngine.Time.timeScale.
public static bool IsNight() True when the current hour is before Sunrise or >= Sunset
public static bool IsDay() True when the current hour is between Sunrise and Sunset
public static int DaysFromPreviousGames { get; internal set; } Days carried over from a previous playthrough (expedition mode). 0 on a plain base run. Mirrored from TimeController so it survives reloads.
public static int RunDay The current run's OWN age in days (1-based). On an expedition it strips the inherited days (Day - DaysFromPreviousGames). Floor 1.
public static float NightBlend(float transitionHours) transitionHours: Hours over which the fade in/out around sunset/sunrise Smooth 0..1 ramp. 1=deep night, 0=midday. Cached per frame + per transitionHours; safe to call from many mods each frame.

Hooks / events

HookSignatureWhenRemarks
Time.OnSunset public static event System.Action OnSunset Fires once per in-game day at sunset. Re-wired each session; safe to subscribe once at plugin load.
Time.OnSunrise public static event System.Action OnSunrise Fires once per in-game day at sunrise.

Vfx static class

Shared smoke prefab cache + pooled point-light flash system. CloneSmokeAt clones the game's work-site smoke; Flash creates a one-shot point-light that fades with quadratic falloff.

MemberParamsReturnsRemarks
public static ParticleSystem SmokePrefab() The game's work-site smoke ParticleSystem, cached after first lookup. Null until at least one Smoke MonoBehaviour exists in the scene.
public static GameObject CloneSmokeAt(Vector3 worldPos, Transform parent) worldPos: World position for the clone
parent: Parent transform (or null)
A clone of the smoke prefab as an active GameObject, or null if prefab not yet cached. Strips injected MonoBehaviours from the clone so it's pure visual.
public static void Flash(Vector3 pos, Color color, float range, float intensity, float lifetime) pos: World position
color: Flash color
range: Light range
intensity: Peak intensity
lifetime: Fade-out lifetime
One-shot point-light flash that fades out with quadratic falloff. Shared pool of 32 lights across all consumer mods; oldest reused once exhausted.

GlowFx static class

Shared additive-glow primitives for 'real glow/bloom' looks (muzzle flashes, tower lamps, beacons, headlights, flares). A Unity Light illuminates surfaces but never blooms on its own; a bright additive sprite at the source does. Centralised here so every mod reuses ONE additive material + shader-resolve + mesh set instead of each re-deriving it.

MemberParamsReturnsRemarks
public static Camera Cam() Main camera (cached, refreshed if lost). Null if no camera.
public static Shader AdditiveShader() Resolve an additive transparent shader once (engine candidates, else borrow a loaded additive material). Null if none.
public static Material MakeAdditiveMaterial(Texture2D tex) tex: Texture to wrap in an additive material An additive Material around tex. Null if no additive shader is available.
public static Texture2D SoftGlowTexture() Shared round soft-glow texture (white core, smooth alpha falloff to the rim). Cached after first call.
public class GlowSource : MonoBehaviour Steady additive glow billboard pinned to a transform — gives a light SOURCE a visible heat halo that feeds Bloom. Set Color/Size/Intensity each frame (or once). Billboard faces the camera.
public static GlowSource GlowSource.Attach(Transform parent, Vector3 localPos, Color color, float size) parent: Parent transform
localPos: Local position under parent
color: Glow color (brightness carries intensity)
size: Billboard size
A GlowSource component attached to a new GameObject, or null if no additive shader is available.
public class LightBeam : MonoBehaviour Additive light-shaft cone along the host transform's +Z (forward). Parent it to a light and it beams where the light aims. Set Color/Length/Radius/Intensity.
public static LightBeam LightBeam.Attach(Transform parent, Color color, float length, float radius) parent: Parent transform
color: Beam color
length: Beam length
radius: Cone tip radius (world)
A LightBeam component attached to a new GameObject, or null if no additive shader is available.
public static class FlashGlow One-shot pooled bright round additive dot for TRANSIENT sources (muzzle, explosion). Camera-facing, pause-aware (frozen while the game clock is paused).
public static void FlashGlow.Spawn(Vector3 pos, Color color, float size, float lifetime) pos: World position
color: Color carries brightness (push >1 to feed Bloom)
size: Diameter in metres
lifetime: Fade-out lifetime
One-shot glow dot. No-ops if no additive shader is available.

BloomControl static class

Drives the game's own PPv2 Bloom up at night so emissive sources actually glow. A Unity light illuminates surfaces but emits no bright pixel; bloom is what makes a bright pixel bleed. We boost Bloom on the game's existing ColorSwitcher.ppVolume profile (no camera-layer matching) and restore the captured original on disable. High threshold = only bright HDR emissive blooms, so the dark scene stays readable. Coexists with DarkerNights (which drives ColorGrading / AutoExposure on the same profile — different settings, no clobber).

MemberParamsReturnsRemarks
internal class Driver : MonoBehaviour Bloom boost driver. Runs on Update() and boosts Bloom at night based on Plugin's config entries. Added to a DontDestroyOnLoad GameObject by Plugin.Awake().

Reflect static class

Cached AccessTools.Field lookups shared across all consumer mods. Drops ~5-15 static FieldInfo declarations per mod.

MemberParamsReturnsRemarks
public static FieldInfo Field(Type t, string name) t: Type to look up
name: Field name
A cached AccessTools.Field lookup, or null if not found. Cached per (Type, name) pair.
public static T Get<T>(object instance, string fieldName) where T : class instance: Object to read from
fieldName: Field name
Field value cast to T, or default(T) if field or value is null.
public static T GetValue<T>(object instance, string fieldName) where T : struct instance: Object to read from
fieldName: Field name
Field value as T, or default(T) if missing.
public static void Set(object instance, string fieldName, object value) instance: Object to write to
fieldName: Field name
value: Value to set
void No-ops if instance is null.

FloatParam static class

PostProcessing v2 FloatParameter has a public value field. Wrapping the boxed-getter dance keeps DarkerNights / future lighting mods simpler.

MemberParamsReturnsRemarks
public static void SetValue(object floatParam, float v) floatParam: A PostProcessing FloatParameter
v: Value to set
void No-ops if floatParam is null.
public static float GetValue(object floatParam) floatParam: A PostProcessing FloatParameter The float value, or 0f if missing.

Wine static class

JIT-safety guards for the game's Proton/Wine Mono runtime. The FIRST time Mono compiles a method it can fail to load a callee's IL body and throw BadImageFormatException: 'Method has zero rva'. A DELEGATE invocation is never inlined by Mono, so routing the risky access through one of these guards keeps the cold callee behind a real call boundary.

MemberParamsReturnsRemarks
[MethodImpl(MethodImplOptions.NoInlining)] public static T Try<T>(Func<T> access, T fallback = default, string label = null) access: A value-returning access that may JIT-fail under Wine
fallback: Value to return if the access throws
label: Optional label for log output
The access result, or fallback (and logs once) if it throws. The delegate boundary stops Mono inlining the cold callee past this guard.
[MethodImpl(MethodImplOptions.NoInlining)] public static bool Try(Action access, string label = null) access: An action that may JIT-fail under Wine
label: Optional label for log output
True on success, false (and logs once) if it throws.

Combat static class

Per-character outgoing-damage multiplier registry. Additive API surface: writers (e.g. SquadTraits veterancy) set a factor by Character.Id; the sole GetDamage patcher (SquadMoveFire) multiplies its result by it. Default 1f => zero effect until something writes, so no mod is coupled to this.

MemberParamsReturnsRemarks
public static float GetDamageMult(string id) id: Character.Id The damage multiplier for the character, or 1f (no effect) if not set.
public static void SetDamageMult(string id, float mult) id: Character.Id
mult: Damage multiplier
void No-ops if id is null/empty.
public static void ClearDamageMult(string id) id: Character.Id void No-ops if id is null/empty.

Production static class

Custom production recipe API for IFZ mods. This static class provides a way for mods to inject custom production recipes into buildings without causing Harmony patch collisions. The API handles all the patching internally and manages both real (local container) and virtual (global container) resource inputs.

MemberParamsReturnsRemarks
internal static void Init() Armed once at API load (from Plugin.Awake), BEFORE any game session fires ContainerReady. Subscribes to Cache.ContainerReady and ProductionUI.RowRefreshed.
public static void Register(RecipeDef def) def: The recipe definition to register void No-ops on null, empty ID, or duplicate ID. Logs warnings.

RecipeDef sealed class

Definition for a custom production recipe.

MemberParamsReturnsRemarks
public string Id Unique ID for this recipe (also used as content unlock ID)
public System.Func<PlaceableObjectDraft, bool> AppliesTo Function to determine which building drafts should receive this recipe
public System.Collections.Generic.List<ResourceInput> Cost Real local-container inputs (e.g. wood/metal/etc.) - these will be consumed from the building's local container
public System.Collections.Generic.List<ResourceInput> VirtualInputs Virtual/global inputs (e.g. virt_infected_corpse) - these must be consumed from the global VirtualResourcesContainer
public System.Collections.Generic.List<ResourceInput> Profit Outputs of this production recipe (required, >=1)
public ResourceID InheritTimeFromOutput = ResourceID.None Borrow cycle time from the draft's existing recipe that outputs this ResourceID
public float TotalProductionTime = 0f Explicit cycle time if not inheriting (0 = use inherited time)
public bool AutoUnlock = true Register and unlock content ID on load
public System.Func<UnityEngine.Sprite> InputIcon Optional custom input glyph for virtual inputs (null = no special glyph)
public UnityEngine.Color? InputIconColor Optional tint for the input glyph. Vanilla resource icons are coloured by their sprite art, so a white monochrome glyph renders white — set this (e.g. a resource-green) to tint it. Null = untinted.
public string InputLabel Optional label text beside the glyph (e.g. '20')

ResourceInput struct

Structure representing a resource input in a recipe.

MemberParamsReturnsRemarks
public ResourceInput(ResourceID resource, float amount) resource: The resource
amount: The amount
A new ResourceInput

ProductionUI static class

Sole patcher of ProductionBar.RefreshBar — the single injection point for the building info-panel 'SELECT PRODUCTION' rows. RefreshBar rebuilds a row from scratch every call (Clear() destroys the input ResourcePanels / output ProductionCycles, then GetCostPairs/GetProfitPairs repopulate them), so any mod that tweaks a row's icons or labels must re-do it on EVERY refresh. Two Harmony patches on one method crash under Wine (zero-rva, see wine-double-patch-zero-rva) and build.sh fatal-gates the collision — so consumer mods must NOT patch RefreshBar themselves. Subscribe to RowRefreshed instead.

Hooks / events

HookSignatureWhenRemarks
ProductionUI.RowRefreshed public static event Action<ProductionBar> RowRefreshed Fires AFTER the game finished rebuilding a production row's input/output icons. Runs on the game/UI thread. Handlers MUST be idempotent per refresh (the row is cleared and repopulated each time). A throwing handler is isolated so one mod cannot break the row for the others. The ProductionBar is passed raw; subscribers reflect whatever private fields they need (_productionData, _productionWork, _productionCycles, neededResourcesParent, producedResourcesParent, ...) themselves — keeps this API surface minimal and additive.

Radio static class

Shared radio helper. A mod calls it to push ONE message into the vanilla radio — cloud bubble + transmission log + optional call audio — and ONLY when a mod calls it. It never patches, and never mutates, the vanilla radio. Message colour travels as TextMeshPro rich-text markup INSIDE the message string, so the game's own per-message type→colour styling (e.g. danger = white text + highlight box) is left completely intact ('typelocked').

MemberParamsReturnsRemarks
public static void Message(string text, string type = null, string colorHex = null, float duration = 0f, bool bubble = true, bool log = true, bool sound = false, RadioSource source = RadioSource.NPC) text: Message text
type: Free label; 'danger'/'alert' also UPPERCASE the text and add a trailing '!' (mirrors the game's own danger styling) — cosmetic only, never touches shared colour.
colorHex: e.g. '#59A6FF' or '59A6FF' tints ONLY this message's bubble text via rich-text; pass null/empty for the game's default colour. It cannot affect vanilla messages.
duration: Message duration (default 5f)
bubble: Show cloud bubble (default true)
log: Add to transmission log (default true)
sound: Opt-in call blip + mumble (default false)
source: Speaker type (default NPC)
void No-ops on null/empty text or during a save load / loading screen.

RadioSource enum

WHO's talking — drives the persistent-log speaker + mumble voice. NPC first so zero-value = NPC.

MemberParamsReturnsRemarks
NPC NPC speaker (default)
Operator Operator speaker
Trader Trader speaker
Scout Scout speaker
Base Base speaker

RadioSeverity enum

Legacy severity preset kept for back-compat callers. New code passes a colour hex to Radio.Message directly.

MemberParamsReturnsRemarks
Info Info severity (null = native default cloud colour)
Warning Warning severity (calm blue #59A6FF)
Alert Alert severity (alert red #FF4D40)

SaveStore static class

Per-save persistence for mods, keyed on the map's stable SaveHandler.Coordinates — NOT SaveInfo.Name, which embeds the in-game clock and drifts every day. That drift silently re-baselines a mod's per-save state on every reload (it bit Expanded Farming and ElderPop before this helper existed: each reload looked like a brand-new save). Layout: one JSON blob per (save, modId) at {SavesDirPath}/.ifzmods/{coordsKey}/{modId}.json — i.e. BESIDE the game's Saves dir (so it travels when a user copies their whole Saves folder) but NOT inside IFZ's per-save timestamped folders — those are recreated on every manual save, so anything written inside one is invisible to the next save of the same game. The coords key is stable across every reload/re-save of the same base location, which is exactly what per-save mod state needs. Serialization is UnityEngine.JsonUtility (Wine-safe, no Newtonsoft): pass a [Serializable] type with PUBLIC FIELDS. JsonUtility does not serialize Dictionary<,> — use a List field instead. All methods are null/exception-safe and no-op when no save is active (see HasSave), so a mod may call them freely without guarding for the main-menu / pre-load window.

MemberParamsReturnsRemarks
public static bool HasSave True once a map is active (coordinates assigned). Persist only while in-game.
public static string SaveKey Clock-independent per-save key. Same base location -> same key across every reload/re-save. Empty string when no save is active.
public static bool Save(string modId, object data) modId: Mod identifier
data: A [Serializable] type with PUBLIC FIELDS
True if saved, false (no-op) if no save is active.
public static object Load(string modId, Type type) modId: Mod identifier
type: The [Serializable] type to cast to
The loaded object, or null if none is stored / parsing fails. NON-GENERIC ON PURPOSE: a generic Load<T> forces a cross-assembly generic instantiation that IFZ's Mono-under-Wine cannot JIT — it throws BadImageFormatException 'Method has zero rva' at the CALLER's entry, which took down ElderPop's sunrise/sunset hooks (the whole method the caller is in fails to compile). Unity's non-generic JsonUtility.FromJson(string, Type) sidesteps it.
public static bool SaveText(string modId, string text) modId: Mod identifier
text: Raw string blob (no JsonUtility)
True if saved, false (no-op) if no save is active. Prefer this over Save/Load for anything list- or map-shaped: JsonUtility does not round-trip collection fields reliably under Wine, whereas a raw string is bulletproof. Stored at the same per-save path as the JSON blob, .txt suffix.
public static string LoadText(string modId) modId: Mod identifier The raw string blob written by SaveText, or null if none.
public static bool Has(string modId) modId: Mod identifier True if this mod has a stored blob for the current save.
public static bool Delete(string modId) modId: Mod identifier True if a file was removed.

SicknessCoordinator static class

The arbiter that stops multiple mods (ExtendedHealth, ElderPop, ...) from independently rolling sickness on the same pop and stacking into a death wave. Consumer mods RegisterSource(modId, fn) once at load; fn returns a per-pop, per-day chance in [0,1] (or <=0 for 'no opinion'). Once per in-game day, at sunset (Time.OnSunset), this runs ONE roll per adult/non-dead/non-sick citizen: merges every registered source's chance (Max or SumClamped — CombineMode), rolls once, and caps the day's total NEW infections to a shared fraction of the population (MaxNewSickPerDayFraction, min 1) so no combination of mods can out-sick the vanilla die-chance/medicine/treatment-bed pipeline in one day. All actual sickness still goes through the game's own SicknessController.MakeCharacterSick, so existing recovery/death machinery is untouched — this only gates WHO gets sick and WHEN.

MemberParamsReturnsRemarks
public static bool Available Presence flag for version-guarded callers (always true).
public static void RegisterSource(string modId, SicknessSource fn) modId: Mod identifier
fn: Per-pop, per-day chance in [0,1] (or <=0 for 'no opinion')
void Register once at load. No-ops on null/empty modId or null fn.
public static void UnregisterSource(string modId) modId: Mod identifier void No-ops on null/empty modId.
internal static void Init() Wired once by Plugin's deferred session wire: SicknessCoordinator.Init() subscribes Time.OnSunset += DailyRoll. Idempotent (unsub/sub) so a re-arm mid-session is harmless. Drops the onset latch so the first roll reloads it from THIS save's SaveStore (or re-latches if this save has no clinic yet).
public static float MaxNewSickPerDayFraction Max fraction of population that mod sickness-sources may newly infect per day (shared cap across all mods). Vanilla infections are separate and uncapped. Config-backed, set by Plugin at load (Config.Bind under the 'Sickness' section). Default 0.10f.
public static Combine CombineMode How multiple mods' infect chances merge for one pop: Max (no compounding) or SumClamped. Config-backed, set by Plugin at load.
public static bool RollEnabled Master switch for the coordinated daily sickness roll. Config-backed, set by Plugin at load.
public static bool DebugLog Log each day's coordinated roll. Config-backed, set by Plugin at load.
public static bool RequireTreatmentBuilding Capability gate: mod-driven sickness stays OFF until the player owns a completed building that can treat citizens (a clinic/hospital). Prevents illness you have no means to cure. Off = sickness can roll from day one. Config-backed, set by Plugin at load.
public static int OnsetGraceDays Days after treatment first becomes available before any mod-driven sickness rolls. A short buffer so a freshly-built clinic doesn't instantly trigger a wave. Config-backed, set by Plugin at load.
public static int OnsetRampDays After the grace window, the day's whole sickness chance ramps linearly 0..1 over this many days, so difficulty eases in rather than spiking. 0 = full strength immediately after grace. Config-backed, set by Plugin at load.

Hooks / events

HookSignatureWhenRemarks
SicknessCoordinator.OnPopFellSick public static event Action<Character> OnPopFellSick Fires when a character becomes sick through the coordinated roll.

Example

// Register a custom production recipe
var recipe = new RecipeDef
{
    Id = "my_mod.special_bricks",
    AppliesTo = draft => draft.Name.Contains("Brick Kiln"),
    Cost = new List<ResourceInput> { new ResourceInput(ResourceID.Clay, 10f) },
    Profit = new List<ResourceInput> { new ResourceInput(ResourceID.Brick, 5f) },
    InputIcon = () => MyMod.SpriteFromAssetBundle("bricks_icon"),
    InputLabel = "10"
};
Production.Register(recipe);

// Listen to production row refreshes
ProductionUI.RowRefreshed += bar => {
    // Inject custom icons into the production row
};

// Use the shared radio
Radio.Message("Hello world", type: "info", colorHex: "#59A6FF", sound: true);

// Per-save persistence
if (SaveStore.HasSave)
{
    SaveStore.Save("MyMod", mySaveData);
    var loaded = (MySave)SaveStore.Load("MyMod", typeof(MySave));
}

IFZModPanels v0.1.1

A BepInEx plugin that provides a panel system for building in-game UI windows with layout, theming, persistence, and interactive controls.

Referencing this API

Load order (BepInDependency): [BepInDependency("com.ifzmod.api")]

Build reference (HintPath):

<Reference Include="IFZModPanels"><HintPath>..\\IFZModPanels\\bin\\Release\\netstandard2.1\\IFZModPanels.dll</HintPath></Reference>

Additive-only API. Do not version-pin the BepInDependency unless you require a specific minimum.

Panels static class

Consumer entry point. Register a builder once; it re-runs on every Game-scene load.

MemberParamsReturnsRemarks
public static Theme DefaultTheme { get; set; } Theme — the default theme applied to windows that don't override. Mutable. Set once during mod init. Windows that pass a theme argument to Panels.Register use that instead.
public static void Register(string id, Action<PanelContext> build) id: Unique identifier for the window. Used for persistence and toggling.
build: A builder callback that receives a PanelContext to construct the window.
void Idempotent — same id replaces. If a Game scene is already live, builds immediately into the current canvas.
public static void Unregister(string id) id: The window id to remove. void Removes the builder and destroys the window if it exists.

PanelContext sealed class

Builder context passed to the Action<PanelContext> callback. Creates a ModWindow and returns it.

MemberParamsReturnsRemarks
public ModWindow Window(string title, SizeMode? size = null, Theme? theme = null, KeyCode toggleKey = KeyCode.None) title: Window title shown in the header.
size: Sizing mode (AutoHeight, Fixed, Resizable). Defaults to DefaultAuto (320×400 max).
theme: Per-window theme override. Defaults to Panels.DefaultTheme.
toggleKey: Keyboard shortcut to show/hide the window. Defaults to None.
ModWindow — the created window, ready for further configuration. Called once during registration. The window is persisted (pos/size/collapsed/visible) via WindowStore.Load.

ModWindow sealed partial class

A single in-game window with header, body, and row-based layout. Supports drag, resize, collapse, and toggle.

MemberParamsReturnsRemarks
public bool Locked { get; set; } bool — whether the window is locked (cannot be dragged or resized). When true, DraggablePanel and ResizeGrip are disabled.
public bool Collapsed { get; set; } bool — whether the body is collapsed (header only). Toggling persists to disk via WindowStore.
public bool Visible { get; set; } bool — whether the window is visible. Toggling persists to disk. Hidden windows can be reopened via toggleKey.
public RectTransform Body { get; } RectTransform — the scrollable content parent (from UiFactory.ScrollView). Use this as the parent for NewRow and other layout calls.
public LabelHandle Label(string text) text: Label text. LabelHandle — a handle to update the label text or color. Creates a new row with the label flexing to fill available width.
public LabelHandle Section(string text) text: Section header text. LabelHandle — a handle to update the section text or color. Like Label but uses Accent color and Bold style.
public ValueRow Value(string label, string initial = "") label: Label text (left-aligned, muted).
initial: Initial value text (right-aligned).
ValueRow — a handle to update the value text or color. Creates a two-column row: label on left, value on right.
public SeparatorHandle Separator() SeparatorHandle — a 1px horizontal divider. Creates a new row with a faint separator line.
public BarHandle Bar(string label = null, float value01 = 0f) label: Optional label text.
value01: Fill level 0..1.
BarHandle — a handle to update fill, color, or label. Creates a track with an Accent-colored fill bar.
public ButtonHandle Button(string text, Action onClick) text: Button label.
onClick: Callback when clicked.
ButtonHandle — a handle to update interactability or label. Creates a 120px-wide button row.
public ButtonHandle IconButton(IconKind icon, Action onClick) icon: Icon to display.
onClick: Callback when clicked.
ButtonHandle — a handle to update interactability. Creates a square icon button (size = RowHeight).
public SliderHandle Slider(string label, float min, float max, Action<float> onChange) label: Optional label text.
min: Slider minimum.
max: Slider maximum.
onChange: Callback with current value.
SliderHandle — a handle to get/set the slider value. Creates a horizontal slider with optional label.
public ToggleHandle Toggle(string label, bool initial, Action<bool> onChange) label: Toggle label text.
initial: Initial checked state.
onChange: Callback with new state.
ToggleHandle — a handle to get/set the toggle state. Creates a checkbox-style toggle with an Accent-colored check indicator.
public InputHandle Input(string placeholder, Action<string> onChange) placeholder: Placeholder text shown when empty.
onChange: Callback with current text.
InputHandle — a handle to get/set the input text. Creates a TMP_InputField with placeholder.
public ListRegion List() ListRegion — a vertical container for ListRow items. Creates a scrollable list with automatic height fitting.
public GraphHandle Graph(GraphKind kind, float height = 80f) kind: Graph type (Line or Bar).
height: Fixed graph height in pixels.
GraphHandle — a handle to push/set graph values. Creates a graph with an inset from the background.
public void EveryFrame(Action cb) cb: Callback invoked every frame. void Called every Tick. Use sparingly.
public void Every(float seconds, Action cb) seconds: Interval in seconds (minimum 0.01f).
cb: Callback invoked at the interval.
void Called every N seconds. Use for periodic updates.

ListRegion sealed class

A vertical container for ListRow items. Created by ModWindow.List().

MemberParamsReturnsRemarks
public void Clear() void Destroys all child row GameObjects.
public ListRow Row() ListRow — a new row inside this list. Creates a new row with the region's theme.

ListRow sealed class

A horizontal row inside a ListRegion. Created by ListRegion.Row().

MemberParamsReturnsRemarks
public LabelHandle Label(string s) s: Label text. LabelHandle — a handle to update the label. Creates a label that flexes to fill available width.
public BarHandle Bar(float v01 = 0f) v01: Fill level 0..1. BarHandle — a handle to update fill or color. Creates a bar with the region's theme colors.
public ButtonHandle Button(string s, Action onClick) s: Button label.
onClick: Callback when clicked.
ButtonHandle — a handle to update interactability or label. Creates a 70px-wide button.
public IconGraphic Icon(IconKind k) k: Icon to display. IconGraphic — the icon graphic. Sizes the icon to RowHeight.

Theme struct

A color and layout configuration applied to windows and their elements.

MemberParamsReturnsRemarks
public Color Panel Color — window background. Default: (0.015, 0.055, 0.052, 0.96)
public Color Header Color — header background. Default: (0.16, 0.22, 0.21, 0.98)
public Color Button Color — button background. Default: (0.18, 0.27, 0.26, 0.98)
public Color ButtonHover Color — button hover state. Default: (0.28, 0.42, 0.40, 1f)
public Color ButtonPressed Color — button pressed state. Default: (0.08, 0.55, 0.36, 1f)
public Color Accent Color — accent color for fills, checks, graphs. Default: (0.03, 0.78, 0.47, 1f)
public Color Faint Color — faint backgrounds (separators, scrollbars). Default: (0.10, 0.13, 0.13, 0.85)
public Color Text Color — primary text. Default: Color.white
public Color TextMuted Color — secondary/muted text. Default: (0.6, 0.7, 0.68, 1f)
public float CornerPad float — padding in pixels for corners. Default: 8f
public float RowHeight float — default row height. Default: 26f
public float HeaderHeight float — default header height. Default: 28f
public TMP_FontAsset Font TMP_FontAsset — font (null resolves to game default). null -> UiFactory resolves the game's default TMP font.

SizeMode struct

Sizing mode for a window: AutoHeight (content-driven), Fixed, or Resizable.

MemberParamsReturnsRemarks
public enum Kind { AutoHeight, Fixed, Resizable } Kind — the sizing mode.
public Kind ModeKind Kind
public float Width float — width in pixels.
public float Height float — height in pixels (Fixed/Resizable).
public float MaxHeight float — max height (AutoHeight).
public Vector2 Min Vector2 — minimum size (Resizable).
public Vector2 Max Vector2 — maximum size (Resizable).
public static SizeMode AutoHeight(float width, float maxHeight) width: Fixed width.
maxHeight: Maximum height (content-driven up to this).
SizeMode
public static SizeMode Fixed(float width, float height) width: Fixed width.
height: Fixed height.
SizeMode
public static SizeMode Resizable(float width, float height, Vector2 min, Vector2 max) width: Initial width.
height: Initial height.
min: Minimum size.
max: Maximum size.
SizeMode
public static SizeMode DefaultAuto SizeMode AutoHeight(320f, 400f).

IconKind enum

Icon types rendered by IconGraphic.

MemberParamsReturnsRemarks
Play
Pause
Prev
Next
Shuffle
List
Lock
Disc

IconGraphic sealed class

A MaskableGraphic that draws icons (play, pause, prev, next, shuffle, list, lock, disc) as vector shapes.

MemberParamsReturnsRemarks
public IconKind Kind { get; set; } IconKind Changes the icon shape. Triggers a vertex rebuild.
public float Fill { get; set; } float — fill level (0..1, default 0.62). Controls the size of the icon within its rect. Triggers a vertex rebuild.

GraphKind enum

Graph types rendered by GraphGraphic.

MemberParamsReturnsRemarks
Line
Bar

GraphGraphic sealed class

A MaskableGraphic that draws line or bar graphs from a list of float values.

MemberParamsReturnsRemarks
public GraphKind Kind GraphKind Line or Bar. Default: Line.
public readonly List<float> Values List<float> Values to graph. Add/remove and call MarkDirty().
public float Min float Y-axis minimum (used when AutoRange is false).
public float Max float Y-axis maximum (used when AutoRange is false).
public bool AutoRange bool When true, auto-scales Y to data range. Default: true.
public float LineThickness float Thickness of line segments. Default: 2f.
public void MarkDirty() void Calls SetVerticesDirty() to schedule a mesh rebuild.

GraphHandle struct

Handle to update graph values, range, and color.

MemberParamsReturnsRemarks
public void SetSeries(IReadOnlyList<float> values) values: All values to set. void Replaces all values and marks dirty.
public void Push(float value, int maxPoints = 120) value: Value to append.
maxPoints: Maximum points to keep (default 120). Evicts oldest.
void Appends a value and evicts oldest if over maxPoints.
public void SetRange(float min, float max) min: Y-axis minimum.
max: Y-axis maximum.
void Disables AutoRange and sets fixed range.
public void SetColor(Color c) c: Graph color. void

ResizeGrip sealed class

Bottom-right drag grip that resizes Target within [Min, Max]. Fires Resized on end-drag.

MemberParamsReturnsRemarks
public RectTransform Target RectTransform The window to resize.
public Vector2 Min Vector2 Minimum size (default 160×80).
public Vector2 Max Vector2 Maximum size (default 900×900).
public Action<Vector2> Resized Action<Vector2> Fired on end-drag with the new size.

PointerHold sealed class

Tracks whether a pointer is held (down/up). Implements IPointerDownHandler, IPointerUpHandler.

MemberParamsReturnsRemarks
public bool Held { get; } bool — true while pointer is held. Reset to false on OnDisable.

HoverTooltip sealed class

Shows/hides a Tooltip GameObject on pointer enter/exit.

MemberParamsReturnsRemarks
public GameObject Tooltip GameObject The tooltip to show/hide.

DraggablePanel sealed class

Makes a panel draggable by pointer. Implements IPointerDownHandler, IDragHandler, IEndDragHandler.

MemberParamsReturnsRemarks
public bool Locked bool When true, dragging is disabled.
public Action<Vector2> Moved Action<Vector2> Fired on end-drag with the new anchored position.
public RectTransform Target RectTransform The panel to drag.

CameraZoomHoverBlocker sealed class

Blocks camera zoom movement while pointer hovers over the panel. Implements IPointerEnterHandler, IPointerExitHandler.

WindowStore static class

Persists window state (position, size, collapsed, visible) to a JSON file under the DLL directory.

MemberParamsReturnsRemarks
public static void Load(ModWindow w) w: Window to restore state for. void Applies saved state (pos/size/collapsed/visible). No-op until a window is registered.
public static void Save(ModWindow w) w: Window to save state for. void Persists current state to disk. Called automatically by ModWindow on move/resize/collapse.

WindowState struct (Serializable)

Serializable snapshot of a window's state for persistence.

MemberParamsReturnsRemarks
public string id string Window identifier.
public float x float X position.
public float y float Y position.
public float w float Width.
public float h float Height.
public bool collapsed bool
public bool visible bool Default: true.
public bool hasSize bool True once user resized / fixed size stored.

LabelHandle struct

Handle to update a label's text or color.

MemberParamsReturnsRemarks
public void Set(string text) text: New text. void
public void SetColor(Color c) c: New color. void

ValueRow struct

Handle to update a value row's text or color.

MemberParamsReturnsRemarks
public void Set(string v) v: Text value. void
public void Set(float v) v: Numeric value (formatted as 0.##). void
public void SetColor(Color c) c: New color. void

BarHandle struct

Handle to update a bar's fill, color, or label.

MemberParamsReturnsRemarks
public void Set(float v01) v01: Fill level 0..1 (clamped). void Sets fill proportionally by anchor.
public void SetColor(Color c) c: Fill color. void
public void SetLabel(string s) s: Label text. void

ButtonHandle struct

Handle to update a button's interactability or label.

MemberParamsReturnsRemarks
public void SetInteractable(bool on) on: Whether the button is interactable. void
public void SetLabel(string s) s: Button label text. void

SliderHandle struct

Handle to get/set a slider's value.

MemberParamsReturnsRemarks
public void SetValue(float v) v: Slider value. void
public float Value { get; } float — current slider value (0f if null).

ToggleHandle struct

Handle to get/set a toggle's state.

MemberParamsReturnsRemarks
public void SetOn(bool on) on: Whether the toggle is on. void
public bool On { get; } bool — current toggle state (false if null).

InputHandle struct

Handle to get/set an input field's text.

MemberParamsReturnsRemarks
public string Text { get; } string — current text (empty string if null).
public void SetText(string s) s: Text to set. void

SeparatorHandle struct

Handle for a separator (no members).

Example

Panels.Register("myPanel", ctx =>
{
    var w = ctx.Window("My Panel", SizeMode.DefaultAuto);
    var label = w.Label("Hello");
    var bar = w.Bar("Progress", 0.5f);
    w.Button("Click", () => label.Set("Clicked!"));
});

IFZModDialog v0.1.1

A BepInEx library that fires the game's native radio transmission modal with 1–4 player-choice buttons and routes each click to a C# callback.

Referencing this API

Load order (BepInDependency): [BepInDependency("com.ifzmod.api")]

Build reference (HintPath):

<Reference Include="IFZModDialog"><HintPath>..\\IFZModDialog\\bin\\Release\\netstandard2.1\\IFZModDialog.dll</HintPath></Reference>

Additive-only API. Do not version-pin the BepInDependency unless you require a specific minimum.

Plugin class

BepInEx plugin entry point for IFZModDialog. Exists so consumer mods can BepInDependency on it for load order, and to own the shared logger.

MemberParamsReturnsRemarks
public const string Guid = "com.ifzmod.dialog" string — the plugin GUID Used by consumers as the BepInDependency target.
internal static ManualLogSource Log ManualLogSource — the plugin's logger Set in Awake; accessible for logging from this library.
private void Awake() void Called by BepInEx; initializes the shared logger.

DialogOption class

One choice on a radio prompt: a button label and the C# callback run when the player picks it.

MemberParamsReturnsRemarks
public string Label string — the button text shown to the player If null, defaults to "Option N" in localization injection.
public Action OnPick Action — the callback invoked when the player selects this option Set via the constructor or property assignment.
public DialogOption() DialogOption Parameterless constructor for property-based initialization.
public DialogOption(string label, Action onPick) label: The button text shown to the player
onPick: The callback invoked when the player selects this option
DialogOption Convenience constructor.

RadioPrompt static class

Fire the game's native radio transmission modal with 1–4 player-choice buttons, and route each click to a C# callback. Uses the real transmission lifecycle (load → show → play → answer → close), so audio and UI teardown are handled by the game.

MemberParamsReturnsRemarks
public const int MaxOptions = 4 int — maximum buttons the native panel supports (default/option2/option3/option4) Options beyond this count are silently truncated.
public static void Ask(string id, string promptText, DialogOption[] options, Action onUnavailable = null) id: A stable unique key per prompt TYPE (used as the transmission id, the localization namespace, and the xml filename — keep it constant across calls of the same prompt)
promptText: The prompt text shown to the player
options: 1–4 options. If more than 4, silently truncated to 4.
onUnavailable: Optional callback run when the UI can't be driven (resolves fail), so game logic never stalls on UI.
void Writes a loose transmission asset, injects localization, subscribes to DialogueManager, and starts the transmission. If any step fails, onUnavailable runs instead so game logic never stalls on UI.

Example

var options = new DialogOption[]
{
    new DialogOption("Yes, send them in", () => SendSquad()),
    new DialogOption("Hold position", () => HoldPosition()),
};
RadioPrompt.Ask("myRadioPrompt", "Squad, we have a contact. Send them in?", options, () => HandleUnavailable());