Hellfire Descent Blueprint, Build Your Own ARPG
JVDesignStudio - https://jvdesignstudio.co.uk/workshops/diablo-blueprint.html

Offline reference pack for this workshop.
This is a companion copy of the build steps, so you can follow along without
the website. Open the workshop online for the interactive screenshots, videos
and the copy buttons.

What you build: Hellfire Descent Blueprint, Build Your Own ARPG

--------------------------------------------------------------------
STEP-BY-STEP BUILD
--------------------------------------------------------------------

## STEP 01 · SETUP - Event BeginPlay
- Connect Event BeginPlay ? Print String. Every Blueprint starts here, fires once when the game loads.

## STEP 02 · HERO - Event BeginPlay',x:16,y:28,w:152,rp:[{id:'r1',type:'exec',label:''}]},{id:'n2',type:'func',title:'Print String',sub:'Hellfire: Ready',x:200,y:28,w:162,lp:[{id:'l1',type:'exec',label:''}],rp:[{id:'r2',type:'exec',label:''}]}],[{f:'r1',t:'l1'}],[]), boxes:[{t:'box-c',tx:'The exec wire (white arrow) controls node order. BeginPlay fires once then flows right through every connected node, the starting fuse for all three weapon systems.'}], onApply(){sout('✅ Engine started! Continue building all three weapon types.');}}, {title:'Hero Stats, HP & Armour
- Connect BeginPlay ? Set MaxHP ? Set Armour. Type your hero's starting values.

## STEP 03 · MOVEMENT - Event BeginPlay',x:6,y:36,w:148,rp:[{id:'r1',type:'exec',label:''}]},{id:'n2',type:'vset',title:'Set MaxHP',x:175,y:12,w:112,lp:[{id:'l2e',type:'exec',label:''},{id:'l2v',type:'int',label:'HP'}],rp:[{id:'r2',type:'exec',label:''}],vf:{hint:'HP 60-150 (e.g. 80)',val:''}},{id:'n3',type:'vset',title:'Set Armour',x:307,y:12,w:118,lp:[{id:'l3e',type:'exec',label:''},{id:'l3v',type:'int',label:'Armour'}],rp:[{id:'r3',type:'exec',label:''}],vf:{hint:'Armour 0-8 (e.g. 3)',val:''}},{id:'n4',type:'vset',title:'Set Level=1',x:445,y:12,w:93,lp:[{id:'l4e',type:'exec',label:''}]}],[{f:'r1',t:'l2e'},{f:'r2',t:'l3e'},{f:'r3',t:'l4e'}],[{id:'n2',ok:v=>parseInt(v)>=30&&parseInt(v)parseInt(v)>=0&&parseInt(v)<=15}]), boxes:[{t:'box-c',tx:'Armour reduces every hit, 5 armour vs 9-damage = 4 actual damage. Always minimum 1. Armour +1 on every level up, so by level 5 you absorb nearly twice as much.'}], onApply(v){G.p.maxHp=parseInt(v['n2'])||80;G.p.hp=G.p.maxHp;G.p.armour=parseInt(v['n3'])||3;updateHUD();sout('✅ HP='+v['n2']+' Armour='+v['n3']+'.');}}, {title:'WASD Movement
- Connect IA_Move ? Multiply Speed × Delta ? Add Movement Input. W=up, S=down, A=left, D=right, simple and intuitive.

## STEP 04 · 🔫 GUN - IA_Move (WASD)',x:4,y:26,w:155,rp:[{id:'r1e',type:'exec',label:''},{id:'r1v',type:'vec3',label:'Axis'}]},{id:'n2',type:'math',title:'× Speed × Delta',x:180,y:8,w:130,lp:[{id:'l2a',type:'vec3',label:'Dir'},{id:'l2b',type:'float',label:'Speed'}],rp:[{id:'r2',type:'vec3',label:'Velocity'}],vf:{hint:'Speed 200-350 (e.g. 280)',val:''}},{id:'n3',type:'func',title:'Add Movement Input',x:331,y:8,w:162,lp:[{id:'l3e',type:'exec',label:''},{id:'l3v',type:'vec3',label:'World Dir'}],rp:[{id:'r3',type:'exec',label:''}]}],[{f:'r1e',t:'l3e'},{f:'r1v',t:'l2a'},{f:'r2',t:'l3v'}],[{id:'n2',ok:v=>parseFloat(v)>=80&&parseFloat(v)<=500}]), boxes:[{t:'box-c',tx:'Collision: separately check X and Y movement each frame. If the new X position hits a wall, block X only, the hero slides along the wall instead of stopping dead. This makes movement feel smooth.'}], onApply(){G.f_move=true;G.phase='playing';G.projs=[];G.particles=[];loadRoom();updateHUD();sout('✅ Movement active! WASD to explore the dungeon.');}}, // --- GUNS --- {title:'Gun System, Click to Fire
- Connect On LMB ? Get Cursor Direction ? Spawn Projectile. Click anywhere on screen to fire toward that point.

## STEP 05 · 🔫 GUN - On LMB Pressed',x:4,y:28,w:145,rp:[{id:'r1',type:'exec',label:''}]},{id:'n2',type:'func',title:'Get Cursor Direction',x:169,y:8,w:148,lp:[{id:'l2e',type:'exec',label:''}],rp:[{id:'r2e',type:'exec',label:''},{id:'r2d',type:'vec3',label:'Dir'}]},{id:'n3',type:'gun',title:'Spawn Projectile\nAt Hero',x:337,y:8,w:150,lp:[{id:'l3e',type:'exec',label:''},{id:'l3d',type:'vec3',label:'Direction'},{id:'l3s',type:'float',label:'Speed'}],rp:[{id:'r3',type:'exec',label:''}],vf:{hint:'Proj speed 400-1000',val:''}},{id:'n4',type:'gun',title:'Set Lifetime',x:507,y:8,w:31,lp:[{id:'l4e',type:'exec',label:''}]}],[{f:'r1',t:'l2e'},{f:'r2e',t:'l3e'},{f:'r2d',t:'l3d'},{f:'r3',t:'l4e'}],[{id:'n3',ok:v=>parseFloat(v)>=200&&parseFloat(v)<=1500}],'gun-t'), boxes:[{t:'box-gun',tx:'Gun Pool (10): Hand Crossbow · Heavy Crossbow · Repeating Bow · Poison Dart · Hell Cannon · Elven Longbow · Triple Shot · Shadow Bolt · Iron Musket · Scatter Shot. Every run picks a random one.'}], onApply(){G.f_attack=true;sout('✅ Guns active! Click to fire.');}}, {title:'Gun Stats, Damage & Fire Rate
- Connect BeginPlay ? Set GunDamage ? Set FireRate ? Set Range. Type your starting crossbow stats.

## STEP 06 · 🔫 GUN - Event BeginPlay',x:6,y:36,w:148,rp:[{id:'r1',type:'exec',label:''}]},{id:'n2',type:'gun',title:'Set Gun Damage',x:175,y:12,w:125,lp:[{id:'l2e',type:'exec',label:''},{id:'l2v',type:'int',label:'Dmg'}],rp:[{id:'r2',type:'exec',label:''}],vf:{hint:'Dmg 5-30 (e.g. 8)',val:''}},{id:'n3',type:'gun',title:'Set Fire Rate',x:320,y:12,w:120,lp:[{id:'l3e',type:'exec',label:''},{id:'l3v',type:'float',label:'Rate(s)'}],rp:[{id:'r3',type:'exec',label:''}],vf:{hint:'Rate 0.2-1.5 (e.g. 0.35)',val:''}},{id:'n4',type:'gun',title:'Set Range',x:460,y:12,w:78,lp:[{id:'l4e',type:'exec',label:''}],vf:{hint:'Range 130-320 (px)',val:''}}],[{f:'r1',t:'l2e'},{f:'r2',t:'l3e'},{f:'r3',t:'l4e'}],[{id:'n2',ok:v=>parseInt(v)>=2&&parseInt(v)parseFloat(v)>=0.1&&parseFloat(v)parseInt(v)>=60&&parseInt(v)<=400}],'gun-t'), boxes:[{t:'box-gun',tx:'Fire rate is cooldown between shots. Lower = faster. Hell Cannon (28dmg, 1.6s) vs Hand Crossbow (8dmg, 0.35s). Range is how far the bolt travels before disappearing.'}], onApply(v){const w={...GUN_POOL[0]};w.dmg=parseInt(v['n2'])||8;w.fireRate=parseFloat(v['n3'])||.35;w.range=parseInt(v['n4'])||200;if(!G.p.weapon){G.p.weapon=w;G.p.weaponType='gun';updateHUD();}sout('✅ Gun: '+v['n2']+'dmg, '+v['n3']+'s, '+v['n4']+'px!');}}, {title:'Gun Specials, Pierce & Explosive
- Connect On Proj Hit ? Switch on Special ? Pierce (continue) or AoE Explosion. Type the blast radius.

## STEP 07 · 🔫 GUN - On Proj Hit Enemy',x:4,y:28,w:150,rp:[{id:'r1e',type:'exec',label:''},{id:'r1s',type:'string',label:'Special'}]},{id:'n2',type:'func',title:'Switch on Special',x:175,y:8,w:148,lp:[{id:'l2e',type:'exec',label:''},{id:'l2s',type:'string',label:''}],rp:[{id:'r2a',type:'exec',label:'pierce'},{id:'r2b',type:'exec',label:'explosive'},{id:'r2c',type:'exec',label:'triple'}]},{id:'n3',type:'gun',title:'AoE Explosion',x:343,y:4,w:125,lp:[{id:'l3e',type:'exec',label:''},{id:'l3r',type:'float',label:'Radius'}],vf:{hint:'AoE radius (e.g. 32)',val:''}},{id:'n4',type:'gun',title:'Continue Travel',x:343,y:72,w:125,lp:[{id:'l4',type:'exec',label:''}]}],[{f:'r1e',t:'l2e'},{f:'r1s',t:'l2s'},{f:'r2b',t:'l3e'},{f:'r2a',t:'l4'}],[{id:'n3',ok:v=>parseFloat(v)>=5&&parseFloat(v)<=100}],'gun-t'), boxes:[{t:'box-gun',tx:'Pierce (Longbow, Musket): bolt continues through enemies, great in tight rooms. Explosive (Hell Cannon): AoE blast on impact. Triple Shot: 3 bolts at 13×. Scatter: 5-bolt cone.'}], onApply(){sout('✅ Gun specials active!');}}, {title:'Gun Loot Drops, Blue Orbs
- Guns drop as BLUE orbs on enemy death (38% chance). Walk over to auto-equip if better DPS.

## STEP 08 · ⚔️ MELEE - On Gun Drop\nOverlap Hero',x:4,y:28,w:152,rp:[{id:'r1e',type:'exec',label:''},{id:'r1w',type:'object',label:'Weapon'}]},{id:'n2',type:'gun',title:'Get DPS\n(dmg×fireRate)',x:177,y:8,w:145,lp:[{id:'l2w',type:'object',label:'Gun'}],rp:[{id:'r2n',type:'float',label:'New'},{id:'r2o',type:'float',label:'Old'}]},{id:'n3',type:'math',title:'> Greater',x:342,y:8,w:104,lp:[{id:'l3a',type:'float',label:'New'},{id:'l3b',type:'float',label:'Old'}],rp:[{id:'r3',type:'bool',label:'Better?'}]},{id:'n4',type:'branch',title:'Branch',x:466,y:8,w:72,lp:[{id:'l4e',type:'exec',label:''},{id:'l4c',type:'bool',label:''}],rp:[{id:'r4t',type:'exec',label:'Equip'},{id:'r4f',type:'exec',label:'Skip'}]}],[{f:'r1e',t:'l4e'},{f:'r2n',t:'l3a'},{f:'r2o',t:'l3b'},{f:'r3',t:'l4c'}],[],'gun-t'), boxes:[{t:'box-gun',tx:'Blue = gun drop. Amber = melee. Purple = wand. All three share the 38% drop pool, any kill might give any weapon type. The minimap would show coloured dots for drops.'}], onApply(){G.f_loot=true;sout('✅ Loot drops active! Blue=gun, Amber=melee, Purple=wand. Walk over to equip.');}}, // --- MELEE --- {title:'Melee System, Sweep Arc
- Connect On LMB ? Get Cursor Angle ? Sweep Arc Hit Detection ? Apply Damage. The blade swings a cone in the click direction.

## STEP 09 · ⚔️ MELEE - On LMB Pressed',x:4,y:28,w:145,rp:[{id:'r1',type:'exec',label:''}]},{id:'n2',type:'func',title:'Get Cursor Angle',x:169,y:8,w:145,lp:[{id:'l2e',type:'exec',label:''}],rp:[{id:'r2e',type:'exec',label:''},{id:'r2a',type:'float',label:'Angle'}]},{id:'n3',type:'melee',title:'Sweep Arc\nDetection',x:334,y:8,w:150,lp:[{id:'l3e',type:'exec',label:''},{id:'l3a',type:'float',label:'Angle'},{id:'l3r',type:'float',label:'Reach'}],rp:[{id:'r3e',type:'exec',label:''},{id:'r3h',type:'object',label:'Hit Actors'}],vf:{hint:'Reach 42-82 (e.g. 56)',val:''}},{id:'n4',type:'melee',title:'Apply Dmg Each',x:504,y:8,w:34,lp:[{id:'l4e',type:'exec',label:''},{id:'l4a',type:'object',label:'Actors'}]}],[{f:'r1',t:'l2e'},{f:'r2e',t:'l3e'},{f:'r2a',t:'l3a'},{f:'r3e',t:'l4e'},{f:'r3h',t:'l4a'}],[{id:'n3',ok:v=>parseInt(v)>=20&&parseInt(v)<=120}],'melee-t'), boxes:[{t:'box-melee',tx:'Melee Pool (12): Rusty Dagger · Short Sword · Broad Sword · War Axe · Battle Axe · Mace · War Hammer · Rapier · Halberd · Greatsword · Hell Blade · Shadowfang. Reach = arc radius. Sweep = cone width.'}], onApply(){G.f_attack=true;sout('✅ Melee sweep active! Click to swing.');}}, {title:'Melee Stats, Damage, Speed & Sweep
- Connect BeginPlay ? Set MeleeDamage ? Set AttackSpeed ? Set SweepAngle.

## STEP 10 · ⚔️ MELEE - Event BeginPlay',x:6,y:36,w:148,rp:[{id:'r1',type:'exec',label:''}]},{id:'n2',type:'melee',title:'Set Damage',x:175,y:12,w:115,lp:[{id:'l2e',type:'exec',label:''},{id:'l2v',type:'int',label:'Dmg'}],rp:[{id:'r2',type:'exec',label:''}],vf:{hint:'Dmg 6-35 (e.g. 12)',val:''}},{id:'n3',type:'melee',title:'Set AtkSpeed',x:310,y:12,w:120,lp:[{id:'l3e',type:'exec',label:''},{id:'l3v',type:'float',label:'Cooldown'}],rp:[{id:'r3',type:'exec',label:''}],vf:{hint:'0.2-0.9 (e.g. 0.4)',val:''}},{id:'n4',type:'melee',title:'Set Sweep°',x:450,y:12,w:88,lp:[{id:'l4e',type:'exec',label:''}],vf:{hint:'25-120 (e.g. 70)',val:''}}],[{f:'r1',t:'l2e'},{f:'r2',t:'l3e'},{f:'r3',t:'l4e'}],[{id:'n2',ok:v=>parseInt(v)>=3&&parseInt(v)parseFloat(v)>=0.1&&parseFloat(v)parseInt(v)>=15&&parseInt(v)<=130}],'melee-t'), boxes:[{t:'box-melee',tx:'Fast (0.2s dagger) = frantic close-range. Slow (0.8s greatsword) = powerful heavy hits. Wide sweep (90°+) clears groups. Narrow (25° rapier) requires precision but reaches further.'}], onApply(v){const w={...MELEE_POOL[1]};w.dmg=parseInt(v['n2'])||12;w.atkSpd=parseFloat(v['n3'])||.4;w.sweep=parseInt(v['n4'])||70;if(!G.p.weapon){G.p.weapon=w;G.p.weaponType='melee';updateHUD();}G.f_attack=true;sout('? Melee: '+v['n2']+'dmg, '+v['n3']+'s, '+v['n4']+'°!');}}, {title:'Melee Specials
- Connect On Melee Hit ? Switch on Special ? Apply Effect. Stun, armour break, lifesteal, fire.

## STEP 11 · ⚔️ MELEE - On Melee Hit',x:4,y:28,w:135,rp:[{id:'r1e',type:'exec',label:''},{id:'r1s',type:'string',label:'Special'}]},{id:'n2',type:'func',title:'Switch on Special',x:159,y:8,w:148,lp:[{id:'l2e',type:'exec',label:''},{id:'l2s',type:'string',label:''}],rp:[{id:'r2a',type:'exec',label:'stun'},{id:'r2b',type:'exec',label:'armour_break'},{id:'r2c',type:'exec',label:'lifesteal'},{id:'r2d',type:'exec',label:'fire'}]},{id:'n3',type:'melee',title:'Apply Stun',x:327,y:4,w:118,lp:[{id:'l3e',type:'exec',label:''},{id:'l3d',type:'float',label:'Duration(s)'}],vf:{hint:'Stun secs (e.g. 1.2)',val:''}},{id:'n4',type:'melee',title:'Reduce Armour\n-3',x:327,y:76,w:118,lp:[{id:'l4',type:'exec',label:''}]}],[{f:'r1e',t:'l2e'},{f:'r1s',t:'l2s'},{f:'r2a',t:'l3e'},{f:'r2b',t:'l4'}],[{id:'n3',ok:v=>parseFloat(v)>=0.3&&parseFloat(v)<=3}],'melee-t'), boxes:[{t:'box-melee',tx:'Stun (Mace/Hammer): freeze enemy briefly. Armour Break (Axes): -3 to target armour. Lifesteal (Shadowfang): restore HP on hit. Fire (Hell Blade): burn DoT (3×4 ticks). Pierce (Rapier): arc extends through.'}], onApply(v){sout('✅ Melee specials active! Stun: '+v['n3']+'s.');}}, {title:'Melee Drops, Amber Orbs
- Melee drops as AMBER orbs. Auto-equip if higher DPS (damage × atkSpeed). Walk over to pick up.

## STEP 12 · 🪄 WAND - On Melee Drop\nOverlap Hero',x:4,y:28,w:152,rp:[{id:'r1e',type:'exec',label:''},{id:'r1w',type:'object',label:'Weapon'}]},{id:'n2',type:'melee',title:'Get DPS\n(dmg×atkSpd)',x:177,y:8,w:145,lp:[{id:'l2w',type:'object',label:'Weapon'}],rp:[{id:'r2n',type:'float',label:'New'},{id:'r2o',type:'float',label:'Old'}]},{id:'n3',type:'math',title:'> Greater',x:342,y:8,w:104,lp:[{id:'l3a',type:'float',label:'New'},{id:'l3b',type:'float',label:'Old'}],rp:[{id:'r3',type:'bool',label:'Better?'}]},{id:'n4',type:'branch',title:'Branch',x:466,y:8,w:72,lp:[{id:'l4e',type:'exec',label:''},{id:'l4c',type:'bool',label:''}],rp:[{id:'r4t',type:'exec',label:'Equip'},{id:'r4f',type:'exec',label:'Skip'}]}],[{f:'r1e',t:'l4e'},{f:'r2n',t:'l3a'},{f:'r2o',t:'l3b'},{f:'r3',t:'l4c'}],[],'melee-t'), boxes:[{t:'box-melee',tx:'Rapier (8dmg, 0.18s) = 44 DPS. Greatsword (22dmg, 0.8s) = 27.5 DPS. Speed wins on raw DPS, but specials make slower weapons situationally better.'}], onApply(){sout('✅ Melee drops active! Amber orbs = melee weapons.');}}, // --- WANDS --- {title:'Wand System, Magic Orb
- Connect On LMB ? Get Direction ? Spawn Magic Orb with AoE Radius and Element. Wands fire slow orbs that explode with elemental effects.

## STEP 13 · 🪄 WAND - On LMB Pressed',x:4,y:28,w:145,rp:[{id:'r1',type:'exec',label:''}]},{id:'n2',type:'func',title:'Get Cursor Direction',x:169,y:8,w:148,lp:[{id:'l2e',type:'exec',label:''}],rp:[{id:'r2e',type:'exec',label:''},{id:'r2d',type:'vec3',label:'Dir'}]},{id:'n3',type:'wand',title:'Spawn Magic Orb',x:337,y:8,w:150,lp:[{id:'l3e',type:'exec',label:''},{id:'l3d',type:'vec3',label:'Dir'},{id:'l3s',type:'float',label:'Speed'}],rp:[{id:'r3',type:'exec',label:''}],vf:{hint:'Orb speed 200-600',val:''}},{id:'n4',type:'wand',title:'Set Element\n+ AoE',x:507,y:8,w:31,lp:[{id:'l4e',type:'exec',label:''}]}],[{f:'r1',t:'l2e'},{f:'r2e',t:'l3e'},{f:'r2d',t:'l3d'},{f:'r3',t:'l4e'}],[{id:'n3',ok:v=>parseFloat(v)>=100&&parseFloat(v)<=1000}],'wand-t'), boxes:[{t:'box-wand',tx:'Wand Pool (10): Apprentice Wand · Fire Staff · Ice Shard · Lightning Rod · Chaos Wand · Bone Staff · Poison Orb · Holy Symbol · Void Sceptre · Storm Wand. Elements: arcane, fire, ice, lightning, chaos, necro, nature, holy, void.'}], onApply(){G.f_attack=true;sout('✅ Wand orbs active! Purple glowing projectile.');}}, {title:'Wand Stats, Damage, Cast & AoE
- Connect BeginPlay ? Set WandDamage ? Set CastTime ? Set AoERadius. AoE 0 = single target. AoE 50 = massive room blast.

## STEP 14 · 🪄 WAND - Event BeginPlay',x:6,y:36,w:148,rp:[{id:'r1',type:'exec',label:''}]},{id:'n2',type:'wand',title:'Set Damage',x:175,y:12,w:115,lp:[{id:'l2e',type:'exec',label:''},{id:'l2v',type:'int',label:'Dmg'}],rp:[{id:'r2',type:'exec',label:''}],vf:{hint:'Dmg 8-28 (e.g. 12)',val:''}},{id:'n3',type:'wand',title:'Set Cast Time',x:310,y:12,w:120,lp:[{id:'l3e',type:'exec',label:''},{id:'l3v',type:'float',label:'Cast(s)'}],rp:[{id:'r3',type:'exec',label:''}],vf:{hint:'0.4-1.0 (e.g. 0.5)',val:''}},{id:'n4',type:'wand',title:'Set AoE Radius',x:450,y:12,w:88,lp:[{id:'l4e',type:'exec',label:''}],vf:{hint:'AoE 0-60 (e.g. 0)',val:''}}],[{f:'r1',t:'l2e'},{f:'r2',t:'l3e'},{f:'r3',t:'l4e'}],[{id:'n2',ok:v=>parseInt(v)>=3&&parseInt(v)parseFloat(v)>=0.2&&parseFloat(v)parseInt(v)>=0&&parseInt(v)<=80}],'wand-t'), boxes:[{t:'box-wand',tx:'Chaos Wand (AoE 52) can clear an entire room. But secondary targets take 60% damage and the cast time is 0.8s. Pure power vs timing, the tradeoff defines the weapon.'}], onApply(v){const w={...WAND_POOL[0]};w.dmg=parseInt(v['n2'])||12;w.castTime=parseFloat(v['n3'])||.5;w.aoeR=parseInt(v['n4'])||0;if(!G.p.weapon){G.p.weapon=w;G.p.weaponType='wand';updateHUD();}sout('✅ Wand: '+v['n2']+'dmg, '+v['n3']+'s, AoE '+v['n4']+'px!');}}, {title:'Wand Elements, Status Effects
- Connect On Orb Hit ? Switch on Element ? Apply Status Effect. Fire burns, ice freezes, lightning chains, void drains, holy heals.

## STEP 15 · 🪄 WAND - On Orb Hit',x:4,y:28,w:130,rp:[{id:'r1e',type:'exec',label:''},{id:'r1el',type:'string',label:'Element'}]},{id:'n2',type:'func',title:'Switch on Element',x:154,y:8,w:145,lp:[{id:'l2e',type:'exec',label:''},{id:'l2s',type:'string',label:''}],rp:[{id:'r2a',type:'exec',label:'fire'},{id:'r2b',type:'exec',label:'ice'},{id:'r2c',type:'exec',label:'lightning'},{id:'r2d',type:'exec',label:'void'}]},{id:'n3',type:'wand',title:'Burn DoT\n3×4 ticks',x:319,y:4,w:118,lp:[{id:'l3',type:'exec',label:''}]},{id:'n4',type:'wand',title:'Freeze\n1.5s',x:319,y:56,w:118,lp:[{id:'l4',type:'exec',label:''}]},{id:'n5',type:'wand',title:'Chain\n+2 enemies',x:319,y:108,w:118,lp:[{id:'l5',type:'exec',label:''}]}],[{f:'r1e',t:'l2e'},{f:'r1el',t:'l2s'},{f:'r2a',t:'l3'},{f:'r2b',t:'l4'},{f:'r2c',t:'l5'}],[],'wand-t'), boxes:[{t:'box-wand',tx:'Fire ? burn (3×4 ticks). Ice ? freeze (1.5s). Lightning ? chain to 2 nearest at 70%. Poison ? 2×6 ticks. Holy ? +10 HP on cast. Void ? steal 8 HP from target.'}], onApply(){sout('✅ Elemental effects wired!');}}, {title:'Wand Drops, Purple Orbs
- Wands drop as PURPLE orbs. Score = dmg × castTime × (1+aoeR/40). Walk over to auto-equip.

## STEP 16 · ENEMIES - On Wand Drop\nOverlap Hero',x:4,y:28,w:152,rp:[{id:'r1e',type:'exec',label:''},{id:'r1w',type:'object',label:'Wand'}]},{id:'n2',type:'wand',title:'Get Score\n(dmg×cast×aoe)',x:177,y:8,w:152,lp:[{id:'l2w',type:'object',label:'Wand'}],rp:[{id:'r2n',type:'float',label:'New'},{id:'r2o',type:'float',label:'Old'}]},{id:'n3',type:'math',title:'> Greater',x:349,y:8,w:104,lp:[{id:'l3a',type:'float',label:'New'},{id:'l3b',type:'float',label:'Old'}],rp:[{id:'r3',type:'bool',label:'Better?'}]},{id:'n4',type:'branch',title:'Branch',x:473,y:8,w:65,lp:[{id:'l4e',type:'exec',label:''},{id:'l4c',type:'bool',label:''}],rp:[{id:'r4t',type:'exec',label:'Equip'},{id:'r4f',type:'exec',label:'Skip'}]}],[{f:'r1e',t:'l4e'},{f:'r2n',t:'l3a'},{f:'r2o',t:'l3b'},{f:'r3',t:'l4c'}],[],'wand-t'), boxes:[{t:'box-wand',tx:'Any kill can drop any weapon type. Start with a crossbow, find a greatsword by room 3, switch to a Chaos Wand in room 6. Each weapon completely changes how you play.'}], onApply(){sout('✅ Wand drops active! Purple orbs = wands.');}}, // --- DUNGEON SYSTEMS --- {title:'Enemy Spawn, Room Population
- Connect On Room Load ? For Loop ? Spawn Enemies. Enemies spawn in the right half of each room so you always have a moment to orient.

## STEP 17 · ENEMIES - On Room Loaded',x:4,y:28,w:148,rp:[{id:'r1e',type:'exec',label:''}]},{id:'n2',type:'func',title:'For Loop\n0×Count',x:172,y:8,w:128,lp:[{id:'l2e',type:'exec',label:''},{id:'l2c',type:'int',label:'Count'}],rp:[{id:'r2e',type:'exec',label:'Loop Body'}],vf:{hint:'Base count (e.g. 5)',val:''}},{id:'n3',type:'func',title:'Get Random\nSpawn Point',x:320,y:8,w:148,lp:[{id:'l3e',type:'exec',label:''}],rp:[{id:'r3e',type:'exec',label:''},{id:'r3p',type:'vec3',label:'Pos'}]},{id:'n4',type:'func',title:'Spawn Enemy\nAt Location',x:488,y:8,w:50,lp:[{id:'l4e',type:'exec',label:''},{id:'l4p',type:'vec3',label:'Pos'}]}],[{f:'r1e',t:'l2e'},{f:'r2e',t:'l3e'},{f:'r3e',t:'l4e'},{f:'r3p',t:'l4p'}],[{id:'n2',ok:v=>parseInt(v)>=1&&parseInt(v)<=15}]), boxes:[{t:'box-c',tx:'Enemy pool: Floor 1-2: Fallen, Skeleton. Floor 3-4: Goatman, Soul. Floor 5-6: Succubus, Stone Demon. Boss floors (every 5th): Lich King ? Dungeon Wyrm ? Diablo.'}], onApply(v){G.f_enemies=true;loadRoom();sout('✅ Enemies spawning! ~'+v['n2']+' per room.');}}, {title:'Enemy AI, Chase the Hero
- Connect Event Tick ? Normalize Direction toward Hero ? Move Actor. Every enemy always chases the player. Separate-axis collision, they slide along walls.

## STEP 18 · ENEMIES - Event Tick',sub:'BP_Enemy',x:4,y:22,w:130,rp:[{id:'r1e',type:'exec',label:''}]},{id:'n2',type:'func',title:'Get Hero Location',x:154,y:8,w:148,lp:[{id:'l2e',type:'exec',label:''}],rp:[{id:'r2e',type:'exec',label:''},{id:'r2l',type:'vec3',label:'Loc'}]},{id:'n3',type:'math',title:'Normalize\nDir to Hero',x:322,y:8,w:128,lp:[{id:'l3t',type:'vec3',label:'Target'},{id:'l3s',type:'vec3',label:'Self'}],rp:[{id:'r3',type:'vec3',label:'Dir'}]},{id:'n4',type:'func',title:'Move × Speed\n · Delta',x:470,y:8,w:68,lp:[{id:'l4e',type:'exec',label:''},{id:'l4v',type:'vec3',label:'Dir'}]}],[{f:'r1e',t:'l2e'},{f:'r2e',t:'l4e'},{f:'r2l',t:'l3t'},{f:'r3',t:'l4v'}],[]), boxes:[{t:'box-c',tx:'Simple AI is more dangerous than it looks. 10 enemies filling a pillared chamber from all sides, your weapon choice decides if you survive. Guns thin at range, wand AoE clears clusters, melee when they close in.'}], onApply(){sout('✅ Enemy AI active!');}}, {title:'Enemy Scaling, Floor Difficulty
- Connect × 0.07 + 1 ? Multiply Base Enemy Stats. Every floor is ×7% harder than the last.

## STEP 19 · LOOT - Get Floor',x:4,y:20,w:105,rp:[{id:'r1',type:'int',label:''}]},{id:'n2',type:'math',title:'× 0.07',x:129,y:6,w:90,lp:[{id:'l2a',type:'int',label:'Floor'}],rp:[{id:'r2',type:'float',label:'Bonus'}]},{id:'n3',type:'math',title:'+ 1.0',x:239,y:6,w:86,lp:[{id:'l3a',type:'float',label:'1'},{id:'l3b',type:'float',label:'Bonus'}],rp:[{id:'r3',type:'float',label:'Mult'}]},{id:'n4',type:'math',title:'× BaseHP',x:345,y:6,w:110,lp:[{id:'l4a',type:'int',label:'BaseHP'},{id:'l4b',type:'float',label:'Mult'}],rp:[{id:'r4',type:'int',label:'ScaledHP'}]}],[{f:'r1',t:'l2a'},{f:'r2',t:'l3b'},{f:'r3',t:'l4b'}],[]), boxes:[{t:'box-d',tx:'Floor 1 Fallen = 18HP. Floor 10 Fallen = 18×1.7 = 31HP. Stone Demon at floor 8 = 85×1.56 = 133HP. Your loot and levels must outpace this, that\'s the ARPG loop.'}], onApply(){sout('✅ Enemy scaling wired!');}}, {title:'Loot, All Three Types Drop
- Connect On Enemy Killed ? 38% Chance ? Roll Type (gun/melee/wand 33% each) ? Spawn Coloured Orb.

## STEP 20 · LOOT - On Enemy Killed',x:4,y:30,w:142,rp:[{id:'r1e',type:'exec',label:''}]},{id:'n2',type:'func',title:'Random Float\n0-1',x:166,y:10,w:118,lp:[{id:'l2e',type:'exec',label:''}],rp:[{id:'r2e',type:'exec',label:''},{id:'r2f',type:'float',label:'Roll'}]},{id:'n3',type:'math',title:'< 0.38\nDrop?',x:304,y:10,w:110,lp:[{id:'l3a',type:'float',label:'Roll'}],rp:[{id:'r3',type:'bool',label:'Drop?'}]},{id:'n4',type:'branch',title:'Branch',x:434,y:10,w:100,lp:[{id:'l4e',type:'exec',label:''},{id:'l4c',type:'bool',label:''}],rp:[{id:'r4t',type:'exec',label:'Drop!'},{id:'r4f',type:'exec',label:''}]}],[{f:'r1e',t:'l2e'},{f:'r2e',t:'l4e'},{f:'r2f',t:'l3a'},{f:'r3',t:'l4c'}],[]), boxes:[{t:'box-r',tx:'Roll type after branching: 0-0.33 ? gun (blue glow), 0.34-0.66 ? melee (amber), 0.67-1.0 ? wand (purple). Three runs in a row can give completely different weapon journeys.'}], onApply(){G.f_loot=true;sout('✅ Ground loot drops active! Blue=gun, Amber=melee, Purple=wand.');}}, {title:'Treasure Chests, Double Drop
- Chests drop 2 weapon orbs when hit by any attack or clicked. Connect On Chest Hit ? Spawn 2 Weapon Drops + Gold.

## STEP 21 · PROGRESSION - On Chest Hit',x:4,y:28,w:145,rp:[{id:'r1',type:'exec',label:''}]},{id:'n2',type:'branch',title:'Branch !Open',x:169,y:10,w:100,lp:[{id:'l2e',type:'exec',label:''},{id:'l2c',type:'bool',label:'!Open'}],rp:[{id:'r2t',type:'exec',label:'Open'},{id:'r2f',type:'exec',label:'Skip'}]},{id:'n3',type:'func',title:'Spawn 2 Weapon\nDrops',x:289,y:10,w:155,lp:[{id:'l3e',type:'exec',label:''}],rp:[{id:'r3',type:'exec',label:''}]},{id:'n4',type:'loot',title:'Spawn Gold\nDrop',x:464,y:10,w:74,lp:[{id:'l4e',type:'exec',label:''}]}],[{f:'r1',t:'l2e'},{f:'r2t',t:'l3e'},{f:'r3',t:'l4e'}],[]), boxes:[{t:'box-c',tx:'Chest drops two weapon orbs, always different types. Never two guns from one chest. Mid-room chests can swing the entire run if you find a Hell Blade or Chaos Wand early.'}], onApply(){sout('✅ Chests active! Hit them to explode loot.');}}, {title:'XP & Level Up
- On Enemy Killed ? Add XP ? Branch (= Threshold) ? Level Up. Every level: +10 MaxHP, +1 Armour, ×1.6.

## STEP 22 · SURVIVAL - On Enemy Killed',x:4,y:28,w:142,rp:[{id:'r1e',type:'exec',label:''},{id:'r1x',type:'int',label:'XP'}]},{id:'n2',type:'math',title:'+ Add XP',x:166,y:10,w:100,lp:[{id:'l2a',type:'int',label:'Total'},{id:'l2b',type:'int',label:'Gain'}],rp:[{id:'r2e',type:'exec',label:''},{id:'r2x',type:'int',label:'New'}]},{id:'n3',type:'math',title:'>= Threshold',x:286,y:10,w:118,lp:[{id:'l3a',type:'int',label:'XP'},{id:'l3b',type:'int',label:'Thresh'}],rp:[{id:'r3',type:'bool',label:'LvlUp?'}]},{id:'n4',type:'branch',title:'Branch',x:424,y:10,w:100,lp:[{id:'l4e',type:'exec',label:''},{id:'l4c',type:'bool',label:''}],rp:[{id:'r4t',type:'exec',label:'Lvl Up!'},{id:'r4f',type:'exec',label:''}]}],[{f:'r1e',t:'l2e'},{f:'r1x',t:'l2b'},{f:'r2e',t:'l4e'},{f:'r2x',t:'l3a'},{f:'r3',t:'l4c'}],[]), boxes:[{t:'box-c',tx:'XP bar fills at the bottom of the screen. Level up = gold particle burst. Fallen 12xp, Stone Demon 75xp, bosses 400-800xp. First level at 100xp, a few clears.'}], onApply(){sout('✅ XP active! Watch the gold bar at the bottom.');}}, {title:'Health Potion (H Key)
- Connect H key ? Branch potions > 0 ? Heal % MaxHP. Start with 3 potions. Type heal percentage.

## STEP 23 · DUNGEON - IA_Potion (H)',x:4,y:28,w:135,rp:[{id:'r1',type:'exec',label:''}]},{id:'n2',type:'math',title:'Potions > 0',x:159,y:10,w:110,lp:[{id:'l2a',type:'int',label:'Potions'},{id:'l2b',type:'int',label:'0'}],rp:[{id:'r2',type:'bool',label:''}]},{id:'n3',type:'branch',title:'Branch',x:289,y:10,w:100,lp:[{id:'l3e',type:'exec',label:''},{id:'l3c',type:'bool',label:''}],rp:[{id:'r3t',type:'exec',label:'Drink'},{id:'r3f',type:'exec',label:'Empty'}]},{id:'n4',type:'func',title:'Heal % MaxHP',x:409,y:10,w:129,lp:[{id:'l4e',type:'exec',label:''},{id:'l4p',type:'float',label:'Percent'}],vf:{hint:'Heal % 0.3-0.6 (e.g. 0.4)',val:''}}],[{f:'r1',t:'l3e'},{f:'r2',t:'l3c'},{f:'r3t',t:'l4e'}],[{id:'n4',ok:v=>parseFloat(v)>=0.1&&parseFloat(v)<=0.9}]), boxes:[{t:'box-t',tx:'Potion timing is the biggest skill expression in ARPGs. Too early = wasted. Too late = dead. Three starting potions plus drops creates constant resource tension.'}], onApply(v){sout('✅ H key: potion restores '+Math.round(parseFloat(v['n4'])*100)+'% HP.');}}, {title:'Stairs, Advance to Next Room
- Walk into the purple ? stairs glyph to advance. Must clear enemies first. Connects On Stairs Overlap ? Check Cleared ? Load Next Room.

## STEP 24 · BOSS - On Stairs Overlap',x:4,y:28,w:150,rp:[{id:'r1',type:'exec',label:''}]},{id:'n2',type:'vget',title:'Get bCleared',x:174,y:10,w:118,rp:[{id:'r2',type:'bool',label:'Cleared?'}]},{id:'n3',type:'branch',title:'Branch',x:312,y:10,w:100,lp:[{id:'l3e',type:'exec',label:''},{id:'l3c',type:'bool',label:''}],rp:[{id:'r3t',type:'exec',label:'Advance'},{id:'r3f',type:'exec',label:'Fight!'}]},{id:'n4',type:'func',title:'Load Next Room\n(Increment Floor)',x:432,y:10,w:106,lp:[{id:'l4e',type:'exec',label:''}]}],[{f:'r1',t:'l3e'},{f:'r2',t:'l3c'},{f:'r3t',t:'l4e'}],[]), boxes:[{t:'box-r',tx:'Stairs glyph appears on the right wall, glows purple when all enemies are dead (usable), dimmed red when enemies remain. Boss floors every 5 rooms, the Lich King, Dungeon Wyrm, then Diablo.'}], onApply(){G.f_stairs=true;loadRoom();sout('✅ Stairs active! Clear the room then walk into ▼ to advance.');}}, {title:'Boss Rooms, Every 5th Floor
- Connect Floor % 5 == 0 ? Spawn Boss in a wide-open chamber. Boss drops triple loot on death.

## STEP 25 · POLISH - Get Floor',x:4,y:20,w:105,rp:[{id:'r1',type:'int',label:''}]},{id:'n2',type:'math',title:'% 5',x:129,y:6,w:82,lp:[{id:'l2a',type:'int',label:'Floor'},{id:'l2b',type:'int',label:'5'}],rp:[{id:'r2',type:'int',label:'Rem'}]},{id:'n3',type:'math',title:'== 0',x:231,y:6,w:82,lp:[{id:'l3a',type:'int',label:'Rem'},{id:'l3b',type:'int',label:'0'}],rp:[{id:'r3',type:'bool',label:'Boss?'}]},{id:'n4',type:'branch',title:'Branch',x:333,y:6,w:100,lp:[{id:'l4e',type:'exec',label:''},{id:'l4c',type:'bool',label:''}],rp:[{id:'r4t',type:'exec',label:'Boss!'},{id:'r4f',type:'exec',label:'Normal'}]},{id:'n5',type:'func',title:'Spawn Boss\n+ Boss HUD',x:453,y:6,w:85,lp:[{id:'l5',type:'exec',label:''}]}],[{f:'r1',t:'l2a'},{f:'r2',t:'l3a'},{f:'r3',t:'l4c'},{f:'r4t',t:'l5'}],[]), boxes:[{t:'box-d',tx:'Floor 5 = Lich King (250HP). Floor 10 = Dungeon Wyrm (320HP). Floor 15+ = DIABLO (500HP, 30ATK). Diablo drops a gun, melee AND wand on death, the biggest loot event in the game.'}], onApply(){sout('✅ Boss rooms active! Something enormous waits every 5 floors.');}}, {title:'Camera Shake + Blood FX
- Connect On Damage Applied ? Scale Shake ? Play Camera Shake. Every hit should feel visceral.

## STEP 26 · POLISH - On Damage Applied',x:4,y:28,w:148,rp:[{id:'r1e',type:'exec',label:''},{id:'r1d',type:'float',label:'Damage'}]},{id:'n2',type:'math',title:'Clamp\nDmg/8?0.1-2',x:172,y:10,w:122,lp:[{id:'l2v',type:'float',label:'Dmg/8'}],rp:[{id:'r2',type:'float',label:'Scale'}]},{id:'n3',type:'func',title:'Play Camera\nShake',x:314,y:10,w:150,lp:[{id:'l3e',type:'exec',label:''},{id:'l3s',type:'float',label:'Scale'},{id:'l3d',type:'float',label:'Duration'}],vf:{hint:'Duration (e.g. 0.12)',val:''}},{id:'n4',type:'func',title:'Spawn Blood\nParticles',x:484,y:10,w:54,lp:[{id:'l4e',type:'exec',label:''}]}],[{f:'r1e',t:'l3e'},{f:'r1d',t:'l2v'},{f:'r2',t:'l3s'},{f:'r3',t:'l4e'}],[{id:'n3',ok:v=>parseFloat(v)>=0.05&&parseFloat(v)<=0.5}]), boxes:[{t:'box-t',tx:'ARPG impact formula: particle burst + camera shake + damage number = satisfying kill. All three must fire every hit, regardless of weapon type.'}], onApply(v){shake(5,8);sout('✅ Camera shake active! '+v['n3']+'s duration.');}}, {title:'Damage Numbers
- On Damage Applied ? Spawn Floating Text ? Float Up ? Fade. White = normal, yellow = critical. The signature of the ARPG genre.

## STEP 27 · COMBAT - On Damage Applied',x:4,y:28,w:150,rp:[{id:'r1e',type:'exec',label:''},{id:'r1d',type:'float',label:'Damage'},{id:'r1c',type:'bool',label:'isCrit'}]},{id:'n2',type:'branch',title:'Branch (isCrit)',x:175,y:10,w:100,lp:[{id:'l2e',type:'exec',label:''},{id:'l2c',type:'bool',label:''}],rp:[{id:'r2t',type:'exec',label:'Crit'},{id:'r2f',type:'exec',label:'Normal'}]},{id:'n3',type:'func',title:'Spawn Yellow\nCrit Number',x:295,y:8,w:138,lp:[{id:'l3e',type:'exec',label:''},{id:'l3d',type:'float',label:'Dmg'}]},{id:'n4',type:'func',title:'Spawn White\nNormal Number',x:295,y:78,w:138,lp:[{id:'l4e',type:'exec',label:''},{id:'l4d',type:'float',label:'Dmg'}]}],[{f:'r1e',t:'l2e'},{f:'r1c',t:'l2c'},{f:'r2t',t:'l3e'},{f:'r2f',t:'l4e'}],[]), boxes:[{t:'box-c',tx:'Damage numbers float up 60px over 0.8s then fade. Crits are 1.5× larger and yellow. Seeing that big yellow number is one of the best moments in any ARPG, never skip this step.'}], onApply(){sout('✅ Damage numbers wired!');}}, {title:'Critical Hits
- On Calculate Damage ? Random Float ? Less Than CritChance ? Branch ? Multiply × 2. Type crit chance (0-1).

## STEP 28 · SCORING - On Calc Damage',x:4,y:28,w:142,rp:[{id:'r1e',type:'exec',label:''},{id:'r1d',type:'float',label:'BaseDmg'}]},{id:'n2',type:'func',title:'Random Float\n0-1',x:166,y:10,w:118,lp:[{id:'l2e',type:'exec',label:''}],rp:[{id:'r2e',type:'exec',label:''},{id:'r2f',type:'float',label:'Roll'}]},{id:'n3',type:'math',title:'parseFloat(v)>=0&&parseFloat(v)<=1}]), boxes:[{t:'box-c',tx:'15% crit × 2× = 30% average damage bonus. The big yellow number on a crit, even expected, is satisfying every single time.'}], onApply(v){sout('✅ Crits active! '+Math.round(parseFloat(v['n3'])*100)+'% chance.');}}, {title:'Gold Economy
- On Enemy Killed ? Add Gold Drop (random range) ? Update HUD. Gold is your run score, bosses drop 30-100.

## STEP 29 · DUNGEON - On Enemy Killed',x:4,y:28,w:142,rp:[{id:'r1e',type:'exec',label:''}]},{id:'n2',type:'func',title:'Get Gold Drop\n(Rand Range)',x:166,y:8,w:155,lp:[{id:'l2e',type:'exec',label:''}],rp:[{id:'r2e',type:'exec',label:''},{id:'r2g',type:'int',label:'Gold'}]},{id:'n3',type:'math',title:'+ Add\nTo Total',x:341,y:8,w:110,lp:[{id:'l3a',type:'int',label:'Total'},{id:'l3b',type:'int',label:'Drop'}],rp:[{id:'r3',type:'int',label:'New'}]},{id:'n4',type:'func',title:'Update Gold\nHUD',x:471,y:8,w:67,lp:[{id:'l4e',type:'exec',label:''},{id:'l4v',type:'int',label:'Gold'}]}],[{f:'r1e',t:'l2e'},{f:'r2e',t:'l4e'},{f:'r2g',t:'l3b'},{f:'r3',t:'l4v'}],[]), boxes:[{t:'box-r',tx:'Gold drops: Fallen 1-4, Skeleton 2-6, Goatman 4-10, Succubus 5-12, Stone Demon 8-20, Bosses 30-100. Plus gold bag drops (22% chance). Boss kills make you rich, if you survive.'}], onApply(){sout('✅ Gold economy active!');}}, {title:'Room Variety, 6 Dungeon Types
- The dungeon has 6 room types: Entrance Hall, Pillared Chamber, Dungeon Corridors, Boss Chamber, Ancient Crypt, Throne Room. Each has different wall layouts and chest chances.

## STEP 30 · LAUNCH - On Load Room',x:4,y:28,w:145,rp:[{id:'r1',type:'exec',label:''}]},{id:'n2',type:'func',title:'Pick Random\nRoom Def',x:169,y:8,w:148,lp:[{id:'l2e',type:'exec',label:''}],rp:[{id:'r2e',type:'exec',label:''},{id:'r2d',type:'object',label:'Room Def'}]},{id:'n3',type:'func',title:'Carve Walls\nfrom Def',x:337,y:8,w:148,lp:[{id:'l3e',type:'exec',label:''},{id:'l3d',type:'object',label:'Def'}],rp:[{id:'r3e',type:'exec',label:''},{id:'r3w',type:'object',label:'Wall Array'}]},{id:'n4',type:'func',title:'Spawn\nEnemies + Chest',x:505,y:8,w:33,lp:[{id:'l4e',type:'exec',label:''}]}],[{f:'r1',t:'l2e'},{f:'r2e',t:'l3e'},{f:'r2d',t:'l3d'},{f:'r3e',t:'l4e'}],[]), boxes:[{t:'box-c',tx:'Room variety: Entrance Hall (open), Pillared Chamber (4 corner pillars), Corridors (horizontal barriers), Boss Chamber (wide open), Ancient Crypt (L-walls), Throne Room (8 corner columns). Boss rooms always use Boss Chamber.'}], onApply(){sout('✅ Room variety wired!');}}, {title:'Descend Into Hell ?
- Every system is live. WASD movement, three weapon types with loot drops, enemies, XP, bosses. Press Begin Descent or Quick Descent for an instant random run.
