Is this script MUI?

Kenny

Back for now.
Reaction score
202
The only reason I am asking this is because I have been getting mixed signals on where or not this is MUI. I was looking over on another site and it seemed as though a script like mine (not a knockback one, just using struct arrays) is 100% MUI, but when posting on here I get the feeling that it isn't. So this time I'm making sure buy making a big deal out of it :p.

So heres my script as of now:

JASS:
library KBS initializer Init

globals
    // CONFIGURABLES:
    private constant integer Dummy_id = 'h000'           // This is the dummy unit.
    private constant real Period = 0.03125               // Recommended Interval.
    private constant real Radius = 150.00                // Radius for killing trees.
    private constant string Attachment_point = "origin"  // Attachment point for effects.
    private constant string Water_SFX = "SlideWater.mdx" // Water slide effect.
    private constant string Dirt_SFX = "Dust.mdx"        // Ground slide effect.
endglobals
     
globals
    private integer Total = 0
    private integer array DataArray
    private real Game_maxX
    private real Game_minX
    private real Game_maxY
    private real Game_minY
    private rect Rect1 = Rect(0.00,0.00,1.00,1.00)
    private timer Timer = CreateTimer()  
endglobals

private function KillEnumDestructables takes nothing returns nothing
    call KillDestructable(GetEnumDestructable())
endfunction

// Thanks to PitzerMike for this function.
private function TreeCheck takes nothing returns boolean
    local destructable dest = GetFilterDestructable()
    local boolean bool = IsDestructableInvulnerable(dest)
    local unit dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),Dummy_id,GetDestructableX(dest),GetDestructableY(dest),0.00)
    local boolean result = false

    call UnitAddAbility(dummy,'Ahrl')
    if bool then
        call SetDestructableInvulnerable(dest,false)
    endif
    set result = IssueTargetOrder(dummy,"harvest",dest)
    call RemoveUnit(dummy)
    if bool then
        call SetDestructableInvulnerable(dest,true)
    endif

    set dest = null
    set dummy = null
    return result
endfunction

private struct Data
    unit targ
    
    real speed
    real decrease
    real sin
    real cos
    
    effect SFX
    integer sfxmode
    boolean killdest
    
    // Checking for terrain type.
    static method TerrainType takes unit u, string sfx returns integer
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        
        if sfx != "" and sfx != null then
            return 0
        elseif IsTerrainPathable(x,y,PATHING_TYPE_FLOATABILITY) then
            return 1
        elseif not IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) then
            return 2
        endif
        
        return 3
    endmethod
    
    static method create takes unit Target, real Startspeed, real Deceleration, real Angle, string Specialeffect, boolean Killtrees returns Data
        local Data d 
        
        if Target == null or Startspeed <= 0.00 or Deceleration <= 0.00 then
            call BJDebugMsg("Error: Invalid input in KBS_Begin") // Error message.
            return 0
        endif
        
        // Allocates struct members to user defined variables.
        set d = Data.allocate()
        set d.targ = Target
        set d.speed = Startspeed
        set d.decrease = Deceleration
        set d.sin = Sin(Angle)
        set d.cos = Cos(Angle)
        set d.killdest = Killtrees
        set d.sfxmode = d.TerrainType(d.targ,Specialeffect)
        
        // Adding effects to the unit.
        if d.sfxmode == 0 then
            set d.SFX = AddSpecialEffectTarget(Specialeffect,d.targ,Attachment_point)
        elseif d.sfxmode == 1 then
            set d.SFX = AddSpecialEffectTarget(Dirt_SFX,d.targ,Attachment_point)
        elseif d.sfxmode == 2 then
            set d.SFX = AddSpecialEffectTarget(Water_SFX,d.targ,Attachment_point)
        elseif d.sfxmode == 3 then
            call BJDebugMsg("Error: Unknown terrain type (KBS)")
        endif
        
        if Total == 0 then
            call TimerStart(Timer,Period,true,function Data.Execute)

        endif
        
        set DataArray[Total] = integer(d)
        set Total = Total + 1
        
        return d
    endmethod
    
    static method Execute takes nothing returns nothing
        local integer i = Total - 1
        local Data d
        local real x
        local real y
        local real newx
        local real newy
        
        loop
            exitwhen i < 0
            set d = Data(DataArray<i>)
            
            set x = GetUnitX(d.targ)
            set y = GetUnitY(d.targ)
            
            if d.speed &lt;= 0 or (x &gt; Game_maxX or y &gt; Game_maxY or x &lt; Game_minX or y &lt; Game_minY) then
                call d.destroy() // Finish knockback if speed == 0 or unit has hit map borders.
                set Total = Total - 1
                if Total &lt; 0 then
                    call PauseTimer(Timer)
                    set Total = 0
                else
                    set DataArray<i> = DataArray[Total]
                endif
            else
                set newx = x+d.speed*d.cos
                set newy = y+d.speed*d.sin
                call SetUnitPosition(d.targ,newx,newy)
                
                if d.killdest then // Kills trees if boolean is true.
                    call SetRect(Rect1,x-Radius,y-Radius,x+Radius,y+Radius)
                    call EnumDestructablesInRect(Rect1,Condition(function TreeCheck),function KillEnumDestructables)
                endif
                
                if d.sfxmode == 0 then
                    set d.sfxmode = d.TerrainType(d.targ,&quot;sfx&quot;)
                else
                    set d.sfxmode = d.TerrainType(d.targ,&quot;&quot;)
                endif
                
                // Adds special effects.
                if d.sfxmode == 1 then
                    call DestroyEffect(d.SFX)
                    set d.SFX = AddSpecialEffectTarget(Dirt_SFX,d.targ,Attachment_point)
                    set d.sfxmode = 2
                elseif d.sfxmode == 2 then
                    call DestroyEffect(d.SFX)
                    set d.SFX = AddSpecialEffectTarget(Water_SFX,d.targ,Attachment_point)
                    set d.sfxmode = 1
                elseif d.sfxmode == 3 then
                    call BJDebugMsg(&quot;Error: Unknown terrain type (KBS)&quot;)
                endif
                
                set d.speed = d.speed - d.decrease
            endif
            
            set i = i - 1
        endloop
    endmethod
    
    private method onDestroy takes nothing returns nothing
        set .targ = null
        if .SFX != null then
            call DestroyEffect(.SFX)
            set .SFX = null
        endif
    endmethod
endstruct

public function BeginEx takes unit Target, real Startspeed, real Deceleration, real Angle, string SpecialEffect, boolean Killtrees returns nothing
    call Data.create(Target,Startspeed,Deceleration,(Angle*0.01745328),SpecialEffect,Killtrees)
endfunction

public function Begin takes unit Target, real Startspeed, real Deceleration, real Angle, boolean Killtrees returns nothing    
    call KBS_BeginEx(Target,Startspeed,Deceleration,(Angle*0.01745328),&quot;&quot;,Killtrees)
endfunction                                                                                                

// Sets map boundries.
private function Init takes nothing returns nothing
    set Game_maxX = GetRectMaxX(bj_mapInitialPlayableArea)-50.00
    set Game_maxY = GetRectMaxY(bj_mapInitialPlayableArea)-50.00
    set Game_minX = GetRectMinX(bj_mapInitialPlayableArea)+50.00
    set Game_minY = GetRectMinY(bj_mapInitialPlayableArea)+50.00
endfunction

endlibrary</i></i>


A clearly defined and definite answer will be greatly appreciated, and +repped.
 

Kenny

Back for now.
Reaction score
202
From the looks of it, it should be MUI. Why not try it out (place a few units on the map and slide them GetRandomReal (300, 600) distance or so towards GetRandomReal (0, 360) degrees?)

I have tried something similar and it seemed to work. But nothing to that extent, ill give it a try when i can, thanks for the idea.

Also, shouldn't the type for DataArray be Data?

Typecasting :). Well at least thats what i think it is. lol. I heard from a source of mine that it isnt a bad thing to do and may even be required in future versions of NewGen.

Typecast

For the moment, assigning a value of an struct type to an integer variable / or variable of any other struct type will already change the type of that reference for the compiler

Notice that sometimes using a variable might get tedious or even create unneeded overhead, that is the reason the type cast operator was added.

Its syntax is mostly like a function but the name of the function is the name of a custom type. It will soon allow native types as well.

JASS:
interface  wack
    //... some declarations
endinterface

struct wek extends wack
   integer x
   // some more declarations
endstruct

function test takes wack W returns nothing
   //You are certain that W is of type wek, a way to cast the value is:
 local wek jo = W
   set jo.x= 5 //done

   // but sometimes creating a variable is too much work for the virtual machine and you
   // are only accessing it once 

   set wek(W).x=5 //also works.
endfunction


type anarrayofdata extends integer array [6]

function getdata5 takes unit u returns integer
    //a reference to an object of type anarrayofdata is saved as the unit&#039;s custom value
    return anarrayofdata(GetUnitUserData(u))[5]
endfunction

function setdata5 takes unit u, anarrayofdata x returns nothing
    // Here we are doing the opposite, notice that integer may be used as a type cast
    // operator for struct and dynamic array types.
    call SetUnitUserData(u,  integer(x))
endfunction

*EDIT*

Does anyone have that clearly defined and definite answer that i am looking for? I can test it in about 15-16 hours but until then i need your opinion.
 

Strilanc

Veteran Scripter
Reaction score
42
The design is MUI (store in a list and iterate over it), so unless you have bugs in there it's MUI.

It's a bit confusing what's actually running the code though. For clarity you might want to start the timer in the init function instead of when the first element is inserted in the list. You're also starting that timer without pausing it, even though it might already be running. At most you should just be pausing it when the list is emptied, and resuming it when the list becomes non-empty.
 

Tukki

is Skeleton Pirate.
Reaction score
29
Yepp, but I must say that it looks very similar to a knockback system made by Rising_Dusk.
 

Kenny

Back for now.
Reaction score
202
Yepp, but I must say that it looks very similar to a knockback system made by Rising_Dusk.

I just found a thread from a while backing about someone asking how to use Dusks knockback.

And unfortunately it does look similar. :( This was however, not intended. I don't even know where to get Dusks knockback system. Im guessing from wc3campaigns or something. Ive never actually gone there specifically for JASS stuff though so i wouldn't be sure.

Thanks for bringing that to my attention. I might try to think of a way to change mine around a bit.

It's a bit confusing what's actually running the code though. For clarity you might want to start the timer in the init function instead of when the first element is inserted in the list. You're also starting that timer without pausing it, even though it might already be running. At most you should just be pausing it when the list is emptied, and resuming it when the list becomes non-empty.

Im not to sure on what your trying to say... I am pausing the timer before i start it. And it does pause when the list is empty.

JASS:
if d.speed &lt;= 0 or (x &gt; Game_maxX or y &gt; Game_maxY or x &lt; Game_minX or y &lt; Game_minY) then
    call d.destroy() // Finish knockback if speed == 0 or unit has hit map borders.
    set Total = Total - 1
    if Total &lt; 0 then
        call PauseTimer(Timer)
        set Total = 0
    else
        set DataArray<i> = DataArray[Total]
    endif
else
</i>


If Total < 0 then PauseTimer(Timer)... So if the list is empty it will pause. Then reset the list for the next instance. If not it will just keep on doing what its doing.

Oh and thanks for your input guys, my doubts about its MUI'ness have vanished... almost.
 

Strilanc

Veteran Scripter
Reaction score
42
Ah, I didn't see that PauseTimer (which is a big hint that you shouldn't be doing that in the middle of the loop).
 

Kenny

Back for now.
Reaction score
202
I see no other way of pausing a timer after checking if an instance of the knockback has finished. Besides, i thought that this is how a struct array worked for this type of spell. I havent seen another one that has PauseTimer() outside of the loop. And im pretty sure it does not matter if it is in the middle or not, PauseTimer() in that situation has never given me problems in the past.

*EDIT*

Would it be more efficient to make the condition in:

JASS:
call EnumDestructablesInRect(Rect1,Condition(function TreeCheck),function KillEnumDestructables) // Condition(function TreeCheck)


A global boolean, as it is checking the same thing everytime?

Also, to make it a bit more different to Dusk's system, should i make it use 1 distance instead of two, and a user defined time? I thought that would be ok.

Then i could use something like this:

JASS:
local real count = (duation/Interva)l // for a two second duration with a 0.03125 interval that would be like 64

set startspeed = ((distance*2)/count) // With a distance of 500 and the above count, thats like 15.625 startspeed
set deceleration = (startspeed/count) // and thats like 0.24414


Its just a thought but. All that math kinda puts me off changing it but lol.

*EDIT 2*

Ok is there a problem in doing this:

JASS:
public function BeginEx takes unit Target, real Startspeed, real Deceleration, real Angle, string SpecialEffect, boolean Killtrees returns nothing
    call Data.create(Target,Startspeed,Deceleration,(Angle*0.01745328),SpecialEffect,Killtrees)
endfunction

public function Begin takes unit Target, real Startspeed, real Deceleration, real Angle, boolean Killtrees returns nothing    
    call Data.create(Target,Startspeed,Deceleration,(Angle*0.01745328),&quot;&quot;,Killtrees)
endfunction


What i mean is: Will using Data.create() in both, instead of the Begin function calling the BeginEx function, be a problem at all? The reason i am using two Data.create's is that it doesn't seem to work properly if i do it the other way.
 

Tukki

is Skeleton Pirate.
Reaction score
29
As Strilanc posted a good idea would be to move the PauseTimer below the main loop function.

Like:
JASS:
           
       loop
            exitwhen i &lt; 0
            set d = Data(DataArray<i>)
            
            set x = GetUnitX(d.targ)
            set y = GetUnitY(d.targ)
            
            if d.speed &lt;= 0 or (x &gt; Game_maxX or y &gt; Game_maxY or x &lt; Game_minX or y &lt; Game_minY) then
                call d.destroy() // Finish knockback if speed == 0 or unit has hit map borders.
                set Total = Total - 1
                set DataArray<i> = 0 // As a uninitialized struct is 0.
            else
                set newx = x+d.speed*d.cos
                set newy = y+d.speed*d.sin
                call SetUnitPosition(d.targ,newx,newy)
                
                if d.killdest then // Kills trees if boolean is true.
                    call SetRect(Rect1,x-Radius,y-Radius,x+Radius,y+Radius)
                    call EnumDestructablesInRect(Rect1,Condition(function TreeCheck),function KillEnumDestructables)
                endif
                
                if d.sfxmode == 0 then
                    set d.sfxmode = d.TerrainType(d.targ,&quot;sfx&quot;)
                else
                    set d.sfxmode = d.TerrainType(d.targ,&quot;&quot;)
                endif
                
                // Adds special effects.
                if d.sfxmode == 1 then
                    call DestroyEffect(d.SFX)
                    set d.SFX = AddSpecialEffectTarget(Dirt_SFX,d.targ,Attachment_point)
                    set d.sfxmode = 2
                elseif d.sfxmode == 2 then
                    call DestroyEffect(d.SFX)
                    set d.SFX = AddSpecialEffectTarget(Water_SFX,d.targ,Attachment_point)
                    set d.sfxmode = 1
                elseif d.sfxmode == 3 then
                    call BJDebugMsg(&quot;Error: Unknown terrain type (KBS)&quot;)
                endif
                
                set d.speed = d.speed - d.decrease
            endif
            
            set i = i - 1
        endloop
        if (Total &lt;= 0) then // like this, so you only stop it once.
            call PauseTimer(Timer)
            set Total = 0
        endif
    endmethod</i></i>


EDIT:

I see no reason why you must create Data in both functions, can't you just do something like this:

JASS:
public function BeginEx takes unit Target, real Startspeed, real Deceleration, real Angle, string SpecialEffect, boolean Killtrees returns nothing
    call Data.create(Target,Startspeed,Deceleration,(Angle*0.01745328),SpecialEffect,Killtrees)
endfunction

public function Begin takes unit Target, real Startspeed, real Deceleration, real Angle, boolean Killtrees returns nothing    
    call BeginEx(Target, Startspeed, Deceleration, Angle, &quot;&quot;, Killtrees // Calls the BeginEx function with same values as it would call Data.create().
endfunction


EDIT_2: Only minior things changed.

Library code:
JASS:
library KBS initializer Init

globals
    // CONFIGURABLES:
    private constant integer Dummy_id = &#039;h000&#039;           // This is the dummy unit.
    private constant real Period = 0.03125               // Recommended Interval.
    private constant real Radius = 150.00                // Radius for killing trees.
    private constant string Attachment_point = &quot;origin&quot;  // Attachment point for effects.
    private constant string Water_SFX = &quot;SlideWater.mdx&quot; // Water slide effect.
    private constant string Dirt_SFX = &quot;Dust.mdx&quot;        // Ground slide effect.
endglobals

//===========================================================================
private keyword Data // We use a keyword to be able to use un-initialized stuff, like our array <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite1" alt=":)" title="Smile    :)" loading="lazy" data-shortname=":)" />

//===========================================================================
globals
    private integer Total      = 0
    private rect Rect1         = Rect(0.00,0.00,1.00,1.00)
    private Data array DataArray         // Now we can get rid of that &#039;integer&#039; typecasting.
    private timer Timer           = null // Initialize the timer in the Init function instead.
    private boolexpr TreeBOOLEXPR = null // We create a global boolexpr.
    private real Game_maxX
    private real Game_minX
    private real Game_maxY
    private real Game_minY
endglobals

//===========================================================================
private function KillEnumDestructables takes nothing returns nothing
    call KillDestructable(GetEnumDestructable())
endfunction

//===========================================================================
private function IsPointOutside takes real x, real y returns boolean // Function for detection when a point is outside map boundaries.
    return (x &gt; Game_maxX or y &gt; Game_maxY or x &lt; Game_minX or y &lt; Game_minY)
endfunction // Just for readability.

//===========================================================================
// Thanks to PitzerMike for this function.
private function TreeCheck takes nothing returns boolean
    local destructable dest = GetFilterDestructable()
    local boolean bool = IsDestructableInvulnerable(dest)
    local unit dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),Dummy_id,GetDestructableX(dest),GetDestructableY(dest),0.00)
    local boolean result = false

    call UnitAddAbility(dummy,&#039;Ahrl&#039;)
    if bool then
        call SetDestructableInvulnerable(dest,false)
    endif
    set result = IssueTargetOrder(dummy,&quot;harvest&quot;,dest)
    call RemoveUnit(dummy)
    if bool then
        call SetDestructableInvulnerable(dest,true)
    endif

    set dest = null
    set dummy = null
    return result
endfunction

//===========================================================================
private struct Data
    unit targ
    
    real speed
    real decrease
    real sin
    real cos
    
    effect SFX
    integer sfxmode
    boolean killdest
    
    //===========================================================================
    // Checking for terrain type.
    static method TerrainType takes unit u, string sfx returns integer
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        
        if sfx != &quot;&quot; and sfx != null then
            return 0
        elseif IsTerrainPathable(x,y,PATHING_TYPE_FLOATABILITY) then
            return 1
        elseif not IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) then
            return 2
        endif
        
        return 3
    endmethod
    
    //===========================================================================
    static method create takes unit Target, real Startspeed, real Deceleration, real Angle, string Specialeffect, boolean Killtrees returns Data
        local Data d 
        
        if Target == null or Startspeed &lt;= 0.00 or Deceleration &lt;= 0.00 then
            call BJDebugMsg(&quot;Error: Invalid input in KBS_Begin&quot;) // Error message.
            return 0
        endif
        
        // Allocates struct members to user defined variables.
        set d = Data.allocate()
        set d.targ = Target
        set d.speed = Startspeed
        set d.decrease = Deceleration
        set d.sin = Sin(Angle)
        set d.cos = Cos(Angle)
        set d.killdest = Killtrees
        set d.sfxmode = d.TerrainType(d.targ,Specialeffect)
        
        // Adding effects to the unit.
        if d.sfxmode == 0 then
            set d.SFX = AddSpecialEffectTarget(Specialeffect,d.targ,Attachment_point)
        elseif d.sfxmode == 1 then
            set d.SFX = AddSpecialEffectTarget(Dirt_SFX,d.targ,Attachment_point)
        elseif d.sfxmode == 2 then
            set d.SFX = AddSpecialEffectTarget(Water_SFX,d.targ,Attachment_point)
        elseif d.sfxmode == 3 then
            call BJDebugMsg(&quot;Error: Unknown terrain type (KBS)&quot;)
        endif
        
        if Total == 0 then
            call TimerStart(Timer,Period,true,function Data.Execute)
        endif
        
        set Total = Total + 1     
        set DataArray[Total] = d // no typecasting required anymore.
        return d
    endmethod
    
    //===========================================================================
    static method Execute takes nothing returns nothing
        local integer i = Total // Also the -1 can be taken away.
        local Data d
        local real x
        local real y
        local real newx
        local real newy
        
        loop
            exitwhen i &lt; 0
            set d = DataArray<i>
            
            set x = GetUnitX(d.targ)
            set y = GetUnitY(d.targ)
            
            if d.speed &lt;= 0 or IsPointOutside(x, y) then
                call d.destroy() // Finish knockback if speed == 0 or unit has hit map borders.
                set Total = Total - 1
                set DataArray<i> = 0
            else
                set newx = x+d.speed*d.cos
                set newy = y+d.speed*d.sin
                // call SetUnitPosition(d.targ,newx,newy) 
                call SetUnitX(d.targ, newx)
                call SetUnitY(d.targ, newy) // This is much faster, but does not check pathing.
                
                if d.killdest then // Kills trees if boolean is true.
                    call SetRect(Rect1, x-Radius, y-Radius, x+Radius, y+Radius)
                    call EnumDestructablesInRect(Rect1, TreeBOOLEXPR, function KillEnumDestructables)
                endif
                
                if d.sfxmode == 0 then
                    set d.sfxmode = d.TerrainType(d.targ,&quot;sfx&quot;)
                else
                    set d.sfxmode = d.TerrainType(d.targ,&quot;&quot;)
                endif
                
                // Adds special effects.
                if d.sfxmode == 1 then
                    call DestroyEffect(d.SFX)
                    set d.SFX = AddSpecialEffectTarget(Dirt_SFX,d.targ,Attachment_point)
                    set d.sfxmode = 2
                elseif d.sfxmode == 2 then
                    call DestroyEffect(d.SFX)
                    set d.SFX = AddSpecialEffectTarget(Water_SFX,d.targ,Attachment_point)
                    set d.sfxmode = 1
                elseif d.sfxmode == 3 then
                    call BJDebugMsg(&quot;Error: Unknown terrain type (KBS)&quot;)
                endif
                
                set d.speed = d.speed - d.decrease
            endif
            
            set i = i - 1
        endloop
        if (Total &lt;= 0) then // Pause it outside the loop.
            call PauseTimer(Timer)
            set Total = 0
        endif
    endmethod
    
    //===========================================================================
    private method onDestroy takes nothing returns nothing
        set .targ = null
        if .SFX != null then
            call DestroyEffect(.SFX)
            set .SFX = null
        endif
    endmethod
endstruct

//===========================================================================
public function BeginEx takes unit Target, real Startspeed, real Deceleration, real Angle, string SpecialEffect, boolean Killtrees returns nothing
    call Data.create(Target,Startspeed,Deceleration,(Angle*0.01745328),SpecialEffect,Killtrees)
endfunction

//===========================================================================
public function Begin takes unit Target, real Startspeed, real Deceleration, real Angle, boolean Killtrees returns nothing    
    call BeginEx(Target, Startspeed, Deceleration, (Angle*0.01745328), &quot;&quot;, Killtrees)
endfunction  
                                                                                              
//===========================================================================
// Sets map boundries, and initializes some stuff.
private function Init takes nothing returns nothing
    set Game_maxX = GetRectMaxX(bj_mapInitialPlayableArea) - 64.00 // 64 is closer <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite7" alt=":p" title="Stick Out Tongue    :p" loading="lazy" data-shortname=":p" />
    set Game_maxY = GetRectMaxY(bj_mapInitialPlayableArea) - 64.00
    set Game_minX = GetRectMinX(bj_mapInitialPlayableArea) + 64.00
    set Game_minY = GetRectMinY(bj_mapInitialPlayableArea) + 64.00
    
    set Timer = CreateTimer()
    set TreeBOOLEXPR = Condition(function TreeCheck)
endfunction
endlibrary</i></i>
 

Kenny

Back for now.
Reaction score
202
As Strilanc posted a good idea would be to move the PauseTimer below the main loop function.

Whats your reasoning behind this? Is it just less calls through the loop or what?

I see no reason why you must create Data in both functions, can't you just do something like this:

Hmm, good idea, thanks for that.

As for your second edit:

- Initialising both the timer and boolean in the init function has already been done in my updated one, but thanks.

- I dont think IsPointOutside() is very necessary. You say it is for readability, but the only thing users will need to read are the first set of globals. I may think about it but, i have some other ideas for map bounds.

- I was using SetUnitPosition for a reason. I want to check for pathing. Anyway i realise the X/Y are faster, but not noticeably.

- I already addressed the public functions and timer pausing above.

- Whats the point of getting rid of typecasting? I don't think it is detrimental to a script, thats why typecast syntax was introduced... to be used. Oh and why can i now remove the -1 from Total at the beginning of the Execute method? Oh yeah and typecasting wasnt required in the first place. I heard that it may been needed in future versions on NewGen, so i did it, it doesn't affect anything. As for:
JASS:
private integer array DataArray
// This can easily be changed to private Data array Dataarray
// by making another global block underneath the struct, but i don&#039;t feel like doing that


- Why is +/- 64.00 closer than +/- 50.00 ? I'm not quite sure i understand the logic of that.

*EDIT*

Also, wouldnt:

JASS:
if d.speed &lt;= 0 or IsPointOutside(x, y) then
    call d.destroy()
    set Total = Total - 1
    set DataArray<i> = 0 // this need to be DataArray<i> = DataArray[Total], or does doing it your way change that completely.
else
</i></i>


Oh and:

JASS:
if (Total &lt;= 0) then // Thats gotta be only &lt; doesn&#039;t it? Or does that change as well with what you have done.
    call PauseTimer(Timer)
    set Total = 0
endif


*EDIT 2*

What would be a better solution?

1. Using the TreeCheck function i already have. (Original idea came from pitzermike)

or

2.
JASS:
private function TreeCheck takes nothing returns boolean
    local integer d = GetDestructableTypeId(GetFilterDestructable())
    return d == &#039;ATtr&#039; or d == &#039;BTtw&#039; or d == &#039;KTtw&#039; or d == &#039;YTft&#039; or d == &#039;JTct&#039; or d == &#039;YTst&#039; or d == &#039;YTct&#039; or d == &#039;YTwt&#039; or d == &#039;JTwt&#039; or d == &#039;JTwt&#039; or d == &#039;FTtw&#039; or d == &#039;CTtr&#039; or d == &#039;ITtw&#039; or d == &#039;NTtw&#039; or d == &#039;OTtw&#039; or d == &#039;ZTtw&#039; or d == &#039;WTst&#039; or d == &#039;LTlt&#039; or d == &#039;GTsh&#039; or d == &#039;Xtlt&#039; or d == &#039;WTtw&#039; or d == &#039;Attc&#039; or d == &#039;BTtc&#039; or d == &#039;CTtc&#039; or d == &#039;ITtc&#039; or d == &#039;NTtc&#039; or d == &#039;ZTtc&#039;
endfunction


Number 2 would remove the need for a dummy unit, but which one would be move efficient?
 

Tukki

is Skeleton Pirate.
Reaction score
29
Whats your reasoning behind this? Is it just less calls through the loop or what?
You only stop the timer once here, and there's no reason to try to stop i mutliple times.

- Whats the point of getting rid of typecasting? I don't think it is detrimental to a script, thats why typecast syntax was introduced... to be used. Oh and why can i now remove the -1 from Total at the beginning of the Execute method? Oh yeah and typecasting wasnt required in the first place. I heard that it may been needed in future versions on NewGen, so i did it, it doesn't affect anything
You doesn't have to use the integer() all the time. If you look at the create method you'll see that I put the Total + 1 over the set DataArray[Total] = <yourdata>, this is only needed if you use DataArray as struct type as structs are un-initialized at 0.

Why is +/- 64.00 closer than +/- 50.00 ? I'm not quite sure i understand the logic of that
It's more correct to the map bounds.

JASS:
if d.speed &lt;= 0 or IsPointOutside(x, y) then
    call d.destroy()
    set Total = Total - 1
    set DataArray<i> = 0 // this need to be DataArray<i> = DataArray[Total], or does doing it your way change that completely.
else</i></i>

Yeah, seems I did something. It needs to be like you posted.

JASS:
if (Total &lt;= 0) then // Thats gotta be only &lt; doesn&#039;t it? Or does that change as well with what you have done.
    call PauseTimer(Timer)
    set Total = 0
endif
That depends on if you are using the array as a struct or not, if you are that leave it as structs are un-initialized at 0. Else if you are using it as a integer then you can make it only <, but I'm not that sure if you would ever pause the timer.

JASS:
private function TreeCheck takes nothing returns boolean
    local integer d = GetDestructableTypeId(GetFilterDestructable())
    return d == &#039;ATtr&#039; or d == &#039;BTtw&#039; or d == &#039;KTtw&#039; or d == &#039;YTft&#039; or d == &#039;JTct&#039; or d == &#039;YTst&#039; or d == &#039;YTct&#039; or d == &#039;YTwt&#039; or d == &#039;JTwt&#039; or d == &#039;JTwt&#039; or d == &#039;FTtw&#039; or d == &#039;CTtr&#039; or d == &#039;ITtw&#039; or d == &#039;NTtw&#039; or d == &#039;OTtw&#039; or d == &#039;ZTtw&#039; or d == &#039;WTst&#039; or d == &#039;LTlt&#039; or d == &#039;GTsh&#039; or d == &#039;Xtlt&#039; or d == &#039;WTtw&#039; or d == &#039;Attc&#039; or d == &#039;BTtc&#039; or d == &#039;CTtc&#039; or d == &#039;ITtc&#039; or d == &#039;NTtc&#039; or d == &#039;ZTtc&#039;
endfunction
This way it's more efficient but it lacks the thing that it works for custom-made trees.
Since your system should be easy to use, I say go for PitzerMike's.
 

Kenny

Back for now.
Reaction score
202
Thanks for all your help :). Just need some final confirmation on the system, to see if everything is in order.

I went with your keyword idea after reading up on them in the jasshelper manual. They can be pretty handy. Therefore, I also changed the integer array to the struct array and it now doesn't use typecasting (and stuff like: local integer i = Total - 1). And i changed the +/-50.00's to +/-64.00's and used the IsPointOutside(). I already had that function in my other library.

And now im basically just wondering about one thing. Its at the bottom of the Execute function:

JASS:
library KBS initializer Init

globals
    // CONFIGURABLES:
    private constant integer Dummy_id = &#039;h000&#039;           // This is the dummy unit.
    private constant real Period = 0.03125               // Recommended Interval.
    private constant real Radius = 150.00                // Radius for killing trees.
    private constant string Attachment_point = &quot;origin&quot;  // Attachment point for effects.
    private constant string Water_SFX = &quot;SlideWater.mdx&quot; // Water slide effect.
    private constant string Dirt_SFX = &quot;Dust.mdx&quot;        // Ground slide effect.
endglobals

//***************************************************************************************
//**                                                                                   ** 
//**          DO NOT TOUCH BELOW HERE UNLESS YOU KNOW WHAT YOUR ARE DOING!             **
//**                                                                                   **
//***************************************************************************************     

private keyword Data

globals
    private integer Total = 0
    private Data array DataArray
    private real Game_maxX
    private real Game_minX
    private real Game_maxY
    private real Game_minY
    private rect Rect1 = null
    private timer Timer = null
    private boolexpr Treefilt = null
endglobals

private function KillEnumDestructables takes nothing returns nothing
    call KillDestructable(GetEnumDestructable())
endfunction

// Thanks to PitzerMike for this function.
private function TreeCheck takes nothing returns boolean
    local destructable dest = GetFilterDestructable()
    local boolean bool = IsDestructableInvulnerable(dest)
    local unit dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),Dummy_id,GetDestructableX(dest),GetDestructableY(dest),0.00)
    local boolean result = false

    call UnitAddAbility(dummy,&#039;Ahrl&#039;)
    if bool then
        call SetDestructableInvulnerable(dest,false)
    endif
    set result = IssueTargetOrder(dummy,&quot;harvest&quot;,dest)
    call RemoveUnit(dummy)
    if bool then
        call SetDestructableInvulnerable(dest,true)
    endif

    set dest = null
    set dummy = null
    return result
endfunction

// Checks if a point is on the map boundaries.
private function IsPointOutside takes real x, real y returns boolean
    return (x &gt; Game_maxX or y &gt; Game_maxY or x &lt; Game_minX or y &lt; Game_minY)
endfunction

private struct Data
    unit targ
    
    real speed
    real decrease
    real sin
    real cos
    
    effect SFX
    integer sfxmode
    boolean killdest
    
    // Checking for terrain type.
    static method TerrainType takes unit u, string sfx returns integer
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        
        if sfx != &quot;&quot; and sfx != null then
            return 0
        elseif IsTerrainPathable(x,y,PATHING_TYPE_FLOATABILITY) then
            return 1
        elseif not IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) then
            return 2
        endif
        
        return 3
    endmethod
    
    static method create takes unit Target, real Startspeed, real Deceleration, real Angle, string Specialeffect, boolean Killtrees returns Data
        local Data d 
        
        if Target == null or Startspeed &lt;= 0.00 or Deceleration &lt;= 0.00 then
            call BJDebugMsg(&quot;Error: Invalid input in KBS_Begin&quot;) // Error message.
            return 0
        endif
        
        // Allocates struct members to user defined variables.
        set d = Data.allocate()
        set d.targ = Target
        set d.speed = Startspeed
        set d.decrease = Deceleration
        set d.sin = Sin(Angle)
        set d.cos = Cos(Angle)
        set d.killdest = Killtrees
        set d.sfxmode = d.TerrainType(d.targ,Specialeffect)
        
        // Adding effects to the unit.
        if d.sfxmode == 0 then
            set d.SFX = AddSpecialEffectTarget(Specialeffect,d.targ,Attachment_point)
        elseif d.sfxmode == 1 then
            set d.SFX = AddSpecialEffectTarget(Dirt_SFX,d.targ,Attachment_point)
        elseif d.sfxmode == 2 then
            set d.SFX = AddSpecialEffectTarget(Water_SFX,d.targ,Attachment_point)
        endif
        
        if Total == 0 then
            call TimerStart(Timer,Period,true,function Data.Execute)
        endif
        
        set Total = Total + 1
        set DataArray[Total] = d
        
        return d
    endmethod
    
    static method Execute takes nothing returns nothing
        local integer i = Total
        local Data d
        local real x
        local real y
        local real newx
        local real newy
        
        loop
            exitwhen i &lt; 0
            set d = DataArray<i>
            
            set x = GetUnitX(d.targ)
            set y = GetUnitY(d.targ)
            
            if d.speed &lt;= 0 or IsPointOutside(x,y) then
                call d.destroy() // Finish knockback if speed == 0 or unit has hit map borders.
                set Total = Total - 1
            else
                set newx = x+d.speed*d.cos
                set newy = y+d.speed*d.sin
                call SetUnitPosition(d.targ,newx,newy) // Set units new position.
                
                if d.killdest then // Kills trees if boolean is true.
                    call SetRect(Rect1,x-Radius,y-Radius,x+Radius,y+Radius)
                    call EnumDestructablesInRect(Rect1,Treefilt,function KillEnumDestructables)
                endif
                
                if d.sfxmode == 0 then
                    set d.sfxmode = d.TerrainType(d.targ,&quot;sfx&quot;)
                else
                    set d.sfxmode = d.TerrainType(d.targ,&quot;&quot;) // Checks for pathing again.
                endif
                
                // Adds special effects.
                if d.sfxmode == 1 then
                    call DestroyEffect(d.SFX)
                    set d.SFX = AddSpecialEffectTarget(Dirt_SFX,d.targ,Attachment_point)
                    set d.sfxmode = 2
                elseif d.sfxmode == 2 then
                    call DestroyEffect(d.SFX)
                    set d.SFX = AddSpecialEffectTarget(Water_SFX,d.targ,Attachment_point)
                    set d.sfxmode = 1
                endif
                
                set d.speed = d.speed - d.decrease // Sets new speed.
            endif
            
            set i = i - 1
        endloop
        // Heres where i still need help.
        if (Total &lt;= 0) then
            call PauseTimer(Timer)
            set Total = 0
        else
            set DataArray<i> = DataArray[Total] // Can i leave this here or does it have to
        endif                                   // be up near the d.destroy() ? 
    endmethod
    
    private method onDestroy takes nothing returns nothing
        set .targ = null
        if .SFX != null then
            call DestroyEffect(.SFX) // Destroys effects if needed.
            set .SFX = null
        endif
    endmethod
endstruct

public function BeginEx takes unit Target, real Startspeed, real Deceleration, real Angle, string SpecialEffect, boolean Killtrees returns nothing
    call Data.create(Target,Startspeed,Deceleration,(Angle*0.01745328),SpecialEffect,Killtrees)
endfunction

public function Begin takes unit Target, real Startspeed, real Deceleration, real Angle, boolean Killtrees returns nothing    
    call BeginEx(Target,Startspeed,Deceleration,Angle,&quot;&quot;,Killtrees)
endfunction                                                                                                

// Sets map boundries and sets timer, rect and filter.
private function Init takes nothing returns nothing
    set Timer = CreateTimer()
    set Rect1 = Rect(0.00,0.00,1.00,1.00)
    set Treefilt = Condition(function TreeCheck)
    set Game_maxX = GetRectMaxX(bj_mapInitialPlayableArea)-64.00
    set Game_maxY = GetRectMaxY(bj_mapInitialPlayableArea)-64.00
    set Game_minX = GetRectMinX(bj_mapInitialPlayableArea)+64.00
    set Game_minY = GetRectMinY(bj_mapInitialPlayableArea)+64.00
endfunction

endlibrary</i></i>


I can't test this at the moment as i cant use world editor. School work :(.
 

Artificial

Without Intelligence
Reaction score
326
> Can i leave this here or does it have to be up near the d.destroy() ?
It should be after the destroying. :p
 

Kenny

Back for now.
Reaction score
202
Thanks for the confirmation, i was pretty sure it had to go up there, i just dont have editor to test it. Most of this has been done in notepad, lol.

Ah well +rep to you to. :).

*EDIT*

Yeah um... I quickly just jumped on WE for a sec to test it, and it doesn't work. It gives this error when used:

Attempt to destroy a null struct of type: KBS___Data

Seeing as though im not 100% sure what has happened with the struct array stuff in the system at the moment, i don't want to touch it in case i make it worse, lol. So help please :p.
 

Tukki

is Skeleton Pirate.
Reaction score
29
I'm away for the weekend, but;

When you called the function, did it work? And this message appeard when you stopped the knockback? Also you should check if your struct has an index of 0. Gtg but gl.
 

Tukki

is Skeleton Pirate.
Reaction score
29
JASS:
loop
            exitwhen i &lt; 0 . . .


Try to count upwards instead, begin at 1 and exitwhen i >= Total.
 

Kenny

Back for now.
Reaction score
202
I was just lookin at another system on this sight and it had something like that. Ill try it.
 

Kenny

Back for now.
Reaction score
202
Ok so i tried: exitwhen i >= Total and the error didn't appear, which is good, however the unit still didnt move. Then i tried just > and i got like 50 of the errors so that didn't work lol.

Script as of now:

JASS:
library KBS initializer Init

globals
    // CONFIGURABLES:
    private constant integer Dummy_id = &#039;h000&#039;           // This is the dummy unit.
    private constant real Period = 0.03125               // Recommended Interval.
    private constant real Radius = 150.00                // Radius for killing trees.
    private constant string Attachment_point = &quot;origin&quot;  // Attachment point for effects.
    private constant string Water_SFX = &quot;SlideWater.mdx&quot; // Water slide effect.
    private constant string Dirt_SFX = &quot;Dust.mdx&quot;        // Ground slide effect.
endglobals

//***************************************************************************************
//**                                                                                   ** 
//**          DO NOT TOUCH BELOW HERE UNLESS YOU KNOW WHAT YOUR ARE DOING!             **
//**                                                                                   **
//***************************************************************************************     

private keyword Data

globals
    private integer Total = 0
    private Data array DataArray
    private real Game_maxX
    private real Game_minX
    private real Game_maxY
    private real Game_minY
    private rect Rect1 = null
    private timer Timer = null
    private boolexpr Treefilt = null
endglobals

private function KillEnumDestructables takes nothing returns nothing
    call KillDestructable(GetEnumDestructable())
endfunction

// Thanks to PitzerMike for this function.
private function TreeCheck takes nothing returns boolean
    local destructable dest = GetFilterDestructable()
    local boolean bool = IsDestructableInvulnerable(dest)
    local unit dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),Dummy_id,GetDestructableX(dest),GetDestructableY(dest),0.00)
    local boolean result = false

    call UnitAddAbility(dummy,&#039;Ahrl&#039;)
    if bool then
        call SetDestructableInvulnerable(dest,false)
    endif
    set result = IssueTargetOrder(dummy,&quot;harvest&quot;,dest)
    call RemoveUnit(dummy)
    if bool then
        call SetDestructableInvulnerable(dest,true)
    endif

    set dest = null
    set dummy = null
    return result
endfunction

// Checks if a point is on the map boundaries.
private function IsPointOutside takes real x, real y returns boolean
    return (x &gt; Game_maxX or y &gt; Game_maxY or x &lt; Game_minX or y &lt; Game_minY)
endfunction

private struct Data
    unit targ
    
    real speed
    real decrease
    real sin
    real cos
    
    effect SFX
    integer sfxmode
    boolean killdest
    
    // Checking for terrain type.
    static method TerrainType takes unit u, string sfx returns integer
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        
        if sfx != &quot;&quot; and sfx != null then
            return 0
        elseif IsTerrainPathable(x,y,PATHING_TYPE_FLOATABILITY) then
            return 1
        elseif not IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) then
            return 2
        endif
        
        return 3
    endmethod
    
    static method create takes unit Target, real Startspeed, real Deceleration, real Angle, string Specialeffect, boolean Killtrees returns Data
        local Data d 
        
        if Target == null or Startspeed &lt;= 0.00 or Deceleration &lt;= 0.00 then
            call BJDebugMsg(&quot;Error: Invalid input in KBS_Begin&quot;) // Error message.
            return 0
        endif
        
        // Allocates struct members to user defined variables.
        set d = Data.allocate()
        set d.targ = Target
        set d.speed = Startspeed
        set d.decrease = Deceleration
        set d.sin = Sin(Angle)
        set d.cos = Cos(Angle)
        set d.killdest = Killtrees
        set d.sfxmode = d.TerrainType(d.targ,Specialeffect)
        
        // Adding effects to the unit.
        if d.sfxmode == 0 then
            set d.SFX = AddSpecialEffectTarget(Specialeffect,d.targ,Attachment_point)
        elseif d.sfxmode == 1 then
            set d.SFX = AddSpecialEffectTarget(Dirt_SFX,d.targ,Attachment_point)
        elseif d.sfxmode == 2 then
            set d.SFX = AddSpecialEffectTarget(Water_SFX,d.targ,Attachment_point)
        endif
        
        if Total == 0 then
            call TimerStart(Timer,Period,true,function Data.Execute) // Starting timer.
        endif
        
        set Total = Total + 1
        set DataArray[Total] = d
        
        return d
    endmethod
    
    static method Execute takes nothing returns nothing
        local integer i = Total
        local Data d
        local real x
        local real y
        local real newx
        local real newy
        
        loop
            exitwhen i &gt;= Total
            set d = DataArray<i>
            
            set x = GetUnitX(d.targ)
            set y = GetUnitY(d.targ)
            
            if d.speed &lt;= 0 or IsPointOutside(x,y) then
                call d.destroy() // Finish knockback if speed == 0 or unit has hit map borders.
                set Total = Total - 1
                set DataArray<i> = DataArray[Total]
            else
                set newx = x+d.speed*d.cos
                set newy = y+d.speed*d.sin
                call SetUnitPosition(d.targ,newx,newy) // Set units new position.
                
                if d.killdest then // Kills trees if boolean is true.
                    call SetRect(Rect1,x-Radius,y-Radius,x+Radius,y+Radius)
                    call EnumDestructablesInRect(Rect1,Treefilt,function KillEnumDestructables)
                endif
                
                if d.sfxmode == 0 then
                    set d.sfxmode = d.TerrainType(d.targ,&quot;sfx&quot;)
                else
                    set d.sfxmode = d.TerrainType(d.targ,&quot;&quot;) // Checks for pathing again.
                endif
                
                // Adds special effects.
                if d.sfxmode == 1 then
                    call DestroyEffect(d.SFX)
                    set d.SFX = AddSpecialEffectTarget(Dirt_SFX,d.targ,Attachment_point)
                    set d.sfxmode = 2
                elseif d.sfxmode == 2 then
                    call DestroyEffect(d.SFX)
                    set d.SFX = AddSpecialEffectTarget(Water_SFX,d.targ,Attachment_point)
                    set d.sfxmode = 1
                endif
                
                set d.speed = d.speed - d.decrease // Sets new speed.
            endif
            
            set i = i - 1
        endloop
        
        if Total &lt;= 0 then
            call PauseTimer(Timer)
            set Total = 0
        endif
    endmethod
    
    private method onDestroy takes nothing returns nothing
        set .targ = null
        if .SFX != null then
            call DestroyEffect(.SFX) // Destroys effects if needed.
            set .SFX = null
        endif
    endmethod
endstruct

//***************************************************************************************
//** Only two functions used by this system. KBS_BeginEx and KBS_Begin.                **
public function BeginEx takes unit Target, real Startspeed, real Deceleration, real Angle, string SpecialEffect, boolean Killtrees returns nothing
    call Data.create(Target,Startspeed,Deceleration,(Angle*0.01745328),SpecialEffect,Killtrees)
endfunction
//**                                                                                   **
public function Begin takes unit Target, real Startspeed, real Deceleration, real Angle, boolean Killtrees returns nothing    
    call BeginEx(Target,Startspeed,Deceleration,Angle,&quot;&quot;,Killtrees)
endfunction                                                                                                
//**                                                                                   **
//***************************************************************************************

// Sets map boundries and sets timer, rect and filter.
private function Init takes nothing returns nothing
    set Timer = CreateTimer()
    set Rect1 = Rect(0.00,0.00,1.00,1.00)
    set Treefilt = Condition(function TreeCheck)
    set Game_maxX = GetRectMaxX(bj_mapInitialPlayableArea)-64.00
    set Game_maxY = GetRectMaxY(bj_mapInitialPlayableArea)-64.00
    set Game_minX = GetRectMinX(bj_mapInitialPlayableArea)+64.00
    set Game_minY = GetRectMinY(bj_mapInitialPlayableArea)+64.00
endfunction

endlibrary</i></i>
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • 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 The Helper:
    New recipe is another summer dessert Berry and Peach Cheesecake - https://www.thehelper.net/threads/recipe-berry-and-peach-cheesecake.194169/
  • The Helper The Helper:
    I think we need to add something to the bottom of the front page that shows the Headline News forum that has a link to go to the News Forum Index so people can see there is more news. Do you guys see what I am saying, lets say you read all the articles on the front page and you get to the end and it just ends, no kind of link for MOAR!
  • The Helper The Helper:
    Happy Wednesday!
    +1

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top