ChaosMixRecipes.xml

The recipe catalog. Every chaos machine combination lives here: which NPC hosts it, which items are accepted as sources, how success rate is computed, how much zen it costs, and what item drops on success.

File Location#

Data/Plugins/Items/ChaosMix/ChaosMix_Recipes.xml

Loaded once at GameServer startup. Hot reloadable via the ChaosMix plugin admin command.

Schema#

<ChaosMixConfig Version="1">
    <Recipes>
        <Recipe MixType="..." MixIndex="..." MixID="...">
            <Display ... Category="..." Result="..." ResultRandom="..." />
            <Requirements Level="..." />
            <ZenCost Type="..." Value="..." />
            <SuccessRate FormulaId="..." MaxRate="..." />
            <Options MixOptionId="..." CharmOptionId="..." ChaosCharmOptionId="..." />
            <Sources>
                <Source Index="..." TypeMin="..." TypeMax="..." LevelMin="..." LevelMax="..."
                        OptionMin="..." OptionMax="..." DurMin="..." DurMax="..."
                        CountMin="..." CountMax="..." SpecialFlags="..."
                        NameText="..." Group="..." />
            </Sources>
            <Rewards>
                <Reward ItemBagId="..." Weight="..." />
            </Rewards>
        </Recipe>
    </Recipes>
</ChaosMixConfig>

Recipe Identity#

AttributeTypeEffect
MixTypeintWhich NPC/context hosts this recipe. See MixType reference
MixIndexint0-based slot within the MixType group
MixIDintMix code. Drives client-side routing (combine animation, UI prompts). For built-in mixes it also selects which reward routine produces the item on success. It does not pick the recipe, but the client must send the same value or the mix is refused. See MixID Ranges

MixID Ranges#

Every mix routes through the plugin first. If a recipe matches the submitted MixType + MixIndex, the plugin handles it. If no recipe matches, the server refuses the mix - there is no legacy fall-through.

The wire field for MixID is a single byte, so keep MixID <= 255. A recipe with MixID above 255 is refused when a player tries it (the client shows "wrong combination"), unless the recipe has its own reward bag (<Reward ItemBagId> greater than 0). The refusal is logged as recipe-MixID=... > 255 without an ItemBag reward - REFUSED. Even with a reward bag, the client only sends the low byte (for example 300 arrives as 44), and that byte must still match.

  • 1..57 - Built-in mix codes (Chaos Item, Devil Square, +Item Level, Dinorant, Fruit, Wings, Fenrir, 380 item, Harmony, Socket, Lucky Item Create 51 / Refine 52, etc.). These are all shipped as plugin recipes. Reuse a value here only when your recipe is the built-in mix (so the matching reward routine runs on success). 51 and 52 are ordinary recipes now, safe like the rest.
  • 58..99 - Gaps between built-in codes. Works today, but a future season update may claim these. Not recommended for new recipes.
  • 100..255 - Recommended for new custom recipes that ship their own <Rewards> block. No collision with built-in codes.

Debugging a Mix That Does Nothing#

If clicking "Combine" plays the animation but nothing else happens:

  1. Confirm the client and XML agree on MixType / MixIndex. That pair is the dispatch key; a mismatch means no recipe is found and the server refuses the mix.
  2. Confirm the client and XML agree on MixID. A different MixID is refused and logged as [MixIDMismatch].
  3. Confirm the plugin loaded (check the GameServer startup log for the recipe count).
  4. Check the ChaosMix log for the day (GameServer/ChaosMix/YYYY-MM-DD.txt). A refused mix records the account, character, and the MixType / MixID / MixIndex that had no matching recipe, plus a dump of the box contents.

Display#

Visual layout in the NPC dialog. Text ids resolve to client display strings, not to Message.xml notices.

Ids below 10000 come from the client's own Text.bmd. Ids at or above 10000 come from GameStrings.xml, which is synced to the client at login - use that range to add new text without patching and reshipping the client.

AttributeEffect
NameText1/2/3Title text IDs
DescText1-3Description text IDs
AdviceText1-3Advice/hint text IDs
Width / HeightGrid cells the recipe occupies in the NPC's recipe list
CategoryRecipe Book group. Default 0 = "Other". The group name is GameStrings id 11300 + Category (shipped: 1 Item Upgrade, 2 Wings & Capes, 3 Pets & Fenrir, 4 Potions & Stones, 5 Events & Chests, 6 Chaos Weapons, 7 Inscription)
ResultItem the Recipe Book shows as the output. "Section,Index" or "Section,Index,Level" (for example "13,15"), or "main" / "main,Level" = the main material (source 0) comes back upgraded. Empty = no result shown. No level = "any level"
ResultRandom1 = the output is one of several items (for example a random wing); the shown icon is only an example. Default 0

Category, Result and ResultRandom are display only. They feed the Chaos Goblin Recipe Book window and never change what the mix accepts or gives.

Requirements#

<Requirements Level="..." />
AttributeEffect
LevelMinimum character level required to attempt

Cost#

<ZenCost Type="A" Value="..." />
AttributeEffect
TypeCost scaling mode. A = flat Value, B = Value * computed success rate, C = flat Value, D = flat Value (harmony cost slot; currently returns Value unchanged)
ValueZen cost input to the mode above

Numeric Types 1..4 are accepted as aliases for A..D.

Success Rate#

<SuccessRate FormulaId="..." MaxRate="100" />
AttributeEffect
FormulaIdFormula to evaluate. Defined in ChaosMix_Formulas.xml
MaxRateHard ceiling on the computed success rate. If omitted, defaults to 100, in which case the recipe inherits the referenced formula's own MaxRate. If set to anything other than 100, the recipe's value wins and the formula's MaxRate is ignored. The final computed rate is also clamped to 100 overall

Options#

<Options MixOptionId="..." CharmOptionId="..." ChaosCharmOptionId="..." LuckBonus="0" />
AttributeEffect
MixOptionIdWhich source-item filter applies
CharmOptionIdCharm policy
ChaosCharmOptionIdChaos charm policy
LuckBonus1 = if the Source 0 item has Luck, add LuckChaosMixRate (ItemOption.xml) plus AddLuckSuccessRate2_AL* (GameServerInfo - Common.dat) to the rate. Default 0. Vanilla grants this only on the +10 to +15 item upgrade mixes; the shipped recipes set it there and nowhere else

The first three refer to entries in ChaosMix_Options.xml.

Sources#

One or more required inputs. Each <Source> describes a valid range of items the chaos box must contain. Source order in the XML defines the source index; the first <Source> element is source 0, the second is source 1, and so on. There is no explicit Index attribute on <Source> - an Index attribute in the XML is ignored by the loader.

AttributeEffect
TypeMin / TypeMaxItem index range, given as section * 512 + type (for example section 12, type 3 = 6147). Use the same value for both to require one specific item. Section and type numbers come from Item.xml
LevelMin / LevelMaxItem +level range
OptionMin / OptionMaxItem +option (additional damage/defense option) range
DurMin / DurMaxDurability range for equipment; for stackable items this is checked against the stack count instead
CountMin / CountMaxMinimum/maximum number of matching items (or total stack count for stackables) that must be present. CountMax is only enforced when set to a value below 255
SpecialFlagsBitmask of required attributes on matching items. 0x01 = Excellent option present, 0x02 = +380 item, 0x04 = Set (Ancient) item, 0x08 = Jewel-of-Harmony-refined item, 0x10 = Socket item. Luck is handled via the formula's LUCKOPT token, not this bitmask
NameTextDisplay override for this source in the combine window's "Items for combination" list. Text id resolved the same way as <Display> ids. 0 or absent = the client names the source after its TypeMin item
GroupRecipe Book display only. Sources with the same Group (1-255) are shown as one "One of:" ingredient that needs just one item (for example the catalysts of an inscribe recipe). Default 0 = no group. Matching ignores it

A recipe may have up to 16 <Source> rows. A recipe with more than 16 is not loaded at all (the GameServer log shows has N <Source> rows (max 16) - skipped).

Naming a grouped source#

By default the client labels a source with the real name of its TypeMin item. That is correct for a source that requires one specific item, and misleading for one that accepts a range: a source spanning every Manticore piece across every class shows "Manticore Helm [BM]" (and changes as the player inserts items), so it reads as if only the Helm is accepted.

NameText replaces the base label:

<Source TypeMin="..." TypeMax="..." CountMin="1" CountMax="6" NameText="10500" />
<!-- GameStrings.xml: <String Id="10500" Text="Manticore Armor Part" /> -->

Only the base noun is replaced. Level, option, durability and count decoration still compose onto it, so the example above renders as Manticore Armor Part 1~6 pcs.

NameText also supersedes the client's built-in group labels (the fixed list that turns certain hardcoded type spans into "Any Armor", "1st Wings" and similar). A source with NameText set never falls through to those.

The engine walks each slot in the chaos box and matches it against the first <Source> whose ranges and flags all apply; each slot is assigned to at most one source. Validation succeeds only if every <Source> has at least CountMin matching items (and no more than CountMax when CountMax < 255). If validation fails, the client sees "wrong combination".

Rewards#

<Rewards>
    <Reward ItemBagId="..." Weight="..." />
</Rewards>
AttributeEffect
ItemBagIdEvent item bag to draw the reward from. > 0 = the plugin creates the reward from that bag and owns delivery end-to-end. 0 = the reward is produced by the built-in reward routine for this MixID (used by the shipped built-in mixes)
WeightWeight for picking this reward when multiple <Reward> entries exist

Event item bags live in EventItemBag/. A recipe with ItemBagId=0 still gets a reward; the built-in reward routine for that mix produces the item on success. New custom recipes should set ItemBagId > 0 so the reward is fully data-driven.

Example Recipe#

ChaosMix_Recipes.xml fragment
<Recipe MixType="0" MixIndex="1" MixID="3">
    <Display NameText1="604" NameText2="0" NameText3="0"
             DescText1="606" DescText2="607" DescText3="608"
             AdviceText1="0" AdviceText2="0" AdviceText3="0"
             Width="5" Height="4" />
    <Requirements Level="10" />
    <ZenCost Type="A" Value="2000000" />
    <SuccessRate FormulaId="2" />
    <Options MixOptionId="2" CharmOptionId="1" ChaosCharmOptionId="2" />
    <Sources>
        <Source TypeMin="0" TypeMax="7167"
                LevelMin="9" LevelMax="9"
                OptionMin="0" OptionMax="255"
                DurMin="0" DurMax="255"
                CountMin="1" CountMax="1"
                SpecialFlags="1" />
        <Source TypeMin="6159" TypeMax="6159"
                LevelMin="0" LevelMax="255"
                OptionMin="0" OptionMax="255"
                DurMin="0" DurMax="255"
                CountMin="1" CountMax="1"
                SpecialFlags="0" />
    </Sources>
    <Rewards>
        <Reward ItemBagId="0" Weight="100" />
    </Rewards>
</Recipe>

Goblin slot 1 (MixType=0 MixIndex=1): combine a +9 item with a Jewel of Chaos (item 6159) for 2M zen. Success formula 2 (50 + LUCKOPT). The first source must be an Excellent item (SpecialFlags=0x01). ItemBagId=0, so the built-in reward routine for this mix produces the result on success.

Important Behavior#

  • Mismatched inputs are rejected, not consumed. If the chaos box contains an item that no <Source> in the matched recipe accepts, the whole mix is refused before anything is charged or destroyed. The client shows "wrong combination". This covers the +380 case: putting a non-+380 item into a recipe that requires +380 (for example a +380 item plus a normal item of the same type) is rejected on the server, and the client filters those items out of the interface, so the player cannot combine them and lose the jewels. Nothing is consumed on a rejected mix.
  • The chaos box is the only source of mix inputs. Recipes match against whatever the player placed in the chaos box, regardless of which inventory area those items came from. Items held in the extended inventory can be placed into the chaos box and used in a mix like any other inventory item.
  • Dispatch is by MixType + MixIndex. MixID does not select the recipe. Two recipes may share a MixID (for example the two Lucky Item Refine variants) as long as their MixIndex differs.
  • MixID must still match. The client sends a MixID with every mix. If it is not the found recipe's MixID, the mix is refused and nothing is consumed. This stops one recipe's rate and cost being used to run a different mix.

Cross-File Dependencies#

AttributeRelated in
FormulaIdChaosMix_Formulas.xml
MixOptionId, CharmOptionId, ChaosCharmOptionIdChaosMix_Options.xml
TypeMin/MaxItem.xml
ItemBagIdEventItemBag

Common Issues#

  • Click "Combine": animation plays, no items consumed, no reward, no error - The submitted MixType / MixIndex has no matching recipe, so the server refused the mix. The animation is client-side. Check the ChaosMix log for the day to see the MixType / MixID / MixIndex that was refused, then confirm the client and XML agree. Also possible: the plugin failed to load (check GameServer startup log), or a custom reward ItemBagId points at a non-existent bag
  • Recipe not found for valid-looking inputs - Source ranges too narrow; verify item indices in Item.xml
  • Client shows "wrong combination" despite correct items - Sources block has fewer entries than the client expects, or an input item matches no <Source> range and is rejected
  • Recipe succeeds with wrong reward - ItemBagId="0" uses the built-in reward routine for that mix. To customize the reward, point ItemBagId at an entry in EventItemBag instead
  • [MixIDMismatch] ... REFUSED in the ChaosMix log - client and XML disagree on MixID. The mix is refused. Set the recipe's MixID to the value the client sends (shown as client-MixID in the log line)
  • > 255 without an ItemBag reward - REFUSED in the ChaosMix log - MixID above 255 does not fit the single-byte wire field. Keep MixID <= 255, or give the recipe its own reward bag (ItemBagId > 0)
  • Recipe missing after load - more than 16 <Source> rows. Split it into smaller recipes
  • Editing a recipe did nothing - reload via admin command or restart. The plugin caches parsed data

Last updated October 1, 2026