Skip to content

Creating Custom Moves

This guide walks you through creating a complete custom titan move from concept to testing.

Time Required: 30-60 minutes per move Difficulty: Intermediate

You’ll Create:

  • Custom ActionEffect timeline
  • OBB hitbox configuration
  • Telegraph warnings
  • Damage application
  • Visual/audio feedback
  • Fight config integration

Answer These Questions:

  • What type of attack is it? (melee, ranged, AOE, ultimate)
  • What element/theme? (fire, ice, electric, physical, magic)
  • How much damage should it deal?
  • How often can it be used? (cooldown)
  • What phase(s) should it appear in?

Example:

Move: Infernal Blast
Type: Ranged AOE
Element: Fire
Damage: 22
Cooldown: 8 seconds
Phases: 2-3

Visual Design:

  • What shape is the hitbox? (cone, sphere, cylinder, etc.)
  • How far does it reach?
  • Where does it appear? (in front, at target, centered on titan)
  • How long is the telegraph warning?

Timing Design:

  • Windup duration (pause before attack)
  • Telegraph duration (warning time)
  • Recovery duration (pause after attack)
  • Total attack duration

Example:

Shape: CONE (flamethrower)
Range: 8 blocks forward
Size: 2 block radius at base, 8 blocks length
Placement: IN_FRONT, 2 blocks from titan
Telegraph: DANGER (orange, ~2s)
Timing: 0.5s windup + 2s telegraph + 0.5s recovery = 3s total
  1. Open OBB Visualizer →
  2. Select shape: CONE
  3. Set positioning: IN_FRONT
  4. Set distance: 2.0
  5. Adjust half-extents:
    • X (base radius): 2.0
    • Y (length): 8.0
  6. Enable Include Pitch if attack should follow vertical aim
  7. Test rotation to see how it behaves

Click “Copy JSON Config” to get:

{
"type": "define_obb",
"name": "infernal_blast",
"shape": "CONE",
"positioning": "IN_FRONT",
"distance": "2.0",
"halfExtents": {
"x": "2.0",
"y": "8.0",
"z": "2.0"
},
"includePitch": true
}

Save this for later!

Section titled “Method A: ActionEffect Builder (Recommended)”
  1. Open ActionEffect Builder →
  2. Add keyframes in order:

Setup:

  • Add add_holds (holds: ["effects"])
  • Add stop_movement (duration: 2500)
  • Add animation (animation: "special")

Windup:

  • Add pause (pause: 0.5)
  • Add entity_particles (type: minecraft:flame, count: 30)

Attack:

  • Add define_obb (paste your OBB config)
  • Add telegraph_obb (name: infernal_blast, type: DANGER)
  • Add sound (sound: entity.blaze.shoot, volume: 1.5)
  • Add damage_obb (name: infernal_blast, damage: 22.0, type: FIRE)

Cleanup:

  • Add set_vulnerable (state: RECOVERING, duration: 3000)
  • Add remove_holds (holds: ["effects"])
  • Add pause (pause: 1.0)
  1. Preview Timeline - Check total duration (~5-6 seconds)
  2. Copy JSON - Export complete ActionEffect

Create file: server/data/titan/action_effects/custom_infernal_blast.json

{
"timeline": [
{"type": "add_holds", "holds": ["effects"]},
{"type": "stop_movement", "duration": "2500"},
{"type": "animation", "animation": "special"},
{"type": "pause", "pause": 0.5},
{"type": "entity_particles", "particleType": "minecraft:flame", "count": 30, "spread": {"x": 1.0, "y": 1.0, "z": 1.0}},
{"type": "define_obb", "name": "infernal_blast", "shape": "CONE", "positioning": "IN_FRONT", "distance": "2.0", "halfExtents": {"x": "2.0", "y": "8.0", "z": "2.0"}, "includePitch": true},
{"type": "telegraph_obb", "name": "infernal_blast", "telegraphType": "DANGER"},
{"type": "sound", "sound": "entity.blaze.shoot", "volume": "1.5", "pitch": "1.0"},
{"type": "damage_obb", "name": "infernal_blast", "damage": "22.0", "damageType": "FIRE"},
{"type": "set_vulnerable", "vulnerabilityState": "RECOVERING", "duration": "3000"},
{"type": "remove_holds", "holds": ["effects"]},
{"type": "pause", "pause": 1.0}
],
"condition": "true"
}

Save as: custom_infernal_blast.json in data pack

Edit fight config: server/config/titan/fights/charizard.json

Find the "moves" section and add:

{
"moves": {
"infernal_blast": {
"name": "Infernal Blast",
"cooldown": "167",
"range": "10.0",
"damage": "22.0",
"damageType": "FIRE",
"actionEffect": "titan:custom_infernal_blast",
"condition": "1.0",
"weight": 1.5,
"minHealthPercent": 0.0,
"maxHealthPercent": 0.66,
"phase": -1
}
}
}

Property Breakdown:

  • cooldown: "167" = 8.35 seconds (167 ticks ÷ 20 tps)
  • range: "10.0" = 10 block range check
  • damage: "22.0" = Expected damage (for AI calculations)
  • actionEffect: "titan:custom_infernal_blast" = Your ActionEffect file
  • weight: 1.5 = Higher weight = more likely to be selected
  • maxHealthPercent: 0.66 = Only usable until 66% HP (Phases 1-2)

Find phase configurations and add move to pools:

Phase 2 (66% HP):

{
"healthThreshold": 0.66,
"moves": ["flamethrower", "infernal_blast", "slash"],
"speedModifier": 1.2,
"damageModifier": 1.1
}

Phase 3 (33% HP):

{
"healthThreshold": 0.33,
"moves": ["infernal_blast", "dragon_rage", "ultimate"],
"speedModifier": 1.4,
"damageModifier": 1.3
}
  1. Reload Configs:

    /titan reload
  2. Spawn Titan:

    /pokespawn charizard level:50
    /titan convert
  3. Test in Creative Mode:

    • Enable god mode: /gamemode creative
    • Stand at various distances
    • Observe attack telegraph
    • Check damage feels appropriate
    • Verify cooldown timing

Visual Feedback:

  • Telegraph appears before damage
  • Telegraph color matches danger level
  • Telegraph shape matches hitbox
  • Particles spawn correctly
  • Animation plays smoothly

Audio Feedback:

  • Sound plays at appropriate time
  • Volume is audible but not overwhelming
  • Pitch feels appropriate

Damage:

  • Damage amount feels balanced
  • Damage type applies correctly (fire sets entities on fire)
  • Knockback (if any) feels appropriate
  • Hitbox matches visual telegraph

Timing:

  • Telegraph gives enough warning
  • Total attack duration feels right
  • Vulnerability window feels fair
  • Cooldown prevents spam

AI Behavior:

  • Titan uses move at appropriate times
  • Move frequency feels balanced
  • Weight relative to other moves works
  • Phase restrictions work correctly

Telegraph Too Short/Long:

// Override auto-duration
{"type": "telegraph_obb", "name": "infernal_blast", "telegraphType": "DANGER", "duration": "2500"}

Damage Too High/Low:

// Adjust damage in ActionEffect
{"type": "damage_obb", "name": "infernal_blast", "damage": "18.0"}
// AND in fight config
"damage": "18.0"

OBB Wrong Size:

  1. Return to OBB Visualizer
  2. Adjust half-extents
  3. Export new config
  4. Replace in ActionEffect
  5. Reload and retest

Cooldown Issues:

// Shorter cooldown (more frequent)
"cooldown": "120" // 6 seconds
// Longer cooldown (less frequent)
"cooldown": "240" // 12 seconds

Move Weight:

// Use more often
"weight": 2.0
// Use less often
"weight": 0.8

Damage vs Cooldown:

  • 2-4s cooldown: 8-12 damage
  • 4-8s cooldown: 15-25 damage
  • 8-15s cooldown: 25-35 damage
  • 15-30s cooldown: 35-50 damage

Telegraph Duration vs OBB Size:

  • Small (2-4 blocks): 1.0-1.5s
  • Medium (5-8 blocks): 1.5-2.5s
  • Large (8-12 blocks): 2.5-3.5s
  • Massive (12+ blocks): 3.5-4.0s

Vulnerability Duration vs Damage:

  • Low damage (<15): 2-3s RECOVERING
  • Medium damage (15-25): 3-4s RECOVERING
  • High damage (25-40): 4-6s RECOVERING or 4-5s EXHAUSTED
  • Ultimate (40+): 6-8s EXHAUSTED

Let’s create a complete multi-hit ice attack.

Move: Ice Shard Barrage
Type: Ranged multi-hit
Element: Ice
Damage: 5 per shard × 4 shards = 20 total
Cooldown: 10 seconds
Phases: 2-3
Visual: Line of ice shards shooting forward
{
"type": "define_obb",
"name": "ice_shard",
"shape": "CYLINDER",
"positioning": "IN_FRONT",
"distance": "5.0",
"halfExtents": {"x": "1.0", "y": "10.0", "z": "1.0"},
"includePitch": true
}
{
"timeline": [
{"type": "add_holds", "holds": ["effects"]},
{"type": "stop_movement", "duration": "3000"},
{"type": "animation", "animation": "special"},
{"type": "pause", "pause": 0.3},
{"type": "define_obb", "name": "ice_shard", "shape": "CYLINDER", "positioning": "IN_FRONT", "distance": "5.0", "halfExtents": {"x": "1.0", "y": "10.0", "z": "1.0"}, "includePitch": true},
{"type": "telegraph_obb", "name": "ice_shard", "telegraphType": "WARNING"},
{"type": "entity_particles", "particleType": "minecraft:snowflake", "count": 20},
{"type": "sound", "sound": "block.glass.break", "volume": "1.0", "pitch": "1.2"},
{"type": "damage_obb", "name": "ice_shard", "damage": "5.0", "damageType": "WATER"},
{"type": "pause", "pause": 0.4},
{"type": "entity_particles", "particleType": "minecraft:snowflake", "count": 20},
{"type": "sound", "sound": "block.glass.break", "volume": "1.0", "pitch": "1.2"},
{"type": "damage_obb", "name": "ice_shard", "damage": "5.0", "damageType": "WATER"},
{"type": "pause", "pause": 0.4},
{"type": "entity_particles", "particleType": "minecraft:snowflake", "count": 20},
{"type": "sound", "sound": "block.glass.break", "volume": "1.0", "pitch": "1.2"},
{"type": "damage_obb", "name": "ice_shard", "damage": "5.0", "damageType": "WATER"},
{"type": "pause", "pause": 0.4},
{"type": "entity_particles", "particleType": "minecraft:snowflake", "count": 20},
{"type": "sound", "sound": "block.glass.break", "volume": "1.0", "pitch": "1.2"},
{"type": "damage_obb", "name": "ice_shard", "damage": "5.0", "damageType": "WATER"},
{"type": "molang_script", "script": "q.apply_potion_all('slowness', 60, 1, 10.0);"},
{"type": "set_vulnerable", "vulnerabilityState": "RECOVERING", "duration": "3500"},
{"type": "remove_holds", "holds": ["effects"]},
{"type": "pause", "pause": 1.0}
],
"condition": "true"
}
"ice_shard_barrage": {
"name": "Ice Shard Barrage",
"cooldown": "200",
"range": "12.0",
"damage": "20.0",
"damageType": "WATER",
"actionEffect": "titan:ice_shard_barrage",
"condition": "1.0",
"weight": 1.4,
"minHealthPercent": 0.0,
"maxHealthPercent": 0.66,
"phase": -1
}
{
"type": "damage_obb",
"name": "attack",
"damage": "q.lerp(15.0, 30.0, 1.0 - q.titan_health_percent)"
// Scales from 15 to 30 damage based on titan HP
}
"charge_attack": {
"condition": "q.target_distance > 8.0",
"weight": 2.5
// Higher weight when target is far
}
"desperate_ultimate": {
"condition": "q.is_phase(3)",
"weight": 1.0,
"minHealthPercent": 0.0,
"maxHealthPercent": 0.33
// Only Phase 3
}
{
"timeline": [
// Stage 1: Charge
{"type": "pause", "pause": 1.0},
{"type": "entity_particles", "particleType": "minecraft:enchant", "count": 30},
// Stage 2: Attack
{"type": "define_obb", "name": "stage2", ...},
{"type": "telegraph_obb", ...},
{"type": "damage_obb", ...},
{"type": "pause", "pause": 0.5},
// Stage 3: Follow-up
{"type": "define_obb", "name": "stage3", ...},
{"type": "telegraph_obb", ...},
{"type": "damage_obb", ...}
]
}

Possible Causes:

  • condition is false
  • weight too low compared to other moves
  • Health percent range doesn’t match current phase
  • Not in correct phase move pool

Fix: Check fight config, increase weight, verify phase assignment

Possible Causes:

  • OBB not defined before telegraph
  • Name mismatch between define_obb and telegraph_obb
  • OBB positioned underground

Fix: Verify OBB definition, check names match exactly, adjust positioning

Possible Causes:

  • OBB not defined
  • Name mismatch
  • OBB positioned incorrectly
  • Target out of range

Fix: Test with large OBB first, verify names, check positioning mode

Possible Causes:

  • Cooldown too short
  • Weight too high
  • Only move available in phase

Fix: Increase cooldown, reduce weight, add more moves to phase

  1. Create basic version (just damage, no effects)
  2. Test and verify it works
  3. Add telegraph
  4. Add particles/sounds
  5. Add vulnerability
  6. Fine-tune all values

Copy existing moves as templates:

  • Fire attacks: charizard_inferno_blaze.json
  • Electric attacks: pikachu_thunderbolt.json
  • Melee attacks: lucario_close_combat.json
  • Ultimates: mewtwo_psycho_break.json
/titan set_health 100 # Full HP
/titan set_health 66 # Phase 2
/titan set_health 33 # Phase 3
Terminal window
git add data/titan/action_effects/custom_*.json
git commit -m "Add custom Ice Shard Barrage move"

Now create your own signature moves! 🎨⚔️