Pixel Dream StudiosWiki

Personalities

Custom archetypes, named characters, hobbies, how archetypes get along, and every quirk.

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
idstring-Required. Short id used by every other file referring to this archetype (e.g. "stoic").
display_keystring-Required. 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
archetypestring-Required. 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
idstring-Required. Short id used by fixed_personalities JSONs (e.g. "bookworm").
display_keystring-Required. Translation key for the hobby's human-readable name.
responsesobject: string→string array-Required. 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_astring-Required. Short id of the first archetype.
archetype_bstring-Required. 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).

On this page