> 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/message.md).

# Message.xml

Defines the server's indexed message strings. The server looks up a string by numeric index; the calling code formats and sends it. The strings may contain printf-style `%d` and `%s` placeholders that the calling code substitutes before sending.

## File Location

```
Data/Message.xml
```

Loaded once at GameServer startup. Changes require a restart.

## Configuration Structure

```xml
<MessageList>
    <Message Index="0" Text="Blood Castle will close in %d minute(s)"/>
    <Message Index="1" Text="Blood Castle closed"/>
    <!-- More messages... -->
</MessageList>
```

## Message Element

Each message is defined with an index and text content.

| Attribute | Type   | Default  | Description                                                                                                                                   |
| --------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `Index`   | int    | Required | Unique message identifier. The shipped file covers 0-880                                                                                      |
| `Text`    | string | Required | Message text. Stored in a 128-byte buffer (127 usable characters plus null terminator). Supports `%d` (number) and `%s` (string) placeholders |

## Important Behavior

{% hint style="info" %}
**How Message Loading Works**: The server reads Message.xml at startup and keeps messages in memory in a map keyed by `Index`. Each message is capped at the 128-byte buffer size; longer strings are silently truncated by the string copy.
{% endhint %}

{% hint style="info" %}
**Missing Messages**: If code requests an index that doesn't exist, the lookup returns a single shared fallback buffer containing `"Could not find message <index>!"` instead of crashing. The fallback buffer is shared across calls, so a second failed lookup on the same tick overwrites the first.
{% endhint %}

{% hint style="warning" %}
**Character Limit**: Message text is stored in a 128-byte buffer (127 printable characters plus null terminator). Longer text will not crash the server; it is silently truncated at load time.
{% endhint %}

{% hint style="info" %}
**How Placeholders Work**: The message lookup returns the raw format string (e.g., `"Blood Castle will close in %d minute(s)"`). The calling code formats it with `sprintf`/`wsprintf` and sends the resulting string through whichever delivery path it uses (server notice, target chat, guild notice, etc.) - there is no single "broadcast" step inside the message subsystem. The placeholder order and types must match the arguments the calling code passes.
{% endhint %}

## Message Categories

### Event Messages (0-11, 16-20, 144-211, etc.)

Event-related announcements and status updates.

| Index Range | Event Type          |
| ----------- | ------------------- |
| 0-11        | Blood Castle        |
| 16-20       | Chaos Castle        |
| 144-149     | Devil Square        |
| 176-184     | Illusion Temple     |
| 192-211     | Invasions           |
| 304-306     | Double Goer         |
| 320-325     | Incubator (Selupan) |
| 336-343     | Kanturu             |
| 352-356     | Castle Deep         |
| 368-415     | Crywolf Fortress    |
| 416-426     | Castle Siege        |

### Account & Permission Messages (32-35, 64-69, 248-251)

Account level indicators and permission errors.

| Index   | Purpose                                       |
| ------- | --------------------------------------------- |
| 32-35   | Account level names (Free/Bronze/Silver/Gold) |
| 64-69   | Generic permission/requirement errors         |
| 248-251 | Account level display with expiration         |

### Command Messages (70-135)

Command execution responses and errors.

| Index Range | Command Type             |
| ----------- | ------------------------ |
| 70-74       | `/add` (stat points)     |
| 75-78       | `/pkclear`               |
| 79-80       | `/money`                 |
| 81-84       | `/change` (evolution)    |
| 85-88       | `/ware` (warehouse)      |
| 89-95       | `/reset`                 |
| 96-113      | GM commands              |
| 114-117     | Auto point/reset toggles |
| 118-125     | `/mreset` (master reset) |
| 126-134     | Reset rate limits        |

### Duel System (160-175)

Player versus player duel messages.

### Guild Messages (432-443)

Guild management and alliance notifications.

### Castle Siege (448-469)

Life Stone summoning and soldier recruitment.

### System Messages (480-498)

Server shutdown warnings, anti-cheat, and game state changes.

| Index   | Purpose                 |
| ------- | ----------------------- |
| 480     | Server closed           |
| 481-489 | Shutdown timers         |
| 482     | Duplicated item warning |
| 485-486 | Self Defense state      |

### Custom Features (500-880)

Server-specific custom features and events.

| Index Range | Feature                                |
| ----------- | -------------------------------------- |
| 500-511     | King of MU event                       |
| 602-628     | Marriage system                        |
| 630-659     | Character management                   |
| 660-726     | Custom events (Veloz, Quiz, Tag, etc.) |
| 730-768     | Economy (WC/WP/GP)                     |
| 769-798     | PvP and attack commands                |
| 799-824     | DeathMatch event                       |
| 825-834     | Team vs Team event                     |
| 863-880     | Guild vs Guild event                   |

## Examples

{% tabs %}
{% tab title="Simple Message" %}

```xml
<Message Index="1" Text="Blood Castle closed"/>
```

No placeholders - string is sent as-is by the calling code.
{% endtab %}

{% tab title="Single Placeholder" %}

```xml
<Message Index="0" Text="Blood Castle will close in %d minute(s)"/>
```

The caller formats the string with the minutes-left value before sending, producing `"Blood Castle will close in 5 minute(s)"`.
{% endtab %}

{% tab title="Multiple Placeholders" %}

```xml
<Message Index="69" Text="%s: %s"/>
```

The caller formats with both strings before sending, producing e.g. `"System: Message text"`.
{% endtab %}

{% tab title="String and Number" %}

```xml
<Message Index="95" Text="You reset successfully, and now have %d resets"/>
```

The caller formats with the reset count before sending, producing `"You reset successfully, and now have 10 resets"`.
{% endtab %}
{% endtabs %}

## Cross-File Dependencies

| Value                     | Related in                                                                                                                 |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| Monster-spoken chat lines | [CustomDeathMessage.txt](/docs/data/customdeathmessage.md) provides its own string table and does not use Message.xml      |
| Command responses         | Triggered by commands defined in [Command.xml](/docs/data/command-xml.md) / [Command.dat](/docs/gameserver/command-dat.md) |
| Item-related notices      | Item names referenced in messages come from [Item.txt](/docs/data/item/item.md)                                            |

## Common Issues

{% hint style="warning" %}
**Incorrect Placeholder Types**: Using `%s` for numbers or `%d` for strings will produce display errors or crashes, since the calling code passes positional arguments without type checking. Ensure placeholder types match the data being passed.
{% endhint %}

{% hint style="warning" %}
**Missing Placeholders**: If the calling code passes values but the text has no placeholders, the values are ignored. If the text has placeholders but the caller passes nothing, the formatter will read past the argument list and produce garbage.
{% endhint %}

{% hint style="info" %}
**Index Gaps**: The configuration has many gaps in index numbers (e.g., 11->16, 20->32, 35->36). This is intentional to group related messages and leave room for expansion. Don't renumber existing indices - add new messages in gaps or at the end.
{% endhint %}

{% hint style="info" %}
**"Unknown Message" Placeholders**: Indices 37-58 contain `"Unknown Message"` as reserved slots. These can be replaced with actual messages as needed; the calling code treats them like any other entry.
{% endhint %}
