diff --git a/README.md b/README.md
index d807ac0..b7232db 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# Create/Mekanism Modular
A [Truly Modular](https://modrinth.com/mod/modular-item-api) addon for Minecraft
-1.21.1 / NeoForge. It adds 126 materials drawn from 22 mods - Create, Mekanism, Ice
+1.21.1 / NeoForge. It adds 127 materials drawn from 22 mods - Create, Mekanism, Ice
and Fire, Immersive Engineering, Ender IO, Applied Energistics, Occultism,
Ars Nouveau, Iron's Spells, Pastel, Crystal Chronicles, NauTec, Superb Warfare,
Industrial Foregoing, RFTools, Create Deco, Steampunk Dimension and the Create
@@ -58,6 +58,10 @@ watches for it. Neither side knows about the other.
**Breathing in a vacuum.** The same trick, for the space set - see below.
+**Breathing underwater.** And again, for sea serpent fang: `WaterBreathing.java`
+answers the same `LivingBreatheEvent`, but only when the bearer's eyes are in
+water, so a fang is a fang rather than half a spacesuit.
+
## Modules
Three of the packs hold modules rather than materials. They are hand-written
@@ -213,6 +217,23 @@ folders, so the hand-written packs survive it.
emissive, so it still reads as fire in game.
- Dragon scales are one material per colour (12 dragon, 7 sea serpent, 3 death
worm chitin). Colours within an element share stats and differ only in palette.
+- Bones are the other half of that. Dragon bone already built grips, handles
+ and hafts - `bone` is on every tool and bow whitelist - and now carries
+ `gem_armor` as a hidden group as well, so a piece can be set into an armour
+ socket instead of only shaped into the armour. Sea serpent fang is new and
+ does both: Ice and Fire has no sea serpent bone, and the fang is what a
+ serpent leaves behind besides its scales. It grants water breathing, which is
+ what Ice and Fire's own Tide Guardian armour does, from slot `any` - so one
+ fang socketed, worn or held is enough, and a second neither adds nor dilutes.
+- Scales are in the `scute` group, and no module in Truly Modular accepts that
+ group - not Armory's armour, not Arsenal's or Archery's parts, and MIAPI's own
+ turtle and armadillo scutes are stuck the same way. So each scale material
+ carries `bone` as a hidden group: matched when a module decides what it will
+ accept, ignored when the workbench decides what heading to file the material
+ under, which is how Armory hands its own gem slots vanilla materials. Bone is
+ on every armour whitelist except the scuba set - that one takes
+ fabric/metal/glass, being a sealed suit rather than a plated one - so a scale
+ builds every other piece of armour, and tool and bow parts besides.
- Interstellar Expansion is mostly machinery. Only three of its items are a
material rather than a component; solid E-710 is left out because it is rocket
fuel.
diff --git a/gradle.properties b/gradle.properties
index 12c446b..e8081b0 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -7,7 +7,7 @@ neo_version=21.1.248
mod_id=cmmodular
mod_name=Create/Mekanism Modular
-mod_version=1.2.0
+mod_version=1.3.0
mod_group_id=eu.abdelbaki.cmmodular
mod_authors=themiro
mod_description=Materials from Create, Mekanism, Ice and Fire, Iron's Spells and the Create aerospace addons, for Truly Modular - plus a khopesh blade and a sealed space suit.
diff --git a/src/main/java/eu/abdelbaki/cmmodular/CMModular.java b/src/main/java/eu/abdelbaki/cmmodular/CMModular.java
index 4691cbe..ea29e0d 100644
--- a/src/main/java/eu/abdelbaki/cmmodular/CMModular.java
+++ b/src/main/java/eu/abdelbaki/cmmodular/CMModular.java
@@ -73,6 +73,7 @@ public class CMModular {
public CMModular(IEventBus modBus) {
FireImmunity.register(modBus);
VacuumSeal.register(modBus);
+ WaterBreathing.register(modBus);
modBus.addListener(this::addMaterialPacks);
}
diff --git a/src/main/java/eu/abdelbaki/cmmodular/WaterBreathing.java b/src/main/java/eu/abdelbaki/cmmodular/WaterBreathing.java
new file mode 100644
index 0000000..c1b59ae
--- /dev/null
+++ b/src/main/java/eu/abdelbaki/cmmodular/WaterBreathing.java
@@ -0,0 +1,62 @@
+package eu.abdelbaki.cmmodular;
+
+import net.minecraft.core.registries.Registries;
+import net.minecraft.tags.FluidTags;
+import net.minecraft.world.entity.ai.attributes.Attribute;
+import net.minecraft.world.entity.ai.attributes.AttributeInstance;
+import net.minecraft.world.entity.ai.attributes.RangedAttribute;
+import net.neoforged.bus.api.EventPriority;
+import net.neoforged.bus.api.IEventBus;
+import net.neoforged.neoforge.common.NeoForge;
+import net.neoforged.neoforge.event.entity.EntityAttributeModificationEvent;
+import net.neoforged.neoforge.event.entity.living.LivingBreatheEvent;
+import net.neoforged.neoforge.registries.DeferredHolder;
+import net.neoforged.neoforge.registries.DeferredRegister;
+
+/**
+ * Sea serpent fang lets its bearer breathe underwater, which is what Ice and
+ * Fire's own Tide Guardian armour does and the only reason to hunt the thing.
+ *
+ *
There is no attribute for it and MIAPI has no property for it either - the
+ * closest data can get is a fake Respiration enchantment, which only postpones
+ * drowning. So this follows the pattern {@link FireImmunity} and
+ * {@link VacuumSeal} already set: an attribute of this mod's own that the
+ * material grants like any other, and a listener here that watches for it.
+ *
+ *
It answers the same event {@link VacuumSeal} does but only underwater, so
+ * a fang is a fang and not half a spacesuit.
+ */
+public final class WaterBreathing {
+ private static final DeferredRegister ATTRIBUTES =
+ DeferredRegister.create(Registries.ATTRIBUTE, CMModular.MOD_ID);
+
+ /** At or above 1 the bearer never drowns; the fang grants a whole one. */
+ public static final DeferredHolder WATER_BREATHING =
+ ATTRIBUTES.register("water_breathing", id -> new RangedAttribute(
+ "attribute.cmmodular.water_breathing", 0.0D, 0.0D, 1.0D).setSyncable(true));
+
+ private WaterBreathing() {
+ }
+
+ static void register(IEventBus modBus) {
+ ATTRIBUTES.register(modBus);
+ modBus.addListener(WaterBreathing::attachToEntities);
+ // Last, so it answers after whatever said there was no air.
+ NeoForge.EVENT_BUS.addListener(EventPriority.LOWEST, WaterBreathing::onBreathe);
+ }
+
+ /** Attributes only exist on an entity if they were added to its type. */
+ private static void attachToEntities(EntityAttributeModificationEvent event) {
+ event.getTypes().forEach(type -> event.add(type, WATER_BREATHING));
+ }
+
+ private static void onBreathe(LivingBreatheEvent event) {
+ if (event.canBreathe() || !event.getEntity().isEyeInFluid(FluidTags.WATER)) {
+ return;
+ }
+ AttributeInstance instance = event.getEntity().getAttribute(WATER_BREATHING);
+ if (instance != null && instance.getValue() >= 1.0D) {
+ event.setCanBreathe(true);
+ }
+ }
+}
diff --git a/src/main/resources/assets/cmmodular/lang/en_us.json b/src/main/resources/assets/cmmodular/lang/en_us.json
index 6f136e7..3e1a17d 100644
--- a/src/main/resources/assets/cmmodular/lang/en_us.json
+++ b/src/main/resources/assets/cmmodular/lang/en_us.json
@@ -1,6 +1,7 @@
{
"attribute.cmmodular.fire_immunity": "Fire Immunity",
"attribute.cmmodular.vacuum_seal": "Vacuum Seal",
+ "attribute.cmmodular.water_breathing": "Water Breathing",
"miapi.module.cmmodular.blade.khopesh.name": "Khopesh Blade",
"miapi.module.cmmodular.pommel.gem_socket.name": "Socketed Pommel",
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/bone/dragonbone.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/bone/dragonbone.json
index a2aeae3..042da0f 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/bone/dragonbone.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/bone/dragonbone.json
@@ -3,6 +3,9 @@
"groups": [
"bone"
],
+ "hidden_groups": [
+ "gem_armor"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:dragonbone"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/bone/sea_serpent_fang.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/bone/sea_serpent_fang.json
new file mode 100644
index 0000000..0359563
--- /dev/null
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/bone/sea_serpent_fang.json
@@ -0,0 +1,64 @@
+{
+ "translation": "Sea Serpent Fang ",
+ "groups": [
+ "bone"
+ ],
+ "hidden_groups": [
+ "gem_armor"
+ ],
+ "icon": {
+ "type": "item",
+ "item": "iceandfire:sea_serpent_fang"
+ },
+ "hardness": 6.0,
+ "density": 3.0,
+ "flexibility": 4,
+ "durability": 760,
+ "enchantability": 16,
+ "toughness": 2,
+ "tier": 4,
+ "mining_speed": 7,
+ "mining_level": "minecraft:incorrect_for_diamond_tool",
+ "armor_durability": 26,
+ "color": "C8C8C9",
+ "color_palette": {
+ "type": "grayscale_map",
+ "colors": {
+ "24": "12131d",
+ "68": "222538",
+ "107": "525f68",
+ "150": "525f68",
+ "190": "8c8c8c",
+ "216": "c8c8c9",
+ "255": "e2fffa"
+ },
+ "filler": "interpolate"
+ },
+ "textures": [
+ "rough",
+ "shiny"
+ ],
+ "properties": {
+ "default": {
+ "attributes": [
+ {
+ "attribute": "cmmodular:water_breathing",
+ "value": "1",
+ "operation": "+",
+ "slot": "any"
+ }
+ ]
+ },
+ "boot": {
+ "fake_enchants": {
+ "minecraft:depth_strider": 1
+ }
+ }
+ },
+ "items": [
+ {
+ "item": "iceandfire:sea_serpent_fang",
+ "value": 1.0
+ }
+ ]
+}
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/deathworm_chitin_red.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/deathworm_chitin_red.json
index 7c32a8a..13226d9 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/deathworm_chitin_red.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/deathworm_chitin_red.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:deathworm_chitin_red"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/deathworm_chitin_white.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/deathworm_chitin_white.json
index c0e8ab1..4f894b6 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/deathworm_chitin_white.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/deathworm_chitin_white.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:deathworm_chitin_white"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/deathworm_chitin_yellow.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/deathworm_chitin_yellow.json
index 377ca09..0221325 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/deathworm_chitin_yellow.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/deathworm_chitin_yellow.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:deathworm_chitin_yellow"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_amethyst.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_amethyst.json
index a833291..6b3da22 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_amethyst.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_amethyst.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:dragonscales_amethyst"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_black.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_black.json
index c845e0a..7552590 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_black.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_black.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:dragonscales_black"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_blue.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_blue.json
index 5aed92d..cf00d4f 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_blue.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_blue.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:dragonscales_blue"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_bronze.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_bronze.json
index c853bea..86946b9 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_bronze.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_bronze.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:dragonscales_bronze"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_copper.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_copper.json
index 1217a89..2b6feb0 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_copper.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_copper.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:dragonscales_copper"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_electric.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_electric.json
index 1573902..931d4d4 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_electric.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_electric.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:dragonscales_electric"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_gray.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_gray.json
index e9e970e..524792c 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_gray.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_gray.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:dragonscales_gray"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_green.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_green.json
index bd88933..9ae7fc5 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_green.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_green.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:dragonscales_green"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_red.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_red.json
index b2d1f3a..d31315a 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_red.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_red.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:dragonscales_red"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_sapphire.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_sapphire.json
index ac64583..c8d8069 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_sapphire.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_sapphire.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:dragonscales_sapphire"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_silver.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_silver.json
index 67e9305..a6929a4 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_silver.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_silver.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:dragonscales_silver"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_white.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_white.json
index 4259544..7a6b25a 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_white.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/dragonscales_white.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:dragonscales_white"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_blue.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_blue.json
index 504476b..e42b91d 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_blue.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_blue.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:sea_serpent_scales_blue"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_bronze.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_bronze.json
index 2d8a3c6..bdba393 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_bronze.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_bronze.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:sea_serpent_scales_bronze"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_deepblue.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_deepblue.json
index 0540c00..25f81c1 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_deepblue.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_deepblue.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:sea_serpent_scales_deepblue"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_green.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_green.json
index 46d2a5c..c7b02ca 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_green.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_green.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:sea_serpent_scales_green"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_purple.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_purple.json
index 6a7e5c0..c219c4b 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_purple.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_purple.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:sea_serpent_scales_purple"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_red.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_red.json
index 3284898..423f998 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_red.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_red.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:sea_serpent_scales_red"
diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_teal.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_teal.json
index 47f250c..124927b 100644
--- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_teal.json
+++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/scute/sea_serpent_scales_teal.json
@@ -3,6 +3,9 @@
"groups": [
"scute"
],
+ "hidden_groups": [
+ "bone"
+ ],
"icon": {
"type": "item",
"item": "iceandfire:sea_serpent_scales_teal"
diff --git a/tools/generate_materials.py b/tools/generate_materials.py
index 211badc..390b39c 100644
--- a/tools/generate_materials.py
+++ b/tools/generate_materials.py
@@ -183,6 +183,10 @@ def build_material(spec, jars: Jars):
out = {
"translation": spec["translation"] + " ", # trailing space: "Steel Sword"
"groups": spec["groups"],
+ # Counts for what a module will accept, but is not a heading the
+ # workbench files the material under. See SCALE_CRAFTING_GROUP.
+ **({"hidden_groups": spec["hidden_groups"]}
+ if spec.get("hidden_groups") else {}),
"icon": {"type": "item", "item": spec["icon"]},
}
out.update(spec["stats"])
diff --git a/tools/materials.py b/tools/materials.py
index 5c40a64..dd0a414 100644
--- a/tools/materials.py
+++ b/tools/materials.py
@@ -80,9 +80,10 @@ PACKS = {
"armory": {"mod": "tm_armory", "name": "Armory Modules"},
}
-# Attribute this mod registers itself, so a material can grant something the
-# game has no attribute for. See FireImmunity.java.
+# Attributes this mod registers itself, so a material can grant something the
+# game has no attribute for. See FireImmunity.java and WaterBreathing.java.
FIRE_IMMUNITY = "cmmodular:fire_immunity"
+WATER_BREATHING = "cmmodular:water_breathing"
def attribute(attr, value, slot, operation="+"):
@@ -91,7 +92,7 @@ def attribute(attr, value, slot, operation="+"):
def M(name, pack, group, translation, palette_from, items, tier, hardness, density,
flexibility, durability, enchantability, mining_speed, *, groups=None,
- toughness=0, armor_durability=None, armor_toughness=None,
+ hidden_groups=None, toughness=0, armor_durability=None, armor_toughness=None,
knockback_resistance=None, textures=("metallic",), properties=None,
icon=None, mining_level=None):
"""One material. `palette_from` is the item whose texture seeds the palette."""
@@ -104,6 +105,7 @@ def M(name, pack, group, translation, palette_from, items, tier, hardness, densi
"icon": icon or palette_from,
"items": items,
"groups": list(groups) if groups else [group],
+ "hidden_groups": list(hidden_groups) if hidden_groups else [],
"textures": list(textures),
"properties": properties or {},
"stats": {
@@ -418,10 +420,36 @@ MATERIALS = [
{"item": "iceandfire:dragon_bone_block", "value": 4.0}],
tier=4, hardness=6.2, density=4.4, flexibility=3, durability=700,
enchantability=12, mining_speed=7, toughness=2, armor_durability=24,
- groups=("bone",), textures=("rough",),
+ groups=("bone",), hidden_groups=("gem_armor",), textures=("rough",),
properties={"head": {"fracturing": "10"}}),
# Vanilla bone with the numbers pushed to diamond tier; keeps the
- # fracturing quirk MIAPI gives bone.
+ # fracturing quirk MIAPI gives bone. The `bone` group already builds
+ # grips, handles and hafts wherever Arsenal and Archery take bone;
+ # `gem_armor` on top of it lets a piece sit in an armour socket too, so a
+ # dragon's bones can be set into a suit rather than only shaped into one.
+
+ M("sea_serpent_fang", "iceandfire", "bone", "Sea Serpent Fang",
+ "iceandfire:sea_serpent_fang",
+ [{"item": "iceandfire:sea_serpent_fang", "value": 1.0}],
+ tier=4, hardness=6.0, density=3.0, flexibility=4, durability=760,
+ enchantability=16, mining_speed=7, toughness=2, armor_durability=26,
+ groups=("bone",), hidden_groups=("gem_armor",), textures=("rough", "shiny"),
+ properties={
+ "default": {
+ "attributes": [
+ # Ice and Fire's own sea serpent armour grants water
+ # breathing, and that is the whole reason to hunt one. Slot
+ # `any`, capped at 1 and read as "at or above 1" by the
+ # handler, so one fang anywhere - socketed, worn or held - is
+ # enough and a second neither adds nor dilutes, exactly as
+ # cinder essence does for fire.
+ attribute(WATER_BREATHING, 1, "any"),
+ ],
+ },
+ "boot": {"fake_enchants": {"minecraft:depth_strider": 1}},
+ }),
+ # Lighter and springier than dragon bone and quicker to enchant, but
+ # softer: a serpent's tooth, not a wyrm's femur.
M("witherbone", "iceandfire", "bone", "Witherbone", "iceandfire:witherbone",
[{"item": "iceandfire:witherbone", "value": 1.0},
@@ -1042,6 +1070,25 @@ DRAGON_SCALE_PROPERTIES = {
SEA_SERPENT_COLORS = ["blue", "bronze", "deepblue", "green", "purple", "red", "teal"]
DEATHWORM_COLORS = {"red": "Red", "white": "White", "yellow": "Tan"}
+# No module anywhere accepts the "scute" group. Armory's armour whitelists
+# wood/fabric/metal/flint/bone/stone/crystal/glass, Arsenal's and Archery's
+# parts much the same, and none of the four lists "scute" - so a scale material
+# was a material you could look at and never build with, the same trap the
+# gem groups below were in. MIAPI's own turtle and armadillo scutes are stuck
+# there too, so this is not something the scales were doing wrong.
+#
+# Bone is the group they join: it is on every armour whitelist except the scuba
+# set (fabric/metal/glass - a sealed suit, not a plated one), it is what a hard
+# organic plate is nearest to, and it carries them into tool and bow parts as
+# well, which suits stats that were always meant to be usable and unremarkable
+# in hand rather than unusable.
+#
+# It goes in `hidden_groups` rather than `groups`: MIAPI matches a module's
+# whitelist against both, but only `groups` decides where the material is filed
+# in the workbench, so a dragonscale still lists as a scale rather than as a
+# bone. Armory itself does this to hand its gem slots vanilla materials.
+SCALE_CRAFTING_GROUP = ("bone",)
+
def _scales():
out = []
@@ -1057,7 +1104,8 @@ def _scales():
enchantability=15, mining_speed=7, toughness=4,
armor_durability=44, armor_toughness=3.5,
mining_level=MINING_LEVEL[4],
- groups=("scute",), textures=("rough", "shiny"),
+ groups=("scute",), hidden_groups=SCALE_CRAFTING_GROUP,
+ textures=("rough", "shiny"),
properties=DRAGON_SCALE_PROPERTIES[element]))
# Armour-first, like Tinkers' ancient hide: high toughness and
# armour durability, unremarkable as a cutting edge.
@@ -1071,7 +1119,8 @@ def _scales():
tier=4, hardness=5.4, density=2.4, flexibility=5, durability=950,
enchantability=16, mining_speed=6, toughness=3,
armor_durability=32, armor_toughness=2.5,
- groups=("scute",), textures=("rough", "shiny"),
+ groups=("scute",), hidden_groups=SCALE_CRAFTING_GROUP,
+ textures=("rough", "shiny"),
properties={"armor": {"fake_enchants": {"minecraft:respiration": 1}},
"boot": {"fake_enchants": {"minecraft:depth_strider": 1}}}))
for color, label in DEATHWORM_COLORS.items():
@@ -1082,7 +1131,8 @@ def _scales():
tier=4, hardness=5.6, density=2.2, flexibility=4, durability=880,
enchantability=13, mining_speed=6, toughness=3,
armor_durability=30, armor_toughness=2.0,
- groups=("scute",), textures=("rough",),
+ groups=("scute",), hidden_groups=SCALE_CRAFTING_GROUP,
+ textures=("rough",),
properties={"default": {"fire_proof": True}}))
# Desert worms, so heat immunity comes with the shell.
return out