# CultTweaker ![CultTweaker](https://cotlmod.infernodragon.net/images/culttweaker/1.png) CultTweaker is a mod that lets players add their own custom content to Cult of the Lamb. It began as a Spine loader for custom lamb skins and has grown into a full content toolkit: an in-game editor called the **Worldshaper**, custom dungeons, weapons, NPCs with quests, enemies, structures, items, meals, tarot cards, follower forms and a modding API other mods can build on. ::warning **CultTweaker 2.0 is an experimental pre-release.** Bugs may corrupt or lose save data. Back up your game saves (`AppData/LocalLow/Massive Monster/Cult Of The Lamb/saves`) - ideally play on a spare slot - and back up your creations in `BepInEx/plugins/CultTweaker/`: `CustomNodeBlueprints`, `CustomLevelBlueprints`, `CustomDungeonMaps`, `CustomWorldMaps`, `CustomBaseMaps`, `CustomMainMenus`, `CustomShapeProfiles`, `LightingProfiles.json`, `QuestProgress`. :: ## Where to start ::card-group :::card --- icon: i-lucide-download title: Installation to: https://cotlmod.infernodragon.net/docs/culttweaker/installation --- BepInEx, COTL\_API, the folder layout, the config file and every hotkey. ::: :::card --- icon: i-lucide-hammer title: The Worldshaper to: https://cotlmod.infernodragon.net/docs/culttweaker/worldshaper --- The F4 editor: tools, layers, triggers, dungeons, hubs, world maps and co-editing. ::: :::card --- icon: i-lucide-user title: Player spines to: https://cotlmod.infernodragon.net/docs/culttweaker/player-spines --- Export a Spine skeleton, load it as the Lamb, and control fleece transmog. ::: :::card --- icon: i-lucide-users title: Follower forms to: https://cotlmod.infernodragon.net/docs/culttweaker/follower-forms --- Per-part overrides, colour sets, the F8 live editor and the web builder. ::: :::card --- icon: i-lucide-sword title: Custom weapons to: https://cotlmod.infernodragon.net/docs/culttweaker/custom-weapons --- Combos, hit boxes, timings and chain weapons declared in a spine's config. ::: :::card --- icon: i-lucide-message-square title: Custom NPC quests to: https://cotlmod.infernodragon.net/docs/culttweaker/custom-npc-quests --- Dialogue that hands out quests tracked in the game's own objectives panel. ::: :::card --- icon: i-lucide-skull title: Custom enemies to: https://cotlmod.infernodragon.net/docs/culttweaker/custom-enemies --- Mimic a vanilla enemy's AI, then tune its numbers by name. ::: :::card --- icon: i-lucide-home title: Custom structures to: https://cotlmod.infernodragon.net/docs/culttweaker/custom-structures --- Sprite and Spine structures, plus overrides for the game's own building art. ::: :::card --- icon: i-lucide-package title: Items and meals to: https://cotlmod.infernodragon.net/docs/culttweaker/custom-items-and-meals --- Inventory items, refining, fuel, and meals with recipes and effects. ::: :::card --- icon: i-lucide-sparkles title: Tarot cards to: https://cotlmod.infernodragon.net/docs/culttweaker/custom-tarot-cards --- Custom tarots with the full set of run modifiers. ::: :::card --- icon: i-lucide-plug title: Modding API to: https://cotlmod.infernodragon.net/docs/culttweaker/modding-api --- Ship content with no code, or call `CultTweakerApi` from your own plugin. ::: :::card --- icon: i-lucide-history title: Changelog to: https://cotlmod.infernodragon.net/docs/culttweaker/changelog --- Every pre-release of 2.0, then the 1.x stable history. ::: :: ## Features - Load custom player spines, with multiple skins per skeleton and a separate spine per player in co-op - Fleece transmog and fleece cycling across every player skin, custom ones included - Custom follower forms with variants, per-part placement and colour sets, plus full follower colour control - Custom weapons declared inside a player spine, built on a vanilla weapon - Custom NPCs with branching dialogue and quests that appear in the game's own objectives panel - Custom enemies that mimic a vanilla enemy's AI and re-tune its numbers - Custom structures as sprites or animated Spine skeletons, and overrides for the game's existing structure art - Custom inventory items, meals and tarot cards - The Worldshaper: an in-game room, base, hub, dungeon, world map and main menu editor - Custom dungeons built from room blueprints, level blueprints and dungeon maps - Editing together over COTL MP Steam - A no-code content path and a code contract for other mods ## Version facts | Fact | Value | | ----------------------------- | ---------------------------------------------------------------- | | Plugin version | `2.0.0`, with `PreRelease` set to `true` | | Pre-release 6 package version | `2.0.5` | | Built for | Cult of the Lamb **1.5.26** (earlier versions are not supported) | | Plugin GUID | `InfernoDragon0.cotl.CustomSpineLoader` | | Plugin name | `CultTweaker` | | Hard dependency | COTL\_API (`io.github.xhayper.COTL_API`) | ## Download - [NexusMods](https://www.nexusmods.com/cultofthelamb/mods/49){rel=""nofollow""} - the mod and the content templates - [GitHub](https://github.com/InfernoDragon0/COTL-CustomSpineLoader){rel=""nofollow""} - source ## Compatibility with saved work Maps, levels, worlds, hubs, base edits and menu presets saved in pre-release 5 still open in pre-release 6. Maps saved by pre-release 6 carry an id on every object, which older builds ignore. ::note Quest progress is kept in CultTweaker's own per-save-slot file rather than the game's save, so it travels with the `CultTweaker` folder. Copy both when moving a save. :: # Installation CultTweaker is a BepInEx plugin with a hard dependency on **COTL\_API**. Both must be installed before the mod will load. ::warning Pre-release 6 is an experimental build. Back up your saves ( `AppData/LocalLow/Massive Monster/Cult Of The Lamb/saves` ) and your creations in `BepInEx/plugins/CultTweaker/` before installing. :: ::steps ### Install BepInEx Install BepInEx for Cult of the Lamb and run the game once so it creates the `BepInEx/plugins` and `BepInEx/config` folders. ### Install COTL\_API CultTweaker declares COTL\_API (`io.github.xhayper.COTL_API`) as a hard dependency, so the plugin will not load without it. Pre-release 6 ships against COTL\_API `0.3.4`. ### Install CultTweaker Download the mod from [NexusMods](https://www.nexusmods.com/cultofthelamb/mods/49){rel=""nofollow""} and place the `CultTweaker` folder into `BepInEx/plugins/`, so that `CultTweaker.dll` sits at `BepInEx/plugins/CultTweaker/CultTweaker.dll`. ### Launch the game Start the game once. The plugin creates its content folders and writes its config file to `BepInEx/config/InfernoDragon0.cotl.CustomSpineLoader.cfg`. ### Check the log `BepInEx/LogOutput.log` reports every piece of content as it registers. It is overwritten on every launch, so copy it before relaunching when reporting a bug. :: ## The content folder Everything CultTweaker loads or saves lives under `BepInEx/plugins/CultTweaker/`, one folder per content kind: ```text BepInEx/plugins/CultTweaker/ CultTweaker.dll Assets/ art the mod ships with PlayerSkins/ custom player spines (and custom weapons) FollowerSkins/ custom follower forms, one folder per skin BuildingOverrides/ replacement art for the game's own structures CustomStructures/ custom buildings, sprite or Spine CustomInventoryItems/ custom items CustomMeals/ custom meals CustomTarotCards/ custom tarot cards CustomEnemies/ custom enemies CustomNpcs/ custom NPCs, their dialogue and their quests CustomCutscenes/ cutscene videos CustomNodeBlueprints/ saved rooms CustomLevelBlueprints/ saved levels CustomDungeonMaps/ saved dungeon maps CustomWorldMaps/ saved overworld maps CustomBaseMaps/ saved base edits CustomMainMenus/ main menu presets CustomShapeProfiles/ sprite shape profiles QuestProgress/ quest state, one file per save slot LightingProfiles.json saved lighting profiles followerSlots.json dumped follower slot list (see below) ``` ::note Other mods can ship content through these same folder names without any code, by putting a `CultTweaker` folder inside their own plugin folder. See the [modding API](https://cotlmod.infernodragon.net/docs/culttweaker/modding-api) . :: ## The config file `BepInEx/config/InfernoDragon0.cotl.CustomSpineLoader.cfg` is written on the first launch. The sections are: ### [Debug] | Setting | Type | Default | Description | | ------------------------ | ---- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `DumpFollowerSpineAtlas` | bool | `false` | Dumps the follower spine slots to `followerSlots.json`. May impact performance while enabled. Make sure `followerSlots.json` is not already present before dumping. | | `WeaponHitboxes` | bool | `false` | Draws the outline of every attack hit box where it lands, with a line from the attacker to its centre: cyan for a custom weapon's light hit, amber for any other player attack, red for enemies. For tuning a custom weapon's `range` and `hitboxRadius`; leave it off for play. | ### [Fleece] Holds the fleece state the mod remembers between sessions, plus the transmog switches. | Setting | Type | Default | Description | | ----------------------------------------------- | ------ | ------------------------------ | --------------------------------------------------------------------------------- | | `CurrentFleeceIndexP1` / `CurrentFleeceIndexP2` | int | `-1` | Current fleece index for player 1 and player 2. | | `CurrentFleeceNameP1` / `CurrentFleeceNameP2` | string | empty | Current fleece skin name, kept alongside the index so its spine can load at boot. | | `FleeceCyclingEnabled` | bool | `true` | Enables fleece cycling for all players. | | `FleeceTransmogP1`, `FleeceTransmogP2`, ... | bool | follows `FleeceCyclingEnabled` | Per-player fleece transmog. This is also toggled from the F7 panel. | ### [Spine] | Setting | Type | Default | Description | | ----------------- | ------ | ------- | --------------------------------- | | `SelectedSpineP1` | string | empty | Chosen player spine for player 1. | | `SelectedSpineP2` | string | empty | Chosen player spine for player 2. | ### [MainMenu] | Setting | Type | Default | Description | | --------- | ------ | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | `Enabled` | bool | `true` | Lets a saved main menu preset dress the title screen. Off leaves the menu exactly as the game draws it and hides the Customize Menu button. | | `Preset` | string | empty | Which saved preset the title screen wears, by folder name. Empty is the game's own menu; the menu editor writes this when a preset is made active. | ### [MapEditor] | Setting | Type | Default | Description | | ----------------- | ------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `VanillaPanelArt` | bool | `true` | Backs the editor's panels with the game's own photo mode plate instead of the mod's plain rounded one. | | `PanelPlate` | string | empty | Which piece of that art to use, by sprite or object name. Empty picks the largest nine-sliced panel; everything the source prefab draws is listed in the log the first time the editor opens. | | `PanelSource` | string | empty | Which prefab that art comes from, by addressable key. Empty uses photo mode's take-photo overlay. | | `PanelOpacity` | float | `0.82` | How solid the editor's panels are. `1` is the art as the game draws it; lower lets the room show through. | | `PanelCrop` | string | empty | Extra pixels to trim off that art, as `left,bottom,right,top`. Empty trims only the transparent padding the atlas records. | | `VanillaWidgets` | bool | `true` | Uses the game's own settings toggle and slider in the editor's tool panels, scaled to the editor's row height. | | `FullWeather` | bool | `true` | Offers every strength of every weather the game has art for, building the ones it does not ship (extreme wind, for instance) from the nearest one it does. The weather a player gets on a normal day is unaffected either way. | | `NetVerbose` | bool | `false` | Logs every multiplayer editor change sent and applied, with its entry keys, and every reconcile decision. For tracking a desync between two machines. | ## Hotkeys | Key | Action | | -------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | `F4` | Open or close the Worldshaper. Works in Dungeon1 scenes; in the base, only once a hub or the base editor has been opened from the F7 panel. | | `F5` | Enter the test dungeon - or, with the editor open, reset the room. | | `F6` | Hide or show the editor's UI while it stays paused (for screenshots); on an open world map, flip between play view and editing. | | `F7` | Open the CultTweaker panel (fleeces, player spines, base editor, hubs, world maps, mod info). | | `F8` | Open the follower skin editor. Works anywhere in the game except the title screen. | | `Ctrl+S` | Quicksave under the current name. | | `Ctrl+Z` | Undo the last change. | | `Ctrl+G` | Group the selection; on a whole group, dissolve it. | Inside the editor: | Key | Action | | ------------------- | ------------------------------------------------ | | `WASD` / arrow keys | Pan the camera | | `Z` / `X` | Zoom in and out | | Mouse wheel | Switch tool, or scroll the list under the cursor | | `Shift`-click | Add to or remove from the selection | | `Del` | Delete the selection (tool-dependent) | ::note `F5` , `F6` , `F7` and `F4` are ignored while the menu editor or the follower skin editor is open, so the editors never fight over a key. :: # The Worldshaper Press **F4** in a dungeon room and it becomes your canvas, edited live with the real game systems. Nothing is a preview: the shapes you draw have real collision, the enemies you place have their real AI, and the room you save is the room the game loads. :video-player{caption="The Worldshaper in use: building a room with the editor's tools, then playing it." src="https://cotlmod.infernodragon.net/images/documentation/worldshaper.mp4"} ::note In the base, `F4` only opens once a hub or the base editor has been started from the **F7** CultTweaker panel. :: ## Tools | Icon | Tool | What it does | | -------------------------------------------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Select.png) | Select | Pick, move, resize and re-depth objects. `Shift`-click multi-selects, `Ctrl`-drag copies, `Ctrl+G` groups. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Shape.png) | Shape | Draw the terrain itself, with real collision, from sprite shape profiles. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Structures.png) | Structure | Place vanilla and custom structures. Custom ones sit in a **Custom** group; the browser also carries the DLC dungeon dressing (**DLC Dungeon / Ewefall**, **DLC Dungeon / Rot**), the **Art** groups and **Tile Decorations**. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Enemies.png) | Enemy | Place enemies, including bosses (under "Bosses (inside rooms)") and everything under **Custom (mods)**. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/NPCs.png) | NPC | Place custom NPCs with their dialogue and quests. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Podiums.png) | Podium | Place reward podiums. A **Weapon** dropdown pins which weapon the podium hands out, vanilla or custom. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Triggers.png) | Trigger | Volumes that run action sequences: cutscenes, camera moves, screen text, lighting, music. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Doors.png) | Door | Connect rooms and control where each exit leads. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Whiteboard.png) | Whiteboard | Draw planning marks over the room. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Lighting.png) | Lighting | Ambient, sun and fog values for the room, plus a weather override. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Music.png) | Music | Change the room's FMOD music event. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Clear.png) | Clear | Wipe the scenery, the terrain, the placed objects or every trigger. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Load%20Map.png) | Load Map | A full-screen browser of saved rooms, with a picture and details of the map you pick. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Level.png) | Level | Assemble rooms into a level blueprint. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Dungeon%20Builder.png) | Dungeon Builder | Turn level blueprints into a playable dungeon map. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Save.png) | Save | Save the room under a name, through the game's own naming modal. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/Preview.png) | Preview | Hide the editor's UI and look at the room the way a player would. | The world editor adds two of its own: | Icon | Tool | What it does | | ----------------------------------------------------------------------------------------- | ------------ | ------------------------------------------------------ | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/World%20File.png) | World File | New, open and save a world map. | | ![](https://cotlmod.infernodragon.net/images/culttweaker/editor-icons/World%20Layers.png) | World Layers | The sprite and Spine layers a world map is drawn from. | Picking a tool opens its panel at the right edge; the shortcuts for whatever is in your hand are always listed at the left. The tools that have a screen of their own - Load Map, Level, Dungeon Builder - are covered further down. ### Select ![The Select tool, with a signpost selected and its details in the panel](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-select.png){format="webp" loading="lazy" quality="72" width="1280"} The panel names what you have picked and shows its position, its scale and a picture of it, along with how much is behind it - scripts, child objects and renderers - which is the quickest way to tell a single prop from a whole assembly. **Flipped horizontally** mirrors it in place. Dragging is colour-coded: the yellow handle moves, the blue ones resize, and `Shift` with a blue handle stretches one axis only. #### Layers, multi-select and groups The **Layers** panel at the left edge, opened with the `+` beside the shortcut hints, lists every object in the room by what placed it - Shapes, Podiums, Enemies, NPCs, Structures, Props and Triggers - under the same names the tools use. - Click a row to select that object with the Select tool. The tree follows your selection in the world and scrolls to it, and section headers stay pinned while you scroll. - `Shift`-click two rows to select the run between them, like a file list. - It is built for big rooms: a base town of six hundred objects scrolls and highlights without lag. **Multi-selection** lives on the Select tool: `Shift`-click adds an object to the selection or takes it out. Move and depth drags move everything together, one undo puts the whole drag back, and `Del` removes the lot. **Groups** are made with `Ctrl+G`: two or more selected objects become a group, and picking any member picks the group. `Ctrl+G` on a whole group dissolves it, and both are undoable. Groups are saved with the map and come back on load; the Layers panel shows each group as a folder whose row selects the whole group. ### Shape ![The Shape tool, with a terrain outline's nodes shown and the shape list in the panel](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-shape.png){format="webp" loading="lazy" quality="72" width="1280"} The dropdown at the top is the material the terrain is drawn from - `Biome1_Grass` and the rest of the game's sprite shape profiles. | Control | What it does | | ----------------------- | ------------------------------------------------------------------------ | | Show Collision | Draws the collider over the shape so you can see what it actually blocks | | Shape Has Collision | Whether the outline blocks anything at all | | Vanilla Floor Collision | Keeps the room's original floor collision underneath | | Open Ended | Leaves the outline unclosed, for a ledge rather than an island | | Collider Detail | How closely the collider follows the outline | | Collider Offset | Pushes the collider in or out from the drawn edge | **New Shape (screen centre)** starts another one, and every shape in the room is listed below with its point count; `-` and `+` walk through them and `X` deletes one. On the shape itself, `LMB` drags a node, `Ctrl+LMB` inserts one, `RMB` removes one, and `Del` deletes the whole shape. ### Structure ![The Structure tool with the Build Menu Structures browser open](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-structure.png){format="webp" loading="lazy" quality="72" width="1280"} A search box and a category dropdown - **Build Menu Structures**, the DLC dungeon dressing, the **Art** groups, **Tile Decorations** and **Custom** - over a grid of everything in that group. The name of the current pick sits under the grid, and four toggles change how placement behaves: **Multi-select randomised placement**, **Break apart randomised sets**, a **Structure quick pick dock** for what you have been using, and **Place see-through**. ### Enemy ![The Enemy tool with the enemy browser open on Enemy Forest Swordsman](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-enemies.png){format="webp" loading="lazy" quality="72" width="1280"} The same shape of browser: search, a category dropdown that starts on **All** with the count beside it, and a grid. The selected enemy is named under the grid, and **Clear Selection** puts the tool down without placing anything. ### NPC ![The NPC tool, hovering a tile to preview RatNPC](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-npcs.png){format="webp" loading="lazy" quality="72" width="1280"} **Search scanned NPCs** covers everything CultTweaker found at startup, grouped by where they come from. Hovering a tile blows it up into a portrait with the NPC's name, drawn from the NPC's own spine - so a custom one looks here exactly as it will in the room. ### Podium ![The Podium tool set to hand out a custom weapon](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-podiums.png){format="webp" loading="lazy" quality="72" width="1280"} Two dropdowns: what kind of podium it is, and what it hands out. Custom rewards are listed as `Mod/Name`, so `TEST1/TestFlail` is the `TestFlail` weapon from the `TEST1` mod. **Equip clears all** makes the room's other podiums disappear once the player takes one, the way a vanilla weapon choice does. ### Trigger A trigger is a volume that runs a sequence of actions when the players enter it. It can also be marked a **blocking volume**, which turns it into an invisible wall for players and enemies, drawn in red, with enemy pathfinding routed around it as it is moved and resized. ![The Trigger tool with a volume placed and the camera actions listed](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-triggers.png){format="webp" loading="lazy" quality="72" width="1280"} The header names the trigger, its size in tiles and how many actions it carries. | Control | What it does | | -------------------------- | ---------------------------------------------------------------------------------- | | Fire once | The sequence runs a single time instead of on every entry | | Lock control while playing | Takes input off the players while the sequence runs | | Trigger method | What sets it off - **On player step** and the rest | | Show volumes in play | Leaves the volume drawn outside the editor, for testing | | Re-arm All Triggers | Arms everything in the room again, so a fire-once sequence can be tried repeatedly | Actions are built underneath: pick a category, pick a **Target** if the action needs one, then press the action itself; every action is listed below. While picking, `V` sets the camera offset from the view you are looking at and `Esc` abandons the pick; `Ctrl`-drag copies a trigger and everything on it. #### Player | Action | Target | Behaviour | | ------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | Move players to trigger | another trigger's Id | Walks the players to that volume's centre. | | Move players to object | a clicked object | Walks them to that object, falling back to the authored position. | | Talk to custom NPC | a registered `InternalName` | Runs that NPC's dialogue tree and waits for it. | | Play animation on players | an animation on the player skeleton | Plays it once, or loops it for 2 / 5 / 10 s. | | Play animation on object | anything in the room with a spine | Plays one of its animations once or on a loop, with a choice of what happens when it ends so an enemy or NPC can return to its idle. | | Hub spawn point | — | A mark, not a step: the trigger's position is where a hub's arrival walks the player to. A hub cannot be saved without one. | #### Camera | Action | Target | Behaviour | | ------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------ | | Look at object | a clicked object | Frames it for 0.5-8 s, then hands the camera back. | | Look at trigger | another trigger's Id | The same, aimed at that volume's centre. | | Set camera offset | framed in the editor | Shifts the camera relative to whatever it follows. | | Reset camera offset | — | Back to centred on the players. | | Set camera zoom | 1-10 | Follow distance; smaller is closer, `10` is the rig's own resting value. | | Reset camera zoom | — | Back to whatever the rig was on before a trigger touched it. | | Camera shake | — | Shakes the camera. | | Play camera effect | chromatic aberration, vignette, desaturate, shake, letterbox in/out | Runs the effect and waits for it. | | Play cutscene | a video in `CustomCutscenes`, or a vanilla one | Plays fullscreen and waits for it to end. | #### Screen text | Action | Where | | --------------- | ------------------------------------- | | Caption | Bottom left, left aligned. | | Title | Top centre. | | Fullscreen text | Centred, over a screen dimmed to 75%. | Each takes a typed title and subtext. #### Enemies and ambient | Action | Target | Behaviour | | --------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | Pause enemy AI | every enemy in the room, or a clicked one | Freezes it where it stands - no decisions, no movement, the pose held. Does not wait. | | Resume enemy AI | the same two choices | Hands it back to its own AI, at the animation speed it had. | | Apply lighting | a saved lighting profile, or "Vanilla lighting" | Cross-fades the room's lighting over 1 / 2 / 4 s, or instantly, then moves on. Vanilla restores the biome's own values. | | Change music | an FMOD music event | Starts the track and keeps it looping. Does not wait. | | Open world map | a saved world map | Opens it and waits until it closes - a hub's travel portal. | | Return to base | — | Ends any run and sends the players home, as the dungeon portal does. Nothing after it runs. | ### Door ![The Door tool, with two of the four doors enabled](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-doors.png){format="webp" loading="lazy" quality="72" width="1280"} **All four doors are required to save** - a room blueprint carries a north, east, south and west door whether or not a given level uses them. Each has its own toggle, **Enable All Doors** turns the lot on at once, and the volumes themselves are dragged around the room's edge with `LMB`. ### Lighting ![The Lighting tool with the ambient, sun and fog sliders](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-lighting.png){format="webp" loading="lazy" quality="72" width="1280"} Everything here is a live slider - the room relights as you drag. | Group | Values | | ------- | ------------------------------------------------------- | | Ambient | R, G, B | | Sun | R, G, B, Sun Intensity, Shadow Strength, Exposure | | Fog | R, G, B, Fog Near, Fog Far, Fog Height, Fog Spread | | Weather | **Override weather**, then which weather and how strong | The values are saved with the room. Cross-fading to a *saved profile* during play is the trigger action [Apply lighting](https://cotlmod.infernodragon.net/#enemies-and-ambient), not this panel. ### Music ![The Music tool with the FMOD event list open](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-music.png){format="webp" loading="lazy" quality="72" width="1280"} One dropdown of the game's own FMOD events, listed as `bank/event` - `base/base_main`, `cave/cave`, `forest/forest_main`, `haunted_marshes/haunted_marshes`, `death_cat_battle/death_cat_battle` and the rest, including the credits and the Devolver splash. **Vanilla (no override)** at the top leaves the room playing whatever it normally would. ### Clear ![The Clear tool's four buttons](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-clear.png){format="webp" loading="lazy" quality="72" width="1280"} Four buttons, each wiping one kind of thing: **Clear Scenery** for the vanilla dressing, **Clear Terrain** for the shapes, **Clear Placed Objects** for everything you put down, and **Clear All Triggers**. ## The whiteboard ![The Whiteboard tool, with a stroke drawn over the room](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-whiteboard.png){format="webp" loading="lazy" quality="72" width="1280"} The **Whiteboard** tool draws freehand over the room, in the world, to plan with: a *Show whiteboard* toggle, *Draw* with a size slider and nine colours, *Erase* with its own size, and *Clear all*. Strokes are never selectable and never part of the room. They show only while the editor is open, are saved with the map, and travel to the other player live as you draw. One drag is one stroke and one undo; an erase drag is one undo too, and *Clear all* wipes the board in a single undoable step. The chosen colour shows a white border instead of being covered, and the brush lands exactly under the cursor. ## Saving and loading `Ctrl+S` quicksaves under the current name; the Save tool names a new map through the game's own naming modal, with a live overwrite warning. Rooms are saved to `CustomNodeBlueprints`, levels to `CustomLevelBlueprints`, dungeon maps to `CustomDungeonMaps`, world maps to `CustomWorldMaps`, base edits to `CustomBaseMaps` and menu presets to `CustomMainMenus`. A room blueprint is a **full snapshot**: loading always clears the room first, so a deleted object is simply absent from the snapshot and vanilla scenery is captured as props. Structures and custom enemies are stored **by name**, never by enum id, because vanilla ids shift between game versions and custom ones are minted at runtime. Every object saved by pre-release 6 also carries an id, so it can be told apart from its neighbours across a save, a load and a second machine. Maps saved by pre-release 5 still open. The **Load Map** browser is a full screen with a picture and details of the map you pick, and click-to-enlarge on the picture. ![The Load Map browser, with a map selected and its contents listed](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-loadmap.png){format="webp" loading="lazy" quality="72" width="1280"} Saved rooms are tiled by name and date. Picking one fills the left-hand pane with its picture, when it was saved, how much it takes on disk, and a count of what is in it - terrain shapes, props, structures, enemies, NPCs, podiums, triggers, doors and the vanilla objects the room kept. If the room you are standing in has unsaved changes, the pane warns you before **Load Map** discards them. ## Dungeon builder and levels The **Level** tool assembles rooms into a floor: - Hand-built floor layouts ("custom walk") on a visual layout screen, or a random walk tickbox - Auto-connecting doors, fixed entrance and exit rooms, and a choice of vanilla podium entrance and exit rooms - A pool of maps per room, one picked at random per run - Combat and Reward room markers On the layout screen: | Gesture | Does | | --------------------------- | -------------------------------------------------------- | | `Ctrl` + left click | Add a room in that cell, doored to everything it touches | | Left click | Select a room; drag to move it | | Right click a room | Open or close the door between it and the selection | | `Del` | Delete the selected room | | `Ctrl+S` / `Ctrl+Z` / `Esc` | Quicksave, undo, close | ![The level layout screen, with two rooms placed and the Rooms panel open](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-leveleditor.png){format="webp" loading="lazy" quality="72" width="1280"} Rooms are numbered in the order the run visits them, and the coloured tab on a cell's edge marks its doors. Selecting one opens its settings on the right: **Entrance** and **Exit** mark where the floor starts and ends, **Room kind** chooses what sort of room it is, and **Modifier** applies one of the game's room modifiers. Under **Maps** is that room's pool: search the saved rooms and pick as many as you like, and the run draws one of them at random. Leave the pool empty - it says so - and *any* saved map can come up there. **Clear Map Selection** empties it again. The **Dungeon Builder** is a full-screen map drawn with the game's own artwork. Nodes are placed freely: `Ctrl`+click places, right-click links or cuts, `Del` deletes, and placing beside a selected node links it automatically. Any node can lead to any other, links follow a node as it is dragged, **Preview Map** shows the result, and the builder checks live whether the map will actually play. Close it with `Esc`, the X button or `F4`. ![The dungeon builder, with fourteen nodes over six layers and the map reported playable](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-dungeoneditor.png){format="webp" loading="lazy" quality="72" width="1280"} The panel keeps a running readout: how many nodes over how many layers, how many of them play a level of yours rather than a vanilla floor, and which floor the run starts on. **Type for new nodes** is what the next node will be, and each node is labelled in the map with its type, its layer and what it leads to. **Playable** in the corner is the live check - it tells you the map will actually run before you try it. Where a run's exit door leads depends on the layer it is on: | Where the run is | What the exit door does | | --------------------------- | --------------------------------------------- | | Below the top layer | Opens the map selector to pick the next floor | | On the top layer | Shows the completion screen - the run is over | | Map not playable or missing | Shows the completion screen | ## The base editor The base editor, started from the **F7** panel, edits your real town - structures, terrain and paths - with the same F4 tools. Every change is kept in the mod's own files; the game's save is never written to. | Tier | What | Can be | | --------- | -------------------------------------------------------------------------------------------------------------------- | ----------------------- | | Editable | What this mod placed, and inert scenery - trees, rocks, grass | moved, resized, deleted | | Move only | Everything else of the player's: shrines, temples, beds, farm plots, dungeon doors, the town centre, the build totem | moved | | Protected | Followers and their pets, and the placement region object | nothing | Structures that block the camera while you edit turn see-through. ## Hubs and the build totem A **hub** is a safe town built in the emptied DLC town. The F7 panel offers three entries: | Panel control | What happens | | ------------- | -------------------------------------------------------------------------------------- | | **New Hub** | Travels to the base, raises the town room, empties it, opens the editor on a blank hub | | **Edit Hub** | The same trip, then rebuilds the saved hub in the room for editing | | **Visit Hub** | The same trip, then rebuilds it and leaves the player in it | ![A hub open in the editor, with the reduced hub toolbar along the bottom](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-hubeditor.png){format="webp" loading="lazy" quality="72" width="1280"} A hub is edited with the same `F4` tools, minus the ones a town has no use for: there are no enemies, podiums or doors in the hub toolbar, and no level or dungeon screens. Every hub needs a trigger carrying the **Hub spawn point** action - that is where arrivals walk in, and a hub cannot be saved without one. Add *Return to base* or *Open world map* triggers as portals. ![The same hub being played, with the day counter and quest tracker running](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-hub.png){format="webp" loading="lazy" quality="72" width="1280"} Visited, it is an ordinary part of the game: the day clock runs, quests track, and followers go about their business in it. The **build totem** lets a hub's structures be built during play through the game's own build menu, at costs you set. Building costs and refunds are kept in the hub rather than the save, and a placement region stops hub building from reaching your real town. ## World maps The world editor, opened from the F7 panel's **World Maps** section, builds a custom overworld in the shape of the DLC's Ewefall map: a full-screen travel menu built from the map's own art, with travel nodes that unlock outward from what the player has completed. The vanilla DLC map is never touched, and completion lives in the mod's own per-save-slot file. ![A custom world map with a base node, a boss node and a locked node](https://cotlmod.infernodragon.net/images/documentation/Worldshaper-worldeditor.png){format="webp" loading="lazy" quality="72" width="1280"} Nodes sit on the map's own artwork and are joined by dashed paths. Each carries the vanilla styling for its kind, its own label, and - where one is set - its lock: the node here asks for eight keys and shows `???` until it is opened. ```text CustomWorldMaps/ / config.json the map (layers + nodes) *.png sprite layers and node icons, referenced by file name / one spine per subfolder: skeleton .json + .atlas + pages progress_slot.json per-save-slot completion (managed by the mod) ``` **F6** flips between edit and play view. ### Nodes and unlocking Positions are in the canvas's 1920x1080 reference space. A node's `Id` is a string it keeps forever - progress is keyed on it, so renaming a node orphans progress earned under the old id. States follow the DLC cascade: a **completed** node's children become **selectable**, its grandchildren become a grey **preview** ("???"), and everything further stays **hidden**. States only ever upgrade when branches meet. On top of that: - `InitialState` (`Hidden` / `Preview` / `Selectable`) is what a node is before any completion reaches it. The starting node is authored `Selectable`. - A **Base** node is home: selecting it closes the map, it never completes, and its children unlock from the start. - A **Key** node banks `KeysGranted` keys when completed, once however often it is replayed. - A **Lock** node surfaces where a selectable node would be, priced at `KeysCost` keys, and blocks its branch until opened. An opened lock passes completion straight through. A lock is the one node that asks before it acts. - `RequiredCompletedCount` plus `RequiredNodes` holds a node at preview until N of the listed nodes are completed. A node's destination is `TargetKind` plus `Target`: a saved **dungeon map** from `CustomDungeonMaps`, a saved **level** from `CustomLevelBlueprints`, or **None**, which completes on the spot when selected. Completion is recorded only when a run entered from the map ends in the success path - dying records nothing. `NodeType` chooses which vanilla node style is borrowed: | NodeType | Vanilla style | | ------------------- | ------------------------------------------------ | | `Base` | The home node | | `Dungeon` | A standard Ewefall dungeon | | `MiniBoss` / `Boss` | The miniboss / boss nodes | | `Key` / `Lock` | The key and lock nodes, with their extra outline | | `Reward` | The reward cache | ### Layers Sprite layers are the PNG at its authored pixel size, tinted and scaled as configured. Spine layers render on the canvas and animate even while the world is paused; for them, **scale 1 means the size the game draws that skeleton at**, matching what 1 means for a sprite. ::caution The game's Spine runtime draws a canvas skeleton with a single texture, so world map spines should use a **single-page atlas** . A multi-page skeleton renders its first page correctly and misdraws the rest. :: `ParallaxDistance` (0 pinned, 1 moves most) drifts a layer toward the mouse in play view. The editor keeps everything pinned so placement is exact. ## The menu editor **Customize Menu** on the title screen opens the main menu editor. Looks are saved as named presets under `CustomMainMenus/`, a folder each with a `config.json` beside its art, and the chosen preset dresses the menu on every launch. - The **Look** tool: palette pick and blend, background colour, hue / saturation / brightness, dither, grain, the glitch effect, and a negative effect for the field behind the lamb. - The **Centrepiece** tool: skin, animation, position, scale and rotation for the lamb - or a custom spine dropped into the preset's folder. - The **Title** tool: replace the logo with any PNG, move, resize or hide it, and set, move, recolour or hide the edition line. Drop a PNG into a preset's folder to use it as the title; drop a spine folder (`.json` + `.atlas` + pages) to stand it where the lamb is. ## Editing together With **COTL MP Steam** on both machines - a build that includes editor sync - press **F4** in the base while in a session and the world pauses for both players. The other player is invited in chat and can press **F4** to edit with you. - Your selection is cyan, theirs is amber, on the object, its outline, their cursor and in the layer list. - An object the other player has selected or is dragging is locked until they let go. - Moves, resizes and reshapes show on the other screen while the mouse is still down, not only on release; lighting changes fade in. - Saving from either side saves on the host's machine; the guest receives the files. - Custom dungeon levels work in a session: the host starts a level, the guest follows into the same layout with the same rooms, and both can edit the rooms together. - If the two rooms ever disagree, the **Resync** button in the shortcut panel puts them back in step. `MapEditor / NetVerbose` in the config logs every change sent and received, and a **Sync self-test** button runs the room through the sync on one machine. # Custom player spines A custom player spine replaces the Lamb's skeleton with one of your own. Spines live in `BepInEx/plugins/CultTweaker/PlayerSkins`, one folder per skeleton. :video-player{caption="A custom player spine in game, in place of the Lamb." src="https://cotlmod.infernodragon.net/images/documentation/playerspine.mp4"} ## Exporting a usable Spine skin - Export the Spine skin via **Spine 3.8.99**. - Export as a **JSON** file. - Output: `Nonessential data: TRUE`, `Animation cleanup: TRUE`, `Warnings: TRUE`. - Texture atlas: `Pack TRUE` with the default pack settings. - If any warnings occur it may be best to fix them, or the skin may not load into the game. ## Folder layout In the `PlayerSkins` folder, create a new folder for each individual spine you want to load. The folder is named after your skin - this example uses `DEBUGSKIN`. In it, place: - a `.json` file, your exported Spine skeleton - an `.atlas` file, your exported Spine atlas - any number of `.png` files packed with it - a `config.json` with the settings below A complete skin folder looks like this: ```text | CustomSpineLoader.dll | PlayerSkins | DEBUGSKIN | player-main.json | player-main.png | player-main.atlas | config.json ``` ## config.json Each spine folder must have a `config.json`: ```json { "defaultSkin": "CustomSkinName", "skins": [ "CustomSkinName", "CustomSkinName2" ] } ``` `defaultSkin` will be the first skin that is loaded when the game starts. `skins` is an array of any number of strings naming the skins that exist in your Spine skeleton and that you want loaded into the game. ### Optional settings ```json { "defaultSkin": "A_Tiger", "skins": [ "A_Tiger" ], "disableFleeceCycling": true, "hiddenSlots": [ "CROWN", "CROWN_EYE", "images/PonchoLeft", "images/PonchoRight" ] } ``` | Field | Type | Default | Description | | ---------------------- | ------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `defaultSkin` | string | — | The first skin loaded when the game starts. | | `skins` | string array | — | The skins in your skeleton to load into the game. | | `disableFleeceCycling` | bool | `false` | Stops fleece transmog from dressing this spine. | | `hiddenSlots` | string array | empty | Slot names this spine never draws. | | `preloadWeapons` | bool | `false` | Loads this spine at boot so its custom weapons never show the base look while loading. See [custom weapons](https://cotlmod.infernodragon.net/docs/culttweaker/custom-weapons). | | `weapons` | array | — | Custom weapons declared by this spine. See [custom weapons](https://cotlmod.infernodragon.net/docs/culttweaker/custom-weapons). | **disableFleeceCycling** stops fleece transmog from dressing this spine. The fleece writes to the body, the poncho, the rope and the bell, so on a skin that draws its own body the lamb's artwork replaces yours. The fleece picker keeps working and keeps remembering your choice - it simply is not applied while this spine is worn, and comes back when you swap to one that allows it. **hiddenSlots** is a list of slot names this spine never draws. Use it for parts of the lamb rig your art replaces, such as the crown. Hiding a slot **in the Spine editor does not export**, and clearing its setup attachment only lasts until the first animation that keys the slot - the lamb skeleton keys `CROWN` in 276 animations and `PonchoLeft` in 181, and the game re-attaches the crown by name whenever it flies back or you change room. Listing the slot here replaces its artwork with fully transparent copies in the skin that all of those resolve through, so it stays hidden however it is re-attached. The attachments are replaced rather than deleted because some are required to exist: the game throws `Attachment not found: CROWN` if the crown cannot be resolved by name. Both settings apply per player and only while that spine is worn; other skins in the same file, and the vanilla lamb, are untouched. ## Fleece transmog and cycling ![Fleece cycling across six lamb skins](https://cotlmod.infernodragon.net/images/culttweaker/fleececycler.png) Fleece transmog swaps the visual fleece on any player skin, custom spines included, at any time and anywhere. It is controlled from the **F7** CultTweaker panel, which keeps a transmog toggle per player, and by the `[Fleece]` section of the config file: - `FleeceCyclingEnabled` turns fleece cycling on or off for all players. - `FleeceTransmogP1`, `FleeceTransmogP2` and so on hold the per-player switch. - `CurrentFleeceIndexP1` / `CurrentFleeceNameP1` (and the P2 pair) remember the chosen fleece between sessions, the name kept alongside the index so its spine can load at boot. A spine with `disableFleeceCycling` still hides its `hiddenSlots`; it is only the fleece artwork that is skipped. ## Per-player spines in co-op The player spine loader supports co-op with a separate spine per player. The chosen spine for each player is kept in the `[Spine]` config section as `SelectedSpineP1` and `SelectedSpineP2`, and the F7 panel has a player dock with a moving character preview and a preview animation dropdown for picking them. Player spines load in at startup rather than the first time the base is entered, so a custom lamb skin can be used in the intro. ::note Players beyond the second are dressed but not remembered: the config and the skin patch only know two, so the choice lasts until the skin next rebuilds. The F7 panel carries the same note. :: Custom player spines also show on the player tab of the inventory, in Knucklebones and in Flockade, for both players and on the Flockade result card. ## Known issue ::warning Custom player spines may not have the correct colour when attacking with certain weapons. :: # Custom follower forms ![A custom follower form](https://cotlmod.infernodragon.net/images/culttweaker/customfollowerform.png) A follower form is a set of per-slot overrides layered over one of the game's own follower base skins. Each override names a slot on the follower skeleton and supplies an image, a placement and a list of colour choices. Forms live in `BepInEx/plugins/CultTweaker/FollowerSkins`, one folder per skin, with a folder per variant inside it. ::tip The site has a [follower skin builder](https://cotlmod.infernodragon.net/builder) that authors these forms in the browser, converts legacy COTL JSONLoader skins into the CultTweaker format, and previews the result on a live Spine skeleton. :: ::note There is also a longer walkthrough with better formatting at [hackmd.io/@InfernoDragon0/HyxvdQ4wWg](https://hackmd.io/@InfernoDragon0/HyxvdQ4wWg){rel=""nofollow""} . :: ## Preparing followerSlots.json `followerSlots.json` is an important part of building skins: it provides the `SlotIndex` and `PartName` for each part you want to override. Every major update of Cult of the Lamb may change the format of follower forms, which means skins have to be updated to match the new format. To get the latest slot list for an update, enable the `DumpFollowerSpineAtlas` config inside `BepInEx/config/InfernoDragon0.cotl.CustomSpineLoader.cfg`. This generates `followerSlots.json` for that particular update, written to `CultTweaker/followerSlots.json`. ::caution Make sure `followerSlots.json` is not already present before dumping, and turn the setting back off afterwards - it may impact performance while enabled. :: Woolhaven's `followerSlots.json` is provided in the template's instruction folder. ## Folder layout The provided template folder, `ruffTemplateSkin`, shows the folder structure of a custom follower form, including how to set up the base and variant forms. Put the folder into the CultTweaker plugin folder so that it reads `CultTweaker > FollowerSkins > ruffTemplateSkins`, and the plugin will load the forms into the game. ```text | CultTweaker.dll | FollowerSkins | YourSkinName | base | head.png | config.json | variant | head.png | config.json ``` Inside each form folder you need: - a `config.json` file - any number of image files for your parts The image files should be separated as **single sprites, not a spritesheet**. They can have any name, as long as you name them in the `config.json`. ::note Variants do not have colour support and will only take their colour from the base skin. :: ![Variants of the same follower form](https://cotlmod.infernodragon.net/images/culttweaker/2.png) ## config.json Create a JSON file with `partConfigs` as the main key. Only `SlotIndex` and `PartName` are required; everything else is optional. ```json { "overrideBaseSkin": "Cat", "partConfigs": { "part2": { "SlotIndex": 89, "PartName": "HEAD_SKIN_BTM", "scaleX": 1.0, "scaleY": 1.0, "rotation": -90.0, "offsetX": 0.0, "offsetY": 0.0, "colorChoices": ["#FF0000"], }, "part1back": { "SlotIndex": 89, "PartName": "HEAD_SKIN_BTM_BACK", "colorChoices": ["#FF0000"] }, "part2top": { "SlotIndex": 91, "PartName": "HEAD_SKIN_TOP", "colorChoices": ["#FF0000"] }, "part1backtop": { "SlotIndex": 91, "PartName": "HEAD_SKIN_TOP_BACK", "colorChoices": ["#FF0000"] }, "color_leg_left": { "SlotIndex": 48, "PartName": "LEG_LEFT_SKIN", "colorChoices": ["#0000FF"], }, "color_leg_right": { "SlotIndex": 49, "PartName": "LEG_RIGHT_SKIN", "colorChoices": ["#0000FF"] } } } ``` In this example `part2.png` is applied to slot 89 at `HEAD_SKIN_BTM`, and `part1back.png` is applied to slot 89 at `HEAD_SKIN_BTM_BACK`. ### Top-level fields | Field | Type | Default | Description | | ------------------ | ------ | ------- | ---------------------------------------------- | | `overrideBaseSkin` | string | `Cat` | The base skin the custom skin is applied over. | | `partConfigs` | object | — | The parts you want to override, keyed by name. | Each key in `partConfigs` (such as `part2`) can be any name. If it matches an image file name in the same folder, that image is used for the `SlotIndex` / `PartName` specified in it. Each `partConfig` is named after the image file without the extension: `part2.png` = `part2`. The image file is optional. A key with no image lets you override just the slot's colours, like `color_leg_left` above. ### Part fields | Field | Type | Default | Description | | -------------- | ------------ | ------- | -------------------------------------------------------------------------- | | `SlotIndex` | int | — | Required. Which slot to override. Found in `followerSlots.json`. | | `PartName` | string | — | Required. The attachment name on that slot. Found in `followerSlots.json`. | | `ScaleX` | float | `1` | Increases or decreases the width of that part. | | `ScaleY` | float | `1` | Increases or decreases the height of that part. | | `Rotation` | float | `-90` | Rotates the part. | | `OffsetX` | float | `0` | Moves the part away from the centre point horizontally. | | `OffsetY` | float | `0` | Moves the part away from the centre point vertically. | | `HideSlot` | bool | `false` | Hides that slot entirely. | | `ColorChoices` | string array | white | The colours to choose from when indoctrinating. | Field names are matched case-insensitively, which is why the example above mixes `SlotIndex` with `scaleX`. ::warning `colorChoices` must have the same length for every `partConfig` . If the counts do not match, the skin will not be added to the game. :: ## The follower skin editor (F8) ![The follower customiser](https://cotlmod.infernodragon.net/images/culttweaker/customizer.png) Press **F8** anywhere in the game except the title screen. The editor edits the same `FollowerSkins/` folders the mod loads, so there is no separate project format. The **left panel** picks which skin and variant you are editing (and starts new ones), the colour set, the base skin every layer sits on (Cat, Dog and so on), an outfit for the preview to wear (just for looking - it is not part of the skin), the animation the preview plays, and the list of layers: pick a slot to override it, then click a layer to work on it. The **right panel** is that layer - its slot, the image covering it, whether it is hidden, its placement, and its colour for the set you are editing. Names are written as `skin/variant`, so one prompt makes either a new variant of a skin you have or a whole new skin. **Ctrl+S** saves, and saving makes the skin wearable straight away: it rebuilds the skin for the game, which pauses for a moment. Drop PNGs into the variant's folder and they show up in the image picker. Adding a colour set is an entry at the top of the Colour set list, like new skins and new layers. ::note Custom follower skins are baked once and kept rather than rebuilt on every launch. A skin is rebuilt only when you change it, and the kept copy can be shipped with a skin so other players never pay for the first build either. :: Custom follower forms can only be selected during indoctrination. For the rest of follower customisation - colour (R, G, B, A) and what they wear - you must toggle **Enable Customization** for the costume override to take effect. ## Migrating from JSONLoader - Instead of a spritesheet with all of the sprites in one image, you must separate them into single sprites. - The JSON config file differs in the following ways: - The JSON file should be named `config.json`, and be in the folder together with the skin. - `colors` and `overrides` are both combined as `partConfig`. - `name` is now `partName` and `slotIndex`. - `rect` is not needed; it will automatically use the sprite size. The [follower skin builder](https://cotlmod.infernodragon.net/builder) does this conversion for you: import a JSONLoader skin and it produces the CultTweaker part configs, then previews them live. ## Known issue ::warning Custom follower forms combined with follower customisation colour may lead to an incorrect preview in the UI. :: # Custom structures Structures live in `BepInEx > plugins > CultTweaker > CustomStructures`, one folder each, with a `config.json`. ## A sprite structure ```json { "StructureName": "Custom Altar", "StructureDescription": "A custom altar for your cult.", "SpritePath": "icon.png", "BuildDurationMinutes": 60, "BuildOnlyOne": true, "RequiresTempleToBuild": true, "CanBeFlipped": false, "HideFromBuildMenu": false, "Bounds": { "X": 2, "Y": 2 }, "ItemCost": { "LOG": 20, "STONE": 10 } } ``` The shipped template, `Templates/CustomStructures/ExampleStructure`, is the same config with an `Overrides` array: ```json { "StructureName": "Custom Altar", "StructureDescription": "A custom altar for your cult.", "SpritePath": "custom_altar.png", "Overrides": [], "BuildDurationMinutes": 60, "BuildOnlyOne": true, "RequiresTempleToBuild": true, "CanBeFlipped": false, "HideFromBuildMenu": false, "Bounds": { "X": 2, "Y": 2 }, "ItemCost": { "LOG": 20, "STONE": 10 } } ``` ### Fields | Field | Type | Description | | ----------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------- | | `StructureName` | string | The name the structure is listed and built under. | | `StructureDescription` | string | The description shown in the build menu. | | `SpritePath` | string | A PNG in the same folder. For a sprite structure this is the structure; for a Spine structure it is only the build menu icon. | | `Overrides` | array | Sprite overrides, in the same shape as a [building override](https://cotlmod.infernodragon.net/#overriding-the-games-own-structures). | | `BuildDurationMinutes` | number | How long the structure takes to build. | | `BuildOnlyOne` | bool | Whether only one may exist in the settlement. | | `RequiresTempleToBuild` | bool | Whether a temple is needed before it can be built. | | `CanBeFlipped` | bool | Whether the structure can be mirrored when placed. | | `HideFromBuildMenu` | bool | Keeps the structure out of the player's build menu. | | `Bounds` | `{ X, Y }` | The footprint in tiles. | | `ItemCost` | object | Item name to quantity, the cost to build it. | | `Spine` | object | Builds the structure as an animated skeleton instead of a flat sprite. See below. | Set `HideFromBuildMenu` to `true` to keep a structure out of the player's build menu while still being able to place it yourself in the map editor. This is useful for scenery that belongs to a map rather than to a cult. ::note Hidden or not, every custom structure appears in the map editor's structure tool under the **Custom** group, and saved maps load it either way. :: Custom structures also gain the editor's structure extras: an **Affected by wind** checkbox so they sway with the biome's own wind, shadows, and see-through when they block the camera during editing. ## Building a Spine structure instead of a sprite Add a `Spine` block and drop the Spine export (`.json` skeleton, `.atlas`, `.png` pages) into the same folder. The structure is then built as an animated skeleton rather than a flat sprite: ```json "Spine": { "SkinName": "Marble", "Animation": "idle", "Loop": true, "Offset": { "X": 0, "Y": 0, "Z": 0 }, "Scale": { "X": 1, "Y": 1, "Z": 1 } } ``` The shipped `Templates/CustomStructures/ExampleSpineStructure` is a complete example: ```json { "StructureName": "Occultist Effigy", "StructureDescription": "A scamp of the Old Faith, knelt in endless prayer. It does not look up when you pass.", "SpritePath": "icon.png", "Overrides": [], "BuildDurationMinutes": 45, "BuildOnlyOne": false, "RequiresTempleToBuild": true, "CanBeFlipped": true, "Bounds": { "X": 1, "Y": 1 }, "ItemCost": { "LOG": 15, "STONE": 5 }, "Spine": { "SkinName": "SF_Occultist_Scamp", "Animation": "_idles/pray", "Loop": true, "SkeletonScale": 0.005, "Offset": { "X": 0, "Y": 0, "Z": 0 }, "Scale": { "X": 1, "Y": 1, "Z": 1 }, "HideSprite": true } } ``` ### Spine block fields Every field is optional. | Field | Type | Default | Description | | ------------------------------------------- | -------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `SkinName` | string | the skeleton's default skin | Which skin to dress the structure in. | | `Animation` | string | none | Which animation to play once placed. Empty holds the setup pose, which is what a static prop wants. | | `Loop` | bool | `true` | Whether that animation loops. | | `Offset` | `{ X, Y, Z }` | zero | Nudges the skeleton relative to the structure's tile. | | `Scale` | `{ X, Y, Z }` | one | Scales the skeleton relative to the structure's tile. | | `Rotation` | `{ X, Y, Z }` | matches the structure's sprite | The world is drawn on a tilt, so anything standing upright in it is rotated `-60` on X (`300` in the inspector). Left out, the skeleton copies whatever the structure's own sprite does, falling back to that tilt. Set it to `{ "X": 0, "Y": 0, "Z": 0 }` for a prop meant to lie flat on the ground. | | `SkeletonScale` | float | `0.005` | Spine's import scale, for art authored at a different unit size. `0.005` matches the game's own skeletons. | | `SkeletonPath`, `AtlasPath`, `TexturePaths` | string / array | auto-discovered | Set these only when the folder holds more than one export. | | `ShaderName` | string | `Spine/Skeleton` | The material shader used for the skeleton. | | `HideSprite` | bool | `true` | Hides the flat sprite underneath. Set `false` to keep a painted base under an animated skeleton. | ### Auto-discovery Nothing needs to be named in the `Spine` block because everything is discovered from the folder: - the **skeleton** is the one `.json` that is not `config.json` - the **atlas** is the one `.atlas` - the **pages** are every `.png` except the one `SpritePath` claims as the icon Set `SkeletonPath` / `AtlasPath` / `TexturePaths` only if a folder holds more than one set. ::caution `SpritePath` is still used as the **build menu icon** , so keep a sprite for it. The icon PNG is deliberately excluded from atlas page discovery - without that exclusion it would be loaded as an atlas page and the skeleton would render blank. Without an icon the structure falls back to a placeholder and still builds as the skeleton. :: A skin or animation name the skeleton does not have is a warning in the log, not a crash: the structure falls back to the default skin and the setup pose. ### Log lines to look for ```text Found custom structure folder: ... Structure '...': spine attached ``` The first appears at startup, the second the first time the structure is placed. ::note The ready-made `ExampleSpineStructure` is an occultist scamp knelt in prayer, written against the same Spine export the `CustomNpcs/TestNpc` sample uses - the `Human.json` / `Human.atlas` / `Human.png` / `Human2.png` export - so copying those four art files in beside it makes it work as-is. :: ## Overriding the game's own structures ![A fishing hut before and after a structure override](https://cotlmod.infernodragon.net/images/culttweaker/structure-override.png) Create a folder named after the structure you want to override in the `BuildingOverrides` folder. Add images and a `config.json`. A complete structure skin folder looks something like this: ```text | CultTweaker.dll | BuildingOverrides | FISHING_HUT | fishing_hut_BACK.png | fishing_hut_FRONT.png | config.json ``` Each structure override folder must have a `config.json` in it: ```json { "overrides": [ { "spriteImageName": "fishing_hut_BACK.png", "offset": { "x": 0, "y": 0, "z": 0 }, "scale": { "x": 1, "y": 1, "z": 1 }, "rotation": { "x": 0, "y": 0, "z": 0 } }, { "spriteImageName": "fishing_hut_FRONT.png", "offset": { "x": 0, "y": 0, "z": 0 }, "scale": { "x": 1, "y": 1, "z": 1 }, "rotation": { "x": 0, "y": 0, "z": 0 } }, ] } ``` | Field | Type | Description | | ----------------- | ------------- | ------------------------------------------------ | | `spriteImageName` | string | A PNG in the same folder. | | `offset` | `{ x, y, z }` | Where the sprite sits relative to the structure. | | `scale` | `{ x, y, z }` | How large it is drawn. | | `rotation` | `{ x, y, z }` | How it is oriented in the world. | Change your offset and rotation accordingly, so as to build your structure design. A few things to note when building a custom structure design: - When sprites are rendered at rotation `0,0,0` the sprite is placed flat against the ground. - An **offset Z of at least `-0.027`** should be applied to flat sprites to remove z-fighting. To place other sprites above that one, go more negative, such as `-0.04`. - If the sprites should be facing the camera, a **rotation of `300,0,0`** is necessary. # Custom items and meals Items live in `BepInEx > plugins > CultTweaker > CustomInventoryItems` and meals in `CustomMeals`, one folder each, with a `config.json` and the sprite it names. A meal is an item with extra fields, so everything on this page's first table also applies to meals. Templates for both ship with the mod under `Templates/CustomInventoryItems` and `Templates/CustomMeals`. ## Custom inventory items ```json { "ItemName": "Cult Tweaker Test Item", "Lore": "An experimental item created for testing CultTweaker.", "Description": "A test item used to validate CustomInventoryItem loading.", "SpritePath": "placeholder.png", "ItemType": 0, "CanBeRefined": true, "RefineryInputQty": 10, "CustomRefineryDuration": 60.0, "FuelWeight": 2, "FoodSatitation": 90, "IsFish": false, "IsFood": true, "IsBigFish": false, "IsCurrency": false, "IsBurnableFuel": true, "CanBeGivenToFollower": true, "AddItemToOfferingShrine": true, "AddItemToDungeonChests": true, "DungeonChestSpawnChance": 50, "DungeonChestMinAmount": 1, "DungeonChestMaxAmount": 2 } ``` | Field | Type | Default | Description | | ------------------------- | ------ | ------------------------------------------------- | ---------------------------------------------------------------------- | | `ItemName` | string | — | The item's name. Spaces become underscores in its internal name. | | `Lore` | string | `Custom Item created with CultTweaker.` | The item's lore line. | | `Description` | string | `This is a custom item created with CultTweaker.` | The item's description. | | `SpritePath` | string | — | A PNG in the same folder, used as the inventory icon and world sprite. | | `ItemType` | int | — | `0` = ITEM, `1` = CURRENCY, `2` = FOOD. | | `CanBeRefined` | bool | `false` | Whether the item can be refined. | | `RefineryInputQty` | int | `15` | How many are consumed per refine. | | `CustomRefineryDuration` | float | `0` | How long a refine takes. | | `FuelWeight` | int | `1` | How much fuel one item is worth. | | `FoodSatitation` | int | `75` | How much hunger the item satisfies. | | `IsFish` | bool | `false` | Whether the item counts as a fish. | | `IsBigFish` | bool | `false` | Whether the item counts as a big fish. | | `IsFood` | bool | `false` | Whether the item counts as food. | | `IsCurrency` | bool | `false` | Whether the item counts as currency. | | `IsBurnableFuel` | bool | `false` | Whether the item can be burned as fuel. | | `CanBeGivenToFollower` | bool | `false` | Whether the item can be given to a follower. | | `AddItemToOfferingShrine` | bool | `false` | Whether the item appears at the offering shrine. | | `AddItemToDungeonChests` | bool | `false` | Whether the item can appear in dungeon chests. | | `DungeonChestSpawnChance` | int | `100` | The chance it is rolled for a dungeon chest. | | `DungeonChestMinAmount` | int | `1` | The fewest that drop at once. | | `DungeonChestMaxAmount` | int | `1` | The most that drop at once. | ## Custom meals A meal config carries every item field above plus the meal fields below. ```json { "ItemName": "Hearty Stew", "Lore": "A filling stew made from local ingredients.", "Description": "Restores stamina and heals slightly.", "SpritePath": "hearty_stew.png", "ItemType": 2, "CanBeRefined": false, "RefineryInputQty": 0, "CustomRefineryDuration": 0.0, "FuelWeight": 0, "FoodSatitation": 150, "IsFish": false, "IsFood": true, "IsBigFish": false, "IsCurrency": false, "IsBurnableFuel": false, "CanBeGivenToFollower": true, "AddItemToOfferingShrine": false, "AddItemToDungeonChests": false, "DungeonChestSpawnChance": 0, "DungeonChestMinAmount": 0, "DungeonChestMaxAmount": 0, "SatiationLevel": 3, "TummyRating": 0.85, "MealQuality": "GOOD", "MealSafeToEat": true, "Recipe": { "MEAT": 1, "VEGETABLE": 2 }, "MealEffectsDictionary": { "HEAL": 50 } } ``` | Field | Type | Default | Description | | ----------------------- | ------ | -------- | -------------------------------------------------------------------------------------------- | | `SatiationLevel` | int | `0` | How filling the meal is. | | `TummyRating` | float | `0` | The meal's tummy rating. | | `MealQuality` | string | `NORMAL` | The meal's quality. Parsed case-insensitively; an unrecognised value falls back to `NORMAL`. | | `MealSafeToEat` | bool | `true` | Whether the meal is safe to eat. | | `Recipe` | object | empty | Ingredient name to quantity. | | `MealEffectsDictionary` | object | empty | Effect name to amount. | ::note Ingredients and effects are named the same way content is named everywhere else in CultTweaker: by internal name. Custom items work as ingredients. :: The log reports each item and meal as it registers, with the internal name it was given. Search `BepInEx/LogOutput.log` for the item's name if it does not turn up in game. # Custom tarot cards Tarot cards live in `BepInEx > plugins > CultTweaker > CustomTarotCards`, one folder each, with a `config.json` and the sprites it names. A template ships with the mod at `Templates/CustomTarotCards/ExampleTarot`. ## config.json ```json { "CardName": "Omen of Fortune", "SpritePath": "omen_of_fortune.png", "BackSpritePath": "tarot_back.png", "Category": "Custom", "TarotCardWeight": 200, "MaxTarotCardLevel": 1, "IsCursedRelated": false, "Lore": "A mysterious card promising small blessings.", "Description": "Increases loot and chance for relics.", "SpiritHeartCount": 0.0, "SpiritAmmoCount": 0, "WeaponDamageMultiplierIncrease": 0.0, "CurseDamageMultiplierIncrease": 0.0, "WeaponCritChanceIncrease": 0.05, "LootIncreaseModifier": 1, "MovementSpeedMultiplier": 0.05, "AttackRateMultiplier": 0.0, "BlackSoulsMultiplier": 0.0, "HealChance": 0.0, "NegateDamageChance": 0.0, "DamageAllEnemiesAmount": 0, "HealthAmountMultiplier": 0, "AmmoEfficiency": 0.0, "BlackSoulsOnDamage": 0, "ItemToDropInternalName": "CULT_TWEAKER_TEST_ITEM", "ChanceOfGainingBlueHeart": 0.02, "ChanceForRelicsMultiplier": 0.10, "RelicChargeMultiplier": 0.1 } ``` ## Fields | Field | Type | Default | Description | | -------------------------------- | ------ | -------------------------------------------------- | -------------------------------------------------------------------- | | `CardName` | string | — | The card's displayed name. | | `SpritePath` | string | — | A PNG in the same folder, the card's front face. | | `BackSpritePath` | string | — | A PNG in the same folder, the card's back face. | | `Category` | string | `Custom` | The tarot card category. | | `TarotCardWeight` | int | `150` | How likely the card is to be offered. | | `MaxTarotCardLevel` | int | `0` | The highest level the card can reach. | | `IsCursedRelated` | bool | `false` | Whether the card counts as curse-related. | | `Lore` | string | `Custom Tarot created with CultTweaker.` | The card's lore line. | | `Description` | string | `This is a custom tarot created with CultTweaker.` | The card's description. | | `SpiritHeartCount` | float | `0` | Spirit hearts granted. | | `SpiritAmmoCount` | int | `0` | Spirit ammo granted. | | `WeaponDamageMultiplierIncrease` | float | `0` | Increase to the weapon damage multiplier. | | `CurseDamageMultiplierIncrease` | float | `0` | Increase to the curse damage multiplier. | | `WeaponCritChanceIncrease` | float | `0` | Increase to weapon critical hit chance. | | `LootIncreaseModifier` | int | `0` | Loot increase modifier. | | `MovementSpeedMultiplier` | float | `0` | Movement speed multiplier. | | `AttackRateMultiplier` | float | `0` | Attack rate multiplier. | | `BlackSoulsMultiplier` | float | `0` | Black souls multiplier. | | `HealChance` | float | `0` | Chance to heal. | | `NegateDamageChance` | float | `0` | Chance to negate damage. | | `DamageAllEnemiesAmount` | int | `0` | Damage dealt to all enemies. | | `HealthAmountMultiplier` | int | `0` | Health amount multiplier. | | `AmmoEfficiency` | float | `0` | Ammo efficiency. | | `BlackSoulsOnDamage` | int | `0` | Black souls gained when damaged. | | `ItemToDropInternalName` | string | none | The internal name of an item the card drops. Custom items work here. | | `ChanceOfGainingBlueHeart` | float | `0` | Chance of gaining a blue heart. | | `ChanceForRelicsMultiplier` | float | `0` | Multiplier on the chance for relics. | | `RelicChargeMultiplier` | float | `0` | Multiplier on relic charge. | ::note `ItemToDropInternalName` is looked up by internal name each session, never by the number the game assigned it - those numbers are handed out per install, in load order. See [the ids warning](https://cotlmod.infernodragon.net/docs/culttweaker/modding-api) . :: # Custom enemies Enemies live in `BepInEx > plugins > CultTweaker > CustomEnemies`, one folder each, with a `config.json`. **The AI is a vanilla enemy's.** An enemy here names one of the game's own enemy prefabs to mimic and keeps its brain wholesale - its states, attacks, animations and death - then changes what can be changed from outside. ## config.json ```json { "EnemyName": "Test Brute", "Mimic": "Assets/Prefabs/Enemies/DLC/Enemy Swordsman Wolf.prefab", "Health": 24, "Scale": 1.5, "BossHealthBar": true, "BossBarName": "THE BRUTE", "SkinName": "", "Tuning": { "maxSpeed": 0.075, "AttackWithinRange": 5.0, "MaintainTargetDistance": 3.0, "DoubleAttack": 1 } } ``` ## Fields | Field | Type | Default | Description | | ------------------------------------------------------------ | ----------------------- | --------------- | --------------------------------------------------------------------------------- | | `EnemyName` | string | — | Required. The name it is listed under in the map editor. | | `Mimic` | string | a bat | The vanilla enemy prefab this one is built from, and whose AI it uses. | | `Health` | number | `5` | Total HP. | | `Scale` | number | `1` | Multiplies the spawned enemy's size. A brute is the same enemy at 1.6. | | `SkinName` | string | — | A skin on the skeleton - your own if the folder ships one, otherwise the mimic's. | | `BossHealthBar` | bool | `false` | Shows the game's boss bar across the top of the screen while it is alive. | | `BossBarName` | string | `EnemyName` | What that bar is labelled. | | `Tuning` | object | — | Any public field or property on the mimic's own controller, by name. | | `SkeletonPath`, `AtlasPath`, `TexturePaths`, `SkeletonScale` | string / array / number | auto-discovered | Set only when the folder holds more than one Spine export. | ## Giving it your own art Drop a Spine export (`.json` skeleton, `.atlas`, `.png` pages) in the folder to give it your own art. Without one it wears the mimic's skeleton, and `SkinName` then picks a skin off *that*. ## Tuning **Tuning** is where the behaviour lives. Every vanilla enemy exposes its numbers as public fields - `EnemySwordsmanWolf` alone has around fifty - so `AttackWithinRange`, `MaintainTargetDistance`, `DoubleAttack`, `ChargeAndAttack`, `KnockbackModifier`, `Damage`, plus `maxSpeed` and `SpeedMultiplier` on every enemy, are all reachable by name. Values are numbers because a tuning table is numbers; a true/false field takes `0` or `1`. ::note A name that does not exist on that enemy is reported in the log rather than ignored silently, so a typo is findable. :: ## Placing them Custom enemies appear in the map editor's enemy tool under **Custom (mods)**, place like any other, and save into blueprints. # Custom weapons A custom player spine can add weapons to Cult of the Lamb. Each one is built on a vanilla weapon and swaps in your artwork, your combo, your numbers and your timings. It keeps the base weapon's heavy attack, sounds, hit shapes and pickup card. :video-player{caption="A custom weapon in game: the artwork, combo and numbers come from the config, everything else from the vanilla weapon it is built on." src="https://cotlmod.infernodragon.net/videos/customweaponsample.mp4"} ## Where the config goes Weapons are part of the spine that carries their artwork. They go in the spine's `config.json`, under `weapons`, beside the usual skin settings: ```text PlayerSkins/ FlameLamb/ player-main.json player-main.atlas player-main.png flamesword.png <- optional icon config.json ``` ```json { "defaultSkin": "Lamb", "skins": [ "Lamb" ], "preloadWeapons": false, "weapons": [ { "name": "FlameSword", "displayName": "Flame Sword", "description": "Burns a little.", "lore": "Forged in the Old Faith's last fire.", "baseWeapon": "Sword", "skin": "Weapons/FlameSword", "modifierSkin": "Normal", "pickupAnimation": "weapons/get-weapon-flamesword", "icon": "flamesword.png", "inPool": true, "combo": [ { "animation": "attack-combo1-flame", "damage": 1.0, "speed": 1.0 }, { "animation": "attack-combo2-flame", "damage": 1.0, "speed": 1.2 }, { "animation": "attack-combo3-flame", "damage": 1.5, "speed": 0.9, "range": 1.2, "hitboxRadius": 0.9, "knockback": 1.5 } ] } ] } ``` A spine can declare any number of weapons. A weapon is known to the game as `/`, for example `FlameLamb/FlameSword`; that is the name the map editor's Podium tool shows. ## Weapon fields | Field | Type | Default | Description | | ----------------- | ------ | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | required | Id of the weapon inside this spine. Letters, digits and underscores are safest. Changing it later changes the weapon's id, so saves that had it in the weapon pool forget it. | | `displayName` | string | `name` | Name on the pickup card and the HUD. | | `description` | string | empty | Text under the name on the pickup card. | | `lore` | string | empty | Small italic line on the pickup card. | | `baseWeapon` | string | `Sword` | The vanilla weapon this one is built on: `Sword`, `Axe`, `Hammer`, `Dagger`, `Gauntlet`, `Blunderbuss`, `Shield` or `Chain`. Decides the heavy attack, the sounds, the swipe shape, the default combo and the default pickup animation. | | `skin` | string | none | A skin in your Spine file holding the weapon's attachments. Without it the weapon looks like the base weapon. | | `modifierSkin` | string | `Normal` | The vanilla modifier skin layered under yours: `Normal`, `Poison`, `Critical`, `Healing`, `Fervor`, `Godly` or `Necromancy`. Cosmetic only; the modifier's effect is not applied. | | `pickupAnimation` | string | base weapon's | Animation played when the weapon is picked up from a podium, the ground or a shop. | | `icon` | string | `hookIcon`, else the base weapon's | A PNG in the spine folder, used on the HUD, the podium and the pickup card. Drawn at the size of the base weapon's icon. | | `hookIcon` | string | the chain's hook | Chain-based weapons only: a PNG in the spine folder drawn at the end of the chain while it swings. | | `hookScale` | number | `1` | Chain-based weapons only: size of `hookIcon` relative to the chain's own hook. | | `inPool` | bool | `true` | Whether weapon podiums, weapon rooms and chests can roll this weapon. `false` keeps it to podiums pinned to it by the map editor. | | `combo` | array | base weapon's chain | The chain of hits, in order. | And one field at the top level of the spine config, not inside a weapon: | Field | Type | Default | Description | | ---------------- | ---- | ------- | ------------------------------------------------------------------------------ | | `preloadWeapons` | bool | `false` | Load this spine at boot so its weapons never show the base look while loading. | ## Hit fields `combo` is a list; each entry is one hit, in the order they chain. Pressing attack repeatedly plays hit 1, 2, 3, ... and wraps to hit 1 after the last. Every hit starts as a copy of the base weapon's hit at the same position in its chain (a longer chain than the base's wraps: hit 4 of a Sword-based weapon starts as a copy of the sword's hit 1), and each field below replaces one value on that copy. Anything left out keeps the base hit's value. | Field | Type | Default | Description | | --------------- | ------ | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `animation` | string | base hit's | The Spine animation this hit plays. | | `damage` | number | base hit's | Base damage before the run's multipliers. Vanilla light hits are around 1. | | `speed` | number | `1` | Playback speed of the animation. `1.5` is half again as fast, `0.5` half speed. Everything in the animation scales with it, including where the hit lands in time. | | `range` | number | base hit's | How far in front of the player the hit's circle is placed, in world units. Vanilla swords use about 1. Also the circle's radius unless `hitboxRadius` is set. | | `hitboxRadius` | number | `range` | Radius of the hit's circle, in world units, independent of `range`. A large `range` with a small `hitboxRadius` is a poke; a small `range` with a large `hitboxRadius` is a sweep around the player. | | `knockback` | number | base hit's | Push applied to whatever the hit strikes. | | `lungeSpeed` | number | base hit's | Speed of the forward lunge the player takes while swinging (vanilla default 20). | | `lungeDuration` | number | base hit's | How long that lunge lasts, in seconds (vanilla default 0.15). | | `cameraShake` | number | base hit's | Camera shake strength when the hit lands. | | `attackType` | string | base hit's | `Melee`, `Heavy`, `Projectile`, `Poison`, `NoKnockBack`, `Ice` or `Charm`. Changes how enemies react (`NoKnockBack` is what it says; `Ice` and `Charm` apply those effects the way curses do). | | `canQueueNext` | bool | base hit's | Whether pressing attack during this hit queues the next one. `false` makes the player wait for the hit to finish before the next input counts. | | `canTurn` | bool | base hit's | Whether the player may change facing while this hit plays. | | `hook` | object | chain's own | Chain-based weapons only: the hook's move on this hit and the shape of its sweep. | | `hitAt` | number | `0.35` | Only used when the animation has no attack events: where "Attack Deal Damage" is placed, as a fraction of the animation's length. | | `breakAt` | number | `0.65` | Only used when the animation has no attack events: where "Attack Can Break" is placed, as a fraction of the animation's length. | ## Making the weapon's skin The game does not tell weapons apart by skin. Its weapon skins (`Weapons/Normal`, `Weapons/Poison` and so on) carry only the tint of the modifier; the shape of the weapon comes from the attack animations, which key the `WEAPON` slot to a named attachment: `Weapons/Sword`, `Weapons/Axe`, `Weapons/Hammer`, `Weapons/Dagger`, `Weapons/Blunderbuss`, `Shield`. Your skin works the same way. Make a skin in your Spine project (any name; `Weapons/FlameSword` follows the vanilla pattern) and put the weapon's attachments in it, on the `WEAPON` slot. Then: - **If you reuse the base weapon's animations**, name your attachments the way those animations expect them. A Sword-based weapon whose skin puts an attachment named `Weapons/Sword` on the `WEAPON` slot shows your image wherever the sword animations showed the sword. Do the same on `Weapons/SwordHeavy` for the heavy attack (`AxeHeavy`, `HammerHeavy`, `Blunderbuss_Heavy` for the others). - **If you make your own animations**, key the `WEAPON` slot to whatever you named your attachments, and give the skin those attachments. Nothing else is required, but keep the base names too if you want the weapon to look right on other spines. The skin only needs to exist; do not add it to the spine's `skins` list unless you also want it selectable as a look. ### Any spine can wield it A custom weapon is not tied to the spine that declares it. Whoever picks it up, on any skin, gets the skin's attachments copied onto their skeleton the way a fleece is copied. What cannot be copied is animations, so on a skin without your custom animations the base weapon's animations play, and they show your artwork only if your skin also provides the base attachment names. The same applies in multiplayer, where each player may wear a different spine. ## Hit timings The game's combat code drives an attack by three named events inside the animation. It does not look at the animation's length or its frames; it waits for the events. Every vanilla attack has them, and any animation you make for a hit should carry them too. Copy them from a vanilla attack in Spine, then move them to fit your swing. | Event name | What happens when it fires | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Attack Deal Damage` | The hit lands: the swipe circle is spawned in front of the player for a tenth of a second and damages everything it overlaps once. The attack sound plays and the camera shakes. | | `Attack Can Break` | The hit may now be interrupted: a queued attack starts the next hit immediately, a dodge cancels the swing, the player can move. Before this event the player is locked in the swing. | | `Attack Has Finished` | The swing is over. The player returns to idle if nothing was queued. | | `Update Angle` | Optional. The moment the facing is committed: the player turns toward the stick or mouse until this fires, then the swing keeps that direction. Vanilla puts it on or just before "Attack Deal Damage". | So a hit has three phases: 1. **Wind-up**, from the start to `Attack Deal Damage`. Nothing can be hit yet. This is the part that makes a weapon feel heavy or quick. 2. **Follow-through**, from `Attack Deal Damage` to `Attack Can Break`. The hit has landed but the player is still committed. Pressing attack here queues the next hit. 3. **Recovery**, from `Attack Can Break` to `Attack Has Finished`. The player may cancel into the next hit, a dodge or a move. If nothing is pressed the animation plays out. The combo counter goes back to hit 1 when 0.2 seconds pass without an attack after a hit finished. For reference, the vanilla timings, in seconds from the start of the animation: | Animation | Update Angle | Deal Damage | Can Break | Finished | | ------------------------------------- | ------------ | ----------- | --------- | -------- | | Sword hit 1 (`attack-combo1`) | 0.03 | 0.03 | 0.27 | 0.60 | | Dagger hit 1 (`attack-combo1-dagger`) | 0.03 | 0.03 | 0.20 | 0.53 | | Axe hit 1 (`attack-combo1-axe`) | 0.17 | 0.20 | 0.63 | 0.83 | | Axe hit 3 (`attack-combo3-axe`) | 0.20 | 0.30 | 0.63 | 0.97 | | Hammer hit 1 (`attack-combo1-hammer`) | 0.40 | 0.43 | 0.77 | 1.13 | The sword and dagger hit almost at once and recover fast; the axe and hammer wind up. A weapon that wants to feel heavy needs a later "Attack Deal Damage", not just more damage. **Speed and the events.** `speed` scales the whole animation, events included. Hit 1 of the sword at `speed: 2` deals damage at 0.017 s and can be broken at 0.13 s. This is how vanilla's weapon level and the attack-speed tarot cards work too, so a fast weapon is a fast animation, not a short one. ::caution **If an animation has none of the three events** , the mod adds them when the spine loads, so a hit can never lock the player in place: "Update Angle" and "Attack Deal Damage" at `hitAt` (default 35% of the animation), "Attack Can Break" at `breakAt` (default 65%), and "Attack Has Finished" at the end. The log names the animation and the times it used. This only happens when the animation has **none** of them; an animation with one or two is assumed to be deliberate and left alone, so make sure a hand-placed set is complete: without "Attack Can Break" and "Attack Has Finished" the player stays locked in the swing. :: **The pickup animation** has no required events. It is played once and its length is what holds the player in place, so a long pickup animation is a long pause. ## Damage and speed Every hit's damage is its `damage` multiplied by the run's bonuses: the weapon's level (vanilla adds 13% plus 7% per level), the fleece, tarot cards, relics, and the difficulty setting. So `damage` is the number to compare against vanilla, not the number that appears on enemies. Vanilla swords deal about 1 per light hit, axes and hammers more, daggers less. The pickup card shows the average of the hits through the same formula, and calls the weapon faster or slower than the held one by the average `speed` of its hits. Heavy attacks are not part of the config. They keep the base weapon's animation, damage and fervour cost, and their animations are looked up by family, so a Sword-based weapon always has the sword's heavy attack. ## Loading and preloading The weapon's artwork lives in your spine file, which is large and only loaded when needed. At boot the spine loads only if a player is wearing it. Otherwise it starts loading the moment one of its weapons appears in a room, when a podium rolls it, a chest offers it or an enemy drops it, in the background while the player walks over. A player who reaches it before the load finishes holds it with the base weapon's look until the artwork lands, usually a few seconds. Nothing pauses. Set `preloadWeapons: true` at the top level of the spine config to load the spine at boot instead, whether or not anyone wears it. The weapon then always has its artwork from the first room. The cost is a longer start and a few hundred megabytes of memory per spine, for as long as the game runs, so leave it off for spines whose weapons are rarely rolled. ## Testing a weapon Custom weapons join the weapon pool, so weapon podiums and chests can roll them, but the roll is random. To get one on purpose: ::steps ### Open the editor Enter a dungeon and press `F4` to open the map editor. ### Pick a weapon on the Podium tool Under the podium type there is a **Weapon** list: "Any" rolls from the pool as usual, the vanilla weapons pin the podium to that weapon, and every custom weapon is listed by its `/` key. Picking a weapon sets the podium type to Weapon for you. ### Place it Place one and close the editor. That podium always offers that weapon. :: Podiums placed this way are saved with the room like any other, so a test room can be kept. The log (`BepInEx/LogOutput.log`) reports each weapon as it registers, with the id it was given, and warns about a skin or animation the spine does not have, an icon that could not be read, or a hit whose events were added. Search for the weapon's name. ### Seeing the hit box In the mod's config file (`BepInEx/config/InfernoDragon0.cotl.CustomSpineLoader.cfg`) set `WeaponHitboxes` under `[Debug]` to `true`. Every attack then draws the outline of its hit box where it lands, with a line from the attacker to its centre, fading out over most of a second: cyan for a custom weapon's light hit, amber for any other attack of the player's (vanilla weapons, heavy attacks), red for enemies. Swing a vanilla sword and your weapon side by side to compare `range` and `hitboxRadius`; the value in the config is in the same units as the drawing. Chain hooks are drawn too, following the hook while it is out: its circle and the chain's box, dimmed while they cannot hurt. Leave it off for play. ## Chain-based weapons The Chain (the hook-and-chain from the Unholy Alliance DLC) is the one weapon whose swing is not in the Spine animation. The skeleton only plays the body pose; the chain and hook are a separate object that the game moves along a scripted arc per hit, drawn as a line from the player's hand to the hook, and the hit is the hook's own collider, not a swipe circle. So a Chain-based custom weapon changes less than the others: - `damage`, `speed`, `range` (the hook's collider radius), `knockback`, `cameraShake` and the body `animation` work as for any hit. `hitboxRadius` does not apply, because the hook never goes through the swipe path; `range` is the hook's circle. - The hook's move and the shape of its sweep are set per hit with a `hook` block: ```json { "animation": "attack-chain-combo1", "damage": 1.0, "hook": { "pattern": "left", "startAngle": -90, "sweep": 360, "width": 2.5, "height": 1.5, "offset": 0, "duration": 0.45 } } ``` `pattern` picks the move: `left` sweeps one hook around the player's left side, `right` the other hook around the right, `slam` throws both hooks out and slams them down (the chain's third hit, auto-aimed at the nearest enemy), `fallback` is the game's untuned quick sweep, only available on hit four or later. Without a pattern the chain's own order applies: left, right, slam, then fallback for every hit after the third. A sweep is an ellipse around the player, in the plane of the screen: | Field | Type | Default | Description | | ------------------ | ------ | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `pattern` | string | the chain's own order | `left`, `right`, `slam` or `fallback`. | | `startAngle` | number | the chain's own | Where on the ellipse the hook starts, in degrees from the direction the player faces. | | `sweep` | number | the chain's own | How far it travels, in degrees. Negative goes the other way round; `360` is a full circle. | | `width` | number | the chain's own | The ellipse's horizontal radius, in world units. | | `height` | number | the chain's own | The ellipse's vertical radius, in world units. | | `offset` | number | the chain's own | Moves the ellipse's centre sideways from the player, to the left for `left` and the right for `right`. `0` centres it. | | `duration` | number | the chain's own | The sweep's time in seconds at normal attack speed. | | `colliderOn` | number | the chain's own | Seconds after the start before the hook starts hurting. | | `colliderOff` | number | the chain's own | When it stops hurting. The chain's own thrusts stop at 0.28 s; with a `duration` set and no `colliderOff`, the hook stays live for the whole sweep. | | `radiusCurve` | array | the chain's own | `[time, multiplier]` pairs, time from 0 to 1 across the hit, scaling the ellipse's radius as the hit plays. | | `scaleCurve` | array | the chain's own | The same shape, scaling the hook picture over the hit, for a wind-up or a flourish. | | `hooks` | int | 1 | `2` on a `left` or `right` hit swings both chains. | | `secondStartAngle` | number | `180` | How far behind the first the second chain is, in degrees. `0` puts them together. | | `secondDelay` | number | 0 | Holds the second chain back by that many seconds. | Any value left out is the chain's own for that move: a hit with a pattern starts as a copy of the chain's hit for that move, including its swing effect (the white arc), rather than the chain's hit at the same position. The log prints the chain's own numbers for its three hits the first time a Chain-based weapon is built, so there is a reference to start from. The `slam` pattern reads the same numbers but flies the hooks along the facing direction rather than around the player. The hook appears at the start of its path rather than travelling out from the hand, so a thrust is made with `radiusCurve`. A stab is a sweep of `0` (the chain is drawn straight) with `"radiusCurve": [[0, 0], [0.4, 1], [1, 0.2]]`: the hook shoots out to full reach by 40% of the hit and pulls most of the way back. There are two chains. The game swings one on a sweep and both only on the slam; `hooks: 2` on a `left` or `right` hit swings both, the second on the mirrored side of the player and half a turn behind the first, which on a full circle puts a head on each end of the spin. The second chain rolls its own critical hit and carries the same damage, reach and curves as the first, and takes the direction the player faces at the moment it leaves. Two chains are all there are, so a hit that swings both cuts short whatever the previous hit still had in the air. The chain held in the hand between attacks is part of the skeleton (`Weapons/Chain_Long` and `Weapons/GrappleHook` slots), so your skin can restyle it like any weapon. The picture at the end of the swinging chain is **not** in the skeleton: set `hookIcon` to a PNG in the spine folder to replace it, an axe head for a flail for instance. Whatever its pixel size, it is scaled so its larger side matches the chain's own hook; `hookScale` makes it bigger or smaller than that (`1.5` is half again as large). Without `hookIcon` the chain's usual hook is used. The heavy attack keeps the game's heavy hook. When there is no `icon`, the hook picture is also the weapon's icon on the podium and the HUD. ## Limits - The hit box is always a circle in front of the player, sized by `range` and `hitboxRadius`. The artwork never collides, so a very long or oddly shaped weapon still hits in a circle. - Heavy attacks, blocking (Shield) and the chain's hook are the base weapon's and cannot be changed. - A weapon's id comes from its spine folder name and its `name`. Renaming either makes it a new weapon; the old one lingers in saves as an unknown id that is skipped by rolls and, if held, replaced by the sword. - In multiplayer both players need the spine installed for the weapon to look right on both screens. Only the host's worn skin is shipped to the guest, so a weapon spine the other player lacks shows there as the base weapon. # Custom NPC quests A custom NPC can hand out quests. They show up in the objectives panel on the right of the screen, next to the game's own, with the same look, the same tick boxes and the same counters. Everything lives in the NPC's `config.json`, next to its dialogue. ::note The mod ships a **Test Npc** carrying two quests to try. :: ## A first quest ```json { "NpcName": "Bramble", "SkinName": "A_Tiger", "Quests": [ { "Id": "firewood", "Title": "Wood for Bramble", "ReturnText": "Bring the wood back to Bramble", "Goals": [ { "Type": "collectItem", "Target": "LOG", "Count": 10, "Text": "Gather logs", "Consume": true } ], "Reward": { "Items": [ { "Item": "GOLD_NUGGET", "Count": 5 } ] } } ], "Dialogue": { "Start": "greet", "Entry": [ { "QuestReady": "firewood", "Node": "handin" }, { "QuestActive": "firewood", "Node": "nag" }, { "Node": "greet" } ], "Nodes": [ { "Id": "greet", "Lines": [ { "Text": "My fire is dying. Would you fetch me wood?" } ], "Choices": [ { "Id": "yes", "Text": "I will.", "Next": "taken", "GiveQuest": "firewood" }, { "Id": "no", "Text": "Find your own.", "Next": "bye" } ] }, { "Id": "taken", "Lines": [ { "Text": "Ten logs. I will count them." } ] }, { "Id": "nag", "Lines": [ { "Text": "Still no wood?" } ] }, { "Id": "handin", "Lines": [ { "Text": "Wood! Take this gold." } ], "TurnInQuest": "firewood" }, { "Id": "bye", "Lines": [ { "Text": "Then walk safely." } ] } ] } } ``` That is a whole quest: the NPC offers it, the panel counts the logs, the NPC takes them and pays. ## Quest fields | Field | Type | Default | Description | | --------------- | ------ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `Id` | string | — | Unique within this NPC. Dialogue names the quest by this. | | `Title` | string | — | The header the quest gets in the panel. | | `ReturnText` | string | `Return to ` | The line shown once every goal is met. | | `TurnIn` | bool | `true` | `true`: the quest finishes when the player talks to the NPC again. `false`: it finishes the moment the last goal is met. | | `Repeatable` | bool | — | Lets the player take the quest again after finishing it. | | `AutoTrack` | bool | `true` | Pins the quest to the panel when it is accepted. The game shows at most three pinned groups and drops the oldest. | | `ExpireSeconds` | number | `0` | Game seconds before the quest fails on its own. Omit or `0` for never. A quest with a timer gets the game's countdown wheel. | | `Goals` | array | — | One or more lines of work. Every one has to be met. | | `Reward` | object | — | What the player gets on completion. | ## Goal types | `Type` | `Target` | What moves it | | ----------------- | ---------------------------------- | ------------------------------------------------------------------------ | | `collectItem` | an item | The player holding that many. `Consume: true` takes them at hand-in. | | `killEnemies` | an enemy | Kills of that enemy anywhere. | | `buildStructure` | a structure | Structures of that type standing in the settlement. | | `followers` | — | How many followers the cult has. | | `completeDungeon` | a dungeon | Walking out of a run in that dungeon alive. Custom dungeons work. | | `performRitual` | a ritual | Performing it. | | `gameEvent` | one of the game's own quest events | The game reaching that beat. | | `talkTo` | another custom NPC's internal name | Speaking to them. | | `flag` | any name you choose | `CultTweakerApi.NoteQuestEvent("name")`, or a dialogue node's `SetFlag`. | Goal fields: | Field | Type | Default | Description | | --------- | ------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Text` | string | — | The line shown in the panel. When `Count` is 2 or more the game appends " 3 / 10" to it; when it is 1 the counter is hidden, so write the line as a whole sentence. | | `Count` | int | `1` | How many. | | `Total` | bool | — | `collectItem`, `buildStructure` and `followers` only. Counts what the player already has instead of only what they gather after taking the quest. | | `Consume` | bool | — | `collectItem` only. Takes the items at hand-in. | The first four types are read back from the world rather than counted up, but only when the game says that part of the world changed: the inventory was updated, an enemy died, a building went up or came down, a follower joined or left. They are the same signals the game's own objectives listen to. That means these goals also catch up on their own after a load, a cheat, or another mod handing the player items, without anything running on a timer. The rest are counted as the game announces them. `gameEvent` is the wide one: it listens to the same channel the game's own story quests use, so any of its roughly two hundred beats can end a custom quest - `CookFirstMeal`, `CatchFish`, `BuryBody`, `DeclareDoctrine`, `PlayFlockade` and so on. The names are the game's own; a wrong one is reported in the log at load. ## Naming content in a goal Vanilla names come first: `LOG`, `CRYSTAL`, `GOLD_NUGGET` for items, `Scamp` for enemies, `Ritual_Feast` (or just `Feast`) for rituals, `Dungeon1_1` for dungeons, `BED_3` for structures. Custom content is named the same way it is named everywhere else in CultTweaker: by its internal name. A custom item, meal, enemy, structure or dungeon is found by name, and the number the game gave it is looked up fresh each session. That is deliberate - those numbers are handed out per install, in load order, so a saved number would mean a different thing on another machine or after a mod is added. Nothing but names is ever written to the progress file. ## Handing quests out in dialogue Four fields work on a dialogue node and on an answer: | Field | Type | Description | | -------------- | ------ | -------------------------------------------------------------- | | `GiveQuest` | string | Hands the quest out. | | `TurnInQuest` | string | Finishes it and pays the reward, if every goal is met. | | `AbandonQuest` | string | Gives it up. The record goes away, so it can be offered again. | | `SetFlag` | string | Raises a flag any `flag` goal is watching for. | On an answer, these are how a real yes or no works. On a node they fire as the node is reached. A node with no `Lines` is allowed when it does one of these: a silent node is the tidy way to give a quest between two spoken ones. It runs its action and moves on to `Next`. A quest id is enough for the NPC's own quests. To name another NPC's quest, write `NpcInternalName/questId` - the internal name is `CultTweaker_` plus the NPC's name with spaces turned into underscores. ## Different words for different states `Entry` is a list of conditional ways into the conversation, checked in order. The first one whose conditions all hold decides where the conversation starts; if none do, `Start` is used. ```json "Entry": [ { "QuestReady": "firewood", "Node": "handin" }, { "QuestActive": "firewood", "Node": "nag" }, { "QuestDone": "firewood", "Node": "thanks" }, { "Node": "greet" } ] ``` The conditions are `QuestNotStarted`, `QuestActive`, `QuestReady`, `QuestDone` and `QuestFailed`, each naming a quest. An entry with several of them needs all of them to hold. An entry with none is the catch-all, so put it last. `Ready` means every goal is met and the player has not handed the quest in yet. That is the state the "come back to me" line is written for. ## Rewards ```json "Reward": { "Items": [ { "Item": "GOLD_NUGGET", "Count": 5 }, { "Item": "MyCustomItem", "Count": 1 } ] } ``` Items are handed over as the game hands over any item. Custom items and meals work by internal name. ## Where progress is saved In `BepInEx/plugins/CultTweaker/QuestProgress/quests_slot.json`, one file per save slot, keyed by quest name. The game's own save file is deliberately left out of it. The lines a quest puts in the objectives panel are real vanilla objectives whose text points at a term this mod registers, so leaving them in the save would strand them there if CultTweaker were ever removed: a raw term in the quest panel that nothing could finish. They are lifted out for the moment the game writes, and put straight back. ::warning The practical consequence is that quest progress travels with the CultTweaker folder, not with the save file. Copy both when you move a save. :: ## Text tags Dialogue text supports the game's own Febucci tags and TMP markup: | Tag | Effect | | ----------- | --------------------------------------------------- | | `` | Waving text | | `` | Wiggling text | | `` | Shaking text | | `` | Bouncing text | | `` | Rotating text | | `` | Swinging text | | `` | Rainbow text | | `` | Changes the typing speed; reset it with `` | The shipped `CustomNpcs/TestNpc/config.json` demonstrates each one. ## Limits - Quests are single-player state. In a multiplayer session each player has their own. - The game pins at most three objective groups at a time and drops the oldest, so a player carrying three quests will see one fall off the panel. It is still running; it comes back when another is finished. - The dialogue wheel shows exactly two answers, so a node offering a quest offers one yes and one no. - A quest with no goals is refused at load, since nothing could finish it. - Abandoning is not the same as failing: the record is deleted, so the NPC can offer the quest again. A quest that runs out of time is failed and stays failed unless it is `Repeatable`. # Modding API There are two ways to build on CultTweaker: ship content as files and write no code at all, or reference the assembly and call a small contract. Most mods want the first. ## Shipping content with no code Every content folder is read from two places: CultTweaker's own plugin folder, and a folder named `CultTweaker` inside any other mod's folder. Put your files there and they load beside the player's own, with no reference to our assembly and no code from you: ```text BepInEx/plugins/YourMod/CultTweaker/CustomDungeonMaps/YourDungeon.json BepInEx/plugins/YourMod/CultTweaker/CustomLevelBlueprints/YourLevel.json BepInEx/plugins/YourMod/CultTweaker/CustomNodeBlueprints/YourRoom.json BepInEx/plugins/YourMod/CultTweaker/CustomNpcs/YourNpc/config.json BepInEx/plugins/YourMod/CultTweaker/CustomEnemies/YourEnemy/config.json BepInEx/plugins/YourMod/CultTweaker/PlayerSkins/YourSkin/config.json ``` The search is a bounded walk three folders deep, so a nested install is still found. Three rules apply: - Reading is shared but writing is not, so your files are never edited in place. - Where two mods use the same name, the player's own copy wins and the other is skipped with a warning. - Everything the editors save goes to CultTweaker's own folder, never into yours. ## The code contract One class: `CustomSpineLoader.Api.CultTweakerApi`, in `CultTweaker.dll`. Everything else in the assembly is internal in spirit and gets rearranged without notice. Members here are never removed or changed in meaning; new ones are added and `ContractVersion` is raised. Reference the DLL with `Private="false"` so you do not ship a copy of it: ```xml lib\CultTweaker.dll false ``` ## Reaching it safely Declare a soft dependency, probe before the first call, and keep every call to our types inside a method marked no-inlining so the JIT never loads them when CultTweaker is absent: ```csharp [BepInDependency("InfernoDragon0.cotl.CustomSpineLoader", BepInDependency.DependencyFlags.SoftDependency)] public class YourPlugin : BaseUnityPlugin { private static bool _available; private void Awake() { _available = Chainloader.PluginInfos.ContainsKey("InfernoDragon0.cotl.CustomSpineLoader") && Probe(); if (_available) Bridge.WhenReady(); } private static bool Probe() { try { var type = Type.GetType("CustomSpineLoader.Api.CultTweakerApi, CultTweaker"); return type != null && CultTweakerApi.ContractVersion >= 1; } catch (Exception) { return false; } } } internal static class Bridge { [MethodImpl(MethodImplOptions.NoInlining)] public static void WhenReady() => CultTweakerApi.OnReady(() => { foreach (var name in CultTweakerApi.Names(CultTweakerApi.Kind.Dungeons)) Log.LogInfo("CultTweaker dungeon available: " + name); }); } ``` ::note Nothing throws out of the contract. A query for a kind this build does not know logs a warning and returns an empty list. :: ## Content kinds Pass one of these to the queries. The constants are on `CultTweakerApi.Kind`. | Kind | What it lists | Folder | | ------------------- | ------------------------------------------------------------ | --------------------------- | | `Dungeons` | Playable custom dungeons, by internal name | none, registered at runtime | | `DungeonMaps` | Dungeon map documents | `CustomDungeonMaps` | | `Levels` | Level documents | `CustomLevelBlueprints` | | `Rooms` | Room blueprint documents | `CustomNodeBlueprints` | | `WorldMaps` | World map documents | `CustomWorldMaps` | | `MainMenus` | Main menu presets | `CustomMainMenus` | | `Npcs` | Registered custom NPCs | `CustomNpcs` | | `Enemies` | Registered custom enemies | `CustomEnemies` | | `Structures` | Registered custom structures | `CustomStructures` | | `Items` | Registered inventory items | `CustomInventoryItems` | | `Meals` | Registered meals | `CustomMeals` | | `Tarots` | Registered tarot cards | `CustomTarotCards` | | `Weapons` | Custom weapons, as `spineFolder/weaponName` | `PlayerSkins` | | `PlayerSkins` | Player spines, as `spineFolder/skinName` | `PlayerSkins` | | `FollowerSkins` | Custom follower skins | `FollowerSkins` | | `Cutscenes` | Cutscene videos | `CustomCutscenes` | | `ShapeProfiles` | Sprite shape profiles | `CustomShapeProfiles` | | `BuildingOverrides` | Buildings with overridden art | `BuildingOverrides` | | `Quests` | Quests declared by custom NPCs, as `npcInternalName/questId` | `CustomNpcs` | `CultTweakerApi.Kinds()` returns the whole list, so you can iterate without hard-coding it, and `FolderFor(kind)` gives the folder name, or null for a kind with no folder. ## Queries ```csharp IReadOnlyList Names(string kind); // what this install has bool Has(string kind, string name); int IdOf(string kind, string name); // see the warning below string FolderFor(string kind); IReadOnlyList Kinds(); bool Ready { get; } string Version { get; } void OnReady(Action callback); ``` Registered kinds answer with what actually loaded. Document kinds answer with the file names found across every mod's folders, including yours. ## Actions ```csharp bool EnterDungeon(string name); // by internal name or in-game name string CurrentDungeon(); // internal name, or null GameObject SpawnNpc(string name, Vector3 position, Transform parent = null); ``` `EnterDungeon` starts a run the way the player entering it would, so call it from a normal gameplay moment rather than during a load. It returns false when this install does not have that dungeon. ## Quests (contract version 2) ```csharp string QuestState(string key); // notStarted, active, ready, done, failed, or null IReadOnlyList ActiveQuests(); bool GiveQuest(string key); bool TurnInQuest(string key); bool AbandonQuest(string key); void NoteQuestEvent(string flag); ``` Keys are the names `Names(Kind.Quests)` returns: `npcInternalName/questId`. `ready` means every goal is met and the player has not handed the quest in yet. `NoteQuestEvent` is the hook for a quest that has to wait on something the game never announces: declare a goal of type `flag` with a name of your choosing, and raise that name when your own mod decides the moment has come. Quests, their goals and their text are written by whoever makes the NPC - see [custom NPC quests](https://cotlmod.infernodragon.net/docs/culttweaker/custom-npc-quests) - so a mod can ship a quest with no code at all and only reach for these calls when it needs to drive one. Quest progress is CultTweaker's own per-slot file, not the game's save, and it is keyed by name throughout, so none of this carries the id warning below. ## Where content lives ```csharp string ContentRoot(string folderName); // CultTweaker's own folder IReadOnlyList ContentRoots(string folderName); // ours, then every mod's IReadOnlyList ContentDirectories(string folderName); // per-item folders, absolute IReadOnlyList ContentFiles(string folderName, string pattern); string FindContentFile(string folderName, string fileName); string FindContentDirectory(string folderName, string subFolder); ``` Use these to find your own shipped content on disk, or to read a document a player made. Do not write into `ContentRoot`: that folder holds the player's own creations. Ship your files inside your own plugin folder as shown at the top. ## Ids and why you must not save them `IdOf` returns the number the game gave a piece of content, for the kinds backed by a game enum: items, meals, tarots, structures, enemies, weapons and dungeons. ::warning **These numbers are allocated per install, in load order.** The same dungeon is a different number on another machine, and adding or removing any mod can renumber everything. Use an id for an immediate call into the game and nothing else. Never write one to a save file and never send one to another machine: send the name and call `IdOf` again on the other side. :: This is not theoretical. A multiplayer mod sent a custom dungeon's raw id to the other player, whose install had a different number for it, and the guest sat on a black loading screen because the dungeon it was told to load did not exist there. ## Load order CultTweaker registers its content during its own `Awake`, and BepInEx does not promise plugin order. A mod that reads the registries from its own `Awake` may see nothing. Either read them lazily, when a scene loads or when the player does something, or pass a callback to `CultTweakerApi.OnReady`, which runs immediately if content is already loaded and at the end of our boot otherwise. ## Versioning `CultTweakerApi.ContractVersion` started at 1 and goes up by one whenever members are added. Members are never removed and never change meaning, so code written against 1 keeps working against 2. Check it once at startup if you need a member added later: ```csharp if (CultTweakerApi.ContractVersion >= 2) { /* the quest members */ } ``` | Version | Added | | ------- | ------------------------------------------------------------------ | | 1 | The kinds, the queries, the actions, the content paths, `OnReady`. | | 2 | `Kind.Quests` and the quest members. | If you need something the contract does not expose, ask rather than reflecting into the assembly: anything reached by reflection will break the next time those internals move. # Changelog ## 2.0.0 - World Shaper, pre-release 6 Package version `2.0.5`. Built for Cult of the Lamb **1.5.26**; earlier versions of the game are not supported. ### Custom weapons - A **player spine can now add weapons to the game**, declared in the spine's own `config.json` under `weapons`. Each is built on a vanilla weapon, keeping its heavy attack, sounds, hit shapes and pickup card while swapping in your look, your combo and your numbers - Every hit of a combo is yours to set: animation, damage, swing speed, range, hit box size, knockback, lunge speed and length, camera shake, attack type, whether the next hit can be queued, whether you can turn mid-swing, and when in the animation the hit lands and the swing can be broken out of - **Any spine can wield any spine's weapon.** The art is transplanted into whichever player skin is worn, and a swing with no animation of its own falls back to the base weapon's - **Chain weapons** are supported in full: sweep shapes, hook motion patterns, up to two chains swung at once with a delay between them, and your own hook art and size at the end of the chain - Added `preloadWeapons` to load a spine's weapon art at startup rather than at the moment a weapon is picked up - Added a `Debug / WeaponHitboxes` config that draws the hit shape of every swing, and the chain hook's own collider as it flies - The **Podium tool** now has a dropdown to pin which weapon a podium hands out ### Custom NPC quests - **A custom NPC can now hand out quests**, shown in the game's own objectives panel with the same headings, tick boxes, counters and countdown wheels - Quests finish on the same kinds of criteria the game's own do: gathering items, killing enemies, building, growing the flock, clearing a dungeon (custom ones included), performing a ritual, speaking to another custom NPC, a flag another mod raises, or **any of the game's own story beats** - Dialogue drives them: a node or an answer can hand a quest out, take it in, or give it up - An NPC greets you differently depending on where a quest stands - untaken, under way, ready to hand in, finished or failed - Quests can pay out items, be repeatable, run on a timer, and take the items they asked for when they are handed in - Progress is kept in CultTweaker's own file, one per save slot; the game's save file is left untouched ### Whiteboard ::note The pre-release 6 notes restate the pre-release 5 entries for this section and add the refinements listed below. :: - Added a **Whiteboard** tool: a Show whiteboard toggle, Draw with a size slider and nine colours, Erase with its own size, and **Clear all** - Strokes are never selectable and never part of the room; they show only while the editor is open, are saved with the map, and travel to the other player live - One drag is one stroke and one undo; an erase drag is one undo too, and Clear all wipes the board in one undoable step - The chosen colour shows a white border instead of being covered, and the brush lands exactly under the cursor ### Multiplayer ::note The pre-release 6 notes restate the pre-release 5 entries for this section and add the refinements listed below. :: - Added editing together over COTL MP Steam: either player can open the map editor in the base and both see every change as it happens - Added a shared pause, and a chat line inviting the other player to press F4 - Added two selection colours: yours cyan, theirs amber, on the object, its outline, their cursor and in the layer list - Added locking: an object the other player has selected or is dragging cannot be taken until they let go - Added live drags: moves, resizes and reshapes show on the other screen while the mouse is still down; cursors no longer flicker, dragged objects glide instead of jittering, and lighting changes fade in - Saving from either side saves on the host's machine; the guest receives the files - Custom dungeon levels work in a session, and both players can edit the rooms together - Added a **Resync** button, a `MapEditor / NetVerbose` config and a "Sync self-test" button for tracking down a desync - Every saved object now carries an id in its map file; maps saved by pre-release 5 still open ### For mod authors - Added a small **code contract**, `CultTweakerApi`, which lists and finds every kind of custom content this install has - dungeons, NPCs, enemies, items, meals, tarots, structures, weapons, skins, rooms, levels, world maps, menus, cutscenes and quests - and can enter a custom dungeon, spawn a custom NPC, drive a quest and locate content on disk - Shipping content through CultTweaker still needs no code at all - Documented the load-order trap and why the numbers the game gives custom content must never be saved or sent to another machine ### Fixes - Fixed door pads growing across the whole room when the room's centre is a hole (a pit, a tree) - Fixed placed enemies waking up and attacking while the editor was open with multiplayer enabled, even when hosting alone - Fixed the guest being stuck on the summoning screen when the host entered a custom dungeon level - Fixed a move or resize received from the other player sometimes respawning the object instead of moving it, which left enemy bodies behind on the guest's screen ## 2.0.0 - World Shaper, pre-release 5 ### Layers - Added a **Layers** panel at the left edge of the map editor: every object in the room listed by what placed it - Shapes, Podiums, Enemies, NPCs, Structures, Props and Triggers - Click a row to select that object; the tree follows your selection and scrolls to it, and section headers stay pinned - Shift-click two rows to select the run between them - Built for big rooms: a base town of six hundred objects scrolls and highlights without lag ### Multi-selection and groups - Added multi-selection to the Select tool: Shift-click adds or removes; move and depth drags move everything together, one undo puts the whole drag back, and Delete removes the lot - Added groups with **Ctrl+G**; Ctrl+G on a whole group dissolves it, and both are undoable - Groups are saved with the map and come back on load; the Layers panel shows each group as a folder ### Whiteboard - Added a **Whiteboard** tool with Show, Draw (size slider, nine colours), Erase and **Clear all** - Strokes are never selectable, show only while the editor is open, are saved with the map, and travel to the other player live - One drag is one stroke and one undo ### Structures - Added the DLC dungeons' dressing to the structure browser: **DLC Dungeon / Ewefall** and **DLC Dungeon / Rot**, with the whole decoration plots beside them as **... Plots** - Added the **Art** groups (cave biome pieces, the base's weeds, some boss and shop room dressing) and **Tile Decorations** - The old **Placement Objects / DLC** and **VFX / DLC** folders are now **... / Misc** ### Multiplayer - Added editing together over COTL MP Steam, a shared pause, two selection colours, locking, live drags, host-side saving, custom dungeon levels in a session, a **Resync** button, a `MapEditor / NetVerbose` config and a "Sync self-test" button - Every saved object now carries an id in its map file; maps saved by pre-release 4 still open ### Fixes - Fixed door pads growing across the whole room when the room's centre is a hole ## 2.0.0 - World Shaper, pre-release 4 ### Follower skin editor - Added a follower skin editor on **F8**, editing the same `FollowerSkins/` folders the mod loads - Added a left panel: skin and variant picking, new skins and variants, colour set, base skin, animation preview, and the list of overridden slots - Added an **Outfit** picker to the preview, for looking only - never saved with the skin - Added a right panel for the selected layer: slot, image, hide, placement sliders and colour - Added `skin/variant` naming, so one prompt saves either a new variant or a whole new skin - Added live reload: a saved skin can be worn by followers without restarting - Adding a colour set is now an entry at the top of the Colour set list ### Player skins - Custom player spines now show on the player tab of the inventory, in Knucklebones and in Flockade, for both players and on the Flockade result card ### Structures - Added an "Affected by wind" checkbox, armed for the next placement or set on anything already placed - Added wind to structures built from several sprites - Added shadows to custom structures, which previously cast none - Improved see-through so it can be worn together with wind - Added `"HideFromBuildMenu": true` to a custom structure's `config.json` - Added a **Custom** group to the structure tool, holding every custom structure, hidden ones included ### Triggers - Added a "Blocking volume" checkbox: the trigger becomes an invisible wall to players and enemies, drawn in red - Added enemy pathfinding around blocking volumes, updated as they are moved and resized - Added a "Play animation on object" action, with a choice of what happens when that animation ends ### Loading - Custom follower skins are now baked once and kept: roughly 10 seconds off the startup and about 2 GB less memory while it loads - A skin is rebuilt only when you change it, and the kept copy can be shipped with a skin ### Compatibility - Built for Cult of the Lamb **1.5.26**; earlier versions are no longer supported ### Fixes - Fixed F5 starting the test dungeon from the title screen and during scene changes - Fixed a structure's own sprites, added as it is placed, missing the look it was given - Fixed naming a skin confirming a name the editor would not accept - Fixed the skin editor claiming to get a skin ready to edit while doing nothing ## 2.0.0 - World Shaper, pre-release 3 ### Base editor - Added editing of your own base town: move and place structures, terrain and paths with the F4 tools - Added save protection - changes live in the mod's own files, and the game's save is never written to - Added protection so bought buildings can be moved but never deleted - Added see-through for structures that block the camera while editing - Improved the Select, Shape and Structure tools for base work ### Hub building - Added a build totem for hubs: build the game's own structures through the game's own build menu - Added building costs and refunds, kept in the hub rather than the save - Added a placement region so hub building cannot reach your real town ### Main menu editor - Added a "Customize Menu" button on the title screen - Added named menu presets, kept as folders with their art; one applies on every launch - Added a Look tool: palette pick and blend, background colour, hue / saturation / brightness, dither, grain, the glitch effect, and a negative effect - Added a Centrepiece tool: skin, animation, position, scale and rotation for the lamb, or a custom spine - Added a Title tool: replace the logo with any png, move, resize or hide it, and set, move, recolour or hide the edition line ### Follower skin editor - Added a follower skin editor on F8 with left and right panels, `skin/variant` naming and live reload ### Editor look - Improved every editor panel with the game's own artwork, toggles, sliders, section dividers, buttons, dropdowns and confirm prompt ### Weather - Added per-room weather to the Lighting tool, for dungeons and hubs - Added every strength of every weather, including ones the game never shows (extreme wind) - Added protection so the game cannot clear a room's chosen weather early ### Triggers - Added a Camera shake action ### Fixes - Fixed the room editor's status bar going quiet after using the world editor - Fixed dragging an editor slider stuttering the menu's lamb animation - Fixed the menu editor's panels vanishing after loading a preset - Fixed the editor buttons having no ribbon until a save had been entered - Fixed preset art changed on disk not being picked up until restart ## 2.0.0 - World Shaper, pre-release 2 ### Dungeon Builder - Improved the dungeon map into a full screen, using the game's own artwork - Added free node placement, `Ctrl+click` to place, right-click to link or cut, `Del` to delete - Added auto linking when you place beside a selected node - Improved dragging so links follow the node, and linking so any node can lead to any other - Added **Preview Map** and live checking of whether the map will play - Improved compatibility with maps saved in pre-release 1 - Improved closing with `Esc`, the X button or `F4` ### Level tool - Added hand-built floor layouts ("custom walk") and a visual layout screen - Added auto connecting doors, a random walk tickbox, fixed entrance and exit rooms, and a choice of vanilla podium entrance and exit rooms - Added a pool of maps per room, one picked at random - Added Combat and Reward room markers - Added right-click to turn a room's doors on and off - Improved the door labels to Up / Down / Left / Right - Removed the Done button, the second menu, Rename Level and Delete Room - Fixed a 2-room floor generating 4 rooms ### Room editor - Added move, resize and depth handles, `Ctrl`-drag copying, a preview picture of the selection, and right-click to deselect - Improved flip into a tickbox and terrain ordering into a list with `-` and `+` - Added `Ctrl`-drag copying of whole triggers and colours to trigger boxes - Improved *Clear All Triggers* into the Clear tool, and long trigger lists to scroll - Fixed older rooms having their terrain order changed ### Editor panels - Added an unsaved changes prompt, search by name to the Structure, Enemy, NPC and Level tools, a "Bosses (inside rooms)" list, and a bigger hover preview - Improved the icon lists to scroll on their own and the scrollbars into a thin rail - Improved the Load Map browser into a full screen, with a picture and details of the map you pick and click to enlarge - Improved the Lighting tool to capture the room's lighting on open - Fixed typing pressing the button under the mouse, the game's menus stealing the keyboard while naming, *Reset To Biome* leaving the sliders where they were, the Load Map browser stuttering, picking a room in the Level tool pausing each time, blurry map pictures, and character previews not drawing after a game update ### Door tool - Improved the floor padding beside doors to be invisible but walkable ### F7 CultTweaker panel - Added a player panel in the bottom-left corner, a moving character preview and a preview animation dropdown - Added saving of your chosen skin - Improved fleece transmog to be per player - Improved the layout into **Go** and **Extras** sections, and the text sizes to match the editor ### Custom dungeons - Fixed doors not locking with monsters in the room - Fixed a boss statue room replacing the weapon podium ## v1.1.1 - Added hide slot for follower skins to hide specific slots - Removed test code for custom dungeons to prevent errors ## v1.1.0 - Added Custom Dungeons - Fixed an issue with Custom Structures not loading fully (use new custom structure template) ## v1.0.7 / v1.0.8 - Added Scale setting (1x to 5x) to followers - Player Spine loader now supports co-op separate spine loading - Re-added Intro fleece to the fleece transmogs - Player Spines now load in instantly instead of loading it when entering the base for the first time, which allows custom lamb skins to be used in the Intro ## v1.0.6 - Fixed an issue where fleece cycling did not include parts of certain fleeces ## v1.0.5 - Fixed an issue where fleece cycling was going over array bounds - Fixed an issue where fleece cycling caused a softlock - Added Custom Player Spine Fleece Cycling support - Added a toggle to turn on or off fleece cycling (F9) - Added Custom Follower Form + Variant support - Added a config to dump follower spine slots ## v1.0.4 - Fixed an issue where red overlays are present on custom player spines ## v1.0.3 - Fix an issue where Fleece Cycling did not override some extra parts of the fleece - Full Follower Customization Support ## v1.0.2 - Fix an issue where picking up weapons caused an error ## v1.0.1 - Fleece Cycling for all player skins ## v1.0.0 - Name Changed to CultTweaker - Support for Woolhaven - Custom Data Loader - create your own custom stuff! - Custom Items - Custom Food [WIP] - Custom Structure - Custom Tarot Cards ## v0.0.5 - Add Structure Overrides ## v0.0.3 - Add Custom Follower Color Control ## v0.0.2 - Added Multi-skin support per Spine skeleton ## v0.0.1 - Initial Release # Supercharged Series The Supercharged series is a pair of standalone mods that push the Lamb well past the vanilla power ceiling. They were built to be stacked: the tarots make the Lamb absurdly strong, the followers turn your cult into an army that fights alongside you, and both of them exist so that difficulty mods such as [Trial of the Gods](https://cotlmod.infernodragon.net/docs/minimods/trial-of-the-gods) stay survivable. Each mod installs and runs on its own. Installing both is supported and is the intended way to play. ::card-group :::card --- icon: i-lucide-sparkles title: Supercharged Tarots to: https://cotlmod.infernodragon.net/docs/supercharged/tarots --- Twenty-four extra tarot cards across three sets, from near-infinite curse casting to turning every weapon drop into a Blunderbuss. ::: :::card --- icon: i-lucide-users title: Supercharged Followers to: https://cotlmod.infernodragon.net/docs/supercharged/followers --- Rally your followers into dungeon runs as real combatants, equip them, assign a commander, and level them through ten prestige ranks. ::: :: ## What each mod does | Mod | Adds | Where it changes the game | | ---------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------- | | Supercharged Tarots | 14 tarot cards (Set 1 and Set 2), plus a separate 10-card Unholy Alliance expansion | Inside runs - the cards join the normal tarot pool | | Supercharged Followers | 3 structures, follower combat AI, class and prestige progression | Both in base (structures) and inside runs (rallied followers) | ## Requirements Both mods are BepInEx plugins that build on the COTL modding API. - [BepInEx Pack for Cult of the Lamb](https://thunderstore.io/c/cult-of-the-lamb/p/BepInEx/BepInExPack_CultOfTheLamb/){rel=""nofollow""} - [COTL\_API](https://thunderstore.io/c/cult-of-the-lamb/p/xhayper/COTL_API/){rel=""nofollow""} Install BepInEx first, launch the game once so it generates its folders, then drop the mod folder into `BepInEx/plugins`. ```text Cult of the Lamb/ └── BepInEx/ └── plugins/ ├── SuperchargedTarots/ └── SuperchargedFollowers/ ``` ::note If you are upgrading a save from COTL API 0.1.6 to 0.1.7 or newer, run it through the [save converter](https://cotlminimod.infernodragon.net/saveconverter){rel=""nofollow""} first. :: ## Links - Supercharged Tarots on [NexusMods](https://www.nexusmods.com/cultofthelamb/mods/20){rel=""nofollow""} and [Thunderstore](https://thunderstore.io/c/cult-of-the-lamb/p/InfernoDragon0/Supercharged_Tarots/){rel=""nofollow""} - Supercharged Followers on [Thunderstore](https://thunderstore.io/c/cult-of-the-lamb/p/InfernoDragon0/SuperchargedFollowers/){rel=""nofollow""} - [Modding Discord](https://discord.gg/MUjww9ndx2){rel=""nofollow""} for support, feedback and suggestions - Support development on [Ko-fi](https://ko-fi.com/infernodragon0){rel=""nofollow""} or [Patreon](https://www.patreon.com/InfernoDragon0){rel=""nofollow""} # Supercharged Followers Supercharged Followers turns your cult members into combatants. Rally them at a flag in your base and they come with you into the next run, find the nearest enemy, and fight for you. Everything you do to a follower back home - the necklace they wear, the class you assign, the prestige you invest - changes how they perform in the dungeon. ::warning You must click one of the rally flags again after **every** run to let your followers join the fight. Rallying is not persistent. :: ::note All of the art in this mod is currently placeholder art. If you would like to contribute art, DM `InfernoDragon1` on Discord or join the [modding Discord](https://discord.gg/MUjww9ndx2){rel=""nofollow""} . :: ## Rallying your followers - Followers you rally are brought into battle as actual fighters. They path to the nearest enemy and attack it for you. - There is no cap - rally as many followers as you want. - Followers keep fighting when new enemies spawn after the original wave is cleared. - Their stats come from the equipment and progression you have given them, listed in [Equipment and bonuses](https://cotlmod.infernodragon.net/#equipment-and-bonuses) below. ## Structures | Structure | Left click | Right click | | ---------------- | -------------------------------------------------------- | ---------------------------------- | | Rally Flag | Rally your followers to battle | Set a commander for your followers | | Super Rally Flag | Rally or un-rally **all** followers at once | - | | Barracks | Change a follower's class for a different set of bonuses | Prestige levelling | The Super Rally Flag was added in v1.0.3 as a bulk alternative to walking the Rally Flag through your whole cult. ## Prestige Prestige is the mod's long-term progression currency. You earn it by surviving, and you spend it in the Barracks. - For each follower still alive when a run ends, you gain **1 prestige**. - A single run can award at most **12 prestige**. - Prestige is given to individual followers to boost their stats. - Each follower can reach **prestige level 10**. - View and grant prestige at the Barracks. Prestige required per level: | Level | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | | ----- | - | - | - | -- | -- | -- | -- | -- | -- | --- | | Cost | 3 | 6 | 9 | 12 | 15 | 20 | 40 | 60 | 80 | 100 | ## Equipment and bonuses ### Commander boosts Set the commander by right clicking the Rally Flag. Only one commander can be set at a time. | Stat | Bonus | | -------------- | ------------------------------- | | Attack | +3 | | Health | +10 | | Attack Speed | +1 | | Movement Speed | +9 | | Regen Per Room | +1.5 | | Size | Double the normal follower size | Since v1.0.3 the commander strikes 3 times per attack, and the delay between attacks is 0.6 seconds (down from 1 second). ### Necklace boosts The necklace a follower is wearing carries into the run. | Necklace | Bonus | | ------------ | ---------------------------------------------- | | Feather | Movement Speed +2 | | Flower | Attack Speed +1 | | Moon | Damage +1 | | Nature | Regen 0.25 health per room clear | | Skull | Health +3 | | Golden Skull | Revives on room clear, except in the boss room | ### Class boosts Set a follower's class at the Barracks. | Class | Bonus | | ---------- | ------------------------------------------ | | Missionary | Movement Speed +2, Health +1 | | Holiday | Health +4 | | Warrior | Damage +2, Health +2 | | Prayer | Damage +4 | | Undertaker | Regenerates 0.5 hearts on finishing a room | ### Prestige boosts Prestige levels are cumulative - a level 5 follower has everything from levels 1 through 5. | Level | Bonus | | ----- | ---------------------------------------------------------------------------- | | 1 | Base attack +0.5 damage, base health +0.5 hearts | | 2 | Min/max attack delay reduced by 0.25 seconds, base health +0.5 hearts | | 3 | Movement speed +25%, base health +1 heart | | 4 | Base attack +0.5 damage again, base health +0.5 hearts | | 5 | Min/max attack delay reduced by another 0.5 seconds, base health +0.5 hearts | | 6 | Regenerates 0.5 hearts when killing an enemy | | 7 | 20% chance of dropping blue half hearts when killing an enemy | | 8 | Regenerates a small amount of curse and relic charge when hitting an enemy | | 9 | 10% chance of dropping prestige when killing an enemy | | 10 | 10% chance of dealing crit damage (5x damage) on a hit | ## Configuration ### `shoudBypassHitstop` Added in v1.0.5 and defaulting to `true`, this config bypasses the brief pause in gameplay that normally happens when you land a hit on an enemy. With a screen full of rallied followers all hitting at once that hitstop stacks up, so bypassing it smooths out the combat. ```ini ## This config improve the combat experience by bypassing the pause in gameplay ## when attacking an enemy. # Setting type: Boolean # Default value: true shoudBypassHitstop = true ``` ::note The key is spelled `shoudBypassHitstop` in the mod, missing the `l` . Use that spelling exactly or the setting will not be read. :: ### Follower transparency Added in v1.0.2, a config controls the transparency of followers and the commander. It defaults to `0.5`; set it to `1` for fully opaque followers. ## Requirements - BepInEx Pack - COTL\_API ## Download - [Thunderstore](https://thunderstore.io/c/cult-of-the-lamb/p/InfernoDragon0/SuperchargedFollowers/){rel=""nofollow""} ## Credits - Developer: [InfernoDragon0](https://github.com/InfernoDragon0){rel=""nofollow""} - Tester: danylopez123, for testing the many iterations of fixing the follower combat brain # Changelog ## v1.0.5 - Woolhaven support - Added support for Woolhaven - Added a new config `shoudBypassHitstop`, defaulting to `true`. It improves the combat experience by bypassing the pause in gameplay when attacking an enemy ## v1.0.3 - AI improvements ### New structure - Added a Super Rally Flag to rally or un-rally all followers ### Balancing - Commander now strikes 3 times per attack - Reduced delay between attacks to 0.6 seconds, from 1 second ### Performance improvements and bugfixes - Rewritten the follower AI again, to only have one brain per follower - Improved pathfinding and reduced delays for each follower finding enemies - Followers should continue fighting if new enemies spawn after the original enemies are cleared - Removed white flashing and camera shake from followers attacking - Follower brain no longer stops working at random chances ## v1.0.2 - Optimization and bugfixes - Performance improvements by removing stacking coroutines, reducing the chance of crashing - Teleport followers back into the map if they end up out of bounds - Added config to change transparency of followers and the commander, defaulting to 0.5. Set it to 1 for fully opaque - Improved pathfinding for followers, preventing them from hitting air - Custom random targeting priority instead of always picking the closest target - Fixed an issue where prestige was given instead of taken if the follower was max level - Fixed regeneration per room not working as expected ## v1.0.1 - Potentially fixed an issue with followers loading early and no longer pathfinding # Supercharged Tarots ![Supercharged Tarots](https://cotlmod.infernodragon.net/images/tarotlogo.png) Supercharged Tarots adds tarot cards that are deliberately far above the vanilla power curve - infinite ammo, permanent crits, 300% curse damage. The point is to feel the true potential of the Lamb, and to give you enough power to survive heavily modded difficulty settings. The mod ships two sets in one package: - **Set 1** - ten general-purpose cards. See [Card list](https://cotlmod.infernodragon.net/docs/supercharged/tarots/cards). - **Set 2: Guns Blazing** - four cards built around the Blunderbuss. A third set, the **Unholy Alliance expansion**, is distributed as its own package and adds ten more cards including six co-op specific ones. ## How the cards enter the pool The cards are registered with COTL\_API's custom tarot card manager when the game loads. From that point they are part of the normal tarot card pool: you find them the same way you find vanilla cards, from tarot card pickups during a run. Because they are pool members and not guaranteed drops, the fastest way to get a specific card is to fish it out of the pool deliberately. ::tip **Wishing Well synergy.** [CotL MiniMods](https://cotlmod.infernodragon.net/docs/minimods) adds a Wishing Well structure to your base. In MiniMods 1.3.0 the [Wishing Well v2](https://cotlmod.infernodragon.net/docs/minimods/structures) lets you pick any number of tarot cards from the combined vanilla and custom pool at no cost, and carry them into your next run. That is the intended way to collect Supercharged Tarots on demand rather than waiting for them to roll. :: ## Configuration The config file is written by BepInEx on first launch to `BepInEx/config/`, under the `SuperchargedTarots` section. Every numeric entry is a multiplier for the card of the same name, so you can tone the set down instead of removing it. ### Removing Gunslinger from the card pool The Gunslinger card converts every weapon choice in a run into a Blunderbuss, which some players do not want in the pool at all. Added in v1.0.3, this is the switch: ```ini [SuperchargedTarots] ## Set to false to disable Gunslinger Tarot Card # Setting type: Boolean # Default value: true EnableGunslingerCard = true ``` Set `EnableGunslingerCard` to `false` and the card is never registered, so it can never appear in the pool. The other three Guns Blazing cards are unaffected. ### Other config entries | Key | Default | Controls | | ---------------------- | ------- | ---------------------------------------------------------------------------------------------------- | | `Ammo` | `66` | Fervor use discount. Higher is cheaper - do not go over 100 | | `CurseDamage` | `3` | Curse damage multiplier | | `Damage` | `1` | Damage multiplier | | `Hearts` | `20` | Black hearts granted, at 2 per full heart | | `RelicCharge` | `30` | Relic charge multiplier | | `AttackSpeed` | `5` | Attack speed multiplier | | `SpeedRun` | `3` | Move speed multiplier. Above 10 you move too fast to play | | `Sun` | `2` | Sun damage multiplier | | `Moon` | `3` | Moon damage multiplier | | `AddCards` | `false` | Workaround for the double tarot bug. Set to true if tarots are not being added when you collect them | | `EnableGunslingerCard` | `true` | Whether the Gunslinger card is registered at all | ::note The Unholy Alliance expansion has its own config file. It can enable or disable each of its ten cards individually, and exposes `EnableCoopSoloEffects` (default `false` ) to allow the co-op cards to be used in solo play. The co-op cards are very strong in solo mode. :: ## Requirements - BepInEx Pack - COTL\_API ## Download Sets 1 and 2: - [NexusMods](https://www.nexusmods.com/cultofthelamb/mods/20){rel=""nofollow""} - [Thunderstore](https://thunderstore.io/c/cult-of-the-lamb/p/InfernoDragon0/Supercharged_Tarots/){rel=""nofollow""} Set 3, the Unholy Alliance expansion, is a separate package (currently v1.0.1): - [Thunderstore](https://thunderstore.io/c/cult-of-the-lamb/p/InfernoDragon0/Supercharged_Tarots_UA/){rel=""nofollow""} ## Credits - Developer: [InfernoDragon0](https://github.com/InfernoDragon0){rel=""nofollow""} - Tester: jenwalter666 - Card art and thumbnail for the Unholy Alliance expansion: [LiteLikesArt](https://x.com/LiteLikesArt){rel=""nofollow""} # Card list ![Supercharged Tarots](https://cotlmod.infernodragon.net/images/tarots.png) All of these cards join the normal tarot pool once the mod is installed. Numeric effects are the shipped defaults - most of them are multipliers you can retune in the [config file](https://cotlmod.infernodragon.net/docs/supercharged/tarots#configuration). ## Set 1: Ten powerful tarot cards | Card | Effect | | ------------------- | ---------------------------------------------------------------------------------------- | | Shadow Quiver | Near infinite curse casting | | Deadeye | Always crit | | Supernova | 300% more curse damage | | Ruinous Strike | 100% more damage | | Ace of Hearts | Grants you 10 black hearts | | Curse Perfected | Always perfect curse casting. Curses that require charging release perfectly at any time | | Speedrunner | 4x movement speed | | Sonic Surge | 5x attack speed | | The Solunar Eclipse | 200% more damage during the day, 300% more damage during the night | | Relic Overdrive | 30x relic charge speed | ## Set 2: Guns Blazing Four cards that turn the Blunderbuss from a situational pickup into the whole build. They combine: Gunslinger guarantees you get the weapon, and the other three remove every reason not to use it. | Card | Effect | | ---------------- | --------------------------------------------- | | The Gunslinger | All weapon choices are now Blunderbuss | | Multishot | Blunderbuss attacks shoot in all 4 directions | | Resilient Gunner | No recoil when using the Blunderbuss | | Blunder Buster | Infinite ammo for the Blunderbuss | ::note The Gunslinger can be removed from the pool entirely by setting `EnableGunslingerCard = false` . See [Configuration](https://cotlmod.infernodragon.net/docs/supercharged/tarots#removing-gunslinger-from-the-card-pool) . :: ## Set 3: Unholy Alliance expansion Set 3 ships as a separate package, *Supercharged Tarots: Unholy Alliance Expansion*. It adds ten cards split between solo play and the Unholy Alliance co-op mode. Each card can be individually enabled or disabled in that mod's own config file. ### Solo cards | Card | Effect | | --------------- | --------------------------------------------------------------------------------------------- | | Blood for Blood | Killing an enemy grants you half a spirit heart | | Reinforcement | You are immune to traps. Each time you take damage, summon a combat follower to fight for you | | Second Wind | Gain 2 blue hearts for each heart you currently have | | Final Stand | For every dead follower you own, increase weapon damage by 10% | ### Co-op cards | Card | Effect | | ------------------ | ------------------------------------------------------------------------------------ | | Static Electricity | While near each other, pressing Attack generates lightning strikes | | Duality | Attacking an enemy heals the other player for half a heart | | Ignite | Both players explode when pressing Attack at the same time | | Transference | Taking damage makes the other player explode in a large radius | | Warding Bond | While near each other, negate damage taken at a 70% chance | | Death Contract | Taking damage to red hearts transfers that damage as blue hearts to the other player | ::warning The co-op cards can be used in solo play by setting `EnableCoopSoloEffects` to `true` in the Unholy Alliance config, but they are balanced around two players and are very strong on their own. :: # Changelog ## v1.0.4 - Update for Woolhaven ## v1.0.3 - Added a config to remove Gunslinger from the card pool (`EnableGunslingerCard`) - Updated for Unholy Alliance - Fixed an issue where the Resilient Gunner was not working as expected ## Earlier releases The releases before v1.0.3 are not itemised in the mod's own release notes. The content they introduced was: | Release | Content | | ------------------- | ------------------------------------------------------------------ | | Set 2: Guns Blazing | The Gunslinger, Multishot, Resilient Gunner, Blunder Buster | | Set 1 | The ten original cards, from Shadow Quiver through Relic Overdrive | ::note The Unholy Alliance expansion (Set 3) is versioned separately from Sets 1 and 2 and is not covered by this changelog. :: # CotL MiniMods ![CotL MiniMods](https://cotlmod.infernodragon.net/images/cotlminimodsbanner.png) CotL MiniMods is a large content mod for Cult of the Lamb. It automates the busywork of running a cult - mining, cooking, serving, burying - through new structures and follower roles, adds a resource economy built on Strange Material and Strange Energy, and since v1.3.0 adds **Trial of the Gods**, an opt-in difficulty system that makes runs considerably harder. ::card-group :::card --- icon: i-lucide-flame title: Trial of the Gods to: https://cotlmod.infernodragon.net/docs/minimods/trial-of-the-gods --- Five Trials and ten Augments you stack yourself to raise run difficulty as far as you can survive. ::: :::card --- icon: i-lucide-hammer title: Structures to: https://cotlmod.infernodragon.net/docs/minimods/structures --- Every custom building, from the AIO Quarry to the Stasis Chamber. ::: :::card --- icon: i-lucide-briefcase title: Roles to: https://cotlmod.infernodragon.net/docs/minimods/roles --- New follower jobs and the structure each one needs. ::: :::card --- icon: i-lucide-flame-kindling title: Rituals to: https://cotlmod.infernodragon.net/docs/minimods/rituals --- Mass resurrection, exile, fusion, youth and more. ::: :::card --- icon: i-lucide-message-square title: Commands to: https://cotlmod.infernodragon.net/docs/minimods/commands --- Extra options on the follower interaction wheel. ::: :::card --- icon: i-lucide-package title: Items to: https://cotlmod.infernodragon.net/docs/minimods/items --- Strange Material and Strange Energy - where they come from and what spends them. ::: :: ## What it adds | Category | Contents | | ---------- | --------------------------------------------------------------------------------- | | Structures | \~20 buildings covering production, follower services, energy and run preparation | | Roles | Sous Chef, Waiter, Fisher, Astrologer, Scholar, Reaper, Miner, Narinder Devotion | | Rituals | 8 additions to the temple ritual menu | | Commands | Knucklebones, Flip Coin, Divorce, plus the work commands for the custom roles | | Items | Strange Material and Strange Energy | | Tarots | Strange Extraction, obtainable only from the Wishing Well | | Difficulty | Trial of the Gods - 5 Trials and 10 Augments | ## Quality of life extras These are toggled independently in the config file. | Extra | Default | Effect | | ------------------------ | -------- | ------------------------------------------------------------------------------------------------------------ | | All you can eat Buffet | Enabled | Players can eat as many food items as they want. Deaths due to excessive eating are not covered by insurance | | Large Shrine | Enabled | The Shrine stores 2000 souls instead of the vanilla cap | | Instant Collection | Enabled | Clicking the Shrine once grabs all souls instead of one | | Skip intro cutscene | Enabled | Skips the intro cutscene | | Repeatable One Who Waits | Disabled | Challenge "The One Who Waits" repeatedly and add more of them to your collection | ## Installation Paste the plugins folder into your BepInEx folder. The mod consists of `CotlMiniMods.dll` plus an `Assets` folder - both must be present. ```text Cult of the Lamb/ └── BepInEx/ └── plugins/ └── CotlMiniMods/ ├── CotlMiniMods.dll └── Assets/ ``` ### Requirements - BepInEx Pack - COTL API 0.1.28 and above ::note Upgrading a save from COTL API 0.1.6 to 0.1.7 or above? Run it through the [save converter](https://cotlminimod.infernodragon.net/saveconverter){rel=""nofollow""} first. :: ::caution Upgrading from v1.0.6 or below by hand? The folder structure changed in v1.0.7 - delete the old DLL first. :: ## Known issues - **Follower Management Device**: assigning a task a follower cannot do may turn them invisible. Re-assign another task to fix it. ## Download - [NexusMods](https://www.nexusmods.com/cultofthelamb/mods/12){rel=""nofollow""} - [Thunderstore](https://cult-of-the-lamb.thunderstore.io/package/InfernoDragon0/CotLMiniMods/){rel=""nofollow""} Localisation files are downloaded separately from the [NexusMods files tab](https://www.nexusmods.com/cultofthelamb/mods/12?tab=files){rel=""nofollow""}. ## Links - [Modding Discord](https://discord.gg/MUjww9ndx2){rel=""nofollow""} - [Credits](https://cotlmod.infernodragon.net/docs/minimods/credits) - [Changelog](https://cotlmod.infernodragon.net/docs/minimods/changelog) # Trial of the Gods Trial of the Gods is the headline feature of MiniMods v1.3.0. Runs are more dangerous than ever, and you choose exactly how much more. Nothing here is mandatory: with no Trials and no Augments selected, runs behave normally. ## Getting started 1. Build an **Infernal Infuser** in your base. It replaces the Relic Infuser from v1.2.1 - if you already had a Relic Infuser built, that structure becomes the Infernal Infuser. 2. Interact with it. 3. Select any number of Trials and Augments. 4. They apply to your next run. ::note All Trials and all Augments can be active at the same time. Trials and Augments also feed each other - most Trials scale off how many Augments you have active, and vice versa - so difficulty rises faster than the count of things you selected. :: ::tip Need more power to overcome the Trials? That is what the Supercharged series is for. [Supercharged Tarots](https://cotlmod.infernodragon.net/docs/supercharged/tarots) and [Supercharged Followers](https://cotlmod.infernodragon.net/docs/supercharged/followers) both stack with Trial of the Gods, and running everything at maximum difficulty is intended to be close to impossible without them. :: ## Trials | Trial | Effect | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Trial of Narinder | Each active Augment increases your dodge cooldown by 25%. Each active Trial grants enemies a 10% chance of instantly killing you on hit, and increases your vulnerability to damage by 1% for each enemy you have killed during the run | | Trial of Leshy | For each active Augment, whenever a non-boss enemy takes non-lethal damage there is a 5% chance for it to duplicate at half of its current HP. For each active Trial, a copy of each non-boss enemy spawns every 10 seconds at half of its current HP | | Trial of Heket | For each active Trial, whenever you take damage you have a 10% chance of losing a tarot card. For each active Augment, each time you take damage you lose 10% of your curse charge | | Trial of Shamura | For each active Trial, each time you take damage all enemies heal 10% of their health. For each active Augment, when enemies take damage their damage resistance increases by 0.5%, up to 90% | | Trial of Kallamar | Every 10 seconds, all enemies drop a pool of poison - each active Trial speeds this up by 1 second. Every 15 seconds, a pool of poison spawns on your location - each active Augment speeds this up by 1 second | ## Augments | Augment | Effect | | ---------------------- | ----------------------------------------------------------------------------------------------- | | Augment of Exhaustion | Each time you dodge, you lose 0.1 movement speed. Minimum 1.0 speed | | Augment of Swarm | Enemies move 20% faster | | Augment of Explosion | Enemies explode on death | | Augment of Bloodpact | When an enemy dies, other enemies spawn a poison puddle under them | | Augment of Persistence | Enemies heal 5% of their health every 3 seconds. Bosses heal 3% of their health every 3 seconds | | Augment of Resistance | Enemies have a 25% chance of not taking damage from hits | | Augment of Dissonance | Dodging costs 20% curse charge, and you cannot dodge below 20% curse charge | | Augment of Curse | Each time you attack, you lose 5% curse charge | | Augment of Grace | When an enemy dies, all other enemies heal 25% of their max HP | | Augment of Bombardment | Each time you hit an enemy, 2 bombs appear around you | ## Notes - Trials and Augments apply to normal runs. - Every trigger of a Trial or Augment is recorded in the debug log, which is useful when working out what killed you. - Trial of the Gods assets are currently placeholders. # Structures MiniMods adds around twenty buildable structures. They fall into four groups: things that produce resources, things that serve your followers, the Strange Energy grid, and the two structures you use to set up your next run. ::note v1.3.0 changed several of these. The Relic Infuser was removed and replaced by the [Infernal Infuser](https://cotlmod.infernodragon.net/#run-preparation) , the Wishing Well and the Fishing Hut were both replaced by v2 versions, and the sprites for several structures were redrawn. :: ## Run preparation These two structures are where a run is decided before you ever enter a door. ### Infernal Infuser ![Infernal Infuser](https://cotlmod.infernodragon.net/images/cauldron.png) Replaces the Relic Infuser, which was removed in v1.3.0. - **Removed:** select one relic to bring into your next run. - **New:** select any amount of Trials and Augments to increase the difficulty of your next run. Full effect list on the [Trial of the Gods](https://cotlmod.infernodragon.net/docs/minimods/trial-of-the-gods) page. ### Wishing Well II ![Wishing Well](https://cotlmod.infernodragon.net/images/Icon_Pond.png) The long-awaited wishing well is back and improved. With the help of Strange Materials it is fully powered, and lets you prepare for the most daunting challenges ahead. - **Removed:** pay 20 gold and select one out of two cards. - **New:** at no cost, select any amount of tarot cards from the vanilla and custom pool, plus a relic, to bring into your next run. - Tarot effects no longer apply while you are in the base. ::tip This is the intended way to collect [Supercharged Tarots](https://cotlmod.infernodragon.net/docs/supercharged/tarots) on demand, and it is the only source of the mod's own Strange Extraction card. :: ## Production | Structure | What it does | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | AIO Quarry | Select from 10 different types of materials to collect and a follower mines it for you. Left click to collect, right click to set the material | | AIO Incubator | Choose from several plants to farm and a follower farms the one you select | | Bone Mines | Followers mine bones here. Lasts indefinitely | | Silk Mines | Followers mine silk here. Lasts indefinitely | | Crystal Mines | Followers mine crystals here. Lasts indefinitely | | Tree of Giving | Followers work here to generate small and medium gifts | | Fishing Hut II | The custom replacement for the vanilla Fishing Hut, used by the Fisher role. Each hut stores up to 75 fish | | Food Storage I & II | Store additional food to prevent it rotting | ![AIO Quarry](https://cotlmod.infernodragon.net/images/aio.png) ::caution The vanilla Fishing Hut is deprecated. Use the custom Fishing Hut II introduced in v1.3.0 instead. :: Since v1.1.3, items from the mines and the AIO Quarry can be collected much faster, and followers stand to the side of a mine rather than on top of it so you can still interact with the deposit. ## Follower services | Structure | What it does | | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Waiter Desk | Build one and your followers start serving food to other followers, and collect food from the Follower Kitchen. Build one per waiter you want, anywhere you like | | Sous Chef Desk | Select 1 of 10 dishes for the Sous Chef to cook. No more manually queueing meals | | Follower Management Device | Spy on your followers and assign work commands remotely | | Endless Pit of Gluttony | Dead followers can be buried here an unlimited number of times. Only the Reaper can bury them this way - the player currently cannot | | Alchemy Cauldron | Select a necklace to create, then play a minigame. Succeed with no failures and the necklace is yours | | Study Table | Where the Scholar works. See the [Study role](https://cotlmod.infernodragon.net/docs/minimods/roles) | | Telescope | Where the Astrologer works. See the [Astrologer role](https://cotlmod.infernodragon.net/docs/minimods/roles) | | Lucky Narinder Statue | For devoting to Narinder. Narinder himself can devote to it to instantly level up | ![Follower Management Device](https://cotlmod.infernodragon.net/images/cotlpc.png) The Waiter Desk and the Sous Chef Desk act as **role proxies**: the corresponding role only exists if the desk is built, and followers then take the role up naturally. ## Strange Energy grid ![Stasis Chamber](https://cotlmod.infernodragon.net/images/stasis.png) | Structure | What it does | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | Strange Generator | Converts Strange Material plus gold into Strange Energy | | Energy Controller | Transfers energy from generators to the structures that use energy. Currently it draws from the Endless Pit and the Strange Generator | | Stasis Chamber | Uses 50 Strange Energy to freeze time. While you are in base with time frozen it drains 10 Strange Energy per real minute | See [Items](https://cotlmod.infernodragon.net/docs/minimods/items) for where Strange Material and Strange Energy come from. ## Later additions The reference list above reflects the structures documented in the mod's own feature list. The [changelog](https://cotlmod.infernodragon.net/docs/minimods/changelog) records further structures added in later compatibility releases - the Boutique in v1.2.2, for example - which are not yet covered by that list. # Roles Each custom role is tied to a structure. Build the structure and the role becomes available; without it, the role does not exist. ## Summary | Role | Required structure | What they do | | ----------------- | --------------------------------------- | ----------------------------------------------------------- | | Sous Chef | Sous Chef Desk | Cooks the dish you selected whenever followers are hungry | | Waiter | Waiter Desk | Serves food to hungry followers | | Fisher | Fishing Hut II | Fishes, with an expanded loot table when commanded directly | | Astrologer | Telescope | Stargazes for inspiration and Strange Material | | Scholar (Study) | Study Table | Studies to raise loyalty and generate Strange Material | | Reaper | Endless Pit of Gluttony | Wraps and buries dead followers | | Miner | Bone / Silk / Crystal Mines, AIO Quarry | Mines bones, silk and crystals | | Narinder Devotion | Lucky Narinder Statue | Devotes to Narinder, increasing cult faith | ## Sous Chef ![Sous Chef](https://cotlmod.infernodragon.net/images/Follower-cook.gif) - There will only be a Sous Chef if you build a Sous Chef Desk. - Select 1 of 10 food choices and the Sous Chef cooks it automatically when followers are hungry. - A food bubble appears above the chef while they are cooking. - Food is stored in the available Follower Kitchens first, then on the floor. ## Waiter ![Waiter](https://cotlmod.infernodragon.net/images/Follower-food-food-run.gif) - There will only be a Waiter if you build a Waiter Desk. - The Waiter serves food that is on the floor first, then takes food from the Follower Kitchen if there is none. Kitchen food is thrown on the floor first. - If you have a Waiter, followers stop running to food and wait to be served. - Waiters only reposition to a follower if that follower wanders more than 7 units from their initial spot. - Food stays on the floor until the follower finishes it. If you eat it before it reaches them, they do not get it. - Followers tip 2 gold on their location when they receive food. - Being served doubles a follower's hunger satiation. - The Waiter teleports food out of the kitchen. ## Fisher ![Fisher](https://cotlmod.infernodragon.net/images/Follower-fishing-fishing.gif) Updated in v1.3.0 to use the custom Fishing Hut II. - Command a follower to fish via **Follower > Fisher**. - By default, worker followers navigate to fishing huts on their own - but when they fish that way they only produce salmon. - Using the command enables the custom loot table instead: | Chance | Catch | | ------ | --------------------------------------- | | Higher | Small Fish, Fish | | Lower | Octopus, Lobster, Squid, Blowfish, Crab | ## Astrologer ![Astrologer](https://cotlmod.infernodragon.net/images/Follower-astrologer.gif) - See the stars, gain inspiration. - Used in the morning, it creates a new quest for the follower. Once per day. - Provides Strange Material at night. Night-time yield was increased in v1.1.2. - Quest giving via the Telescope can be disabled in the config, added in v1.2.0. ## Scholar (Study) ![Scholar](https://cotlmod.infernodragon.net/images/Follower-studying.gif) - The follower studies and increases loyalty. - Invest in the Study Table to generate Strange Material. ## Reaper ![Reaper](https://cotlmod.infernodragon.net/images/Follower-undertaker-collect-corpse.gif) - Followers can wrap and bury dead followers. - Requires an Endless Pit of Gluttony. Normal graves will not work. ## Miner ![Miner](https://cotlmod.infernodragon.net/images/Follower-mining.gif) Followers can mine bones, crystals and silk at the matching mine, and any of the ten AIO Quarry materials at the quarry. ## Narinder Devotion ![Narinder Devotion](https://cotlmod.infernodragon.net/images/Follower-pray.gif) Increases the faith of the cult when a follower devotes at the Lucky Narinder Statue. # Rituals Eight additions to the temple's ritual menu. Several of them are paid for with [Strange Material](https://cotlmod.infernodragon.net/docs/minimods/items) rather than gold or bones. | Ritual | Effect | Cost | | --------------------------- | ------------------------------------------------------------------------------------------- | ---------------- | | Ritual of Mass Resurrection | Brings every dead follower back at once | Strange Material | | Ritual of Exile | Removes a follower from existence | - | | Fusion Ritual | Sacrifices the first selected follower. The second gains all of the first follower's traits | - | | Distribution Ritual | Instantly levels up all your followers | Gold | | Ritual Frenzy | Clears all ritual cooldowns immediately | Gold | | Ritual of Youth | Makes all old followers young again and doubles their life expectancy | Strange Material | | Ritual of Reversal | Swaps the first mutually exclusive trait of a follower for its positive counterpart | - | | Mistletoe Ritual | Bonds two selected followers together | Strange Material | ## Details ### Ritual of Mass Resurrection ![Mass Resurrection](https://cotlmod.infernodragon.net/images/ritual_massres.png) Too many dead followers and no time to revive them one by one. This brings every one of them back in a single ritual, for a small cost in Strange Materials. ### Ritual of Exile ![Ritual of Exile](https://cotlmod.infernodragon.net/images/ritual_exile.png) Too many followers? Snap one of them out of existence. ### Fusion Ritual ![Fusion Ritual](https://cotlmod.infernodragon.net/images/ritual_fusion.png) Sacrifice the first selected follower; the second selected follower gains all of their traits. ::warning Traits are mutually exclusive between negatives and positives, and fusing overwrites an existing opposite trait. Stack them deliberately. :: ### Distribution Ritual ![Distribution Ritual](https://cotlmod.infernodragon.net/images/ritual_leveling.png) Instantly levels up every follower you own, at the cost of gold. Also referred to as the Distribution Frenzy in the mod's feature list. ### Ritual Frenzy ![Ritual Frenzy](https://cotlmod.infernodragon.net/images/ritual_frenzy.png) Clears the cooldown on all of your other rituals immediately, at the cost of gold. ### Ritual of Youth ![Ritual of Youth](https://cotlmod.infernodragon.net/images/ritual_youth.png) Uses the power of Strange Material to make all old followers young again, and doubles the affected followers' life expectancy. ::note You need to exit the temple before the followers visually change. :: ### Ritual of Reversal ![Ritual of Reversal](https://cotlmod.infernodragon.net/images/ritual_reversal.png) Swaps the first mutually exclusive trait a follower has for its positive counterpart. ### Mistletoe Ritual Select two followers and infuse them with the power of Strange Material to bond them together. ::note The changelog for v1.2.2 records this ritual being renamed to the **Ritual of Love** . The mod's feature list still calls it the Mistletoe Ritual, so you may see either name depending on your version. :: # Commands Custom commands appear on the follower interaction wheel alongside the vanilla options. They split into two kinds: social commands you use on any follower, and work commands that assign one of the [custom roles](https://cotlmod.infernodragon.net/docs/minimods/roles). ## Social commands | Command | What it does | | ------------ | --------------------------------------------------------------- | | Knucklebones | Play a game of knucklebones with your follower | | Flip Coin | Flip a coin with your follower and see if you win. 5 coins each | | Divorce | Too many spouses? Here is the solution | ![Knucklebones](https://cotlmod.infernodragon.net/images/knucklebones.png) ## Work commands These require the matching structure to be built, and are also assignable remotely from the Follower Management Device. | Command | Requires | Assigns | | ------------- | --------------------------------------- | --------------------------------------------------- | | Custom Miners | Bone / Silk / Crystal Mines, AIO Quarry | The Miner role for that deposit | | Sous Chef | Sous Chef Desk | The Sous Chef role | | Waiter | Waiter Desk | The Waiter role | | Fisher | Fishing Hut II | The Fisher role, with the custom loot table enabled | ::tip Commanding a follower to fish is not the same as letting them wander to a fishing hut on their own. Followers who go fishing by themselves only produce salmon; the **Fisher** command switches them to the full custom loot table. See [Roles](https://cotlmod.infernodragon.net/docs/minimods/roles#fisher) . :: ::note The [changelog](https://cotlmod.infernodragon.net/docs/minimods/changelog) lists further commands added in later compatibility releases, such as "For I have Sinned" in v1.2.2, which are not covered by the reference list above. :: # Items ![Strange Material](https://cotlmod.infernodragon.net/images/strange.png) MiniMods adds a two-stage resource chain on top of the vanilla economy. Strange Material is the raw resource your followers produce; Strange Energy is what you refine it into to power the futuristic structures. ## Strange Material A strange material that is used for rituals and futuristic machines. It was introduced in v1.1.2, and its current art is by Rimanah. ### Where it comes from | Source | Notes | | ----------------------------- | ---------------------------------------------------------------------------------------------- | | Astrologer at the Telescope | Provides Strange Material at night. Night-time yield was increased in v1.1.2 | | Scholar at the Study Table | Invest in the Study Table to generate Strange Material | | Strange Extraction tarot card | Enemies you kill drop Strange Material at a 100% chance. Only obtainable from the Wishing Well | ### What spends it | Consumer | Use | | --------------------------- | -------------------------------------------------------- | | Strange Generator | Converted, together with gold, into Strange Energy | | Ritual of Mass Resurrection | Paid as the cost of reviving every dead follower | | Ritual of Youth | Powers the ritual that makes old followers young again | | Mistletoe Ritual | Infused into two followers to bond them | | Wishing Well II | Strange Materials are what keep the rebuilt well powered | ## Strange Energy An experimental energy system that powers futuristic structures. Introduced in v1.1.3 together with the machines that use it. ### Where it comes from | Source | Notes | | ----------------------- | ----------------------------------------------------------------- | | Strange Generator | Converts Strange Material plus gold into Strange Energy | | Endless Pit of Gluttony | The other generator the Energy Controller can currently draw from | ### What spends it | Consumer | Use | | -------------- | ---------------------------------------------------------------------------------- | | Stasis Chamber | 50 Strange Energy to freeze time, then 10 per real minute while you remain in base | The **Energy Controller** is the link between the two halves: it transfers energy from the generators to the structures that consume it. ## Custom tarot | Card | Effect | Source | | ------------------ | ----------------------------------------------------- | ---------------------------------- | | Strange Extraction | Enemies killed drop Strange Material at a 100% chance | Wishing Well custom structure only | ::note Strange Extraction cannot be found in the normal tarot pool during a run. The [Wishing Well](https://cotlmod.infernodragon.net/docs/minimods/structures#wishing-well-ii) is the only place to pick it up. :: # Changelog ## v1.3.3 - Minor fix and Alchemy Cauldron update - Fixed an issue where the Alchemy Cauldron would softlock the player - Fixed an issue where fishing followers became overly attached to the fishing hut - Added new necklaces to the Alchemy Cauldron ## v1.3.2 - Woolhaven support - Quick temporary fix for Woolhaven support ## v1.3.1 - Localization support and Wishing Well relic fix - Localization for the mod is now supported. Translations are downloaded from the [NexusMods files tab](https://www.nexusmods.com/cultofthelamb/mods/12?tab=files){rel=""nofollow""} - Minor fix to powdered boxes not generating random relics when selected from the Wishing Well ## v1.3.0 - Season 2: Trial of the Gods ### Trial of the Gods - Added five Trials and ten Augments. All of them can be active at the same time. See [Trial of the Gods](https://cotlmod.infernodragon.net/docs/minimods/trial-of-the-gods) ### Infernal Infuser, previously the Relic Infuser - The interaction for this structure has changed - Removed: select one relic to bring into your next run - New: select any amount of Trials and Augments to increase the difficulty of your next run ### Wishing Well v2 - The interaction for this structure has changed - Tarot effects no longer apply in base - Removed: pay 20 gold and select one out of two cards - New: at no cost, select any amount of tarot cards from the vanilla and custom pool, plus a relic, to bring into your next run ### Fishing Hut v2 - A new custom structure for fishing. Use it instead of the vanilla Fishing Hut, which is deprecated ### Other - The Fisher role now uses the custom Fishing Hut v2 - The sprites for certain custom structures have been changed - Removed the Relic Infuser ## v1.2.3 - Compatibility update and minor content update - Updated for Unholy Alliance - Added Ritual of Massacre ## v1.2.2 - Compatibility update and minor content update - Updated for Sins of the Flesh - Added `NoExhaustMating` config - Added Boutique structure - Renamed Mistletoe Ritual to Ritual of Love - Drink from Drinkhouse - "For I have Sinned" command ## v1.2.1 - Compatibility update and minor content update - Fixed an issue with follower commands not loading - Added Relic Infuser - Added `RelicNoReset` config ## v1.2.0 - Season 1, Finale - Added Ritual of Mass Resurrection - Added Ritual of Exile - Added Sous Chef role and desk - Added the ability to take food out of the Follower Kitchen - Added the Strange Extraction tarot card - Added a config to enable or disable giving quests via the Telescope - Updated the Alchemy Table to give new necklaces - Updated the Waiter Desk to serve from the Follower Kitchen - Changed the Study Table interaction - Fixed an issue with the Cooking Fire not able to start manual cooking ## v1.1.6 - Compatibility update - Minor compatibility update for COTL 1.2.1 and COTL API 0.1.17 - Removed Kitchen 1 and 2 - Sous Chef Desk has changed - you can now interact with it, but it is not complete yet ## v1.1.5 - Compatibility update - Minor compatibility update for COTL 1.1.4 and COTL API 0.1.16. No extra features ## v1.1.4 - Mini Christmas update - AIO Farmer: the follower mines from the Incubation Chamber at a far higher rate than normal farms - Incubation Chamber: choose from several plants to farm and a follower farms the one you select - Tree of Giving: followers work here to generate small and medium gifts - Mistletoe Ritual: select two followers and infuse them with the power of Strange Material to bond them together - Changed the keys for the AIO Quarry to use a custom one, so it no longer modifies the farm plot data. Same for the new AIO Farmer ## v1.1.3 - Season 1, Episode 3 - Added the Strange Energy mechanic - Added the Stasis Chamber, AIO Quarry, Energy Controller and Strange Generator - Items from mines including the AIO Quarry can be collected much faster now - Followers now move to the side of the mines to work instead of standing directly on them, making the mines easier to interact with - Ritual animations have been improved ## v1.1.2 - Season 1, Episode 2 - Compatible with COTL API 0.1.14 - Added the Strange Material item - Added the Ritual of Youth - Added Strange Material to the Study role - Increased Strange Material yield at night when stargazing - Added the Reaper role - Added the Alchemy Cauldron - Added the Endless Pit of Gluttony - Added config to the in-game menu ## v1.1.1 - Compatible with COTL API 0.1.10 ## v1.1.0 - Season 1, Episode 1 - Fixed the Waiter role not persisting through food - Fixed softlocked food caused by interrupted waiters - Added structures: Telescope, Study Table, Narinder Statue - Added roles: Astrologer, Study, Narinder Devotion ## v1.0.10 - Hotfix for the ritual menu error ## v1.0.9 - Should fix reflection errors - Removed the waiter restriction on follower eating, so followers are no longer prevented from eating when there is no waiter - Reworked the Chef role - Made the Waiter and Chef roles natural - New structures - New rituals ## v1.0.8 - Added new structures - Added new commands ## v1.0.7 - The folder structure has changed. Upgrading from 1.0.6 or below manually? Delete the old DLL first - The Follower Manager Device has been implemented - Some leftover code intended for 1.0.8 remains - see known issues ## v1.0.6 - Kitchen II has been re-implemented - The new structures now have icons - Kitchen and Kitchen II can now be moved - New Divine Bell for Kitchen II - Food Storage is now interactable ## v1.0.5 - Several Waiter buffs - The Waiter no longer needs to return to the kitchen to collect food, and continues serving directly - Followers now tip the Waiter 2 gold, dropped on their current location - The kitchen catches fire when the chef starts cooking, to indicate cooking - You can now build fishing huts - Added the fishing drop table - You can now bring more than one "The One Who Waits" home. Ideally only enable this after collecting him once ## v1.0.4 - Bumped the COTL API version to 0.1.4 - Minor bugfix for a Reflection Exception that could occur when loading the mod ## v1.0.3 - A config file has been added to tweak the mod to your liking - The chef has been repositioned slightly upwards so he is not inside the cooking pot - The chef now has a bubble showing whether they are cooking - New role: Waiter - Challenge "The One Who Waits" repeatedly. Enable it in the config file first - Challenge the Shrimp Chef Rakshasa repeatedly, untested. Enable it in the config file first ## v1.0.2 - Kitchens reduce food cost by 50%, minimum 1 per ingredient - Players can now eat as much as they want ## v1.0.1 and v1.0.0 - Initial release # Credits ## Developer - [InfernoDragon0](https://github.com/InfernoDragon0){rel=""nofollow""} ## Artists | Artist | Contributions | Link | | ---------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------- | | Klara Chaos | Distribution Ritual, Lucky Narinder Statue | [Instagram](https://instagram.com/klara_chaos?igshid=YmMyMTA2M2Y=){rel=""nofollow""} | | ScreenySketches | Fusion Ritual, Ritual Frenzy | [Carrd](https://screeny.carrd.co/){rel=""nofollow""} | | Scribblekid | Telescope, Ritual Frenzy, Ritual of Youth | - | | Rimanah | Strange Material v2 | - | | InfernoDragon0 | Additional art | [GitHub](https://github.com/InfernoDragon0){rel=""nofollow""} | | Cult of the Lamb | The base game art the mod builds on | [cultofthelamb.com](https://www.cultofthelamb.com/){rel=""nofollow""} | Scribblekid is credited as `Scribblekid#0606` and Rimanah as `Rimanah#4072` in the mod's own credits. ## Others - Pocam's [animation website](http://cotl-spoilers.xl0.org/){rel=""nofollow""}, used as a reference for follower animations ## Testers Testers for Trial of the Gods were credited on request during the beta. If you tested and would like to be listed, say so in the [modding Discord](https://discord.gg/MUjww9ndx2){rel=""nofollow""}. ## How to contribute Art contributions for any part of the mod are welcome. DM `Infernodragon1` on Discord or join the [modding Discord](https://discord.gg/MUjww9ndx2){rel=""nofollow""}. ## Support If you like the mod, consider donating on [Ko-fi](https://ko-fi.com/infernodragon0){rel=""nofollow""} or [Patreon](https://www.patreon.com/InfernoDragon0){rel=""nofollow""}. # COTL MP Steam COTL MP Steam adds online two-player co-op to Cult of the Lamb. It runs over Steam peer-to-peer networking, so there is no dedicated server and nothing to port forward: one player hosts on their own save and the other joins from the Steam friends list or a Discord invite. ::warning{title="Not a public release"} MP Steam is an experimental test build. The mod files are handed to testers directly and are not shared publicly, so there is no download on this site. Ask in the [modding Discord](https://discord.gg/MUjww9ndx2){rel=""nofollow""} if you want in. :: ## How it works The host is authoritative. Their save is loaded, streamed to the guest in memory, and it is the copy that keeps the progress. The guest plays inside that world as the vanilla goat, with their own camera, HUD, health and curses — and their own saves are never written to. ::card-group :::card --- icon: i-lucide-play title: Hosting and joining to: https://cotlmod.infernodragon.net/docs/mpsteam/hosting-and-joining --- Starting a lobby, inviting a friend, chat, pings and the parity checks that run on connect. ::: :::card --- icon: i-lucide-history title: Changelog to: https://cotlmod.infernodragon.net/docs/mpsteam/changelog --- Everything in the current test build. ::: :: ## Requirements - Cult of the Lamb on Steam, the **same game version** on both machines. - BepInEx 5.4.21 and [COTL\_API](https://thunderstore.io/c/cult-of-the-lamb/p/xhayper/COTL_API/){rel=""nofollow""}. - The **same mods** on both sides. The handshake compares the protocol version, the MP build and every installed plugin by file hash, and tells you exactly what does not match. - Discord running, if you want Invite to Play and Ask to Join. ## What is synced Dungeons (room seeds, decoration, enemies, damage, knock-outs and revives), boss fights, base building, follower commands, altar rituals, the cult's inventory, conversations, the adventure map, and CultTweaker skins and content. Rewards are instanced, so both players take their own weapons, curses, relics and tarot cards from a room. ::note Many interactions still have to be patched by hand, so something you try may only happen on one screen. Reporting those is the point of the test — send steps to reproduce plus `BepInEx/LogOutput.log` from **both** machines. :: ## CultTweaker together If both players run a matching [CultTweaker](https://cotlmod.infernodragon.net/docs/culttweaker) build: - custom follower and player skins follow all session long, including switching back to a vanilla skin; - the host's CultTweaker content can be downloaded on join, after a consent prompt, on its own low-priority transfer lane so it does not spike your ping; - the F4 room editor works over the link — the world freezes for both of you, edits appear live, the other player's selection is drawn in amber, and the host saves the file and ships it across. # Hosting and joining ## Before you start Back up your saves. They live in: ```text %USERPROFILE%\AppData\LocalLow\Massive Monster\Cult Of The Lamb\saves ``` Only the host's save is modified during a session, but this is a test build and a backup costs nothing. ::steps ### Host a session Load the save you want to play, open the pause menu with `Esc`, and choose **Host Multiplayer**. The lobby is created immediately and the pause menu gains the online controls. ### Invite your friend Invite from the Steam overlay, from your Steam friends list, or through Discord if Discord Rich Presence is on. The guest accepts the invite or joins from your friends list. ### Wait for the handshake On connect the mod compares the protocol version, the MP build, the game version and every installed plugin by file hash. A mismatch stops the join with a message naming what differs, rather than desyncing later. ### Play The guest drops into your world with their own camera and HUD. Press `Enter` to chat, middle-click to ping a spot for both players. :: ## In-session controls | Input | What it does | | ------------ | ------------------------------------------------------------------------------------------- | | `Enter` | Opens text chat. Steam avatars and lobby events are shown; it hides itself when quiet. | | Middle mouse | Drops a world ping visible to both players and announced in chat. | | `Esc` | Pause menu, including the online section and a Pause Game button that freezes both players. | ## Rewards, inventory and building - **Dungeon rewards are instanced.** Weapons, curses, relics and tarot cards can each be taken by both players. Tarot lists are shared back to the host so defensive cards protect the guest too. - **The cult's inventory is the host's.** It is streamed to the guest, and buildings the guest places are paid from it. If the host cannot afford a placement it is refused and the guest's copy is taken back. - **Structures replicate as results.** Placement, hammering progress and removal cross over, and you see the other player's placement ghost while they aim. ## Discord Rich Presence While Discord is running you get Invite to Play and Ask to Join, and your presence shows where you are: the base with a follower count, a dungeon, or a hub — including CultTweaker's custom hubs and maps. Turn it off in the `[Discord]` section of the mod's config file. ## Reporting a bug Send a DM with: 1. Steps to reproduce, and whether you were the host or the guest. 2. `BepInEx/LogOutput.log` from **both** machines. 3. If the game crashed, `Player.log` from `%USERPROFILE%\AppData\LocalLow\Massive Monster\Cult Of The Lamb\` and the newest folder in `%LOCALAPPDATA%\Temp\Massive Monster\Cult Of The Lamb\Crashes`. 4. Screenshots or video, if you have them. ::caution Screenshots, video and streams of the mod are fine to share. The mod files themselves are not — do not pass the build on to anyone else. :: ## Known limits - Steam overlay invites do not work on app id 480. Invite through the Discord or Steam friends list instead, and make sure both players use the same app id. - Not every interaction is patched yet. Anything that shows up on one screen and not the other is worth reporting. - CultTweaker support varies by build; older versions such as 1.1.2 may not behave. # Changelog ## v0.1.0 — first test build The bullets below are grouped by system; the mod's own changelog lists them flat. ### Session and connection - Steam peer-to-peer two-player co-op: host from the pause menu, join from the Steam overlay. - The host's save is streamed to the guest in memory; the guest's own saves are never written. - Separate camera and HUD per player, with the vanilla goat as the guest avatar. - The handshake compares protocol, mod build and every installed plugin by file hash, with a clear mismatch message, and refuses to start on an older game version. - Time scale is synced from any source: the pause menu, meditation and mod panels slow or freeze both players together. ### Dungeons and combat - Dungeon seed, rooms, enemies, damage, knock-out and revive are replicated. - Rooms are decorated identically on both screens. - Projectiles, curses and swipes are mirrored on the other player. - Enemy poison puddles reach the guest; enemies removed by the host without dying disappear on the guest too. - Rewards are instanced: weapons, curses, relics and tarot cards can be taken by both players, and first-room podiums reserved for the other player close when they pick. Tarot lists are shared with the host so defensive cards protect the guest. - Base doors and the dungeon door are host-led and are never tripped by the other player's puppet. - Tarot cards that grant hearts keep them on the guest, including the extra heart containers. - When both players go down the run ends for both of you, and the respawn room after a double knock-out brings the guest along. ### Bosses - The temple door cutscene, boss-spawned enemies, the boss health bar and the cutscene camera moves all reach the guest. - Boss dialogue opens on both screens and the host's Continue turns the page for both of you. - Boss projectiles fired through a helper component appear on the other screen. - The adventure map freezes both players while it is open, and opens for both together. ### The cult - The cult's inventory is streamed from the host, and buildings placed by the guest are paid from it; a placement the host cannot afford is taken back. - Structures are per player: placement, hammering progress and removal replicate as results, with the other player's placement ghost shown. Both players can hammer the same build site. - Rituals at the altar play on both screens, including the follower chosen for a sacrifice, a wedding and similar picks. - Follower commands from the interaction wheel — imprison, bless, work orders, gifts, daycare, sacrifice and the rest — replay on the other screen with the right puppet acting. - Followers walk the same paths on both screens, either player can indoctrinate, and the next recruit steps up on both screens afterwards. - Summoned allies, demons and familiars appear on the other player's screen. - Opening a new dungeon door with the required followers plays the whole ritual on both screens, and a door opened by the guest stays open. - Divine inspiration is spent by the host only, so unlocks stick. ### Conversations - NPC conversations open for both players and follow the host page by page, including dialogue answers; a conversation you start is driven by you. - Talking to a follower no longer takes the other player's controls away. ### Mod support - COTL\_API custom content ids are remapped between machines, and modded per-slot save data ships with the save. - CultTweaker skins sync by name and keep following all session long, including switching back to a vanilla skin. - Opt-in download of the host's CultTweaker content, behind a consent dialog. - CultTweaker's F4 room editor works over the link: the world freezes for both players, edits appear live, both can edit at once with the peer's selection in amber, and the host saves and copies the file across. Needs a CultTweaker build with the editor contract on both sides. - Enemies placed with CultTweaker's editor are matched by their editor id (CultTweaker contract 2). - Content downloads and editor files travel on their own low-priority lane at a configurable send rate (`Network.SendRateKB`, default 2048), so a download no longer raises ping. ### Social - Text chat on `Enter` with Steam avatars and lobby events, hidden when quiet. - Middle-mouse world ping shown on both screens and announced in chat. - Steam rich presence with a player group, and Discord Rich Presence with Invite to Play and Ask to Join. - Presence shows the current area: the base with a follower count, a dungeon, or a hub name, including CultTweaker hubs and maps. # MCP server ## What this is This documentation is also served as an [MCP](https://modelcontextprotocol.io){rel=""nofollow""} server. Specifically, if you are building on top of CultTweaker or COTL MP Steam, this MCP helps you with that. this MCP does not provide direct documentation to the game's source code, only for the mods that are available in this page. ```text https://cotlmod.infernodragon.net/mcp ``` The transport is streamable HTTP. There is no API key, no account and no rate limit to sign up for — it serves the same pages you are reading now. ::note The server is read-only. It can list and read documentation pages, and that is all. It has no access to the mods, your game files or anything else. :: ## Quick example Most clients take a name and a URL. In Claude Code that is one line: ```bash claude mcp add --transport http cotl-docs https://cotlmod.infernodragon.net/mcp ``` For clients configured by file, the entry looks like this: ```json { "mcpServers": { "cotl-docs": { "type": "http", "url": "https://cotlmod.infernodragon.net/mcp" } } } ``` That shape works for Cursor, in `~/.cursor/mcp.json` for every project or `.cursor/mcp.json` inside one. VS Code uses the same fields under `servers` instead of `mcpServers`, in `.vscode/mcp.json`. For Claude's desktop and web apps, add it as a custom connector and paste the same URL. Every page on this site also carries an **Add MCP Server** item in the menu beside its *Copy page* button, which installs the server into Cursor in one click, and a **Copy MCP Server URL** item for pasting into anything else. Once it is connected, ask the tool something the docs answer and it will fetch the page itself: > Using the cotl-docs server, what does CultTweaker's `IdOf` return, and why > should I not save the value? ## What the server exposes Two tools, both read-only and cached for an hour: | Tool | Takes | Returns | | ------------ | ------- | ----------------------------------------------- | | `list-pages` | nothing | Title, path, description and URL for every page | | `get-page` | a`path` | That page's metadata plus its full markdown | A client normally calls `list-pages` first to find what exists, then `get-page` for the pages it needs. Paths are the same ones in your address bar, so `/docs/culttweaker/modding-api` is a valid argument to `get-page`. ## Without an MCP client The same content is available as plain files, which is often enough: | Route | What you get | | ------------------------------------------------------------------- | ------------------------------------------------------ | | [`/llms.txt`](https://cotlmod.infernodragon.net/llms.txt) | Every page's title, description and link, in one index | | [`/llms-full.txt`](https://cotlmod.infernodragon.net/llms-full.txt) | The entire documentation as a single file | | `/raw/docs/.md` | Any single page as its original markdown | For example, the modding API page in markdown is at [`/raw/docs/culttweaker/modding-api.md`](https://cotlmod.infernodragon.net/raw/docs/culttweaker/modding-api.md). The *Copy page* menu on each page links to the same file, and can copy the page straight to your clipboard or hand it to ChatGPT or Claude. ::tip Pasting a link to `/llms-full.txt` into a chat is the fastest way to give an assistant the whole reference at once, with no setup at all. :: # Documentation Reference material for every mod in this collection. Each category covers what the mod adds, how to install it, and the exact configuration files it reads. ::card-group :::card --- icon: i-lucide-wand title: CultTweaker to: https://cotlmod.infernodragon.net/docs/culttweaker --- The world editor, custom dungeons, player and follower spines, weapons, NPC quests, enemies, structures, and the modding API. ::: :::card --- icon: i-lucide-zap title: Supercharged Series to: https://cotlmod.infernodragon.net/docs/supercharged --- Supercharged Tarots and Supercharged Followers: card lists, rally mechanics, class boosts and prestige levels. ::: :::card --- icon: i-lucide-boxes title: CotL MiniMods to: https://cotlmod.infernodragon.net/docs/minimods --- Custom structures, follower roles, rituals, commands and the Trial of the Gods difficulty system. ::: :::card --- icon: i-lucide-users title: COTL MP Steam to: https://cotlmod.infernodragon.net/docs/mpsteam --- Online two-player co-op over Steam peer-to-peer. In closed testing — notes on hosting, joining and what is synced. ::: :: ## Before you start Every mod here runs on [BepInEx](https://thunderstore.io/c/cult-of-the-lamb/p/BepInEx/BepInExPack_CultOfTheLamb/){rel=""nofollow""} and needs [COTL\_API](https://thunderstore.io/c/cult-of-the-lamb/p/xhayper/COTL_API/){rel=""nofollow""}. Install those first, then drop the mod folder into `BepInEx/plugins`. Questions, bug reports and modding talk all happen in the [modding Discord](https://discord.gg/MUjww9ndx2){rel=""nofollow""}. ## Tools - [Follower skin builder](https://cotlmod.infernodragon.net/builder) — convert old COTL JSONLoader skins into the CultTweaker follower form format, author new ones, and preview them on a live skeleton. - [MCP server](https://cotlmod.infernodragon.net/docs/mcp) — connect Claude, Cursor or another AI tool directly to these docs, or read them as plain markdown.