Give arcane essence per-slot mana and make one cinder gem enough

Arcane essence granted max mana through a single modifier with slot `armor`.
On a weapon that reads as "+200 Max Mana when worn", which is nonsense - you
do not wear a greatsword - and it gave every armour piece the same amount.

Each slot now carries its own modifier: 1300 on a helmet, 900 chest, 800 legs,
700 boots, and 900 in the main hand / 400 offhand so a weapon grants it while
held. They stack per module, so a piece built out of arcane essence that also
carries an arcane gem counts twice.

Cinder essence moves to slot `any`, so a single gem grants fire immunity
wherever it sits rather than only from an armour piece. The attribute is capped
at 1 and the handler treats anything at or above 1 as immune, so extra pieces
neither stack nor dilute it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
modules-and-missing-materials
Amir Alexander Abdelbaki 2026-08-12 20:05:14 +02:00
parent 5828bbfb01
commit b7348a69a1
4 changed files with 67 additions and 15 deletions

View File

@ -144,6 +144,14 @@ Requires `pillow` and `numpy`.
and lore rather than by kind, so those are generated from a table with shared
stat bands per tier. What actually tells them apart in game is the palette,
and that still comes from each gem's own texture.
- Arcane essence gives max mana per slot: 1300 on a helmet, 900 chest, 800
legs, 700 boots, 900 held in the main hand, 400 offhand. Separate per-slot
modifiers rather than one `armor`-wide one, so a weapon reads as a held bonus
instead of claiming something "when worn". They stack per module - a piece
built out of arcane essence that also carries an arcane gem counts twice.
- Cinder essence uses slot `any`, so one gem grants fire immunity wherever it
sits, worn or held. The attribute caps at 1 and the handler treats anything at
or above 1 as immune, so extra pieces neither add nor dilute.
- Material properties belong under the `default` key, not `armor` or `handheld`.
A gem socketed into armour is not tagged `armor`: gem modules declare which
material properties they accept and list only `default` plus their own gem

View File

@ -48,15 +48,45 @@
"attributes": [
{
"attribute": "irons_spellbooks:max_mana",
"value": "100",
"value": "1300",
"operation": "+",
"slot": "armor"
"slot": "head"
},
{
"attribute": "irons_spellbooks:max_mana",
"value": "900",
"operation": "+",
"slot": "chest"
},
{
"attribute": "irons_spellbooks:max_mana",
"value": "800",
"operation": "+",
"slot": "legs"
},
{
"attribute": "irons_spellbooks:max_mana",
"value": "700",
"operation": "+",
"slot": "feet"
},
{
"attribute": "irons_spellbooks:max_mana",
"value": "900",
"operation": "+",
"slot": "mainhand"
},
{
"attribute": "irons_spellbooks:max_mana",
"value": "400",
"operation": "+",
"slot": "offhand"
},
{
"attribute": "irons_spellbooks:mana_regen",
"value": "0.15",
"operation": "*",
"slot": "armor"
"slot": "any"
},
{
"attribute": "irons_spellbooks:spell_power",

View File

@ -52,13 +52,13 @@
"attribute": "cmmodular:fire_immunity",
"value": "1",
"operation": "+",
"slot": "armor"
"slot": "any"
},
{
"attribute": "irons_spellbooks:fire_magic_resist",
"value": "0.2",
"operation": "*",
"slot": "armor"
"slot": "any"
},
{
"attribute": "irons_spellbooks:fire_spell_power",

View File

@ -511,23 +511,33 @@ MATERIALS = [
enchantability=32, mining_speed=11, toughness=3, armor_durability=38,
armor_toughness=2.5, groups=("crystal", "gem"), textures=("crystal", "bright"),
# Everything hangs off `default`. A gem socketed into armour is not
# tagged `armor` - the gem modules declare which material properties they
# accept and both list only `default` plus their own gem tags - so
# anything filed under `armor` or `handheld` silently never applied. The
# attribute's own slot decides where it counts instead.
# tagged `armor` or `handheld` - the gem modules declare which material
# properties they accept and both list only `default` plus their own gem
# tags - so anything filed elsewhere silently never applied.
#
# Each slot gets its own modifier rather than one `armor`-wide one. That
# is what lets a helmet be worth more than boots, and it stops a sword
# from advertising a bonus "when worn", which is what a slot of `armor`
# on a weapon reads as.
properties={
"default": {
"emissive": {"sky": 6, "block": 6},
"attributes": [
# Per armour piece, so a full set is roughly +400 on top of
# the 100 base pool Iron's Spells gives a player.
attribute("irons_spellbooks:max_mana", 100, "armor"),
attribute("irons_spellbooks:mana_regen", 0.15, "armor", "*"),
attribute("irons_spellbooks:max_mana", 1300, "head"),
attribute("irons_spellbooks:max_mana", 900, "chest"),
attribute("irons_spellbooks:max_mana", 800, "legs"),
attribute("irons_spellbooks:max_mana", 700, "feet"),
# Held, not worn.
attribute("irons_spellbooks:max_mana", 900, "mainhand"),
attribute("irons_spellbooks:max_mana", 400, "offhand"),
attribute("irons_spellbooks:mana_regen", 0.15, "any", "*"),
attribute("irons_spellbooks:spell_power", 0.10, "mainhand", "*"),
attribute("irons_spellbooks:cooldown_reduction", 0.05, "mainhand", "*"),
],
},
}),
# These stack per module: a piece built out of arcane essence that also
# carries an arcane gem counts twice.
M("cinder_essence", "irons_spellbooks", "crystal", "Cinder",
"irons_spellbooks:cinder_essence",
@ -546,8 +556,12 @@ MATERIALS = [
# above 1 as immune, so this is genuine immunity rather than a
# resistance that stacks up to it.
"attributes": [
attribute(FIRE_IMMUNITY, 1, "armor"),
attribute("irons_spellbooks:fire_magic_resist", 0.20, "armor", "*"),
# Slot `any`, so a single gem grants immunity wherever it
# sits - worn or held. The handler treats anything at or
# above 1 as immune, and the attribute is capped at 1, so
# extra pieces add nothing and nothing can dilute it.
attribute(FIRE_IMMUNITY, 1, "any"),
attribute("irons_spellbooks:fire_magic_resist", 0.20, "any", "*"),
attribute("irons_spellbooks:fire_spell_power", 0.20, "mainhand", "*"),
],
},