promotional bannermobile promotional banner

Iron's Spells:Mana Awakened

An add-on for Iron's Spells 'n Spellbooks that, via datapack integration, lets any mob—vanilla or introduced by other mods—cast spells.
幻翼.png

幻翼.png

娜迦.png

娜迦.png

巫妖.png

巫妖.png

雪怪.png

雪怪.png

Description

The mod has been completely restructured in version 2.0:

# SpellMob

**Data-driven spellcasting for any mob — no new content, no client mod, just JSON.**

SpellMob is an addon for *Iron's Spells 'n Spellbooks* (ISS). It adds no blocks, items, or entities: it binds ISS spells to any mob from vanilla or other mods through data packs. Casting goes through ISS's own pipeline with `CastSource.MOB`, so cast times, cast sounds and spell behaviour match ISS itself. Mobs do not spend mana and are not limited by ISS's own cooldowns — cooldowns are part of the data pack.

- Install the mod alone and nothing changes in your world.
- Server-side only: clients can join without the mod. Casting circles are vanilla particles sent by the server.
- Five trigger types, 15 target types, per-individual variants, health phases, shared cooldown groups, and special-mob drops.

## Requirements

| | |
|---|---|
| Minecraft | 1.20.1 |
| Forge | 47.x |
| Iron's Spells 'n Spellbooks | `1.20.1-3.4.0.9` or newer (verified up to `3.16.3`) |

SpellMob itself has no other dependencies. If you run ISS 3.15+, install the extra dependencies ISS asks for (newer Forge, GeckoLib, Curios, `irons_lib`) — those are ISS's requirements, not SpellMob's.

## Installation

**1. The mod.** Drop `spellmob-<version>.jar` into `mods/`.

**2. A data pack (optional).** Put it under the world's `datapacks` folder:

```
saves/<world>/datapacks/my_spells/
├── pack.mcmeta
└── data/<entity namespace>/spell_casters/<entity path>.json
```

The folder path **must mirror the entity id** — the data pack's own name is irrelevant:

| Entity | File |
|---|---|
| `minecraft:zombie` | `data/minecraft/spell_casters/zombie.json` |
| `twilightforest:lich` | `data/twilightforest/spell_casters/lich.json` |
| `minecraft:zombie_villager` | `data/minecraft/spell_casters/zombie_villager.json` |

**3. Reload.** Run `/reload` in game. The log should show:

```
[SpellMob] Loaded N spell caster definition(s)
```

## Quick start

`data/minecraft/spell_casters/zombie.json`:

```json
{
  "goals": [
    {
      "spell": "irons_spellbooks:fireball",
      "level": 2,
      "cooldown": 200,
      "priority": 1,
      "range": 24,
      "castTime": 30,
      "target": "ATTACK_TARGET"
    }
  ]
}
```

Every zombie now casts a level-2 fireball with a 30-tick wind-up, every 200 ticks, at whatever it is attacking.

> Unknown keys are ignored silently, so a typo in a key name will not raise an error. Use `/spellmob validate` and `/spellmob info <mob>` to see what was actually loaded.

## Cast fields

Every cast object — inside `goals`, `onHurt`, `onTarget`, `onDeath`, `onKill`, or a variant — accepts the same fields.

| Field | Type | Default | Notes |
|---|---|---|---|
| `spell` | string | — | **Required.** ISS spell id. |
| `level` | int | `1` | Clamped to the spell's max level. |
| `cooldown` | int (ticks) | the spell's own | 20 ticks = 1 second. After the config multiplier the minimum is 1 tick. |
| `priority` | int 0–9 | `1` | Lower runs first, and also decides who wins against vanilla AI: the cast goal holds MOVE + LOOK, so `1` preempts melee (priority 2). Raise it if you want melee to win. |
| `range` | number | `16` | Blocks, capped by the config's `maxRange` (32 by default). |
| `castTime` | int (ticks) | ISS's value | `0` = instant, `> 0` = wind-up or channel. Overrides ISS's cast-time reduction attribute. |
| `checkInterval` | int (ticks) | `10` | How often the goal re-checks whether it can cast. |
| `chance` | number 0–1 | `1.0` | Rolled right before the cast starts; a failed roll does not consume the cooldown. |
| `cooldownGroup` | string | — | `[a-z0-9_.-]{1,32}`. Spells sharing a group share one cooldown — useful for phase changes. |
| `interruptOnDamage` | bool | `false` | Normal casts only. Channeled spells use the global switch instead. |
| `repeatOnCast` | bool | `true` | Channeled (CONTINUOUS) spells only: re-run `onCast` every 10 ticks, like ISS's own casters. |
| `target` | string or object | `ATTACK_TARGET` | See [Targets](#targets). |
| `conditions` | object | — | `healthBelow`, `healthAbove`, `minTargetDistance`, `maxTargetDistance`. |

### Conditions

Conditions are checked before the cast starts and compare the **caster's** health with the target's distance.

| Key | Default | Meaning |
|---|---|---|
| `healthBelow` | `1.0` | Only cast when the caster's health fraction is below this. |
| `healthAbove` | `0.0` | Only cast when the caster's health fraction is above this. |
| `minTargetDistance` | `0` | Skip the cast if the target is closer than this. |
| `maxTargetDistance` | unlimited | Skip the cast if the target is farther than this. |

Distance conditions are skipped for position casts (they have no entity target).

## Triggers

| Key | Fires when | Notes |
|---|---|---|
| `goals` | periodically | Array; each entry is an independent casting goal. |
| `onHurt` | the mob takes damage | The attacker is used as the preferred target. |
| `onTarget` | the mob acquires a target | The new target is used as the preferred target. |
| `onDeath` | the mob dies | Cast immediately: cooldown and alive checks are skipped. |
| `onKill` | the mob kills something | Goes through normal cooldown and conditions. |

```json
{
  "goals": [ { "spell": "irons_spellbooks:fireball", "target": "ATTACK_TARGET" } ],
  "onHurt":  { "spell": "irons_spellbooks:heal", "cooldown": 400, "target": "SELF" },
  "onDeath": { "spell": "irons_spellbooks:ice_spikes", "level": 1, "range": 8,
               "target": { "type": "POSITION", "positionMode": "RANDOM_IN_RANGE" } },
  "onKill":  { "spell": "irons_spellbooks:heal", "target": "SELF" }
}
```

A mob only gets one event cast at a time: if it is already casting, further triggers are ignored rather than queued.

## Targets

`target` is either a string shorthand (`"ATTACK_TARGET"`) or an object:

```json
{
  "type": "NEAREST_HOSTILE",
  "sort": "FARTHEST",
  "lineOfSight": true,
  "maxHealthPercent": 0.8
}
```

### Target types

| Type | Picks |
|---|---|
| `SELF` | The caster. |
| `ATTACK_TARGET` | The caster's current attack target. |
| `HOSTILE_TARGET` | Alias of `ATTACK_TARGET`, kept for older packs. |
| `LAST_DAMAGE_SOURCE` | The last entity that hurt the caster. |
| `THREATENING_ENTITY` | An entity that attacked the caster or is targeting it. |
| `NEAREST_HOSTILE` | Nearest player or monster that is neither an ally nor the caster's own kind. |
| `NEAREST_UNDEAD` | Nearest undead mob. |
| `NEAREST_ARTHROPOD` | Nearest arthropod. |
| `NEAREST_ANIMAL` | Nearest animal. |
| `NEAREST_MONSTER` | Nearest monster (anything implementing `Enemy`). |
| `NEAREST_PLAYER` | Nearest survival / adventure player. |
| `OWNER` | The owner of a tamed mob. |
| `NEAREST_ALLY` | Nearest mob of the same type, or on the same team. |
| `RANDOM_HOSTILE` | A random hostile in range. |
| `POSITION` | A point in the world — see position modes. |

### Target object fields

| Key | Default | Notes |
|---|---|---|
| `type` | `ATTACK_TARGET` | One of the types above. |
| `sort` | `NEAREST` | `NEAREST`, `FARTHEST`, `LOWEST_HEALTH`, `HIGHEST_HEALTH`, `RANDOM`. |
| `lineOfSight` | `true` | Entity targets must be visible (ignored for `POSITION`). |
| `maxHealthPercent` | `1.0` | Only accept targets at or below this health fraction. |
| `positionMode` | `RELATIVE` | `POSITION` only — see below. |
| `relativeOffset` | `[0,0,0]` | `POSITION` + `RELATIVE` only. |

### Position modes (`POSITION` only)

| Mode | Where it lands |
|---|---|
| `RELATIVE` | Caster's position + `relativeOffset`. |
| `EYES_LOOK` | Eye position + look direction × `range`. |
| `FEET_LOOK` | Feet position + look direction × `range`. |
| `TARGET_ENTITY` | The target's position; if there is no target the cast is skipped. |
| `RANDOM_IN_RANGE` | A random point within `range` blocks. |

## Variants

`variants` lets one entity file describe different rules for different individuals, and swap rules at a health threshold. Variants are only available in data packs — the config's `[species] extraRules` does not support them.

```json
{
  "goals": [
    { "spell": "irons_spellbooks:magic_missile", "cooldown": 120, "target": "ATTACK_TARGET" }
  ],
  "variants": [
    { "select": { "name": "A", "tags": ["boss_a"] },
      "goals": [ { "spell": "irons_spellbooks:fireball", "cooldown": 100, "range": 24 } ] },

    { "select": { "nameRegex": "^B-[0-9]+$" },
      "goals": [ { "spell": "irons_spellbooks:lightning_lance", "cooldown": 140 } ] },

    { "select": { "name": "C" }, "override": false,
      "goals": [ { "spell": "irons_spellbooks:haste", "target": "SELF" } ] },

    { "select": { "name": "D" }, "override": true },

    { "select": { "healthBelow": 0.4 },
      "goals": [ { "spell": "irons_spellbooks:ice_spikes", "cooldown": 90, "range": 20 } ] }
  ]
}
```

`select` conditions (all of the given ones must match):

| Key | Matches |
|---|---|
| `name` | Exact custom name. |
| `nameRegex` | Full match against the custom name. |
| `tags` | Contains all listed scoreboard tags. |
| `healthBelow` | Health fraction strictly below this. |
| `healthAbove` | Health fraction strictly above this. |

Rules:

- Variants are checked **top to bottom; the first match wins.** Put specific conditions first and broad health bands last.
- `override` defaults to `true`: the variant replaces the top-level defaults entirely. With `false` the variant's spells are **added** to the defaults (variant goals first, then default goals).
- A variant with `override: true` and no spells means "this individual casts nothing".
- `name` and `nameRegex` require the mob to have a custom name.

**Renaming** a mob re-syncs its goals automatically within a tick. **Changing tags does not** — run `/spellmob resync` afterwards.

## Drops

`dropRules` gives loot to the mobs that actually cast. Rules are only evaluated for a mob whose casting config resolves to something non-empty; ordinary mobs are untouched.

```json
"dropRules": [
  {
    "select": { "tags": ["spellmob_boss"] },
    "chance": 1.0,
    "drops": [
      { "item": "minecraft:emerald", "minCount": 2, "maxCount": 4, "looting": true },
      { "lootTable": "minecraft:chests/desert_pyramid", "chance": 0.2 }
    ]
  }
]
```

- Only the **first matching rule** is used.
- Rule-level `chance` rolls once; entry-level `chance` rolls per entry.
- Each entry is either an `item` or a `lootTable`, never both.
- `count` for a fixed amount, or `minCount` / `maxCount` for a range.
- `requirePlayerKill` defaults to `true`, so mob farms and entity cramming do not drop loot.

## Configuration

The config lives at `config/spellmob-common.toml` (COMMON type — one file for the whole installation, not per world).

| Section | Key | Default | Meaning |
|---|---|---|---|
| `general` | `enabled` | `true` | Master switch. |
| | `debugLogging` | `false` | Verbose `[SpellMob]` logging. |
| | `castSounds` | `true` | Play ISS cast start/finish sounds. |
| `balance` | `cooldownMultiplier` | `1.0` | Scales every data pack cooldown; `0` compresses it to the 1-tick minimum. |
| | `maxRange` | `32` | Hard cap on `range` from data packs (up to 128). |
| | `interruptChannelsOnDamage` | `true` | Damage interrupts channeled spells. |
| `filters` | `entityBlacklist` | empty | Entity ids that never cast. |
| | `dimensionBlacklist` | empty | Dimensions where casting is disabled. |
| `protection` | `protectedTags` | empty | Mobs with these tags cannot be renamed with a name tag. |
| | `allowOpsRename` | `true` | Ops (permission 2) bypass the name lock. |
| | `channelImmuneTags` | `["spellmob_boss"]` | Mobs with these tags never lose a channel to damage. |
| `presentation` | `enabled` | `true` | Draw casting circles at all. |
| | `density` | `1` | `0` = no circle, `1/2/3` = 8/12/16 dots. |
| | `distance` | `24` | Particle view distance (4–64). |
| | `interruptFeedback` | `true` | Smoke + fizzle sound when a cast is interrupted. |
| `species` | `extraRules` | empty | Whole-species rules, one JSON object per line. Same schema as a data pack file, minus `variants`. |

When both a data pack and `[species] extraRules` define the same entity, **the data pack wins** and the config entry is ignored (a log line records it).

## Commands

Permission level 2 required.

| Command | Does |
|---|---|
| `/spellmob list` | Lists every loaded entity type with its source (`data pack` / `config`). |
| `/spellmob info <mob>` | Shows the resolved configuration for that mob, including which variant matched and remaining cooldowns. |
| `/spellmob resync [targets]` | Rebuilds casting goals for the given mobs (or yourself). Run after changing tags. |
| `/spellmob validate` | Checks every loaded spell id and lists config entries shadowed by data packs. |

## Compatibility notes

- **Server-side only.** Clients do not need the mod; the circles are ordinary particles the server sends.
- **Data pack paths mirror entity ids.** A file under `data/mypack/` can never affect `minecraft:zombie`.
- **Unknown JSON keys are ignored.** Typos in field names fail silently — `validate` and `info` are the way to catch them.
- **ISS versions.** Built against the 3.4.0.9 API and verified against 3.16.3; the jar declares `[1.20.1-3.4.0.9,)`.

## Examples

The repository ships ready-to-use packs under `examples/`:

| Folder | Contents |
|---|---|
| `examples/classic/` | The original five examples: zombies A/B, skeleton, wolf, villager, husk. |
| `examples/bosses/` | Six name + tag gated bosses (void eye, dune priest, …). |
| `examples/channel_test/` | Pillager and vindicator that channel every CONTINUOUS spell. |
| `examples/full-reference.json` | Field reference — every key in one file. |

 

Iron's Spells:Mana Awakened Team

profile avatar
  • 6
    Projects
  • 3.9K
    Downloads

More from Gai_fan_404View all