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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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
| Hook | Signature | When | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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
| Hook | Signature | When | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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 cloneparent: 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 positioncolor: Flash colorrange: Light rangeintensity: Peak intensitylifetime: 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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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 transformlocalPos: Local position under parentcolor: 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 transformcolor: Beam colorlength: Beam lengthradius: 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 positioncolor: Color carries brightness (push >1 to feed Bloom)size: Diameter in metreslifetime: 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).
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
public static FieldInfo Field(Type t, string name) |
t: Type to look upname: 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 fromfieldName: 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 fromfieldName: 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 tofieldName: Field namevalue: 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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
public static void SetValue(object floatParam, float v) |
floatParam: A PostProcessing FloatParameterv: 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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
[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 Winefallback: Value to return if the access throwslabel: 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 Winelabel: 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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.Idmult: 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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
public ResourceInput(ResourceID resource, float amount) |
resource: The resourceamount: 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
| Hook | Signature | When | Remarks |
|---|---|---|---|
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').
| Member | Params | Returns | Remarks |
|---|---|---|---|
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 texttype: 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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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 identifierdata: 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 identifiertype: 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 identifiertext: 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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
public static bool Available |
— | Presence flag for version-guarded callers (always true). | |
public static void RegisterSource(string modId, SicknessSource fn) |
modId: Mod identifierfn: 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
| Hook | Signature | When | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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().
| Member | Params | Returns | Remarks |
|---|---|---|---|
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().
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
Line |
— | — | |
Bar |
— | — |
GraphGraphic sealed class
A MaskableGraphic that draws line or bar graphs from a list of float values.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
public GameObject Tooltip |
— | GameObject | The tooltip to show/hide. |
DraggablePanel sealed class
Makes a panel draggable by pointer. Implements IPointerDownHandler, IDragHandler, IEndDragHandler.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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 playeronPick: 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.
| Member | Params | Returns | Remarks |
|---|---|---|---|
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 playeroptions: 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());