Gear

Register custom weapons, armor sets, hybrid subclasses, trim patterns, trim materials, enchantments, and equipment scanners.

Weapons

Any Item can be registered as a Craftics weapon. The registration gives it a damage type, base stats, and an optional on-hit ability. Call CrafticsAPI.registerWeapon(item, entry) during onCrafticsInit().

API Method

CrafticsAPI.registerWeapon(Item item, WeaponEntry entry);

WeaponEntry Builder

WeaponEntry entry = WeaponEntry.builder(myItem)
    .damageType(DamageType.SLASHING)   // damage category
    .attackPower(8)                    // flat attack value
    .apCost(1)                         // action points per attack
    .range(1)                          // attack range in tiles
    .ranged(false)                     // true for projectile weapons
    .breakChance(0.0)                  // probability of breaking on use (0.0 to 1.0)
    .ability(myAbilityHandler)         // optional on-hit ability
    .build();
Builder Method Type Default Description
damageType(DamageType)enumPHYSICALWeapon's damage category
attackPower(int)int1Base attack power
attackPower(IntSupplier)supplierDynamic attack power computed each time the weapon attacks
apCost(int)int1Action point cost per attack
range(int)int1Attack range in tiles
ranged(boolean)boolfalseWhether this is a projectile weapon
breakChance(double)double0.0Chance to break on use (0.0 to 1.0)
ability(WeaponAbilityHandler)handlernullOn-hit ability (see below)

DamageType Values

Every weapon belongs to one of eight damage types. Armor sets, trims, and player affinity points grant bonuses to specific types.

ValueDisplay NameTypical Weapons
SLASHINGSlashingSwords
CLEAVINGCleavingAxes
BLUNTBluntMaces, shovels
WATERWaterTridents, corals
SPECIALSpecialBlaze rods, end rods, breeze rods
PETPetPet and ally attacks
RANGEDRangedBows, crossbows
PHYSICALPhysicalDefault / untyped weapons

Built-in Ability Factories (Abilities class)

The Abilities class provides static factory methods that return WeaponAbilityHandler instances. Compose multiple abilities with .and().

WeaponAbilityHandler handler = Abilities.bleed()
    .and(Abilities.sweepAdjacent(0.10, 0.05));
Factory MethodDescription
bleed()Applies bleed stacks equal to the weapon's Sharpness enchant level.
sweepAdjacent(baseChance, bonusPerPoint)Chance to hit one adjacent enemy for half damage. Scales with SLASHING affinity. Chance = baseChance + (affinity * bonusPerPoint) + (luck * 0.02).
armorIgnore(baseChance, bonusPerPoint)Chance to permanently destroy a portion of the target's defense and deal that amount as bonus damage. Scales with CLEAVING affinity.
stun(baseChance, bonusPerPoint)Chance to stun the target for one turn. Scales with BLUNT affinity.
knockbackDirection(distance)Pushes the target away from the player by up to N tiles, checking bounds and walkability each step.
aoe(radius, damageMultiplier)Hits all non-ally enemies within radius (Manhattan distance) of the target for (int)(baseDamage * damageMultiplier).
applyEffect(type, turns, amplifier)Applies a status effect to the target. Supported types: POISON, BURNING, SOAKED, SLOWNESS, CONFUSION.
pierce()Hits the first enemy directly behind the target in the attack direction for full base damage.
fireDamage(bonusDmg)Sets the target on fire and deals flat bonus fire damage.

Custom Ability Handler

WeaponAbilityHandler is a @FunctionalInterface. Implement it directly for fully custom on-hit logic.

@FunctionalInterface
public interface WeaponAbilityHandler {
    WeaponAbility.AttackResult apply(
        ServerPlayerEntity player,
        CombatEntity target,
        GridArena arena,
        int baseDamage,
        PlayerProgression.PlayerStats stats,
        int luckPoints
    );

    // Chain with another handler:
    default WeaponAbilityHandler and(WeaponAbilityHandler next);
}

Return a WeaponAbility.AttackResult(totalDamage, messages, extraTargets). The messages list holds combat log strings and extraTargets lists any additional entities your ability hit.

JSON Datapack Schema

Place weapon JSON files at data/<namespace>/craftics/weapons/*.json. The ability array is an ordered list of built-in ability blocks chained together.

FieldTypeRequiredDescription
itemstringyesFull item registry ID, e.g. minecraft:diamond_sword
damage_typestringnoDamageType name (case-insensitive). Defaults to PHYSICAL.
attack_powerintnoBase attack value. Defaults to 1.
ap_costintnoAction point cost per attack. Defaults to 1.
rangeintnoAttack range in tiles. Defaults to 1.
rangedboolnoWhether this is a projectile weapon. Defaults to false.
break_chancefloatnoProbability of breaking on use (0.0 to 1.0). Defaults to 0.0.
abilityarraynoOrdered list of ability objects (see ability kinds below).

Ability object kind values and their fields:

kindExtra Fields
bleed(none)
pierce(none)
sweepbase_chance (float, default 0.10), bonus_per_point (float, default 0.05)
armor_ignorebase_chance (float, default 0.10), bonus_per_point (float, default 0.05)
stunbase_chance (float, default 0.10), bonus_per_point (float, default 0.05)
knockbackdistance (int, default 1)
aoeradius (int, default 1), damage_multiplier (float, default 0.5)
fire_damagebonus_damage (int, default 2)
apply_effecteffect (string, e.g. POISON), turns (int, default 3), amplifier (int, default 0)
{
  "item": "minecraft:diamond_sword",
  "damage_type": "slashing",
  "attack_power": 7,
  "ap_cost": 1,
  "range": 1,
  "ranged": false,
  "break_chance": 0.0,
  "ability": [
    { "kind": "bleed" },
    { "kind": "sweep", "base_chance": 0.1, "bonus_per_point": 0.05 }
  ]
}

Code Example

import com.crackedgames.craftics.api.CrafticsAPI;
import com.crackedgames.craftics.api.Abilities;
import com.crackedgames.craftics.api.registry.WeaponEntry;
import com.crackedgames.craftics.combat.DamageType;

// Heavy Claymore: cleaving type, armor ignore + knockback
Item claymore = Registries.ITEM.get(Identifier.of("mymod", "heavy_claymore"));
CrafticsAPI.registerWeapon(claymore, WeaponEntry.builder(claymore)
    .damageType(DamageType.CLEAVING)
    .attackPower(7)
    .apCost(2)
    .range(1)
    .ability(Abilities.armorIgnore(0.15, 0.03)
        .and(Abilities.knockbackDirection(2)))
    .build());

Armor Sets

Armor sets grant per-piece damage affinity bonuses and full-set stat bonuses when all four matching armor pieces are worn. The set ID must match the material key that PlayerCombatStats.getArmorSet() derives from the player's equipped armor. Call CrafticsAPI.registerArmorSet(entry) during onCrafticsInit().

Damage affinity is per-piece: each worn piece of a material contributes half the damageBonus value for that type. A full four-piece set contributes twice the value. The flat stat bonuses (speedBonus, defenseBonus, etc.) apply only when all four pieces are worn.

API Method

CrafticsAPI.registerArmorSet(ArmorSetEntry entry);

ArmorSetEntry Builder

ArmorSetEntry entry = ArmorSetEntry.builder("mymod:mythril")
    .damageBonus(DamageType.SLASHING, 2)  // affinity value per 2 pieces (per-piece = 1)
    .damageBonus(DamageType.SPECIAL, 1)
    .allDamageBonus(1)                    // applied first; per-type entries override it
    .speedBonus(1)
    .apBonus(0)
    .defenseBonus(3)
    .attackBonus(1)
    .apCostReduction(0)
    .description("Mythril Armor: light and sharp")
    .build();

CrafticsAPI.registerArmorSet(entry);
Builder MethodTypeDefaultDescription
damageBonus(DamageType, int)per-type0Affinity value per 2 pieces for this damage type. A single piece grants half this amount.
allDamageBonus(int)all typesSets the same affinity value for every damage type. Per-type entries override it for that specific type.
speedBonus(int)int0Movement speed bonus (full set only)
apBonus(int)int0Extra action points per turn (full set only)
defenseBonus(int)int0Defense stat bonus (full set only)
attackBonus(int)int0Base attack bonus (full set only)
apCostReduction(int)int0Reduction in AP cost per attack (full set only)
description(String)string""Tooltip description shown in the combat HUD

JSON Datapack Schema

Place armor set JSON files at data/<namespace>/craftics/armor_sets/*.json. The id must match the armor-set name your material produces.

FieldTypeRequiredDescription
idstringyesArmor-set material key, e.g. mythril
descriptionstringnoTooltip description
all_damage_bonusintnoAffinity value applied to every damage type first
damage_bonusesarraynoPer-type affinity overrides: each object has type (DamageType name) and amount (int)
speed_bonusintnoSpeed bonus (full set only)
ap_bonusintnoExtra action points (full set only)
defense_bonusintnoDefense bonus (full set only)
attack_bonusintnoAttack bonus (full set only)
ap_cost_reductionintnoAP cost reduction per attack (full set only)
{
  "id": "mythril",
  "description": "Mythril Set: light and sharp",
  "all_damage_bonus": 0,
  "damage_bonuses": [
    { "type": "SLASHING", "amount": 2 },
    { "type": "SPECIAL",  "amount": 1 }
  ],
  "speed_bonus": 1,
  "ap_bonus": 0,
  "defense_bonus": 3,
  "attack_bonus": 1,
  "ap_cost_reduction": 0
}

Code Example

import com.crackedgames.craftics.api.CrafticsAPI;
import com.crackedgames.craftics.api.registry.ArmorSetEntry;
import com.crackedgames.craftics.combat.DamageType;

CrafticsAPI.registerArmorSet(ArmorSetEntry.builder("mythril")
    .damageBonus(DamageType.SLASHING, 2)
    .damageBonus(DamageType.SPECIAL, 1)
    .speedBonus(1)
    .defenseBonus(3)
    .attackBonus(1)
    .description("Mythril Armor: light and sharp")
    .build());

Hybrid Sets

A hybrid set is a subclass bonus a player earns by wearing exactly two distinct armor materials at once. The pair is unordered: {iron, diamond} and {diamond, iron} resolve to the same hybrid. Call CrafticsAPI.registerHybridSet(entry) during onCrafticsInit().

API Method

CrafticsAPI.registerHybridSet(HybridSetEntry entry);

HybridSetEntry Builder

HybridSetEntry entry = HybridSetEntry.builder("iron", "diamond")
    .className("Warlord")
    .description("Build stacks on kill; spend them to empower your next attack.")
    .effect(HybridEffect.WARLORD)
    .build();

CrafticsAPI.registerHybridSet(entry);
Builder Method / FieldTypeRequiredDescription
builder(materialA, materialB)yesThe two armor-set material keys. The builder normalizes the pair alphabetically so order does not matter.
className(String)stringnoSubclass display name shown on the armor tooltip
description(String)stringnoOne-line mechanic description shown on the armor tooltip
effect(HybridEffect)enumyesThe combat mechanic applied during Phase 2 (see HybridEffect values below)

HybridEffect Values

Pass one of these enum constants to .effect(). Each constant maps to a distinct combat mechanic implemented internally.

HybridEffectHybridEffectHybridEffect
SKIRMISHER COUNTERPUNCHER LUCKY_STREAK
BREAKER RAMPAGE RUN_AND_GUN
SENTINEL CUTPURSE DUELIST
AMBUSH DEADEYE GILDED_GUARD
WARLORD IMMOVABLE AEGIS
GLADIATOR BERSERKER CONTAGION
STONEWALL SIEGE STORMBRINGER

JSON Datapack Schema

Place hybrid set JSON files at data/<namespace>/craftics/hybrid_sets/*.json. The three required fields are material_a, material_b, and effect.

FieldTypeRequiredDescription
material_astringyesFirst armor material key (e.g. iron)
material_bstringyesSecond armor material key (e.g. diamond)
effectstringyesHybridEffect name (case-insensitive)
class_namestringnoSubclass display name
descriptionstringnoOne-line mechanic description
{
  "material_a": "iron",
  "material_b": "diamond",
  "class_name": "Warlord",
  "description": "Build stacks on kill; spend them to empower your next attack.",
  "effect": "WARLORD"
}

Code Example

import com.crackedgames.craftics.api.CrafticsAPI;
import com.crackedgames.craftics.api.registry.HybridSetEntry;
import com.crackedgames.craftics.combat.HybridEffect;

CrafticsAPI.registerHybridSet(HybridSetEntry.builder("iron", "diamond")
    .className("Warlord")
    .description("Build stacks on kill; spend them to empower your next attack.")
    .effect(HybridEffect.WARLORD)
    .build());

Trim Patterns

Each trim pattern grants a per-piece stat bonus and a full-set bonus activated when all four armor pieces carry the same pattern. Register custom patterns for modded trim templates. Call CrafticsAPI.registerTrimPattern(entry) during onCrafticsInit().

The pattern id must match the registry path of the vanilla trim pattern, not the full namespaced ID. For example, minecraft:sentry uses "sentry".

API Method

CrafticsAPI.registerTrimPattern(TrimPatternEntry entry);

TrimPatternEntry Record

TrimPatternEntry is a record with no builder. Construct it directly.

CrafticsAPI.registerTrimPattern(new TrimPatternEntry(
    "mymod:dragon",                      // patternId
    TrimEffects.Bonus.MELEE_POWER,       // perPieceStat
    "+1 Melee Power per piece",          // perPieceDescription
    TrimEffects.SetBonus.FERAL,          // setBonus
    "Dragon's Fury",                     // setBonusName
    "First attack each turn costs 0 AP"  // setBonusDescription
));
FieldTypeDescription
patternIdStringRegistry path of the trim pattern (e.g. "mymod:dragon")
perPieceStatTrimEffects.BonusStat bonus added once per armor piece carrying this pattern. Null means no per-piece bonus.
perPieceDescriptionStringHuman-readable text for the per-piece bonus
setBonusTrimEffects.SetBonusBonus activated when all four pieces use this pattern. Use NONE for no set bonus.
setBonusNameStringDisplay name for the set bonus
setBonusDescriptionStringHuman-readable text for the set bonus

JSON Datapack Schema

Place trim pattern JSON files at data/<namespace>/craftics/trim_patterns/*.json.

FieldTypeRequiredDescription
idstringyesRegistry path of the trim pattern
per_piece_statstringnoTrimEffects.Bonus name (case-insensitive). Omit for no per-piece bonus.
per_piece_descriptionstringnoDescription of the per-piece bonus
set_bonusstringnoTrimEffects.SetBonus name (case-insensitive). Defaults to NONE.
set_bonus_namestringnoDisplay name for the set bonus
set_bonus_descriptionstringnoDescription of the set bonus
{
  "id": "sentry",
  "per_piece_stat": "RANGED_POWER",
  "per_piece_description": "+1 Ranged Power per trimmed piece",
  "set_bonus": "OVERWATCH",
  "set_bonus_name": "Overwatch",
  "set_bonus_description": "Counter-attack ranged enemies that hit you"
}

TrimEffects.Bonus Values

BonusEffect
RANGED_POWERBonus ranged attack damage
MELEE_POWERBonus melee damage (all melee types)
SPEEDMovement speed (tiles per turn)
APExtra action points per turn
DEFENSEDamage reduction
LUCKAffects loot rolls and ability proc chances
ATTACK_RANGEExtra attack range in tiles
MAX_HPBonus maximum hit points
ARMOR_PENIgnore a portion of enemy defense
REGENHP regeneration per turn
ALLY_DAMAGEBonus damage for pet and ally attacks
STEALTH_RANGEReduced enemy detection range
SWORD_POWERBonus SLASHING damage specifically
CLEAVING_POWERBonus CLEAVING damage specifically
BLUNT_POWERBonus BLUNT damage specifically
WATER_POWERBonus WATER damage specifically
SPECIAL_POWERBonus SPECIAL damage specifically

TrimEffects.SetBonus Values

SetBonusNameEffect
NONENo set bonus
OVERWATCHSentryCounter-attack ranged enemies that hit you
SANDSTORMDuneEnemies within 2 tiles lose 1 Speed
TIDALCoastWater tiles heal 1 HP per turn
FERALWildKill streak: 1.3x damage per streak level (resets if no kills on your turn)
FORTRESSWard50% less damage when you did not move this turn
ALL_SEEINGEyeRanged attacks have +30% crit chance
ETHEREALVex20% chance to dodge incoming attacks
OCEAN_BLESSINGTideFull heal when dropping below 25% HP (once per combat)
BRUTE_FORCESnoutMelee attacks splash to adjacent enemies
INFERNALRibFire attacks deal +3 bonus damage
FORTUNE_PEAKSpireDouble emerald rewards
PATHFINDERWayfinderMovement ignores obstacle tiles
TERRAFORMERShaperMoving 3 or more tiles deals 2 damage to all enemies adjacent to your destination
PHANTOMSilenceInvisible for the first 2 turns (enemies do not act)
RALLYRaiserTamed allies get +2 Speed and +1 Attack
SYMBIOTEHostHeal 1 HP for each enemy killed
CURRENTFlowKilling an enemy refunds 1 AP
THUNDERSTRIKEBoltCritical hits stun the target for 1 turn

Trim Materials

Each trim material grants a per-piece stat bonus stacking once for each armor piece that carries a trim using that material. Register custom materials for modded ingots. Call CrafticsAPI.registerTrimMaterial(entry) during onCrafticsInit().

The material id must match the registry path of the trim material, not the full namespaced ID. For example, minecraft:iron uses "iron".

API Method

CrafticsAPI.registerTrimMaterial(TrimMaterialEntry entry);

TrimMaterialEntry Record

TrimMaterialEntry is a record with no builder. Construct it directly.

CrafticsAPI.registerTrimMaterial(new TrimMaterialEntry(
    "mymod:orichalcum",          // materialId
    TrimEffects.Bonus.ARMOR_PEN, // stat
    2,                           // valuePerPiece
    "+2 Armor Penetration per piece"
));
FieldTypeDescription
materialIdStringRegistry path of the trim material
statTrimEffects.BonusStat bonus type
valuePerPieceintAmount of the stat bonus added per trimmed armor piece
descriptionStringHuman-readable description shown in the armor tooltip

JSON Datapack Schema

Place trim material JSON files at data/<namespace>/craftics/trim_materials/*.json.

FieldTypeRequiredDescription
idstringyesRegistry path of the trim material
statstringyesTrimEffects.Bonus name (case-insensitive). An unknown value causes the file to be skipped.
value_per_pieceintnoBonus amount per trimmed piece. Defaults to 1.
descriptionstringnoHuman-readable description
{
  "id": "iron",
  "stat": "DEFENSE",
  "value_per_piece": 1,
  "description": "+1 Defense per trimmed piece"
}

Code Example

import com.crackedgames.craftics.api.CrafticsAPI;
import com.crackedgames.craftics.api.registry.TrimMaterialEntry;
import com.crackedgames.craftics.combat.TrimEffects;

// Orichalcum trim: +2 armor pen per trimmed piece
CrafticsAPI.registerTrimMaterial(new TrimMaterialEntry(
    "mymod:orichalcum",
    TrimEffects.Bonus.ARMOR_PEN,
    2,
    "+2 Armor Penetration per trimmed piece"
));

Enchantments

Register enchantments that contribute passive stat bonuses during Craftics combat. The handler receives an EnchantmentContext holding the enchantment level, the player, and a StatModifiers accumulator. Call CrafticsAPI.registerEnchantment(enchantmentId, handler) during onCrafticsInit().

Enchantments that modify weapon abilities, such as Sharpness or Smite, are handled by weapon ability handlers rather than this registry.

API Method

CrafticsAPI.registerEnchantment(String enchantmentId, EnchantmentEffectHandler handler);

EnchantmentEffectHandler and EnchantmentContext

@FunctionalInterface
public interface EnchantmentEffectHandler {
    void apply(EnchantmentContext ctx);
}

public class EnchantmentContext {
    public int getLevel();                  // enchantment level (1, 2, 3, ...)
    public ServerPlayerEntity getPlayer();  // the player
    public StatModifiers getModifiers();    // accumulator to add bonuses to
}

Add bonuses to the accumulator using ctx.getModifiers().add(TrimEffects.Bonus, amount). The full list of available TrimEffects.Bonus values is in the Trim Patterns section above.

JSON Datapack Schema

Place enchantment JSON files at data/<namespace>/craftics/enchantments/*.json. Each bonus entry grants (enchantLevel / per_levels) * amount of the specified stat.

FieldTypeRequiredDescription
enchantmentstringyesFull enchantment registry ID, e.g. minecraft:protection
bonusesarraynoList of stat bonus objects
bonuses[].statstringyesTrimEffects.Bonus name (case-insensitive)
bonuses[].amountintnoBonus amount per qualifying level. Defaults to 1.
bonuses[].per_levelsintnoHow many enchantment levels are needed per amount. Defaults to 1 (one bonus per level).
{
  "enchantment": "minecraft:protection",
  "bonuses": [
    { "stat": "DEFENSE", "amount": 1, "per_levels": 2 }
  ]
}

With per_levels: 2 and amount: 1, Protection IV (level 4) grants (4 / 2) * 1 = 2 Defense.

Code Example

import com.crackedgames.craftics.api.CrafticsAPI;
import com.crackedgames.craftics.combat.TrimEffects;

// Holy Blessing: +1 Defense and +1 Regen per enchantment level
CrafticsAPI.registerEnchantment("mymod:holy_blessing", (ctx) -> {
    ctx.getModifiers().add(TrimEffects.Bonus.DEFENSE, ctx.getLevel());
    ctx.getModifiers().add(TrimEffects.Bonus.REGEN, ctx.getLevel());
});

// Swiftness: +1 Speed regardless of level
CrafticsAPI.registerEnchantment("mymod:swiftness", (ctx) -> {
    ctx.getModifiers().add(TrimEffects.Bonus.SPEED, 1);
});

Equipment Scanners

Equipment scanners let addon mods contribute stat bonuses from non-standard inventory slots, such as trinkets, baubles, or curio slots, into Craftics combat stats. The scanner is called during combat stat calculation and its results are merged with trim and armor bonuses. Call CrafticsAPI.registerEquipmentScanner(id, scanner) during onCrafticsInit().

This registry is code-only; no JSON datapack loader exists for scanners. The scanner function must be provided in Java.

API Method

CrafticsAPI.registerEquipmentScanner(String id, EquipmentScanner scanner);

EquipmentScanner Interface

@FunctionalInterface
public interface EquipmentScanner {
    StatModifiers scan(ServerPlayerEntity player);
}

StatModifiers Class

StatModifiers accumulates bonuses using the TrimEffects.Bonus enum as keys. It can also carry an optional set bonus and custom combat effect handlers.

StatModifiers mods = new StatModifiers();
mods.add(TrimEffects.Bonus.DEFENSE, 2);       // +2 Defense
mods.add(TrimEffects.Bonus.SPEED, 1);         // +1 Speed
mods.add(TrimEffects.Bonus.MAX_HP, 4);        // +4 Max HP
mods.addSetBonus(TrimEffects.SetBonus.FERAL, "Feral Ring Set"); // optional set bonus

Call mods.addCombatEffect(name, handler) to register a dynamic CombatEffectHandler alongside the stat bonuses. Combat effect handlers are covered on the Items & Effects page.

Code Example

import com.crackedgames.craftics.api.CrafticsAPI;
import com.crackedgames.craftics.api.EquipmentScanner;
import com.crackedgames.craftics.api.StatModifiers;
import com.crackedgames.craftics.combat.TrimEffects;
import net.minecraft.item.ItemStack;

CrafticsAPI.registerEquipmentScanner("mymod", (player) -> {
    StatModifiers mods = new StatModifiers();

    // Read items from your addon's custom equipment slots
    ItemStack belt = getCustomSlot(player, "belt");
    if (!belt.isEmpty()) {
        if (belt.isOf(MY_SWIFT_BELT)) {
            mods.add(TrimEffects.Bonus.SPEED, 1);
        } else if (belt.isOf(MY_IRON_BELT)) {
            mods.add(TrimEffects.Bonus.DEFENSE, 2);
        }
    }

    ItemStack amulet = getCustomSlot(player, "amulet");
    if (!amulet.isEmpty() && amulet.isOf(MY_LUCKY_CHARM)) {
        mods.add(TrimEffects.Bonus.LUCK, 3);
    }

    return mods;
});