Pixel Dream StudiosWiki
Mods

Magic Realms

An Iron's Spells addon adding spellcasting mobs and hireable mercenaries that level up and develop personalities.

Magic Realms is an Iron's Spells and Spellbooks addon for Minecraft NeoForge 1.21.1 that aims to expand the amount of spellcasting mobs in the world, with a strong focus on hireable mercenary NPCs that level up, develop personalities, and fight alongside the player.

Player guide

Mercenaries

Mercenaries are spellcasting humans that wander the world and can be hired to fight alongside you. Each Mercenary has one of five playstyles with it's own spell list:

  • Mage — Ranged spellcaster, can wield a Staff and Spellbook. Has inate Spell Power in one to four Schools of Magic. Avaliable Schools and Spells are set via Datapack through Tags.
  • Warrior — Melee fighter, can wield Swords. Gains bonus Armor as they level up.
  • Tank — Melee fighter who can wield a Shield in addition to Swords.
  • Archer — Ranged fighter wielding a bow. Can use modded bows, and if any bow doesn't natively work you can add it to the "bows" tag from Magic Realms.
  • Assassin — Melee skirmisher with high Crit Chance and a chance to Dodge attacks.

Mercenaries can Level Up by killing enemies. Every kill grants experience; reaching the next Level boosts core Stats (HP, damage, armor) and Stats related to their Class. Kills against bosses grant additional permanent Stat upgrades up to a configurable cap.

Mercenaries can become immortal by giving them a Hell's Pass, which is dropped from the Dead King and Tyros. Mercenaries with a Hell's Pass who run out of Health will get Stunned for a few seconds (configurable in magic_realms-common.toml).

Each mercenary spawns with:

  • A Gender (male / female), which influences their Name and Appearance.
  • A randomly generated Name drawn from a configurable list (magic_realms-common.toml maleNames / femaleNames).
  • A Personality — an Archetype, a Hobby, a Hometown, and zero to three Quirks. (See Custom archetypes below.)
  • A unique Appearance — either a randomly generated combination of skin / clothes / eyes / hair textures, or a complete preset skin (with about a 10% chance to roll a preset).

Players in Creative Mode can use the Skin Customizer to customize the Appearance of randomly generated Mercenaries.

Hiring Mercenaries — Taverns and Tavernkeepers

Mercenaries hang out in Taverns, structures that generate naturally in plains biomes. Each tavern is staffed by one Tavernkeeper, who sells useful items.

Interacting with a Mercenary will tell you what Contract they will accept and how long it lasts.

To hire a Mercenary, simply right-click them with a Contract item.

From the Tavernkeeper you can buy:

  • Contracts, which are needed to hire Mercenaries. Higher level Mercenaries demand higher tier Contracts.
  • Maps to structures from Iron's Spells & Spellbooks
  • Food and drink
  • A Room for the night, you can buy a Sleeping Pass to sleep in one of the Tavern's beds. Sleeping in the Tavern grants you Absorption and Resistance effects

Players can also interact with the Tavernkeeper giving him an emerald to get either useful information or some chit chat.

Working with a contracted Mercenary

Once a Mercenary is contracted to you, interacting with them will tell you how much longer they will remain contracted for and triggers some chit chatting related to their Personality. When shift + right clicking them a menu will pop up, and inside it you can:

  • Change their equipment — armor, weapons, off-hand items. Mercenaries can use spells from their equipment if they are on their Class' spell list.
  • View their combat stats — full Attribute breakdown (HP, armor, spell power per school, resistances, crit, dodge, life steal, archery stats…) plus their Personality traits.
  • See their inventory — what they've picked up off the ground, plus what they're carrying for you.
  • Give Orders — there's a button to switch between Following you and Patrolling the area.

Mercenaries also react to other Mercenaries you've contracted nearby. Hired Mercenaries interact with eahch other accodin to their their Personalities, which will apply a temporary buff to them based on their Archetypes (rivals, friends, etc.). archetype interactions can be configured via Datapack: see Custom archetype interactions.

A Mercenary's Quirks also drive in-world behavior, for example: a Mercenary with the cant_swim Quirk will not be able to swim in water, a Mercenary with the animal_friend Quirk receives Stat Bonuses when around Animals, a Mercenary who is afraid_of_the_dark becomes weaker and slower in dark places, and so on.

Other Mobs

Magic Realms adds several magic Mobs to spice up the world:

  • Chuchu — Slimes who absorb Magic. Whichever school it absorbs first determines its element going forward, and they can grow absorbing magic. They rarely drop the "Slime Rain" Spell.
  • Fizzles — Sharply dressed Creepers in wizard hats. They don't explode like normal Creepers — instead they cast spells. Be careful: a well-dressed creeper is a dangerous one.
  • Endermages — a conclave of enlightened Endermen living in the Outer End Islands. They have learned magic and use it to teleport across the End freely, no longer bound by the limits of their kin.
  • Tim — a familiar undead lurks in the depths of the Overworld. There are some who call him… Tim.

There's also a small roster of exclusive mercenaries — handcrafted named characters with unique behavior, dialogue, and sometimes special quirks (Eden, Aliana, Amadeus, Catas, Jara, Lilac, Alshanex, GojoMojo). These can appear in Taverns, like normal Mercenaries, identified by their unique skin and name. They are unique to a world: once Amadeus is hired in your save, no other mercenary will ever be Amadeus. They also can't be permanently contracted, they like freedom.

Built-in compatibility

Magic Realms has built-in compatibility for a growing list of other Mods.

Spell Compatability

Spells from these addons are integrated into Mercenary spell lists and can be cast by Fizzles:

  • Tunes 'n Tomes: a Bard's Journey
  • Ender's Spells and Stuff: Requiem
  • Discerning the Eldritch
  • Magic From The East
  • SnackPirate's Aeromancy Additions
  • Cataclysm: Spellbooks

As both Mercenary spell lists and Fizzle spell lists are handled via tag, additional spell compat can be added via Datapack or included in your Mods.

Tavern integration

Taverns can include blocks and items from these other mods:

  • Farmer's Delight
  • Brewin' & Chewin'
  • Hearth and Harvest
  • My Nether's Delight
  • Supplementaries
  • Handcrafted
  • Create

The kitchen, bar, and table jigsaw pools dynamically swap to mod-specific variants when those mods are detected. The Tavernkeep will sell food and drink items from these mods, should they be installed.

Developer guide

This section is for modpack authors, datapack authors, and other modders who want to extend Magic Realms' mercenaries with their own personalities, skins, or named characters.

Almost everything personality- and appearance-related in Magic Realms is datapack-driven.

Also includes all the config options and what are they for.

Config options

Magic Realms ships with a single common config file at config/magic_realms-common.toml, generated automatically on first run.

Leveling and XP

These options control how mercenaries gain XP and how many level-ups they can stack.

KeyDefaultRangePurpose
maxLevel1001 – ∞Hard ceiling on a mercenary's level. Once reached, kills no longer grant XP.
xpGainedMultiplier100.00.0 – ∞Scales how much XP a mercenary gains per kill. 100.0 = base rate, 50.0 = half, 200.0 = double. Set to 0.0 to freeze leveling entirely.
xpNeededMultiplier100.00.0 – ∞Scales how much XP each level-up costs. 50.0 = half the requirement (faster leveling), 200.0 = twice the requirement (slower leveling).

Per-level stat scaling

These bonuses are applied progressively as a mercenary levels up. Each "amount" is the value granted per level; each "times" is the cap on how many times that bonus is applied (so the practical maximum is amount × times, regardless of how high maxLevel is).

KeyDefaultRangeApplies toPurpose
healthAmount10 – ∞AllBonus max HP gained per level-up.
healthAmountTimes1000 – ∞AllMaximum number of times the HP bonus stacks. Cannot effectively exceed maxLevel.
armorAmountWarriors10 – ∞WarriorBonus armor gained per level-up. Warriors only.
armorAmountWarriorsTimes300 – ∞WarriorCap on warrior armor bonus stacks.
maxSpellPowerPercentage50.00.0 – ∞MageCap (in percent) on bonus spell power gained from leveling. 50.0 = +50% spell power at max level. The bonus scales linearly with level / maxLevel.
maxSpellResistancePercentage50.00.0 – ∞MageCap (in percent) on bonus spell resistance from leveling. Scales linearly toward this value as level approaches maxLevel.
maxSpeedPercentage50.00.0 – ∞RogueCap (in percent) on bonus movement speed for rogues (assassins and archers).
maxArrowVelocityPercentage50.00.0 – ∞ArcherCap (in percent) on bonus arrow velocity for archers. Requires Apothic Attributes; silently no-ops if absent.
maxDrawSpeedPercentage50.00.0 – ∞ArcherCap (in percent) on bonus draw speed for archers. Requires Apothic Attributes; silently no-ops if absent.

Note that assassin crit-chance, crit-damage, and dodge bonuses are not exposed as config — they're rolled per mercenary at spawn from class-specific ranges defined in HumanStatsManager.

Boss kill bonuses

Killing entities tagged as bosses via the Magic Realms bosses tag grants permanent stat upgrades on top of normal leveling, capped per category.

KeyDefaultRangePurpose
healthAmountBossKills20 – ∞Bonus max HP per boss kill.
healthAmountBossKillsTimes200 – ∞Maximum number of HP-from-boss bonuses a single mercenary can stack.
damageAmountBossKills10 – ∞Bonus attack damage per boss kill.
damageAmountBossKillsTimes200 – ∞Cap on damage-from-boss stacks.
armorAmountBossKills10 – ∞Bonus armor per boss kill.
armorAmountBossKillsTimes200 – ∞Cap on armor-from-boss stacks.

Contracts

Controls the timing of the contract / hire system.

KeyDefaultRangePurpose
minutesPerContract101 – ∞How long a single contract lasts before it expires and the mercenary returns to neutral.
minutesUntilPermanent2001 – ∞Total contracted time (across renewals) needed before a mercenary can accept a permanent contract.

Spawning and population

KeyDefaultRangePurpose
customTextureChance0.10.0 – 1.0Probability that a newly spawned mercenary uses a complete skin preset instead of compositing skin parts. 0.1 = 10%. Set to 0.0 to disable presets, 1.0 to make every mercenary use one (requires enough presets in the catalog or some will share).
maxMercenariesInRadius81 – ∞Limits how many mercenaries can occupy chairs / bar stools inside a 20-block radius. Prevents tavern overcrowding inside taverns.

Behavior tuning

KeyDefaultRangePurpose
immortalStunDuration101 – 60Seconds an immortal entity (e.g. a Mercenary with a Hell's Pass) stays stunned after being knocked out, before recovering.
attemptCastUnclassifiedSpellsfalseboolIf true, Mercenaries will try to cast spells from addons that haven't been categorized into Magic Realms' class spell tags (classes/mage/*, classes/warrior/*, classes/archer/*, classes/assassin/*). Set at your own risk — uncategorized spells may not work as expected, may target nothing useful, or may break combat AI.

Name, hometown, and tip lists

These string lists are fully editable in the config — you can replace, add to, or trim them without writing a datapack. Translation keys in tavernTips need matching language entries in any active resource pack.

KeyTypeDefault sizePurpose
maleNameslist of strings~140 entriesPool used to name male mercenaries when no name comes from a fixed personality or skin preset.
femaleNameslist of strings~120 entriesSame, for female mercenaries.
hometownslist of strings35 entriesPool used to roll a hometown string for the personality panel ("Westhollow", "Stormkeep", etc.). Picked once per mercenary at spawn.
tavernTipslist of strings5 entriesTranslation keys the Tavernkeeper picks from when offering advice (message.magic_realms.tavernkeep_tip.1 through …tip.5 by default). Each entry must be a key, not the literal text — extend your language file in parallel to add new tips.

Datapack folder layout

All of the following live under data/magic_realms/:

data/magic_realms/
├── mercenaries/
│   ├── personality/
│   │   ├── archetypes/                    # one .json per archetype
│   │   ├── fixed_personalities/           # one .json per named character
│   │   ├── hobbies/                       # one .json per hobby
│   │   └── archetype_interactions/        # one .json per archetype pair relationship
│   ├── skin_parts/                        # one .json per skin / clothes / eyes / hair piece
│   ├── skin_presets/                      # one .json per complete preset texture
│   └── bandit_profiles/                   # one .json per bandit (hostile mercenary) preset
└── tags/
    └── … (spell tags, item tags, etc.)

Every catalog is loaded via a vanilla SimpleJsonResourceReloadListener, so /reload will pick up changes without restarting the server (with the caveat that already-spawned mercenaries keep whatever they originally rolled — only newly spawned mercenaries see the updated catalog).

Custom archetypes

An archetype is a personality bucket like "stoic", "jovial", "ruthless", and so on. Every mercenary has exactly one archetype. The archetype:

  • Drives a mercenary's chat tone (combined with their hobby).
  • Pairs with other archetypes via archetype interactions to apply attribute buffs / debuffs.
  • Biases the random class roll: archetypes can favor mages, warriors, or rogues.

File location

data/magic_realms/mercenaries/personality/archetypes/<id>.json

The file's path is the archetype's stable identifier. The catalog also indexes archetypes by the value inside the JSON's id field, which is what every other JSON file in the mod (fixed_personalities, archetype_interactions) refers to. Keep both in sync to avoid confusion.

Schema

FieldTypeDefaultNotes
idstringRequired. Short id used by every other file referring to this archetype (e.g. "stoic").
display_keystringRequired. Translation key for the human-readable name (e.g. "archetype.magic_realms.stoic").
class_weightsobject: string→int{}Per-class weight bonus on top of base_weight. Keys must be lower-case class names: "mage", "warrior", "rogue".
base_weightint10Base weight before class bonus.
in_random_poolbooltrueIf false, this archetype is only selectable through fixed personalities and is never rolled by a normal mercenary spawn. Useful for archetypes that only make sense on named characters.

The probability of an archetype being rolled is max(0, base_weight + class_weights[entity_class]).

Example

A "stoic" archetype that's slightly more common on warriors and mages, slightly less common on rogues:

{
  "id": "stoic",
  "display_key": "archetype.magic_realms.stoic",
  "base_weight": 10,
  "class_weights": {
    "mage":    2,
    "warrior": 4,
    "rogue":  -2
  },
  "in_random_pool": true
}

A "lone_wolf" archetype that exists only as a reference for an exclusive named character — never rolled randomly:

{
  "id": "lone_wolf",
  "display_key": "archetype.magic_realms.lone_wolf",
  "base_weight": 0,
  "in_random_pool": false
}

Don't forget to add the matching archetype.magic_realms.stoic (or whatever) entry to your language file.

Custom fixed personalities

A fixed personality is a pre-rolled set of personality traits — archetype, hobby, hometown, quirks, optional override name — that can be stamped onto a mercenary instead of doing a fresh random roll.

There are three ways a fixed personality reaches a mercenary:

  1. Exclusive mercenary override — entities like Amadeus and Catas declare their personality directly in code via getFixedPersonality(). They reference a fixed personality id from the catalog with FixedPersonality.fromCatalog("magic_realms:amadeus").
  2. Skin preset locking — a skin preset's JSON can specify fixed_personality_id. Whenever that preset is rolled for a mercenary, the linked personality is also stamped on. Useful for characters whose identity is "this exact skin and this exact personality, always together".
  3. Random pool roll — when a mercenary spawns, there's a flat 10% chance (FIXED_POOL_ROLL_CHANCE) that they roll from the fixed-personality random pool instead of doing a normal random personality roll.

File location

data/magic_realms/mercenaries/personality/fixed_personalities/<id>.json

Schema

FieldTypeDefaultNotes
archetypestringRequired. Short id of an archetype in the catalog (e.g. "stoic").
hobbystring"" (none)Short id of a hobby. May be omitted.
hometownstring"" (none)Free-form text shown in the personality panel. May be omitted.
quirksstring array[]List of quirk ids.
override_entity_namestringabsentIf present and non-empty, the mercenary is renamed to this when the personality is applied.
in_random_poolbooltrueWhether this entry can be rolled by the random-pool roll. Set to false for preset-locked characters who should only appear on their matching skin.
weightint (≥ 1)1Weight inside the random pool.
uniquebooltrueIf true, once this id has been assigned to any mercenary in the world (even one that has since died), no other mercenary can ever roll it. Used for one-of-a-kind named characters.

Example: a generic random-pool entry

A friendly bookworm tinker named "Old Marek" who can show up on any mercenary:

{
  "archetype": "jovial",
  "hobby": "tinkering",
  "hometown": "Eastfield",
  "quirks": ["bookworm", "early_riser"],
  "override_entity_name": "Old Marek",
  "in_random_pool": true,
  "weight": 1,
  "unique": true
}

Example: a preset-locked named character

A unique character "Vex" who only appears when their dedicated skin preset rolls — never as a random personality:

{
  "archetype": "ruthless",
  "hobby": "swordplay",
  "hometown": "the Hollow Reach",
  "quirks": ["claustrophobic"],
  "override_entity_name": "Vex",
  "in_random_pool": false,
  "unique": true
}

You'd then point a skin preset's fixed_personality_id at this entry. (See Custom skin presets.)

Custom hobbies

A hobby is a chat reaction package. When a player types a message near a contracted mercenary, the mercenary checks their hobby's keyword list and may respond from a hobby- and archetype-specific pool.

File location

data/magic_realms/mercenaries/personality/hobbies/<id>.json

Schema

FieldTypeDefaultNotes
idstringRequired. Short id used by fixed_personalities JSONs (e.g. "bookworm").
display_keystringRequired. Translation key for the hobby's human-readable name.
responsesobject: string→string arrayRequired. Map of archetype id → list of translation keys. The special key "default" is used when no matching archetype-specific pool exists.
in_random_poolbooltrueWhether this hobby can be picked by the random hobby roll.

When a mercenary speaks, the resolver looks up responses[archetypeId] first; if the archetype isn't in the map (or its list is empty), it falls back to responses["default"]. If neither exists, the mercenary stays silent.

This is the mechanism that lets a "Bookworm Stoic" sound different from a "Bookworm Jovial" while still sharing the same hobby.

Example

A "tinkering" hobby with a default voice plus dedicated lines for stoic and jovial mercenaries:

{
  "id": "tinkering",
  "display_key": "hobby.magic_realms.tinkering",
  "in_random_pool": true,
  "responses": {
    "default": [
      "speech.my_pack.tinkering.default.1",
      "speech.my_pack.tinkering.default.2"
    ],
    "stoic": [
      "speech.my_pack.tinkering.stoic.1",
      "speech.my_pack.tinkering.stoic.2"
    ],
    "jovial": [
      "speech.my_pack.tinkering.jovial.1",
      "speech.my_pack.tinkering.jovial.2"
    ]
  }
}

The translation keys (speech.my_pack.tinkering.stoic.1, etc.) need matching entries in your language file. Each entry is the actual line the mercenary will say, with %s available for the speaker's name (the formatter splices it in colored).

Custom archetype interactions

An archetype interaction defines what happens when two contracted mercenaries with a specific pair of archetypes are near each other while both contracted by the same player. The most common use is rivalry / friendship buffs and debuffs.

The pair is unordered: archetype_a = "stoic", archetype_b = "jovial" matches both a stoic-near-jovial and a jovial-near-stoic.

File location

data/magic_realms/mercenaries/personality/archetype_interactions/<id>.json

The file's full ResourceLocation becomes the interaction's id.

Schema

FieldTypeDefaultNotes
archetype_astringRequired. Short id of the first archetype.
archetype_bstringRequired. Short id of the second archetype. May be the same as archetype_a (a self-pair).
attribute_modifiersarray of entries[]List of attribute modifiers applied to both mercenaries while in range. See structure below.
radiusdouble12.0Search radius in blocks. Capped at 64.0.
kindstring""Optional tag (e.g. "rival", "friend") read by chat banter code. Purely informational; the attribute_modifiers list is the source of truth for stat effects.

Each entry in attribute_modifiers is:

{
  "attribute": "minecraft:generic.movement_speed",
  "id":        "magic_realms:stoic_jovial.movespeed",
  "amount":    -0.1,
  "operation": "add_multiplied_total"
}

operation accepts the vanilla values: add_value, add_multiplied_base, add_multiplied_total. The id field on each entry is purely an authoring label — at runtime, the tick handler synthesizes a stable per-mercenary modifier ResourceLocation from the interaction id and the entry's index, so collisions with other modifiers are impossible.

Example: stoic vs. jovial rivalry

The two are on the same team but don't get along — both lose 10% movement speed and 5% damage while standing near each other:

{
  "archetype_a": "stoic",
  "archetype_b": "jovial",
  "kind": "rival",
  "radius": 8.0,
  "attribute_modifiers": [
    {
      "attribute": "minecraft:generic.movement_speed",
      "id": "magic_realms:stoic_jovial.movespeed",
      "amount": -0.1,
      "operation": "add_multiplied_total"
    },
    {
      "attribute": "minecraft:generic.attack_damage",
      "id": "magic_realms:stoic_jovial.damage",
      "amount": -0.05,
      "operation": "add_multiplied_total"
    }
  ]
}

Example: stoic-stoic synergy

Two stoics near each other inspire calm — both gain 10% knockback resistance:

{
  "archetype_a": "stoic",
  "archetype_b": "stoic",
  "kind": "friend",
  "radius": 12.0,
  "attribute_modifiers": [
    {
      "attribute": "minecraft:generic.knockback_resistance",
      "id": "magic_realms:stoic_self.kbr",
      "amount": 0.1,
      "operation": "add_value"
    }
  ]
}

Modifiers are applied as transient modifiers: when the mercenaries move out of range, when one of them is unloaded, when their contract ends, or when the datapack is reloaded, the modifiers come off.

Quirks reference

Quirks are not datapack-driven — they're a hardcoded enum because each one has a corresponding piece of behavior code (a goal, a mood reaction, a dialogue hook). You can't add new quirks, but you can reference any of these in your fixed_personalities:

Quirk idEffect summary
afraid_of_the_darkBecomes weaker at dark places.
hates_rainBecomes weaker when rainy.
cant_swimCan't swim in water.
claustrophobicBecomes weaker at narrow spaces.
night_owlActive and happy at night. Mutually exclusive with early_riser.
early_riserActive and happy in the morning. Mutually exclusive with night_owl.
heat_intolerantWeaker in hot biomes. Mutually exclusive with cold_intolerant.
cold_intolerantWeaker in cold biomes. Mutually exclusive with heat_intolerant.
height_scaredWeaker at high altitude.
animal_friendStronger when surrounded by animals.
bookwormStronger when carrying books in the inventory.
gluttonStronger when carrying food in the inventory.

A random mercenary rolls 0 to 3 quirks at spawn (15% / 40% / 35% / 10% odds), filtered to remove conflicting pairs. A fixed personality can declare any subset (the conflict filter is not applied to fixed personalities — author beware).

Custom skin parts

Mercenaries that don't roll a preset are built up from four texture layers stacked on top of one another:

  • skin — base skin tone (face, hands, neutral body).
  • clothes — outfit, armor visuals, robes, etc.
  • eyes — overlaid eye texture.
  • hair — overlaid hair texture.

Each layer is a skin part loaded from a JSON file. At spawn, Magic Realms picks one part of each category, weighted, filtered by the mercenary's gender and entity class.

File location

data/magic_realms/mercenaries/skin_parts/<your_id>.json

The texture itself goes in assets/magic_realms/textures/... (or wherever you point texture to).

Schema

FieldTypeDefaultNotes
texturestringRequired. ResourceLocation of the texture (e.g. "my_pack:textures/entity/human/skin/dark.png").
categorystringRequired. One of "skin", "clothes", "eyes", "hair".
genderstring"any"One of "any", "male", "female".
entity_classstring"any"One of "any", "common", "mage", "rogue", "warrior". "common" is also a wildcard (eligible for every class) but is conventionally used to mark "neutral" pieces like plain shirts.
weightint (≥ 1)1Weight inside its category pool. Higher = more common.

Example: a female-only mage robe

{
  "texture": "my_pack:textures/entity/human/clothes/violet_robes.png",
  "category": "clothes",
  "gender": "female",
  "entity_class": "mage",
  "weight": 2
}

Example: a generic skin tone usable everywhere

{
  "texture": "my_pack:textures/entity/human/skin/freckled.png",
  "category": "skin",
  "weight": 1
}

(Both gender and entity_class default to "any", so they don't need to be listed.)

When the catalog has no matching parts for a given (category, gender, class) combination, the mercenary spawns with that layer missing — Magic Realms logs a warning and continues. So if you're filtering aggressively, make sure each (category, gender, class) triple still has something eligible (or rely on "any" fallbacks).

Custom skin presets

A skin preset is a single complete texture used as-is, instead of compositing the four-layer skin parts. They're meant for handcrafted / iconic looks where you want every pixel to be exactly right.

When a mercenary spawns, there's a chance (configurable via customTextureChance, default ~15%) that a preset is rolled instead of building from parts. If the preset specifies fixed_personality_id, the linked fixed personality is also stamped on the mercenary, so identity (look + behavior) stays welded together.

File location

data/magic_realms/mercenaries/skin_presets/<your_id>.json

Schema

FieldTypeDefaultNotes
texturestringRequired. ResourceLocation of the full preset texture.
display_namestringabsentOptional. If set, the mercenary is named this.
genderstring"any"One of "any", "male", "female". Used to filter the pool by the mercenary's gender.
weightint (≥ 1)1Weight inside the preset pool.
fixed_personality_idstringabsentOptional. Full ResourceLocation of a fixed personality to lock to this preset (e.g. "my_pack:vex").
added_to_poolbooleantrueOptional. When false, the preset is loaded but excluded from the random roll pool. Useful for future bandit profiles.

If both display_name and the linked fixed personality's override_entity_name are present, the preset's display_name wins. If only the personality has an override name, that override is used as the mercenary's display name.

Example: a generic preset

A finely-detailed female ranger that can roll on any random mercenary:

{
  "texture": "my_pack:textures/entity/human/preset/ranger_alia.png",
  "display_name": "Alia",
  "gender": "female",
  "weight": 3
}

Example: an identity-locked preset

A preset for the named character "Vex" defined earlier — appearing only when this preset rolls, and bringing their full personality with them:

{
  "texture": "my_pack:textures/entity/human/preset/vex.png",
  "gender": "female",
  "weight": 1,
  "fixed_personality_id": "my_pack:vex"
}

Notice we don't need display_name here — the override name comes from the linked fixed personality.

Custom bandit profiles

A bandit profile is a preset stamped onto a hostile mercenary (bandit) at spawn time, customizing its class, level, gear, scale, and so on. Profiles let you build varied bandit encounters — a giant brute leading a raid, a fire-mage miniboss in a tower, a hooded archer ambush — and everything data driven.

Bandit profiles are applied to hostile mercenaries only (HostileRandomHumanEntity), the bandit / evil-mercenary variant. Regular contracted mercenaries are unaffected. Each field of a profile is optional: anything you leave out falls back to the random-roll behavior an unprofiled bandit would have, so a profile only constrains what it explicitly sets.

File location

data/magic_realms/mercenaries/bandit_profiles/<id>.json

The file's path is the profile's stable identifier (e.g. data/magic_realms/mercenaries/bandit_profiles/giant_warrior.json becomes magic_realms:giant_warrior).

Schema

FieldTypeDefaultNotes
weightint1Weighted-random selection weight, used when calling pickRandomFiltered.
entity_class"mage" / "warrior" / "rogue"randomPins the class. Without this, the class is rolled normally.
gender"male" / "female"randomPins the gender.
has_shieldboolrandomIf you pined warrior, this sets if it should have shield.
is_archerboolrandomIf you pined rogue, this sets if it should be an archer or an assassin.
star_levelint 1–3randomStat tier, affects the starting attributes and leveling up stat boosts.
min_level_percentfloat 0–1Fraction of Config.maxLevel (lower bound). F.e. if max level is 100, 0.4 equals to level 40.
max_level_percentfloat 0–1Fraction of Config.maxLevel (upper bound). F.e. if max level is 100, 0.8 equals to level 80.
min_level_absoluteintExact lower-bound level. Takes precedence over min_level_percent.
max_level_absoluteintExact upper-bound level. Takes precedence over max_level_percent.
entity_scalefloat1.0Resizes the bandit, useful for tiny or giant bandits. 1.5 = 50% bigger.
override_namestringReplaces the rolled name (e.g. "Hulking Brute").
skin_presetresource locationId of an entry in your skin_presets/ catalog (the resource location of its JSON file, e.g. "magic_realms:vex" for data/magic_realms/mercenaries/skin_presets/vex.json). The full preset is applied — texture, optional display name, and optional fixed_personality_id binding all carry over. Unknown ids log a warning and fall back to layered random skin.
magic_schoolslist of resource locations[]Mage-only. Explicit list of schools.
magic_schools_tagresource locationMage-only. Pulls schools from a tag (used if magic_schools is empty).
explicit_spellslist of resource locations[]Exact spells the bandit casts. Highest priority.
spells_tagresource locationPull spells from a tag (used if explicit_spells is empty).
spells_tag_pick_countintfull tag sizeWhen spells_tag is set, randomly pick this many spells from the tag instead of taking all.
equipmentobject: slot→item id{}Slot keys: "mainhand", "offhand", "head", "chest", "legs", "feet".
attribute_boostslist[]Flat attribute modifiers applied at the end of init, on top of class and level scaling. See below.
loot_tableresource locationOverrides the bandit's loot table on death (e.g. "magic_realms:entities/chuchu").
is_mini_bossboolfalseMarker flag readable as profile.isMiniBoss() for possible features (boss bar, drops, etc.).
immortalboolfalseSets the immortal flag — bandit will be stunned instead of dying.
fixed_personality_idstringReferences an entry from your fixed_personalities catalog. Replaces the random archetype roll.
in_random_poolbooltrueIf false, the profile can only be invoked by id (commands, structures, code) and never selected by random pickers.

The level rules in priority order: if both min_level_absolute and max_level_absolute are set, those are used directly. Otherwise min_level_percent / max_level_percent are multiplied against Config.maxLevel. If neither is set, the bandit uses the default level-roll behavior.

The spell rules in priority order: explicit_spells first, then spells_tag (with optional spells_tag_pick_count), then fall through to the regular class-driven generator.

Attribute boost format

Each boost uses Mojang's standard AttributeModifier codec. The id must be unique per boost — convention is to namespace it under your pack and the profile id:

{
  "attribute": "minecraft:generic.max_health",
  "id": "magic_realms:bandit/giant_warrior/health",
  "amount": 0.5,
  "operation": "add_multiplied_base"
}

Operations: add_value (flat), add_multiplied_base (% of base), add_multiplied_total (% of post-modifier total). Boosts apply after class/level attribute scaling, so add_multiplied_base of 0.5 on generic.max_health cleanly adds 50% on top of whatever the entity would normally have at its level.

Example: a giant warrior raid leader

A warrior bandit at 50–60% of max level, scaled up 1.5×, with full iron armor, 50% more HP, 50% knockback resistance, +3 attack damage:

{
  "weight": 5,
  "entity_class": "warrior",
  "has_shield": false,
  "min_level_percent": 0.50,
  "max_level_percent": 0.60,
  "entity_scale": 1.5,
  "override_name": "Hulking Brute",
  "equipment": {
    "mainhand": "minecraft:netherite_axe",
    "head":     "minecraft:iron_helmet",
    "chest":    "minecraft:iron_chestplate",
    "legs":     "minecraft:iron_leggings",
    "feet":     "minecraft:iron_boots"
  },
  "attribute_boosts": [
    {
      "attribute": "minecraft:generic.max_health",
      "id": "magic_realms:bandit/giant_warrior/health",
      "amount": 0.5,
      "operation": "add_multiplied_base"
    },
    {
      "attribute": "minecraft:generic.knockback_resistance",
      "id": "magic_realms:bandit/giant_warrior/kb_resist",
      "amount": 0.5,
      "operation": "add_value"
    },
    {
      "attribute": "minecraft:generic.attack_damage",
      "id": "magic_realms:bandit/giant_warrior/damage",
      "amount": 3.0,
      "operation": "add_value"
    }
  ],
  "loot_table": "magic_realms:entities/giant_warrior",
  "is_mini_boss": true
}

Example: a fire-mage miniboss

A mage bandit at 85–100% of max level, three stars, casting a hand-picked fire and lightning kit, in netherite mage armor with a blaze manual spellbook in the offhand, plus double base health:

{
  "weight": 2,
  "entity_class": "mage",
  "min_level_percent": 0.85,
  "max_level_percent": 1.0,
  "star_level": 3,
  "override_name": "Pyromancer Initiate",
  "magic_schools": [
    "irons_spellbooks:fire",
    "irons_spellbooks:lightning"
  ],
  "explicit_spells": [
    "irons_spellbooks:fireball",
    "irons_spellbooks:firebolt",
    "irons_spellbooks:lightning_bolt",
    "irons_spellbooks:teleport",
    "irons_spellbooks:ball_lightning"
  ],
  "equipment": {
    "head": "irons_spellbooks:netherite_mage_helmet",
    "chest": "irons_spellbooks:netherite_mage_chestplate",
    "legs": "irons_spellbooks:netherite_mage_leggings",
    "feet": "irons_spellbooks:netherite_mage_boots",
    "offhand": "irons_spellbooks:blaze_spell_book"
  },
  "attribute_boosts": [
    {
      "attribute": "minecraft:generic.max_health",
      "id": "magic_realms:bandit/mage_miniboss/health",
      "amount": 1.0,
      "operation": "add_multiplied_base"
    }
  ],
  "is_mini_boss": true
}

Spawning bandits with a profile

Command — right now it's only available via commands for testing around:

/bandit summon "magic_realms:giant_warrior"
/bandit summon "magic_realms:mage_miniboss" 100 64 -200
/bandit list

On this page