> For the complete documentation index, see [llms.txt](https://axiomemu.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://axiomemu.gitbook.io/docs/data/plugins/dungeons.md).

# Dungeons (Instances)

Tiered, timed, per-player instanced dungeons on existing world maps - ladders, entry fees, schedules, monster sets, bosses and clear rewards

The Dungeon plugin turns any existing world map (or a region of it) into a private, timed challenge. A player (or a whole party, led by its leader) enters through a bound NPC (or the `L` hotkey), gets a private instance of the map region, and must kill every monster including the boss before the timer ends. Clearing a level in time grants the reward bag and unlocks the next level; clearing every level of a tier unlocks the next tier. Progress is per character and permanent.

{% hint style="info" %}
**Paid add-on** (module `dungeon-plugin`). Without the module on your license the plugin loads nothing, the client never receives a dungeon catalog, and the browser window cannot open. Nothing else changes.
{% endhint %}

## File Location

```
Data/Plugins/Dungeons/
```

Each dungeon ladder is its own `.xml` file. There is no master switch file; drop files in, remove them to retire a dungeon.

## Dependencies

| Depends On                                   | Purpose                                                                                          |
| -------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| [Monster.xml](/docs/data/monster/monster.md) | Monster classes spawned inside runs (stats, drops are NOT used - see `ItemBag`)                  |
| [EventItemBag](/docs/data/eventitembag.md)   | `RewardBag` and per-monster `ItemBag` indices                                                    |
| [Gate.txt](/docs/data/gate.md)               | Optional `ExitGate` a player may still use inside a run                                          |
| [Item.xml](/docs/data/item/item.md)          | `FeeItemType` / `FeeItemIndex` identity                                                          |
| DataServer                                   | Table `dbo.DungeonProgress` (Name varchar(10), Blob varbinary(64)) stores per-character progress |

## How Files Are Loaded

* The folder is scanned for `*.xml` at startup and on plugin reload.
* The dungeon index comes from the leading 3-digit number of the filename: `000 - Forgotten Depths.xml` is dungeon 0. Valid indices are 0 to 15.
* Progress is stored by dungeon index, tier index and level index. Renaming a file to a different number, or reordering tiers / levels, changes what a player's stored clears point at.
* A file with a broken `<Dungeon>` root or an invalid index is skipped with a log line; the others still load.

## Dungeon Structure

```xml
<Dungeon Name="..." NpcClass="..." MinLevel="..." InstanceItemLifetimeSec="..." ClearedGraceSec="...">
  <Schedule Mode="Always|Windows">
    <Window Day="-1" StartHour="18" EndHour="22"/>
  </Schedule>
  <Tier Name="Normal">
    <Level Index="1" Map="4" SpawnX="20" SpawnY="20" TimeLimitSec="600" DeathFails="0"
           FeeZen="500000" RewardBag="1" RewardMode="inventory">
      <Area X1="2" Y1="5" X2="57" Y2="60"/>
      <Monster Class="34" Count="25" Boss="0" ItemBag="-1"/>
      <Monster Class="38" Count="1"  Boss="1" ItemBag="-1" Spot="40,45" Dis="3"/>
    </Level>
  </Tier>
</Dungeon>
```

### Dungeon

| Attribute                 | Type              | Default   | Effect                                                                                                                        |
| ------------------------- | ----------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `Name`                    | string (31 chars) | `Dungeon` | Shown in the browser window and the in-run HUD                                                                                |
| `NpcClass`                | int               | -1        | Talking to this NPC opens the dungeon browser. -1 = no NPC (players use the `L` hotkey)                                       |
| `MinLevel`                | int               | 1         | Minimum character level to enter any level of this dungeon                                                                    |
| `InstanceItemLifetimeSec` | int               | 120       | Seconds a ground drop inside a run stays before it expires                                                                    |
| `ClearedGraceSec`         | int               | 60        | Seconds the player may keep looting after a clear before the run closes and they are returned                                 |
| `ExpiredGraceSec`         | int               | 15        | Time ran out: seconds before the run closes and everyone is returned. 0 = at once                                             |
| `MaxPerDay`               | int               | 0         | Entries per account per day (all its characters together). 0 = no limit. See [EntryLimits](/docs/data/plugins/entrylimits.md) |
| `MaxPerWeek`              | int               | 0         | Entries per account per week. 0 = no limit                                                                                    |
| `PartyRange`              | int               | 10        | Party runs: tiles every party member must be within of the leader (same map) to enter together                                |

### Schedule

| Attribute | Type                 | Default  | Effect                                                      |
| --------- | -------------------- | -------- | ----------------------------------------------------------- |
| `Mode`    | `Always` / `Windows` | `Always` | `Windows` restricts entry to the listed `<Window>` elements |

Each `<Window>`:

| Attribute                   | Type | Default | Effect                                     |
| --------------------------- | ---- | ------- | ------------------------------------------ |
| `Day`                       | int  | -1      | 0 = Sunday .. 6 = Saturday, -1 = every day |
| `StartHour` / `StartMinute` | int  | 0 / 0   | Window opens (server local time)           |
| `EndHour` / `EndMinute`     | int  | 24 / 0  | Window closes                              |

A closed schedule only blocks new entries. A run that is already in progress continues.

### Tier

Up to 3 tiers per dungeon, in ladder order. `Name` (23 chars) is the tab label in the browser.

### Tier scaling

Set on `<Tier>`; a `<Level>` may set any of the same keys to override its tier. Percent of the Monster.xml value, `100` = unchanged.

| Attribute                                                               | Default | Effect                                                                                                                   |
| ----------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------ |
| `Life` / `Damage` / `Defense`                                           | 100     | Monster life, damage, and defense + magic defense                                                                        |
| `Exp`                                                                   | 100     | Monster EXP                                                                                                              |
| `Drop`                                                                  | 100     | Monster bag rolls: `100` = one roll per kill, `150` = one roll + 50% chance of a second, `0` = none                      |
| `PartyLife` / `PartyDamage` / `PartyDefense` / `PartyExp` / `PartyDrop` | 0       | Extra % for each party member after the first. A 3-player run with `Life="160" PartyLife="50"` has monsters at 260% life |

The party size is counted when the run starts; players who join later do not rescale the monsters. A Bosses.xml boss inside a dungeon starts its own player scaling from the dungeon-scaled values. The browser shows the scaling under **Monsters** and the EXP / drop bonus under **Rewards**.

```xml
<Tier Name="Heroic" Life="160" Damage="130" Defense="120" Exp="150" Drop="130" PartyLife="50" PartyDamage="10" PartyDrop="10">
```

### Level

Up to 5 levels per tier. `Index` must be contiguous from 1.

| Attribute                      | Type                 | Default     | Effect                                                                                                                                                                    |
| ------------------------------ | -------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Index`                        | int                  | 0           | 1-based level number within the tier                                                                                                                                      |
| `Map`                          | int                  | -1          | The real world map the run happens on. Required                                                                                                                           |
| `SpawnX` / `SpawnY`            | int                  | -1          | Where the player lands. Must be inside an `<Area>`                                                                                                                        |
| `TimeLimitSec`                 | int                  | 600         | Clear timer in seconds                                                                                                                                                    |
| `DeathFails`                   | 0/1                  | 0           | 1 = dying ends the run (town respawn). 0 = respawn at `SpawnX`/`SpawnY`, still inside the run                                                                             |
| `FeeZen`                       | int64                | 0           | Zen taken on entry. Refunded if the instance could not be created                                                                                                         |
| `FeeItemType` / `FeeItemIndex` | int                  | -1          | Item consumed on entry. -1 = no item fee                                                                                                                                  |
| `FeeItemLevel`                 | int                  | 0           | Required item level for the fee item                                                                                                                                      |
| `FeeItemCount`                 | int                  | 1           | How many fee items are consumed                                                                                                                                           |
| `RewardBag`                    | int                  | -1          | ItemBag index granted on an in-time clear. -1 = no reward                                                                                                                 |
| `RewardMode`                   | `inventory` / `drop` | `inventory` | `inventory` puts the bag contents straight into the inventory (overflow drops at the player). `drop` drops the bag at the final-kill position, owner-locked to the runner |
| `ExitGate`                     | int                  | -1          | Gate index the player may still use during the run. Every other portal is sealed while inside                                                                             |

### Area

One or more boxes in tile coordinates. The player cannot walk outside them while in the run; map collision still applies inside. Draw one box around a whole isolated floor and no wall is ever felt.

| Attribute              | Type | Default |
| ---------------------- | ---- | ------- |
| `X1`, `Y1`, `X2`, `Y2` | int  | 0       |

### Monster

| Attribute | Type  | Default | Effect                                                                                                    |
| --------- | ----- | ------- | --------------------------------------------------------------------------------------------------------- |
| `Class`   | int   | -       | Monster class from Monster.xml                                                                            |
| `Count`   | int   | -       | How many to spawn                                                                                         |
| `Boss`    | 0/1   | 0       | 1 = counted as a boss. **Every boss and every trash monster must die to clear**                           |
| `ItemBag` | int   | -1      | ItemBag dropped when this monster dies. -1 = drops nothing. Regular class loot is never used inside a run |
| `Spot`    | `x,y` | -       | Optional. Place the group within `Dis` tiles of this point instead of scattering across the areas         |
| `Dis`     | int   | -       | Radius around `Spot`                                                                                      |

## Important Behavior

* **Sealed teleports**: inside a run, every way out except Leave is refused: map portals, the Move window (M), `/move`, town portal scrolls, a Dark Lord's party summon and event teleports. The player sees "Teleports are sealed during a run. Use Leave to exit." Only the level's `ExitGate` works. Teleport skills inside the run's areas still work. GMs are not blocked.
* **Isolation**: a run is a private instance channel of the real map. Other players on the same tiles are invisible to the runner and the runner's monsters, and vice versa. Aggro, area skills and item pickup all respect this.
* **Progress rule (fixed)**: clear tier T level N in time -> level N+1 unlocks. Clear every level of tier T -> tier T+1 level 1 unlocks. Cleared levels can be run again.
* **Timer expiry**: no reward bag and no unlock. Everyone in the run is moved out after `ExpiredGraceSec` (default 15 s, time to pick up loot).
* **Clear**: reward is granted, the unlock is saved immediately, and the player has `ClearedGraceSec` to loot before being returned.
* **Entry checks in order**: license, valid indices, not already in a run, party leader (see below), progress loaded, schedule open, `MinLevel`, level unlocked, alive, server headroom, every party member, fees. The fee is charged last and refunded if the spawn fails.
* **Party runs**: in a party, only the leader can start a run, and the whole party goes in with them.
  * Every other member must be on the leader's map within `PartyRange` tiles, alive, not in another run, at `MinLevel` or higher, and have that level unlocked. The first member who fails stops the entry, and the leader sees who and why.
  * The leader pays the fee once for the whole party.
  * A party member outside can press Enter to join the leader's run while it is still going (same checks, without the distance, no fee).
  * Dying (with `DeathFails="1"`), Leave, disconnecting, warping out or leaving the party takes only that member out. The run ends for everyone when the leader leaves it.
  * On a clear, every member still inside gets the unlock and their own roll of `RewardBag`. Kill drops can be picked up by every party member.
  * Party EXP is only shared with members inside the same run.
* **Reload**: the plugin reload re-reads the folder; a run already in progress keeps a snapshot of its level and is not affected.
* Players open the browser by talking to `NpcClass` or with the `L` hotkey. The window lists lock / open / cleared state per level. The selected level shows four blocks: **Dungeon** (map, time limit, monsters, death rule), **Monsters** (tier and party scaling), **Requirements** (level, unlock, zen fee, fee item with have / need, party range - green border = met, red = missing) and **Rewards** (reward bag, EXP and drop bonus, what clearing unlocks). Every entry has a tooltip. The last entry result shows under them.

## Entry Result Messages

| Result           | Player sees                                                             |
| ---------------- | ----------------------------------------------------------------------- |
| Locked           | This level is locked. Clear the previous one first.                     |
| Schedule closed  | This dungeon is closed right now.                                       |
| Level too low    | Your level is too low for this dungeon.                                 |
| Already in a run | You are already in a dungeon run.                                       |
| No zen / no item | Not enough Zen for the entry fee. / You are missing the entry item.     |
| Server busy      | The dungeon is busy. Try again in a moment.                             |
| Spawn failed     | The dungeon could not be prepared. Fee refunded.                        |
| Not the leader   | Only the party leader can start a run. Join once your leader is inside. |
| Member too far   | *Name* is too far away. Gather next to the leader.                      |
| Member busy      | *Name* cannot enter right now (dead, busy or already in a run).         |
| Member level     | *Name*'s level is too low for this dungeon.                             |
| Member locked    | *Name* has not unlocked this level yet.                                 |

## GM Commands

| Command                              | Effect                                            |
| ------------------------------------ | ------------------------------------------------- |
| `$dgnenter <dungeon> <tier> <level>` | Enter a level directly (indices are 0-based here) |
| `$dgnleave`                          | Leave the current run                             |
| `$dgnstate`                          | Print run state and remaining time                |
| `$dgnclear`                          | Force-clear the current run                       |

## Examples

{% tabs %}
{% tab title="Single-tier ladder" %}
Save as `001 - Spider Nest.xml`. Three Lorencia levels, always open, no fee.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<Dungeon Name="Spider Nest" NpcClass="253" MinLevel="10">
  <Schedule Mode="Always"/>
  <Tier Name="Normal">
    <Level Index="1" Map="0" SpawnX="140" SpawnY="130" TimeLimitSec="300" RewardBag="2">
      <Area X1="120" Y1="110" X2="170" Y2="160"/>
      <Monster Class="3" Count="20" ItemBag="-1"/>
      <Monster Class="2" Count="1" Boss="1"/>
    </Level>
    <Level Index="2" Map="0" SpawnX="140" SpawnY="130" TimeLimitSec="300" RewardBag="2">
      <Area X1="120" Y1="110" X2="170" Y2="160"/>
      <Monster Class="3" Count="40" ItemBag="-1"/>
      <Monster Class="2" Count="2" Boss="1"/>
    </Level>
  </Tier>
</Dungeon>
```

{% endtab %}

{% tab title="Evening-only, item fee, drop reward" %}

```xml
<?xml version="1.0" encoding="UTF-8"?>
<Dungeon Name="Night Vault" NpcClass="253" MinLevel="300" ClearedGraceSec="90">
  <Schedule Mode="Windows">
    <Window Day="-1" StartHour="19" EndHour="23"/>
  </Schedule>
  <Tier Name="Heroic">
    <Level Index="1" Map="4" SpawnX="100" SpawnY="180" TimeLimitSec="540" DeathFails="1"
           FeeZen="2000000" FeeItemType="14" FeeItemIndex="13" FeeItemCount="5"
           RewardBag="7" RewardMode="drop">
      <Area X1="80" Y1="165" X2="135" Y2="250"/>
      <Monster Class="40" Count="50"/>
      <Monster Class="49" Count="1" Boss="1" Spot="110,240" Dis="2"/>
    </Level>
  </Tier>
</Dungeon>
```

{% endtab %}
{% endtabs %}

## Common Issues

{% hint style="warning" %}
Window never opens: the module is not on the license, or the folder has no valid file. Check the GameServer log for `[Dungeon] Loaded N dungeon(s)`.
{% endhint %}

{% hint style="warning" %}
Player lands and is stuck: `SpawnX`/`SpawnY` is outside every `<Area>` box, or the box covers non-walkable terrain. Spawn inside a box on walkable tiles.
{% endhint %}

{% hint style="warning" %}
"The dungeon is busy": the map has no headroom for the monster count, or the player's progress had not loaded yet. Retry in a moment; if it persists, lower `Count` values.
{% endhint %}
