System Shape Creator

Executor

I see you
Reaction score
57
Shape Creator 2.1
Continued by killingdyl

vJass, sys independent (optional TimerUtils), MI
by Executor alias Lord_Executor

Description:
This library allows you to work easily with various shapes. You simply choose the shape you want, define the number of points you need and define the callback function, which will be called for every single point of the shape. Of course there are more parameters than only number of points and callback function, but this shall help understand how my system works.

Screenshot:
Circle + IntersectedStarPolygon with 5 corners + NonIntersectedStarPolygon with 5 corners:
attachment.php

More Screenshots:
Circle + IntersectedStarPolygon with 7 corners + NonIntersectedStarPolygon with 7 corners:

attachment.php


Line + Circle, Line periodically adjusts sx,sy,sz of the circle => a Spiral

attachment.php


Circle summoning Water Elementals

attachment.php

Interface:
JASS:
// Shaper Interface

//                                                                           
//  Shape.createLine(real sx, real sy, real sz, 
//                   real xyAngle, real zAngle, 
//                   real distance, integer count, 
//                   real interval, 
//                   usrfunc periodic, usrfunc final) 
//                                                                          
//  Shape.createEllipsis(real mx, real my, real mz,
//                       real sAngle, real xyAngle, real zAngle, 
//                       real r1, real r2, integer count,
//                       integer dir, real interval,                                                                           
//                       usrfunc periodic, usrfunc final)  
//
//  Shape.createSquare(real mx, real my, real mz, 
//                     real angleToStartCorner, real zAngle, 
//                     real edgeLength, integer countPerEdge, 
//                     integer dir, real interval,
//                     usrfunc periodic, usrfunc final)
//                                                  
//                                                                           
//  Shape.createIntersectedStarPolygon(real mx, real my, real mz, 
//                                     real angleToStartCorner, real zAngle, 
//                                     real r, integer corners, integer countPerEdge,
//                                     integer dir, real interval, 
//                                     usrfunc periodic, usrfunc final)                                                                        
//                                                                           
//  Shape.createNonIntersectedStarPolygon(real mx, real my, real mz, 
//                                        real angleToStartCorner, real zAngle, 
//                                        real r, integer corners, integer countPerEdge,
//                                        integer dir, real interval, 
//                                        usrfunc periodic, usrfunc final)                                                                           
//                                                                           
//  set Instance.limit = integer
//  set integer = Instance.limit
//  limit equals the total points being calculated. Setting limit to limit*2 (after you called the create func of course)
//  will result in the shape to be drawn two times one after the other...                                                                       
//            
//  call Instance.stop()
//  stops the shape-creation and erases the instance.

Code:
JASS:
// ===============================================================
// ======================== Shape Creator ========================
// ===============================================================
// Desc: 
// This library allows you to easily loop through shapes
// You can for example damage in a line, create effect pentagramms,
// create unit circles, etc.
//
// How to:
//
//  sx : source x   sy : source y   sz : source z   mx : mid x   my : mid y   mz : mid z
//
//      interval: time between each step 
//      periodic: this code will be fired each step
//      final: this code will on the last step, if final == 0 then periodic will be fired
// 
//
//      Line:
//
//          Shape.createLine(real sx, real sy, real sz, real xyAngle, real zAngle, real distance, 
//                           integer count, real interval, usrfunc periodic, usrfunc final)
//
//              xyAngle: in which direction the line shall be created 
//              zAngle: angle between xy-plane and the line
//              distance: the length of the line
//              count: how many steps till end of the line
//
//      Circle:
//
//          Shape.createEllipsis takes real mx, real my, real mz, real r1, real r2, real sAngle, real xyAngle, 
//                     real zAngle, integer dir,integer count, real interval, usrfunc periodic, usrfunc final)
//
//              r1: first radius
//              r2: second radius
//              
//              sAngle: angle to the first point of the circle, 90° will be the most northern point
//              zAngle: angle between xy-plane and the ellipsis-plane
//              xyAngle: where the point with the lowest z-value shall point at, relative to the mid
//              direction: clockwise or not clockwise? 1 or -1
//              count: how many steps till the circle is finished
//          
//      StarPolygons:
//  
//          <a href="http://upload.wikimedia.org/wikipedia/commons/9/96/Regular_Star_Polygons.jpg" target="_blank" class="link link--external" rel="nofollow ugc noopener">http://upload.wikimedia.org/wikipedia/commons/9/96/Regular_Star_Polygons.jpg</a>
//          You can create the far left and the far right diagonal chain
//
//          Far left chain/ IntersectedStarPolygons:
//
//              Shape.createIntersectedStarPolygon takes real mx, real my, real mz, real angleToStartCorner, integer corners,
//                   real r, real zAngle, integer dir, integer countPerEdge, real interval, usrfunc periodic, usrfunc final)
//
//          Far right diagonal chain/ NonIntersectedStarPolygons:
//
//              Shape.createNonIntersectedStarPolygon takes real mx, real my, real mz, real angleToStartCorner, integer corners,
//                   real r, real zAngle, integer dir, integer countPerEdge, real interval, usrfunc periodic, usrfunc final)  
//
//                  angleToStartCorner: angle to the first corner
//                  corners: how many corners?
//                  r: radius of the circumcircle
//                  zAngle: angle between the xy-plane and the plane of the shape
//                  dir: direction of the shape creation, +1 or -1
//                  countPerEdge: steps each edge
//                  interval: time between each step
//                  code: this code will be fired each step
//
//  usrfunc issues:
//  
//  The code has to take nothing and returns nothing
//  When in the usrfunc you may use Shape.getData() to return the &quot;triggering&quot; Shape instance
//  Aswell as .x and .y as parameters for the current step + .customValue (integer) for attaching
//
//  Have Fun!
//  Credits to Lord_Executor


library ShapeCreator requires optional TimerUtils

    private function interface usrfunc takes Shape sp returns nothing
    private function interface flusher takes integer this returns nothing

    private struct LineData
        real vx
        real vy
        real vz
        //! runtextmacro ShapeCreator_Flush()
    endstruct
    private struct EllipsisData
        real    modAngle
        real    currAngle
        real    cosB
        real    sinB
        real    cosA
        real    sinA
        real    r1
        real    r2
        //! runtextmacro ShapeCreator_Flush()
    endstruct
    private struct StarPolygonData
        integer remPointsOnStage
        integer pointsPerStage
        real    modAngle
        real    currAngle
        real    vx
        real    vy
        real    vz
        real    tx
        real    ty
        real    tz
        real    cosB
        real    sinB
        real    cosA
        real    sinA
        real    offset
        //! runtextmacro ShapeCreator_Flush()
    endstruct
    
    struct Shape
        real x
        real y  
        real z
        integer customValue
        
        real sx
        real sy
        real sz
        private integer remPoints
        private integer shapeData
        
        private flusher flushData
        private usrfunc periodic
        private usrfunc final
        private timer intervalTimer      
        
        private static constant real PI2    = 2*bj_PI
        private static constant real PIDiv2 = bj_PI/2 
        
        static if not LIBRARY_TimerUtils then
            private static hashtable link
            private static method onInit takes nothing returns nothing
                set .link = InitHashtable()
            endmethod
        endif
        
        method stop takes nothing returns nothing
            call .flushData.evaluate(.shapeData)
            call .destroy()
        endmethod
        method operator limit takes nothing returns integer
            return .remPoints
        endmethod
        method operator limit= takes integer i returns nothing
            set .remPoints = i
        endmethod
        
        private static method onPause takes nothing returns nothing
            //! runtextmacro ShapeCreator_GetInstance()
            call .flushData.evaluate(.shapeData)
            call .destroy()
        endmethod
        
        private static method onCreateLineTimer takes nothing returns nothing
            //! runtextmacro ShapeCreator_GetInstance()
            local LineData d    = .shapeData
            set .x              = .x + d.vx
            set .y              = .y + d.vy
            set .z              = .z + d.vz
            //! runtextmacro ShapeCreator_ReleaseInstance()
        endmethod
                
        static method createLine takes real sx, real sy, real sz, real xyAngle, real zAngle, real distance, integer count, real interval, usrfunc periodic, usrfunc final returns thistype
            local thistype this = thistype.allocate()
            
            local real offset   = distance/(count-1) 
            local real cosB     = Cos(xyAngle-.PIDiv2)
            local real sinB     = Sin(xyAngle-.PIDiv2)
            local real cosA     = Cos(zAngle)
            local real sinA     = Sin(zAngle)
            local real fac      = cosA * offset
            //! runtextmacro ShapeCreator_VarSetup(&quot;Line&quot;)
            
            set .remPoints      = count
            set .sx             = sx
            set .sy             = sy
            set .sz             = sz
            set d.vx            = -sinB * fac
            set d.vy            =  cosB * fac
            set d.vz            =  sinA * offset
            set .x              = sx - d.vx
            set .y              = sy - d.vy
            set .z              = sz - d.vz

            //! runtextmacro ShapeCreator_TimerSetup(&quot;Line&quot;,&quot;periodic&quot;,&quot;final&quot;)
            return this
        endmethod
        
        private static method onCreateEllipsisTimer takes nothing returns nothing
            //! runtextmacro ShapeCreator_GetInstance()
            local EllipsisData d = .shapeData
            
            local real vx   = d.r1      * Cos(d.currAngle)
            local real vy   = d.r2      * Sin(d.currAngle)
            local real fac  = d.cosA    * vy
            set .x = .sx + d.cosB * vx - d.sinB * fac
            set .y = .sy + d.sinB * vx + d.cosB * fac
            set .z = .sz + d.sinA * vy           
            
            set d.currAngle = d.currAngle + d.modAngle
            //! runtextmacro ShapeCreator_ReleaseInstance()
        endmethod
        
        static method createEllipsis takes real mx, real my, real mz, real sAngle, real xyAngle, real zAngle,/* 
            */real r1, real r2,integer count, integer dir, real interval, usrfunc periodic, usrfunc final returns thistype
            local thistype this = thistype.allocate()
                        
            //! runtextmacro ShapeCreator_VarSetup(&quot;Ellipsis&quot;)
            set .remPoints  = count
            set .sx         = mx                
            set .sy         = my                
            set .sz         = mz
            set xyAngle     = xyAngle - .PIDiv2
            set d.currAngle = sAngle
            set d.cosB      = Cos(xyAngle)
            set d.sinB      = Sin(xyAngle)
            set d.cosA      = Cos(zAngle)
            set d.sinA      = Sin(zAngle)
            set d.r1        = r1
            set d.r2        = r2
            set d.modAngle  = .PI2/(count) * dir
            
            //! runtextmacro ShapeCreator_TimerSetup(&quot;Ellipsis&quot;,&quot;periodic&quot;,&quot;final&quot;)
        endmethod
        
        private static method onCreateStarPolygonTimer takes nothing returns nothing
            //! runtextmacro ShapeCreator_GetInstance()
            local StarPolygonData d = .shapeData
            local real fac = 0
            local real ux  = 0
            local real uy  = 0
            if d.pointsPerStage == 0 then
                set d.remPointsOnStage = d.remPointsOnStage
                set d.pointsPerStage   = d.remPointsOnStage - 1
                return
            endif
            set .x              = .x + d.vx       
            set .y              = .y + d.vy    
            set .z              = .z + d.vz
            set d.remPointsOnStage = d.remPointsOnStage - 1
            if d.remPointsOnStage &lt; 1 then
                set d.currAngle      = d.currAngle+d.modAngle
                set ux  = Cos(d.currAngle) * d.offset  
                set uy  = Sin(d.currAngle) * d.offset
                set fac              = d.cosA * uy
                set d.vx             = d.cosB * ux - d.sinB * fac   
                set d.vy             = d.sinB * ux + d.cosB * fac
                set d.vz             = d.sinA * uy
                set d.remPointsOnStage  = d.pointsPerStage
            endif
            //! runtextmacro ShapeCreator_ReleaseInstance()
        endmethod
        
        static method createIntersectedStarPolygon takes real mx, real my, real mz, real angleToStartCorner, real zAngle, real r,/* 
            */integer corners, integer countPerEdge, integer dir, real interval, usrfunc periodic, usrfunc final returns thistype
            local thistype this = thistype.allocate()
            
            local real edgeLength   = 0
            local real fac          = 0
            local real ux           = 0
            local real uy           = 0
            //! runtextmacro ShapeCreator_VarSetup(&quot;StarPolygon&quot;)
            
            set .remPoints          = countPerEdge * corners - corners
            set d.remPointsOnStage  = countPerEdge
            set .sx                 = mx
            set .sy                 = my
            set .sz                 = mz
            set angleToStartCorner  = angleToStartCorner - .PIDiv2
            set d.cosB              = Cos(angleToStartCorner)
            set d.sinB              = Sin(angleToStartCorner)
            set d.cosA              = Cos(zAngle)
            set d.sinA              = Sin(zAngle)
            set d.pointsPerStage    = 0
            set d.modAngle          = bj_PI-bj_PI/corners
            set edgeLength          = SquareRoot(2*r*r*(1-Cos(d.modAngle)))
            set d.modAngle          = d.modAngle * dir 
            set d.currAngle         = bj_PI+(d.modAngle/2)
            set d.offset            = edgeLength/(countPerEdge-1) * dir
            
            set uy      = r
            set fac     = d.cosA * uy
            set .x      = mx - d.sinB * fac
            set .y      = my + d.cosB * fac
            set .z      = mz + d.sinA * uy
            set ux      = Cos(d.currAngle) * d.offset
            set uy      = Sin(d.currAngle) * d.offset
            set fac     = d.cosA * uy
            set d.vx    = d.cosB * ux - d.sinB * fac
            set d.vy    = d.sinB * ux + d.cosB * fac
            set d.vz    = d.sinA * uy
            set .x      = .x - d.vx
            set .y      = .y - d.vy
            set .z      = .z - d.vz
        
            //! runtextmacro ShapeCreator_TimerSetup(&quot;StarPolygon&quot;,&quot;periodic&quot;,&quot;final&quot;)
        endmethod      
        
        static method createNonIntersectedStarPolygon takes real mx, real my, real mz, real angleToStartCorner, real zAngle, real r,/* 
            */integer corners, integer countPerEdge, integer dir, real interval, usrfunc periodic, usrfunc final returns thistype
            local thistype this = thistype.allocate()
            
            local real edgeLength   = 0
            local real fac          = 0
            local real ux           = 0
            local real uy           = 0
            //! runtextmacro ShapeCreator_VarSetup(&quot;StarPolygon&quot;)
            
            set .remPoints          = countPerEdge * corners - corners
            set d.remPointsOnStage  = countPerEdge
            set .sx                 = mx
            set .sy                 = my
            set .sz                 = mz
            set angleToStartCorner  = angleToStartCorner - .PIDiv2
            set d.cosB              = Cos(angleToStartCorner)
            set d.sinB              = Sin(angleToStartCorner)
            set d.cosA              = Cos(zAngle)
            set d.sinA              = Sin(zAngle)
            set d.pointsPerStage    = 0
            set d.modAngle          = .PI2/corners
            set edgeLength          = 2*r * Sin(d.modAngle/2)
            set d.modAngle          = d.modAngle * dir 
            set d.currAngle         = bj_PI+(d.modAngle/2)
            set d.offset            = edgeLength/(countPerEdge-1) * dir
            
            set uy      = Sin(.PIDiv2) * r
            set fac     = d.cosA * uy
            set .x      = mx - d.sinB * fac
            set .y      = my + d.cosB * fac
            set .z      = mz + d.sinA * uy
            set ux      = Cos(d.currAngle) * d.offset
            set uy      = Sin(d.currAngle) * d.offset
            set fac     = d.cosA * uy
            set d.vx    = d.cosB * ux - d.sinB * fac
            set d.vy    = d.sinB * ux + d.cosB * fac
            set d.vz    = d.sinA * uy
            set .x      = .x - d.vx
            set .y      = .y - d.vy
            set .z      = .z - d.vz
        
            //! runtextmacro ShapeCreator_TimerSetup(&quot;StarPolygon&quot;,&quot;periodic&quot;,&quot;final&quot;)
        endmethod
        
        static method createSquare takes real mx, real my, real mz, real angleToStartCorner, real zAngle, real edgeLength,/*
                                       */integer countPerEdge, integer dir, real interval, usrfunc periodic, usrfunc final returns thistype
            local real e2 = edgeLength*edgeLength
            return .createNonIntersectedStarPolygon(mx,my,mz,angleToStartCorner,zAngle,0.5*SquareRoot(2*e2),4,countPerEdge,dir,interval,periodic,final)
        endmethod
        
        //! textmacro ShapeCreator_GetInstance
            static if LIBRARY_TimerUtils then
                local thistype this = GetTimerData(GetExpiredTimer())
            else
                local thistype this = LoadInteger(.link,GetHandleId(GetExpiredTimer()),0)
            endif
        //! endtextmacro
        
        //! textmacro ShapeCreator_ReleaseInstance
            set .remPoints     = .remPoints- 1
            if .remPoints&lt; 1 then
                call PauseTimer(.intervalTimer)
                call TimerStart(.intervalTimer,0.,false,function thistype.onPause)
                if .final != 0 then
                    call .final.evaluate(this)
                    return
                endif
            endif
            call .periodic.evaluate(this)
        //! endtextmacro
        
        //! textmacro ShapeCreator_Flush
            static method flush takes integer i returns nothing
                call thistype(i).destroy()
            endmethod
        //! endtextmacro
        
        //! textmacro ShapeCreator_VarSetup takes FUNCNAME
            local $FUNCNAME$Data d = $FUNCNAME$Data.create()
            set .shapeData = d
            set .flushData = $FUNCNAME$Data.flush
        //! endtextmacro
        
        //! textmacro ShapeCreator_TimerSetup takes FUNCNAME, PERIODIC, FINAL
            static if LIBRARY_TimerUtils then
                if .intervalTimer == null then
                    set .intervalTimer = NewTimer()
                endif
                call SetTimerData(.intervalTimer,this)
            else               
                if .intervalTimer == null then
                    set .intervalTimer = CreateTimer()
                endif
                call SaveInteger(.link,GetHandleId(.intervalTimer),0,this)
            endif
            set .periodic = $PERIODIC$
            set .final    = $FINAL$
            call TimerStart(.intervalTimer,interval,true,function thistype.onCreate$FUNCNAME$Timer)
            return this
        //! endtextmacro
    endstruct

endlibrary

Example Usage:
JASS:
scope WaterElemental initializer Init

    private function Amount takes integer lvl returns integer
        return lvl * 2
    endfunction
    
    private function Radius takes integer lvl returns real
        return 150.+lvl*40.
    endfunction
    
    private function LifeTime takes integer lvl returns real
        return 10.
    endfunction
    
    private function CreationTimePerElemental takes integer lvl returns real
        return 0.1
    endfunction
    
    globals
        private constant integer SPELLID    = &#039;A000&#039; 
        private constant integer SPAWNID    = &#039;hwat&#039;
        private constant string  SPAWN_SFX  = &quot;Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl&quot;
    endglobals
    
    // End Config

    private function createElemental takes Shape sp returns nothing
        call DestroyEffect(AddSpecialEffect(SPAWN_SFX,sp.x,sp.y))
        call UnitApplyTimedLife(CreateUnit(Player(0),SPAWNID,sp.x,sp.y,bj_RADTODEG * Atan2(sp.y-sp.sy,sp.x-sp.sx)),&#039;0000&#039;,LifeTime(sp.customValue))
    endfunction
    
    private function onCast takes nothing returns boolean
        local unit u = null
        local integer lvl = 0
        if GetSpellAbilityId() != SPELLID then
            return false
        endif
        set u   = GetTriggerUnit()
        set lvl = GetUnitAbilityLevel(u,SPELLID)
        set Shape.createEllipsis(GetUnitX(u),GetUnitY(u),0.,Radius(lvl),Radius(lvl),0.,0.,0.,1,Amount(lvl),CreationTimePerElemental(lvl),createElemental,0).customValue = lvl       
        return false
    endfunction

    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterUnitEvent(t,HERO,EVENT_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t,Condition(function onCast))
    endfunction
endscope

Changelog:
v2.2: Renamed from "Shaper" to "Shape Creator"; Updated some descriptions; Added Square-wrapper
v2.1: Cleaned up the code; Added Instance.stop(); Reorganized function parameters
v2.0: 3D-Upgrade
v1.1: Added optional TimerUtils usage
v1.0: Release

Note:
I'm still working on it, but I'd like to receive constructive criticism to improve.

Greetings
 

Attachments

  • look.JPG
    look.JPG
    105.8 KB · Views: 792
  • look3.JPG
    look3.JPG
    78.9 KB · Views: 788
  • Shaper.w3x
    44.2 KB · Views: 314
  • Look2.JPG
    Look2.JPG
    130.7 KB · Views: 587
  • Look1.JPG
    Look1.JPG
    137.1 KB · Views: 654

Jesus4Lyf

Good Idea™
Reaction score
397
JASS:
    private function onTestRepeater takes nothing returns nothing
        local Shape sd = Shape.getData()
        call DestroyEffect(AddSpecialEffect(&quot;Abilities\\Spells\\Human\\SpellSteal\\SpellStealMissile.mdl&quot;,sd.x,sd.y))
    endfunction

    private function onTest takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real a =  GetUnitFacing(u)*bj_DEGTORAD
        local Shape sd = 0
        set sd = Shape.createIntersectedStarPolygon(x,y,a,5,500.,1,15,0.0,function onTestRepeater)
        // creates a pentagram
    endfunction

-->
JASS:
    private function onTestRepeater takes Shape sd returns nothing
        call DestroyEffect(AddSpecialEffect(&quot;Abilities\\Spells\\Human\\SpellSteal\\SpellStealMissile.mdl&quot;,sd.x,sd.y))
    endfunction

    private function onTest takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real a =  GetUnitFacing(u)*bj_DEGTORAD
        local Shape sd = 0
        set sd = Shape.createIntersectedStarPolygon(x,y,a,5,500.,1,15,0.0,/*function */onTestRepeater)
        // creates a pentagram
    endfunction

Y'know. :thup:
 

BlackRose

Forum User
Reaction score
239
Ahaha. I always love things like these. If you wouldn't mind, make some more pretty shapes and screenshots just for my thrill?
 

Executor

I see you
Reaction score
57
I tried to avoid interfaces, as they are triggers, which have to be created/destroyed/evaluated.

You could also modify KT2 to use callback interfaces with the attached data as parameter ;)
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
JASS:
// ===============================================================
// =========================== Shaper ============================
// ===============================================================
// Desc: 
// This library allows you to easily loop through shapes
// You can for example damage in a line, create effect pentagramms,
// create unit squares, etc.
//
// How to:
//
//  sx : source x   sy : source y   mx : mid x   my : mid y
// 
//      Line:
//
//          Shape.createLine(sx,sy,angle,distance,count,interval,function&#039;s name)
//
//              angle: the direction of the line
//              distance: the length of the line
//              count: how many steps till end of the line
//              interval: time between each step 
//              code: this code will be fired each step
//
//      Circle:
//
//          Shape.createCircle(mx,my,radius,startAngle,direction,count,interval,function&#039;s name)
//
//              radius: radius of the circle
//              startAngle: angle to the first point of the circle
//              direction: clockwise or not clockwise? 1 or -1
//              count: how many steps till the circle is finished
//              interval: time between each step
//              code: this code will be fired each step
//          
//      StarPolygons:
//  
//          <a href="http://upload.wikimedia.org/wikipedia/commons/9/96/Regular_Star_Polygons.jpg" target="_blank" class="link link--external" rel="nofollow ugc noopener">http://upload.wikimedia.org/wikipedia/commons/9/96/Regular_Star_Polygons.jpg</a>
//          You can create the far left and the far right diagonal chain
//
//          Far left chain/ IntersectedStarPolygons:
//
//              Shape.createIntersectedStarPolygon(mx, my, angleToStartCorner, corners, radius, 
//                                                 dir, countPerEdge, interval, function&#039;s name)    
//
//          Far right diagonal chain/ NonIntersectedStarPolygons:
//
//              Shape.createNonIntersectedStarPolygon(mx, my, angleToStartCorner, corners, radius, 
//                                                 dir, countPerEdge, interval, function&#039;s name)  
//
//                  angleToStartCorner: angle to the first point
//                  corners: how many corners?
//                  radius: radius of the circumcircle
//                  dir: direction of the shape creation, +1 or -1
//                  countPerEdge: steps each edge
//                  interval: time between each step
//                  code: this code will be fired each step
//
//  Callback example : function ExampleCallback takes Shaper shape returns nothing
//
//  Have Fun!
//  Credits to Lord_Executor


library Shaper requires optional TimerUtils, optional Table
    
    function interface ShaperCallback takes integer shape returns nothing
    
    struct Shape
        real x
        real y       
        integer customValue
        ShaperCallback callback
        
        private integer totalRest
        private integer restOnStage
        private integer countPerStage
        private real    modAngle
        private real    currAngle
        private real    vx
        private real    vy
        private real    offset
        
        private timer intervalTimer    
        
        private static constant real PI2    = 2*bj_PI
        private static constant real PIDiv2 = bj_PI/2 
        
        static if not LIBRARY_TimerUtils then
            static if LIBRARY_Table then
                private static HandleTable TimerData
                private static method onInit takes nothing returns nothing
                    set TimerData = HandleTable.create()
                endmethod
            else
                private static hashtable link
                private static method onInit takes nothing returns nothing
                    set .link = InitHashtable()
                endmethod
            endif
        endif
            
        private static method onPause takes nothing returns nothing
            //! runtextmacro Shaper_GetInstance()
            static if LIBRARY_TimerUtils then
                call ReleaseTimer(.intervalTimer)
            else
                call PauseTimer(.intervalTimer)
            endif
            call .destroy()
        endmethod
        
        private static method onCreateLineTimer takes nothing returns nothing
            //! runtextmacro Shaper_GetInstance()
            set .x              = .x + .vx
            set .y              = .y + .vy
            set .totalRest      = .totalRest - 1
            //! runtextmacro Shaper_Callback()
        endmethod
                
        static method createLine takes real sx, real sy, real angle, real distance, integer count, real interval, ShaperCallback c returns thistype
            local thistype this = thistype.allocate()
            
            set .offset     = distance/count            
            set .vx         = Cos(angle) * .offset
            set .vy         = Sin(angle) * .offset
            set .x          = sx - .vx
            set .y          = sy - .vy
            set .totalRest  = count
            
            //! runtextmacro Shaper_CreateStandardStuff(&quot;Line&quot;)
        endmethod
        
        private static method onCreateCircleTimer takes nothing returns nothing
            //! runtextmacro Shaper_GetInstance()
            set .x              = .vx + Cos(.currAngle) * .offset         // vx =&gt; mx; dir =&gt; r
            set .y              = .vy + Sin(.currAngle) * .offset         // vx =&gt; my; dir =&gt; r
            set .currAngle      = ModuloReal(.currAngle + .modAngle,.PI2)
            set .totalRest      = .totalRest - 1
            //! runtextmacro Shaper_Callback()
        endmethod
        
        static method createCircle takes real mx, real my, real r, real startangle, integer dir,/*
            */ integer count, real interval, ShaperCallback c returns thistype
            
            local thistype this = thistype.allocate()
            
            set .totalRest  = count
            set .vx         = mx                // vx =&gt; mx
            set .vy         = my                // vy =&gt; my
            set .currAngle  = startangle
            set .offset     = r                 // dir =&gt; r
            set .modAngle   = .PI2/count * dir
            
            //! runtextmacro Shaper_CreateStandardStuff(&quot;Circle&quot;)
        endmethod
        
        private static method onCreateIntersectedStarPolygonTimer takes nothing returns nothing
            //! runtextmacro Shaper_GetInstance()
            if .countPerStage == 0 then
                set .restOnStage    = .restOnStage - 1
                set .countPerStage  = .restOnStage
                return
            endif
            set .x              = .x + .vx       
            set .y              = .y + .vy                
            set .restOnStage    = .restOnStage - 1
            if .restOnStage &lt; 1 then
                set .currAngle      = ModuloReal(.currAngle+.modAngle,.PI2)
                set .vx             = Cos(.currAngle) * .offset    
                set .vy             = Sin(.currAngle) * .offset   
                set .restOnStage    = .countPerStage
            endif
            set .totalRest      = .totalRest - 1
            //! runtextmacro Shaper_Callback()
        endmethod
        
        static method createIntersectedStarPolygon takes real mx, real my, real angleToStartCorner, integer corners,/*
            */real r, integer dir, integer countPerEdge, real interval, ShaperCallback c returns thistype
            local thistype this = thistype.allocate()
            local real edgeLength = 0
            
            set .modAngle   = bj_PI-bj_PI/corners
            set edgeLength  = SquareRoot(2*r*r*(1-Cos(.modAngle)))
            set .modAngle   = .modAngle * dir 
            
            set .x              = mx + Cos(angleToStartCorner) * r
            set .y              = my + Sin(angleToStartCorner) * r
            set .countPerStage  = 0
            set .currAngle      = ModuloReal(angleToStartCorner+.PIDiv2+(.modAngle/2),.PI2)
            set .offset         = edgeLength/(countPerEdge-1) * dir
            set .vx             = Cos(.currAngle) * .offset
            set .vy             = Sin(.currAngle) * .offset
            set .totalRest      = countPerEdge * corners - corners
            set .restOnStage    = countPerEdge
        
            //! runtextmacro Shaper_CreateStandardStuff(&quot;IntersectedStarPolygon&quot;)
        endmethod
        
        private static method onCreateNonIntersectedStarPolygonTimer takes nothing returns nothing
            //! runtextmacro Shaper_GetInstance()
            if .countPerStage == 0 then
                set .restOnStage    = .restOnStage - 1
                set .countPerStage  = .restOnStage
                return
            endif
            set .x              = .x + .vx       
            set .y              = .y + .vy                
            set .restOnStage    = .restOnStage - 1
            if .restOnStage &lt; 1 then
                set .currAngle      = ModuloReal(.currAngle+.modAngle,.PI2)
                set .vx             = Cos(.currAngle) * .offset    
                set .vy             = Sin(.currAngle) * .offset   
                set .restOnStage    = .countPerStage
            endif
            set .totalRest      = .totalRest - 1
            //! runtextmacro Shaper_Callback()
        endmethod
        
        
        static method createNonIntersectedStarPolygon takes real mx, real my, real angleToStartCorner, integer corners,/*
            */real r, integer dir, integer countPerEdge, real interval, ShaperCallback c returns thistype
            local thistype this = thistype.allocate()
            
            local real edgeLength = 0
            
            set .modAngle   = .PI2/corners
            set edgeLength  = 2*r * Sin(.modAngle/2)
            
            set .x              = mx + Cos(angleToStartCorner) * r
            set .y              = my + Sin(angleToStartCorner) * r
            set .countPerStage  = 0
            set .currAngle      = ModuloReal(angleToStartCorner+.PIDiv2+(.modAngle/2)*dir,.PI2)
            set .modAngle       = .modAngle * dir
            set .offset         = edgeLength/(countPerEdge-1) * dir
            set .vx             = Cos(.currAngle) * .offset
            set .vy             = Sin(.currAngle) * .offset
            set .totalRest      = countPerEdge * corners - corners
            set .restOnStage    = countPerEdge
        
            //! runtextmacro Shaper_CreateStandardStuff(&quot;NonIntersectedStarPolygon&quot;)
        endmethod
        
        //! textmacro Shaper_CreateStandardStuff takes FUNCNAME
            static if LIBRARY_TimerUtils then
                set .intervalTimer = NewTimer()
                call SetTimerData(.intervalTimer,this)
            else               
                if .intervalTimer == null then
                    set .intervalTimer = CreateTimer()
                    static if LIBRARY_Table then
                        set TimerData[.intervalTimer] = this
                    else
                        call SaveInteger(.link,GetHandleId(.intervalTimer),0,this)
                    endif
                endif
            endif
            set .callback = c
            call TimerStart(.intervalTimer,interval,true,function thistype.onCreate$FUNCNAME$Timer)
            return this
        //! endtextmacro
        
        //! textmacro Shaper_GetInstance
            static if LIBRARY_TimerUtils then
                local thistype this = GetTimerData(GetExpiredTimer())
            elseif LIBRARY_Table then
                local thistype this = TimerData[GetExpiredTimer()]
            else
                local thistype this = LoadInteger(.link,GetHandleId(GetExpiredTimer()),0)
            endif
        //! endtextmacro
        
        //! textmacro Shaper_Callback
            if .callback != 0 then
                call .callback.execute(this)
            endif
            if .totalRest == 0 then
                call PauseTimer(.intervalTimer)
                call TimerStart(.intervalTimer,0.,false,function thistype.onPause)
            endif
        //! endtextmacro
    endstruct

endlibrary

Cleaned up some code and uses function interface. Added support for Table.


I tried to avoid interfaces, as they are triggers, which have to be created/destroyed/evaluated.
Nothing wrong with it.

You should prevent from creating hashtable since you are not using 2d array.
Hashtable has lame limit.
 

Executor

I see you
Reaction score
57
Cleaned up some code and uses function interface. Added support for Table.

- Good idea with the textmacro. Will use it.
- Well no, I want one completely independent version and well, one optimized version. If I wanted more I could also include KT2 ..

Hashtable has lame limit.

I won't hit the limit. As I reuse the timers/the timer IDs.

JASS:
Nothing wrong with it.


Well, I don't know, are the triggers reused or destroyed and created (=> leak) again everytime?
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
- Well no, I want one completely independent version and well, one optimized version. If I wanted more I could also include KT2 ..
The version I posted is able to work by itself without TimerUtils/Table.

I won't hit the limit. As I reuse the timers/the timer IDs.
Er... Am I misleading you? I meant only 256 hashtables can be exist in a map. If you go beyond this limit, InitHashtable() will returns nothing.

Well, I don't know, are the triggers reused or destroyed and created (=> leak) again everytime?
No, trigger can be reused it if they are not registered to events. You can use trigger to execute codes.
JASS:
library CodeExecutor
    
    globals
        private trigger trig = CreateTrigger()
        private triggercondition cond = null
        private triggeraction act = null
        private boolean result
    endglobals
    
    function EvaluateCode takes code func returns boolean
        set cond = TriggerAddCondition(trig,Condition(func))
        set result = TriggerEvaluate(trig)
        call TriggerRemoveCondition(trig,cond)
        return result
    endfunction
    
    function ExecuteCode takes code func returns nothing
        set act = TriggerAddAction(trig,func)
        call TriggerExecute(trig)
        call TriggerRemoveAction(trig,act)
    endfunction
    
endlibrary
 

Executor

I see you
Reaction score
57
The version I posted is able to work by itself without TimerUtils/Table.
Yes, but then I could also include KT2.. as some maybe don't use TimerUtils or Table.
I will stick to the current solution.

Er... Am I misleading you? I meant only 256 hashtables can be exist in a map. If you go beyond this limit, InitHashtable() will returns nothing.
Ah k, thought you talked about a limit inside the hashtable.. Well if someone decides to use that many hashtables, he is .. pwnd^^

No, trigger can be reused it if they are not registered to events. You can use trigger to execute codes.
Yes, indeed and my question was whether jasshelper cares about the leak of Condition() etc.
Lets get it to the point: Do interfaces leak? Are they faster than my current solution?
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Do interfaces leak? Are they faster than my current solution?
No, they don't. For the speed, stopwatch native is not available for 1.24e, so I can't benchmark it. However, function interface provides better API for users.
 

Executor

I see you
Reaction score
57
No, they don't. For the speed, stopwatch native is not available for 1.24e, so I can't benchmark it. However, function interface provides better API for users.

K. Replaced. Will update it later, I'm currently working on converting everything into 3D :).
 

PurgeandFire

zxcvmkgdfg
Reaction score
509
Do you even need modulo for angles? I am not sure. I think it automatically converts them, but eh, I didn't test it. That might of just been for unit facing.

Otherwise, awesome system. You might want to consider adding a test map though for lazy people like me. =)
 

Lyerae

I keep popping up on this site from time to time.
Reaction score
105
Ah k, thought you talked about a limit inside the hashtable

According to what I know, and the tests I ran*, the amount of data hashtables can store is essentially unlimited. If you need more space, your doing something wrong.

(*I think I stopped the test at I index #500000 on the parentKey. I stopped after that.)
 

Lyerae

I keep popping up on this site from time to time.
Reaction score
105
What makes you say that (probably asking an obvious question, but still.)?
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top