Spell Light Burst

BlackRose

Forum User
Reaction score
239
Light Burst v1.02 by BlackRose

Last updated: 25th May 2009​

Compresses nearby light energy. When this energy can no longer be more compressed, the energy explodes outwards, dealing damage to enemy units hit by the light nova and pushing them back.
Channeling


CODE: vJASS
LEAKS: Most likely no.
LAGS: Not for me it does not.
MUI: Yes.

*Needs PUI
*Needs TimerUtils
*Needs NewGen

SCREENSHOT: <Please, screenshots aren't 100%, test it!>
lightburstnew.jpg
CODE:
JASS:
scope LightBurst initializer Init

//-------------------------------------------------------------
//                Light Burst v1.02 by BlackRose                  
//-------------------------------------------------------------

// WHAT is this spell?
//---------------------------
// ... A remake of an old spell I made called Light Burst.

// I want this spell?
//---------------------------
// ...You need NewGen.

// How do I put it in my map?
//---------------------------
// ... 1. Copy this trigger, TimerUtils and PUI (if you don&#039;t have it already) into your map.
// ... 2. Copy the ability and dummy unit into your map.
// ... 3. Press CTRL + D while in Abilities section in Object Editor to find out the rawcode
// .......of the Light Burst you just pasted, change SPELL_ID to what you find, as well as the dummy unit.
// ... 4. You have imported it! HOORAY!

// Changelog:
//---------------------------
// v1.00:
// ... Initial release.

// v1.01:
// ... Now using PUI to trigger the channelling part.
// ... Updated code.

// v1.02:
// ... Small changes to code.
//---------------------------

// Credits:
//---------------------------
// - Cohadar for PUI.
// - Vexorian for TimerUtils.
// - Creators of JassNewGen.
//---------------------------
// TheHelper.net

// Easier testing.
private function DEBUG takes string s returns nothing
    call DisplayTimedTextToPlayer( Player(0), 0, 0, 1.500, s )
endfunction

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//                             LIST OF CONFIGURABLES
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
    globals
private constant boolean IS_CHANNEL = true //&lt;-- Is the ability channelling? If false, I suggest you also set the
                                           // field in the ability&#039;s Follow Through Time to smaller.

private constant integer SPELL_ID = &#039;A001&#039; //&lt;-- Object rawcodes.
private constant integer DUMMY_ID = &#039;e000&#039; 
private constant string  SPELL_STRING = &quot;channel&quot; //&lt;-- OrderID of spell.

private constant real TIMER_INTERVAL = 0.03 //&lt;-- Timer interval.

private constant real    COMPRESS_AREA          = 600. //&lt;-- How far the light missiles are from when cast. Only for effect.
private constant integer COMPRESS_LIGHT_AMOUNT  = 12     //&lt;-- How many dummy missiles. Only for effect.
private constant real    COMPRESS_DURATION      = 2.00   //&lt;-- How long it take to spin inwards. How long channel.

private constant real    COMPRESS_SPIRAL_ANGLE  = 60 * bj_DEGTORAD //&lt;-- Recommended to be between 0 - 70.
                                                                   // 0 being straight inwards, while above 80 will look weird.

private constant real      EXPLOSION_AOE         = 100.00 //&lt;-- Radius of lines, enemy units will be dragged by. Common sense.
private constant integer   EXPLOSION_LINE_AMOUNT = 9      //&lt;-- How many lines of booms ther are. Too many might cause lag.
private constant string    EXPLOSION_EFFECT      = &quot;Abilities\\Weapons\\FaerieDragonMissile\\FaerieDragonMissile.mdl&quot;
private constant real      EXPLOSION_DISTANCE    = 700.00 //&lt;-- Distance of explosion. 
private constant real      EXPLOSION_SPEED       = 40.00  //&lt;-- How fast it goes.

// (Below) Damage properties.
private constant boolean ATTACK = true
private constant boolean RANGED = false
private constant attacktype ATK_TYPE = ATTACK_TYPE_NORMAL
private constant damagetype DMG_TYPE = DAMAGE_TYPE_MAGIC
private constant weapontype WPN_TYPE = null
    endglobals
    
// GetDamage: Level * 75 = 75/150/225/300
    private function GetDamage takes integer Level returns real
        return Level * 75.00
    endfunction
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

globals
    private constant real    COMPRESS_SPEED  = ( 2.00 * COMPRESS_AREA ) / ( COMPRESS_DURATION / TIMER_INTERVAL ) + 1.00

    private constant real COMPRESS_ANG_DIFF  = ( 360 / COMPRESS_LIGHT_AMOUNT ) * bj_DEGTORAD
    private constant real EXPLOSION_ANG_DIFF = ( 360 / EXPLOSION_LINE_AMOUNT ) * bj_DEGTORAD

    private player TempPlayer
endglobals

private function Cond takes nothing returns boolean
    return GetSpellAbilityId() == SPELL_ID
endfunction

private function UFilter takes nothing returns boolean
    return IsUnitType( GetFilterUnit(), UNIT_TYPE_DEAD ) == false and IsUnitEnemy( GetFilterUnit(), TempPlayer ) and IsUnitType( GetFilterUnit(), UNIT_TYPE_STRUCTURE ) == false
endfunction

private struct ReleaseData
    unit Caster
    real ExplosionDist = 0.00
    player owner
    group array SlideGroup[COMPRESS_LIGHT_AMOUNT]
    group       TempGroup
    
    timer rt
    real rCX
    real rCY
    
    integer rLevel
    method onDestroy takes nothing returns nothing
        debug call DEBUG( &quot;|cffff0000ReleaseData destroyed!|r&quot; )
    endmethod
    
    static method Release takes nothing returns nothing
        local ReleaseData e = GetTimerData( GetExpiredTimer() )
        
        local integer i = 0
        local real x
        local real y
        
        local unit u
        
        set e.ExplosionDist = e.ExplosionDist + EXPLOSION_SPEED
        debug call DEBUG( R2S( e.ExplosionDist ) )
        set TempPlayer = e.owner
        loop
            exitwhen i == EXPLOSION_LINE_AMOUNT
                                    
            set x = e.rCX + e.ExplosionDist * Cos( i * EXPLOSION_ANG_DIFF )
            set y = e.rCY + e.ExplosionDist * Sin( i * EXPLOSION_ANG_DIFF )
            
            call GroupEnumUnitsInRange( e.SlideGroup<i>, x, y, EXPLOSION_AOE, Condition( function UFilter ) )
            loop
                set u = FirstOfGroup( e.SlideGroup<i> )
                exitwhen u == null
                call GroupRemoveUnit( e.SlideGroup<i>, u )
                call SetUnitPosition( u, x, y )
                
                if IsUnitInGroup( u, e.TempGroup ) == false then
                    call GroupAddUnit( e.TempGroup, u )
                    call UnitDamageTarget( e.Caster, u, GetDamage( e.rLevel ), ATTACK, RANGED, ATK_TYPE, DMG_TYPE, WPN_TYPE )
                endif
            endloop
            
            call DestroyEffect( AddSpecialEffect( EXPLOSION_EFFECT, x, y ) )
            set i = i + 1
        endloop
        if e.ExplosionDist &gt; EXPLOSION_DISTANCE then
            set i = 0
                //------------------------------------------------------
                // Destroy groups.
                loop
                    exitwhen i == EXPLOSION_LINE_AMOUNT
                    call DestroyGroup( e.SlideGroup<i> )
                    set i = i + 1
                endloop
            call DestroyGroup( e.TempGroup )
            call ReleaseTimer( e.rt )
            call e.destroy()
        endif
    endmethod
endstruct

private struct Summon
    //! runtextmacro PUI()
    boolean FirstPhaseActive = true
    
    integer Level
    timer SummonTimer
    real TimeElapsed = 0.00
    player Owner
    unit Caster
    real CX
    real CY
    
    unit array LightMissile[COMPRESS_LIGHT_AMOUNT]
    real CompressDist = COMPRESS_AREA
    method onDestroy takes nothing returns nothing
        local integer i = 0
        debug call DEBUG( &quot;Spin inwards - ondestroy&quot; )
        call ReleaseTimer(.SummonTimer)    
        loop
            exitwhen i == COMPRESS_LIGHT_AMOUNT
            call KillUnit( .LightMissile<i> )
            set i = i + 1
        endloop
    endmethod    

    static method create takes nothing returns Summon
        local Summon d = Summon.allocate()
        local integer i = 0
        local real angDiff = 0
        local real x
        local real y
        
        set d.Caster = GetTriggerUnit()
        set d.SummonTimer = NewTimer()

        set d.Owner = GetOwningPlayer( d.Caster )
        set d.CX = GetUnitX( d.Caster )
        set d.CY = GetUnitY( d.Caster )
    
        set d.Level = GetUnitAbilityLevel( d.Caster, SPELL_ID )

        // Creation of the light missiles.
        loop
            exitwhen i == COMPRESS_LIGHT_AMOUNT
            set x = d.CX + COMPRESS_AREA * Cos( angDiff )
            set y = d.CY + COMPRESS_AREA * Sin( angDiff )
            set d.LightMissile<i> = CreateUnit( d.Owner, DUMMY_ID, x, y, 0.00 )
            // Useless? No.
            call SetUnitPosition( d.LightMissile<i>, x, y )
            
            set angDiff = angDiff + COMPRESS_ANG_DIFF
            set i = i + 1
        endloop
        
        return d
    endmethod
    
    static method Spin takes nothing returns nothing
        local integer i = 0
        
        local real angle
        local real x
        local real y
        local real dumx
        local real dumy

        local Summon d = GetTimerData( GetExpiredTimer() )
        local ReleaseData e
        
        set d.TimeElapsed = d.TimeElapsed + TIMER_INTERVAL        
        set d.CompressDist = d.CompressDist - COMPRESS_SPEED
        
        // Move inwards.
        loop
            exitwhen i == COMPRESS_LIGHT_AMOUNT
            
            set dumx = GetUnitX( d.LightMissile<i> )
            set dumy = GetUnitY( d.LightMissile<i> )
            
            set angle = Atan2( d.CY - dumy, d.CX - dumx ) + COMPRESS_SPIRAL_ANGLE
            set x = dumx + COMPRESS_SPEED * Cos( angle )
            set y = dumy + COMPRESS_SPEED * Sin( angle )
            call SetUnitPosition( d.LightMissile<i>, x, y )
            set i = i + 1
        endloop
        
        // Phase 2 start.
        set i = 0
        if d.TimeElapsed &gt;= COMPRESS_DURATION - 0.04 then
            set d.FirstPhaseActive = false
            loop
                exitwhen i == COMPRESS_LIGHT_AMOUNT
                call KillUnit( d.LightMissile<i> )
                set i = i + 1
            endloop

            
            // New struct things.
            set e = ReleaseData.create()
            set e.Caster = d.Caster
            set e.rt     = NewTimer()
            set e.TempGroup = CreateGroup()
            set e.owner = d.Owner
            set e.rLevel = d.Level
            set e.rCX = d.CX
            set e.rCY = d.CY
            set i = 0
            loop
                exitwhen i == EXPLOSION_LINE_AMOUNT
                set e.SlideGroup<i> = CreateGroup()
                set i = i + 1
            endloop
            
            call SetTimerData( e.rt,e )
            call TimerStart( e.rt, TIMER_INTERVAL, true, function ReleaseData.Release )
            
            //call ReleaseTimer( d.SummonTimer )
            call d.release()
        endif
    endmethod
endstruct

private function Main takes nothing returns nothing
    local integer i = 0
    local real angDiff = 0
    
    local real x
    local real y
    
    local unit u = GetTriggerUnit()

    local Summon d
    
    if GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_EFFECT then
        set d = Summon.create()
        set Summon<u> = d
        call SetTimerData( d.SummonTimer, d )
        call TimerStart( d.SummonTimer, TIMER_INTERVAL, true, function Summon.Spin )
    elseif GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_ENDCAST and IS_CHANNEL then
        set d = Summon<u>
        if d.FirstPhaseActive then
            call DEBUG( &quot;Spell cancelled!&quot; )
            call d.release()
        endif
    endif
    set u = null
endfunction


private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_ENDCAST )
    call TriggerAddCondition( t, Condition( function Cond ) )
    call TriggerAddAction( t, function Main )
endfunction

endscope</u></u></i></i></i></i></i></i></i></i></i></i></i></i>


JASS:
// Changelog:
//---------------------------
// v1.00:
// ... Initial release.

// v1.01:
// ... Now using PUI to trigger the channelling part.
// ... Updated code.

// v1.02:
// ... Small changes to code.
//---------------------------

// Credits:
//---------------------------
// - Cohadar for PUI.
// - Vexorian for TimerUtils.
// - Creators of JassNewGen.
//---------------------------
 

wraithseeker

Tired.
Reaction score
122
Why not use EVENT_PLAYER_UNIT_END_CAST and then use PUI to attach data for channeling effects? I think it's much more effective.
 

Romek

Super Moderator
Reaction score
964
> I've never used PUI, and I don't know how it works.
Learn :)
 

Kenny

Back for now.
Reaction score
202
Hmm, I suggest you try updating your other spell(s) first before submitting a new one that also needs a bit of work.

To be honest, by just looking at the script, I'm wondering if it even works.

JASS:
if IS_CHANNEL then
            if .FirstPhaseActive then
                if GetUnitCurrentOrder( .Caster ) != String2OrderIdBJ( SPELL_STRING ) then
                    loop
                        exitwhen i == COMPRESS_LIGHT_AMOUNT
                        call KillUnit( .LightMissile<i> )
                        set i = i + 1
                    endloop
                    call ReleaseTimer( .SummonTimer )
                    call d.destroy()
                endif
            endif
        endif

</i>


Right there, you destroy your struct, yet underneath you keep using it, either im missing something, or this just shouldn't work.

JASS:
local integer this = GetTimerData( GetExpiredTimer() )
local Summon d = this


Why? Maybe just:

JASS:
local Summon d = GetTimerData(GetExpiredTimer())


Your creating lots of groups for this spell, maybe using a global one will work better?

JASS:
            loop
                exitwhen i == EXPLOSION_LINE_AMOUNT
                set .SlideGroup<i> = CreateGroup() // Whats that, like 9 dynamic groups.
                set i = i + 1
            endloop

</i>


JASS:
elseif .TimeElapsed &gt;= COMPRESS_DURATION - 0.05then // Shwaa?
    set .FirstPhaseActive = false
endif


a) Does that even compile?

b) Whats it used for? Your already setting that member to false above in the if block. If you want to do it your way, you can leave that then add:

JASS:
if .FirstPhaseActive == false then
    // Do all the other stuff here.


You are destroying .tempgroup way to many times:

JASS:
            loop
                exitwhen i == EXPLOSION_LINE_AMOUNT
                call DestroyGroup( .SlideGroup<i> )
                call DestroyGroup( .TempGroup ) // Here, theres only one group, but you destroy it like 9 times.
                set i = i + 1
            endloop

</i>


JASS:
// Useless? No.
        call SetUnitPosition( d.LightMissile<i>, x, y )

</i>


What is its usage btw?

Oh, and same with your last spell, you are using one struct for two entirely different functions of the spell. It is not only ugly, but inefficient.

EDIT:

Oh and whats with the backwards indentation?

JASS:
.
    globals // lol?
private constant boolean IS_CHANNEL = true //&lt;-- Is the ability channelling? If false, I suggest you also set the
                                           // field in the ability&#039;s Follow Through Time to smaller.

private constant integer SPELL_ID = &#039;A001&#039; //&lt;-- Object rawcodes.
private constant integer DUMMY_ID = &#039;e000&#039; 
private constant string  SPELL_STRING = &quot;channel&quot; //&lt;-- OrderID of spell.
 

simonake

New Member
Reaction score
72
I found a mistake. You use a dummy unit, to make an effect. You forgot to remove it food cost! i over spammed it and it changed to ent.
 

BlackRose

Forum User
Reaction score
239
Right there, you destroy your struct, yet underneath you keep using it, either im missing something, or this just shouldn't work.
Oops, better fix that? Should I juse Skip Remaining Actions thing? 'return'

Why? Maybe just:

JASS:
local Summon d = GetTimerData(GetExpiredTimer())
I've never really used methods and I was trying, 'static' didn't really I understand, but.... it seeemed easy like that.
Your creating lots of groups for this spell, maybe using a global one will work better?
How will I manage that? To push in all angles?

a) Does that even compile?
Hmmm..... it shouldn't be like that? Ooops, no space.
b) Whats it used for? Your already setting that member to false above in the if block. If you want to do it your way, you can leave that then add:
I'll remember that.
You are destroying .tempgroup way to many times:
Another one of my oops.
What is its usage btw?
If I made it on non-air pathable place, it wil move it onto the closest place, thus making it look weird.
Oh, and same with your last spell, you are using one struct for two entirely different functions of the spell. It is not only ugly, but inefficient.
How is it inefficent? It is just easier to manage also.
EDIT:

Oh and whats with the backwards indentation?
...does that really matter -.-
I found a mistake. You use a dummy unit, to make an effect. You forgot to remove it food cost! i over spammed it and it changed to ent.
I know, I just decided to change it after a review, thanks anyway.

I'll work on it after I know how PUI works and how to use it.. AND I won't submit another one until this one is perfect.

--------------------------
Other notes:
With PUI, I do not understand, even after reading that tutorial and viewing test map:

How does it attach data to a unit?
JASS:
//! runtextmacro PUI_PROPERTY(&quot;private&quot;, &quot;real&quot;, &quot;Mana&quot;, &quot;0&quot; )

I tried playing around with it and, what is private? Is the 'real' the type of variable, and 'mana' the name, and '0', the value?

JASS:
scope StructExample initializer Init

//===========================================================================
//  If we want struct to be attachable to units we run PUI macro inside it.
//  Putting 5-6 unit properties inside struct is more efficient 
//  than declaring 5 PUI_PROPERTY each for itself
//===========================================================================
private struct UnitData
    //! runtextmacro PUI()
    integer KillCounter = 0
    
    // you can add any of your own stuff here
endstruct

//===========================================================================
private function Actions takes nothing returns nothing
    local unit killer = GetKillingUnit()
    local UnitData dat = UnitData[killer]
    
    // is struct attached?
    if dat == 0 then
        set dat = UnitData.create() // if not create it
        set UnitData[killer] = dat // and attach it
    endif

    // again it is simple
    set dat.KillCounter = dat.KillCounter + 1
    
    // do some other stuff with your struct...
endfunction

//===========================================================================
//  WARNING: never destroy PUI structs directly use release() method instead
//  In fact it is best that you never destroy them manually,
//  they will be destroyed automatically when unit is removed from game.
//===========================================================================

//===========================================================================
private function Conditions takes nothing returns boolean
    return true
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger trig = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_DEATH )
    call TriggerAddCondition( trig, Condition( function Conditions ) )
    call TriggerAddAction( trig, function Actions )
endfunction

endscope

This code, I really do not understand it.
JASS:
    local UnitData dat = UnitData[killer]

Huh? A struct on a unit?

EDIT: In truth, I didn't understand that PUI tutorial at all.
 

BlackRose

Forum User
Reaction score
239
You can make a struct instance for a unit? So when you use PUI GetUnitIndex to get that random integer, the random integer is the struct number?
 

Romek

Super Moderator
Reaction score
964
> PUI GetUnitIndex to get that random integer
It doesn't get a 'Random Integer'.
This integer stays with the unit until it's killed.

So you can safely attach things to units using this integer.
 

BlackRose

Forum User
Reaction score
239
Just got a new computer, will update code later.... so no more 'why are you still doing that'... not everyone has free time -.-

God's judgment:
1. GUI :(
2. Weird ripple effect.
3. I don't understand those Faerie Balls moving out in a weird angle.
4. It is god! :p
 

wraithseeker

Tired.
Reaction score
122
Why are you using SetUnitPosition for your missles and not SetUnitX & Y.
Whats with the need for the effects to be units? Couldn't it be just effects or did you wanted to do stuff with them?

I checked and you can just use maths stuffs to use a GroupEnumUnitsInRange to check for them although that maths would be tough but it would
be better.

I have heard that destroying groups is bad not very sure on this case but couldn't you recycle them?

Why are you killing units and not removing them?

You are still not using the PUI method to stop channelling stuffs.
 

BlackRose

Forum User
Reaction score
239
Sorry if it sound like I am impatient, or anything. But can someone please look over :)? Even if the page is on top of the zone :(
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Ghan Ghan:
    Howdy
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though
  • Ghan Ghan:
    Heard Houston got hit pretty bad by storms last night. Hope all is well with TH.
  • The Helper The Helper:
    Power back on finally - all is good here no damage
    +2
  • V-SNES V-SNES:
    Happy Friday!
    +1

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top