System Rectwraps

Azlier

Old World Ghost
Reaction score
461
The combination of rects and regions into one body, in a nice vJassy way.

JASS:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Rectwraps ~~ By Azlier ~~ Version 4.0~~ Documentation ripped off from Jesus4Lyf ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  What is Rectwraps?
//         - Rectwraps are essentially vJass replacements for the native rects and regions.
//         - They can be attached to safely, which has certain uses.
//         - Rectwraps recycles anything it creates.
//
//    =Pros=
//         - Easy to use, once you learn the basic methods.
//         - Possibly faster than even native rects and regions.
//         - Fast, safe region attachment.
//         - No H2I/GetHandleId. Backwards compatability through patch 1.23 and 1.24.
//
//    =Cons=
//         - Uses TriggerExecCount to store data. If over 1000 rectwraps are created at one time,
//           there may be a short lag spike.
//         - Only 8191 rectwraps can exist at one time with the default settings.
//
//    Variables:
//      These coordinate variables can be both read and set. Reading them is much, much faster than setting them.
//      They are faster than their GetRect**** counterparts.
//
//         .minX
//          The x coordinate of the rectwrap's left side.
//
//         .maxX
//          The x coordinate of the rectwrap's right side.
//
//         .minY
//          The y coordinate of the rectwrap's bottom side.
//
//         .maxY
//          The x coordinate of the rectwrap's top side.
//
//         .cenX
//          The x coordinate of the rectwrap's center.
//
//         .cenY
//          The y coordinate of the rectwrap's center.
//
//      This integer variable is really there just for fun. Do not use it in any public resource.
//         .userData
//
//    Methods:
//         ~ Event responses
//             GetTriggeringRectwrap takes nothing returns rectwrap
//               This returns the entered/exited rectwrap when you enter/exit one.
//
//             rectwrap.getTriggering() takes nothing returns rectwrap
//               Same as above, but in static method form.
//
//         ~ Static
//             .wrap takes rect which returns rectwrap
//               Wraps a rect for use as a rectwrap. Purely for gg_rct rects.
//
//             .create takes real x1, real y1, real x2, real y2 returns rectwrap
//               Creates a rectwrap from the given coordinates.
//
//             .createFromPoint takes real x, real y, real width, real height returns rectwrap
//               Creates a rectwrap at a point with a set width and height.
//         ~ Non-static
//            .registerEnter takes trigger which returns trigger
//              Rigs a trigger to fire when the rectwrap is entered.
//              Also returns the given trigger so that you can use that weird one-line
//              coding style... if you really want to.
//
//            .registerExit takes trigger which returns trigger
//              Same as above, but when the rectwrap is exited.
//
//            .registerEnterCode takes code c returns trigger
//              Like .registerEnter, but takes a code. Returns the trigger the code was registered to.
//              THE CODE MUST RETURN A BOOLEAN.
//
//            .registerExitCode takes code c returns trigger
//              ...Must I really explain?
//
//            .destroy takes nothing returns nothing
//              Cleans the rectwrap's members. Recycles all handle members.
//
//            .setTo takes real x1, real y1, real x2, real y2 returns nothing
//              Shifts a rectwrap's dimensions to the given values.
//
//            .moveTo takes real x, real y returns nothing
//              Simply moves a rectwrap to the given coordinates without altering dimensions.
//
//            .copy takes nothing returns rectwrap
//              Copies a rectwrap completely, right down to the user data. Probably not much use, but it's there...
//
//            .replaceTerrain takes integer oldTerrain, integer terrain
//              Swaps all terrain of type oldTerrain for type terrain. Credits to Romek for this method.
//
//            .setPathing takes pathingtype path, boolean on returns nothing
//              Sets the pathingtype for a rectwrap on or off.
//
//            .iterateThrough takes IterateFunc func, real dist returns nothing.
//              Separates the rectwrap into distxdist cells and iterates through them, calling func with
//              that cell's center x and y as arguments.
//
//            .groupEnum takes group g, boolexpr filter returns nothing
//              GroupEnumUnitsInRect without the rect.
//
//            .createWeather takes integer id returns weathereffect
//              AddWeatherEffect without the rect.
//
//            .addFog takes player p, fogstate f, boolean b1, boolean b2 returns fogmodifier
//              CreateFogModifierRect without the rect.
//
//            .enumDestructables takes boolexpr filter, code enum returns nothing
//              EnumDestructablesInRect without the rect.
//
//            .enumItems takes boolexpr filter, code enum returns nothing
//              EnumItemsInRect without the rect.
//
//            .setBlight takes player p, boolean b returns nothing
//              SetBlight without the rect.
//
//            .setDoodadAnimation takes integer i, string s, boolean b returns nothing
//              SetDoodadAnimationRect without the rect.
//
//            .setFogState takes player p, fogstate f, boolean b returns nothing
//              SetFogStateRect without the rect.
//
//            .coordsInRect takes real x, real y returns boolean
//              Returns whether the given coordinates are within the rect or not.
//
//
//  Thanks:
//         - Jesus4Lyf: For his Event struct and TriggerExecCount attachment method.
//
//         - Troll Brain: For discovering a grave bug.
//
//         - Romek: For letting me duplicate his ReplaceTerrain script.
//
//         - Darkfeet (Darthfett): For giving me the idea.
//
//         - Skrarnaks: Spotting ANOTHER grave bug
//
//
//  How to import:
//         - Create a trigger named Rectwraps.
//         - Convert it to custom text and replace all the trigger text with this.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//Hack libraries to allow CamelCase library requirement.
//Yes, even I wanted to be able to do that.
library Rectwrap requires rectwrap
endlibrary
library Rectwraps requires rectwrap
endlibrary
library RectWrap requires rectwrap
endlibrary
library RectWraps requires rectwrap
endlibrary

library rectwrap

globals
    private rectwrap TrigRec = 0
endglobals

//This is to simulate an event response.
constant function GetTriggeringRectwrap takes nothing returns rectwrap
    return TrigRec
endfunction
    
    //Jesus4Lyf's Event
    private struct Event
        private trigger trig
        private Event next
        static method create takes nothing returns Event
            local Event this=Event.allocate()
            set this.next=0
            return this
        endmethod
        private static Event current
        private static trigger t
        method fire takes nothing returns nothing
            local Event curr
            // this = last.
            loop
                set curr=this.next
                exitwhen curr==0
                set .t=curr.trig
                if IsTriggerEnabled(.t) then
                    set .current=curr
                    if TriggerEvaluate(.t) then
                        call TriggerExecute(.t)
                    endif
                    set this=curr
                else
                    call EnableTrigger(.t) // Was trigger destroyed?
                    if IsTriggerEnabled(.t) then
                        call DisableTrigger(.t)
                        set this=curr
                    else // If trigger destroyed...
                        set .current.trig=null
                        set this.next=curr.next
                        call curr.destroy()
                    endif
                endif
            endloop
        endmethod
        method register takes trigger t returns nothing
            local Event new=Event.allocate()
            set new.next=this.next
            set new.trig=t
            set this.next=new
        endmethod
        method chainDestroy takes nothing returns nothing
            loop
                call this.destroy()
                set this=this.next
                exitwhen this==0
                set this.trig=null
            endloop
        endmethod
    endstruct

private function interface IterateFilter takes real x, real y returns nothing

struct rectwrap
    
    //This was privatized because I don't want you touching it. Satisfied?
    private rect theRect
    private region reg
    
    private real minXR
    private real maxXR
    private real minYR
    private real maxYR
    private real cenXR
    private real cenYR
    
    //If you ever find yourself needing more of this, don't add more variables.
    //Use the struct directly as an index in an array.
    integer userData = 0
    
    static constant method getTriggering takes nothing returns thistype
        return TrigRec
    endmethod
    
    //***********************
    //* Rectwrap properties *
    //***********************
    //! textmacro Rectwrap__Property takes NAME, CODE
    method operator $NAME$ takes nothing returns real
        return .$NAME$R
    endmethod
    
    method operator $NAME$= takes real r returns nothing
        call RegionClearRect(.reg, .theRect)
        call SetRect(.theRect, $CODE$)
        call RegionAddRect(.reg, .theRect)
        set .minXR = GetRectMinX(.theRect)
        set .minYR = GetRectMaxX(.theRect)
        set .maxXR = GetRectMinY(.theRect)
        set .maxYR = GetRectMaxY(.theRect)
        set .cenXR = .minXR + (.maxXR - .minXR) / 2
        set .cenYR = .minYR + (.maxYR - .minYR) / 2
    endmethod
    //! endtextmacro
    
    //! runtextmacro Rectwrap__Property("minX", "r, .minYR, .maxXR, .maxYR")
    //! runtextmacro Rectwrap__Property("maxX", ".minXR, .minYR, r, .maxYR")
    //! runtextmacro Rectwrap__Property("minY", ".minXR, r, .maxXR, .maxYR")
    //! runtextmacro Rectwrap__Property("maxY", ".minXR, .minYR, .maxXR, r")
    
    method operator cenX takes nothing returns real
        return .cenXR
    endmethod
    
    method operator cenY takes nothing returns real
        return .cenYR
    endmethod
    
    //.cenX=, .cenY=. What a hack!
    method operator cenX= takes real r returns nothing
        call RegionClearRect(.reg, .theRect)
        call MoveRectTo(.theRect, r, .cenY)
        call RegionAddRect(.reg, .theRect)
        set .minXR = GetRectMinX(.theRect)
        set .minYR = GetRectMaxX(.theRect)
        set .maxXR = GetRectMinY(.theRect)
        set .maxYR = GetRectMaxY(.theRect)
        set .cenXR = .minXR + (.maxXR - .minXR) / 2
        set .cenYR = .minYR + (.maxYR - .minYR) / 2
    endmethod
    
    method operator cenY= takes real r returns nothing
        call RegionClearRect(.reg, .theRect)
        call MoveRectTo(.theRect, .cenXR, r)
        call RegionAddRect(.reg, .theRect)
        set .minXR = GetRectMinX(.theRect)
        set .minYR = GetRectMaxX(.theRect)
        set .maxXR = GetRectMinY(.theRect)
        set .maxYR = GetRectMaxY(.theRect)
        set .cenXR = .minXR + (.maxXR - .minXR) / 2
        set .cenYR = .minYR + (.maxYR - .minYR) / 2
    endmethod
    
    //****************************
    //* Various rectish methods. *
    //****************************
    
    //Wrap an existing rect. Purely for gg_rct_ rects.
    static method wrap takes rect which returns thistype
        local thistype this = thistype.allocate()
        set .minXR = GetRectMinX(which)
        set .minYR = GetRectMinY(which)
        set .maxXR = GetRectMaxX(which)
        set .maxYR = GetRectMaxY(which)
        set .cenXR = .minXR + (.maxXR - .minXR) / 2
        set .cenYR = .minYR + (.maxYR - .minYR) / 2
        if .theRect == null then
            set .theRect = Rect(.minXR, .minYR, .maxXR, .maxYR)
            set .reg = CreateRegion()
            call RegionAddRect(.reg, .theRect)
        else
            call RegionClearRect(.reg, .theRect)
            call SetRect(.theRect, .minXR, .minYR, .maxXR, .maxYR)
            call RegionAddRect(.reg, .theRect)
        endif
        return this
    endmethod
    
    //Creates a rectwrap out of nowhere. Uses recycled rects to minimize waste.
    static method create takes real x1, real y1, real x2, real y2 returns thistype
        local thistype this = thistype.allocate()
        if .theRect == null then
            set .theRect = Rect(x1, y1, x2, y2)
            set .reg = CreateRegion()
            call RegionAddRect(.reg, .theRect)
        else
            call RegionClearRect(.reg, .theRect)
            call SetRect(.theRect, x1, y1, x2, y2)
            call RegionAddRect(.reg, .theRect)
        endif
        set .minXR = GetRectMinX(.theRect)
        set .minYR = GetRectMinY(.theRect)
        set .maxXR = GetRectMaxX(.theRect)
        set .maxYR = GetRectMaxY(.theRect)
        set .cenXR = .minXR + (.maxXR - .minXR) / 2
        set .cenYR = .minYR + (.maxYR - .minYR) / 2
        return this
    endmethod
    
    //Creates a rectwrap from a point, using given width and height.
    static method createFromPoint takes real x, real y, real width, real height returns thistype
        local thistype this = thistype.allocate()
        set width = width / 2
        set height = height / 2
        if .theRect == null then
            set .theRect = Rect(x - width, y - height, x + width, y + height)
            set .reg = CreateRegion()
            call RegionAddRect(.reg, .theRect)
        else
            call RegionClearRect(.reg, .theRect)
            call SetRect(.theRect, x - width, y - height, x + width, y + height)
            call RegionAddRect(.reg, .theRect)
        endif
        set .minXR = GetRectMinX(.theRect)
        set .minYR = GetRectMinY(.theRect)
        set .maxXR = GetRectMaxX(.theRect)
        set .maxYR = GetRectMaxY(.theRect)
        set .cenXR = .minXR + (.maxXR - .minXR) / 2
        set .cenYR = .minYR + (.maxYR - .minYR) / 2
        return this
    endmethod
    
    //Copies a rectwrap. Hey, someone might actually use this. Someday.
    method copy takes nothing returns thistype
        local thistype new = thistype.allocate()
        if new.theRect == null then
            set new.theRect = Rect(.minX, .minY, .maxX, .maxY)
            set .reg = CreateRegion()
            call RegionAddRect(.reg, .theRect)
        else
            call RegionClearRect(.reg, .theRect)
            call SetRect(new.theRect, .minX, .minY, .maxX, .maxY)
            call RegionAddRect(.reg, .theRect)
        endif
        set new.minX = .minX
        set new.minY = .minY
        set new.maxX = .maxX
        set new.maxY = .maxY
        set new.cenX = .cenX
        set new.cenY = .cenY
        set new.userData = .userData
        return new
    endmethod
    
    //Sets a rectwrap to an area, changing dimensions.
    method setTo takes real x1, real y1, real x2, real y2 returns nothing
        call RegionClearRect(.reg, .theRect)
        call SetRect(.theRect, x1, y1, x2, y2)
        call RegionAddRect(.reg, .theRect)
        set .minX = GetRectMinX(.theRect)
        set .minY = GetRectMinY(.theRect)
        set .maxX = GetRectMaxX(.theRect)
        set .maxY = GetRectMaxY(.theRect)
        set .cenX = .minX + (.maxX - .minX) / 2
        set .cenY = .minY + (.maxY - .minY) / 2
    endmethod
    
    //Moves a rectwrap, without changing dimensions.
    method moveTo takes real x, real y returns nothing
        call RegionClearRect(.reg, .theRect)
        call MoveRectTo(.theRect, x, y)
        call RegionAddRect(.reg, .theRect)
        set .minX = GetRectMinX(.theRect)
        set .minY = GetRectMinY(.theRect)
        set .maxX = GetRectMaxX(.theRect)
        set .maxY = GetRectMaxY(.theRect)
        set .cenX = .minX + (.maxX - .minX) / 2
        set .cenY = .minY + (.maxY - .minY) / 2
    endmethod
    
    //Iteration methods (credits to Romek for the original ReplaceTerrain)
    
    //These three variables are to be shared with the other iteration methods.
    private static real curX
    private static real curY
    private static thistype tempRW
    
    private static integer old
    private static integer new
    
    private static method ReplaceTerrainB takes nothing returns nothing
        loop
            if GetTerrainType(.curX, .curY) == .old then
                call SetTerrainType(.curX, .curY, .new, -1, 1, 1)
            endif
            set .curX = .curX + 128
            exitwhen .curX > .tempRW.maxX
        endloop
    endmethod
    
    private static method ReplaceTerrainA takes nothing returns nothing
        loop
            set .curX = .tempRW.minX + 64
            call ReplaceTerrainB.execute()
            set .curY = .curY + 128
            exitwhen .curY > .tempRW.maxY
        endloop
    endmethod
    
    method replaceTerrain takes integer oldTerrain, integer terrain returns nothing
        set .old = oldTerrain
        set .new = terrain
        set .curX = .minX + 64
        set .curY = .minY + 64 //Magic numbers for the win.
        set .tempRW = this
        call ReplaceTerrainA.execute()
    endmethod
    
    //SetPathing methods
    private static pathingtype path
    private static boolean pathOn
    
    private static method SetPathingB takes nothing returns nothing
        loop
            call SetTerrainPathable(.curX, .curY, .path, .pathOn)
            set .curX = .curX + 32
            exitwhen .curX > .tempRW.maxX
        endloop
    endmethod
    
    private static method SetPathingA takes nothing returns nothing
        loop
            set .curX = .tempRW.minX + 16
            call SetPathingB.execute()
            set .curY = .curY + 32
            exitwhen .curY > .tempRW.maxY
        endloop
    endmethod
    
    method setPathing takes pathingtype path, boolean on returns nothing
        set .path = path
        set .pathOn = on
        set .curX = .minX + 16
        set .curY = .minY + 16 //Magic numbers for the win.
        set .tempRW = this
        call SetPathingA.execute()
    endmethod
    
    //Iteration methods
    
    private static real iterateDist
    private static IterateFilter iterateFunc
    
    private static method IterateThroughB takes nothing returns nothing
        loop
            call iterateFunc.execute(.curX, .curY)
            set .curX = .curX + .tempRW.iterateDist
            exitwhen .curX > .tempRW.maxX
        endloop
    endmethod
    
    private static method IterateThroughA takes nothing returns nothing
        loop
            set .curX = .tempRW.minX + .tempRW.iterateDist / 2
            call IterateThroughB.execute()
            set .curY = .curY + .tempRW.iterateDist
            exitwhen .curY > .tempRW.maxY
        endloop
    endmethod
    
    method iterateThrough takes IterateFilter func, real dist returns nothing
        set .iterateFunc = func
        set .iterateDist = dist
        set .curX = .minX + dist / 2
        set .curY = .minY + dist / 2
        set .tempRW = this
        call IterateThroughA.execute()
    endmethod
    
    //! textmacro Rectwraps__wrapperMethod takes NAME, ARGS, RETURNS, CODE
    method $NAME$ takes $ARGS$ returns $RETURNS$
        $CODE$
    endmethod
    //! endtextmacro
    
    //BJlike, shorter to type wrapper methods.
    //! runtextmacro Rectwraps__wrapperMethod("groupEnum", "group g, boolexpr b", "nothing", "call GroupEnumUnitsInRect(g, .theRect, b)")
    //! runtextmacro Rectwraps__wrapperMethod("createWeather", "integer i", "weathereffect", "return AddWeatherEffect(.theRect, i)")
    //! runtextmacro Rectwraps__wrapperMethod("addFog", "player p, fogstate f, boolean b1, boolean b2", "fogmodifier", "return CreateFogModifierRect(p, f, .theRect, b1, b2)")
    //! runtextmacro Rectwraps__wrapperMethod("enumDestructables","boolexpr filter, code enum","nothing","call EnumDestructablesInRect(.theRect, filter, enum)")
    //! runtextmacro Rectwraps__wrapperMethod("enumItems","boolexpr filter, code enum","nothing","call EnumItemsInRect(.theRect, filter, enum)")
    //! runtextmacro Rectwraps__wrapperMethod("setBlight","player p, boolean b","nothing","call SetBlightRect(p, .theRect, b)")
    //! runtextmacro Rectwraps__wrapperMethod("setDoodadAnimation","integer i, string s, boolean b","nothing","call SetDoodadAnimationRect(.theRect, i, s, b)")
    //! runtextmacro Rectwraps__wrapperMethod("setFogState","player p, fogstate f, boolean b","nothing","call SetFogStateRect(p, f, .theRect, b)")
    //! runtextmacro Rectwraps__wrapperMethod("coordsInRect","real x, real y","boolean","return x >= .minX and x <= .maxX and y >= .minY and y <= .maxY")
    //! runtextmacro Rectwraps__wrapperMethod("isPointOn","real x, real y","boolean","return IsPointInRegion(.reg, x, y)")
    //! runtextmacro Rectwraps__wrapperMethod("isUnitOn","unit u","boolean","return IsUnitInRegion(.reg, u)")
    
    //***************************************************
    //* Onto the nasty stuff (regions, triggers, etc.). *
    //***************************************************
    
    private Event EnEv
    private Event ExEv
    
    private trigger EnTrig
    private trigger ExTrig
    
    
    private static boolexpr OnEnter
    private static boolexpr OnExit
    
    //The function fired when a unit enters the rectwrap.
    private static method OnEnterFunc takes nothing returns boolean
        set TrigRec = GetTriggerExecCount(GetTriggeringTrigger())
        call TrigRec.EnEv.fire()
        set TrigRec = 0
        return false
    endmethod
    
    //Same as above, but when the unit leaves.
    private static method OnExitFunc takes nothing returns boolean
        set TrigRec = GetTriggerExecCount(GetTriggeringTrigger())
        call TrigRec.ExEv.fire()
        set TrigRec = 0
        return false
    endmethod
    
    private static method SetTrigData takes trigger t, integer i returns nothing
        loop
            exitwhen i == 0
            call TriggerExecute(t)
            set i = i - 1
        endloop
    endmethod
    
    //Readies a trigger to fire when the rectwrap is entered.
    method registerEnter takes trigger whichTrigger returns trigger
        if .EnEv == 0 then
            set .EnEv = Event.create()
        endif
        if .EnTrig == null then
            set .EnTrig = CreateTrigger()
            call thistype.SetTrigData.execute(.EnTrig, this)
            call TriggerRegisterEnterRegion(.EnTrig, .reg, null)
            call TriggerAddCondition(.EnTrig, .OnEnter)
        elseif not IsTriggerEnabled(.EnTrig) then
            call EnableTrigger(.EnTrig)
        endif
        call .EnEv.register(whichTrigger)
        return whichTrigger
    endmethod
    
    //Does the same as above, but for when a unit leaves.
    method registerExit takes trigger whichTrigger returns trigger
        if .ExEv == 0 then
            set .ExEv = Event.create()
        endif
        if .ExTrig == null then
            set .ExTrig = CreateTrigger()
            call thistype.SetTrigData.execute(.ExTrig, this)
            call TriggerRegisterLeaveRegion(.ExTrig, .reg, null)
            call TriggerAddCondition(.ExTrig, .OnExit)
        elseif not IsTriggerEnabled(.ExTrig) then
            call EnableTrigger(.ExTrig)
        endif
        call .ExEv.register(whichTrigger)
        return whichTrigger
    endmethod
    
    //registerCode methods. They return the trigger in case the user wants to destroy it.
    private static trigger tempTrig
    
    method registerEnterCode takes code c returns trigger
        set .tempTrig = CreateTrigger()
        call TriggerAddCondition(.registerEnter(.tempTrig), Condition(c))
        return .tempTrig
    endmethod
    
    method registerExitCode takes code c returns trigger
        set .tempTrig = CreateTrigger()
        call TriggerAddCondition(.registerExit(.tempTrig), Condition(c))
        return .tempTrig
    endmethod
    
    //Now, we clean everything up in the event that the rectwrap is destroyed.
    method onDestroy takes nothing returns nothing
        if .EnEv != 0 then
            call .EnEv.chainDestroy()
            set .EnEv = 0
        endif
        if .ExEv != 0 then
            call .ExEv.chainDestroy()
            set .ExEv = 0
        endif
        if .EnTrig != null then
            call DisableTrigger(.EnTrig)
        endif
        if .ExTrig != null then
            call DisableTrigger(.ExTrig)
        endif
        //The rects, regions, and triggers are not destroyed.
        //They are recycled.
    endmethod
    
    //*************************
    //* Struct initialization *
    //*************************
    
    private static method onInit takes nothing returns nothing
        set .OnEnter = Filter(function thistype.OnEnterFunc)
        set .OnExit = Filter(function thistype.OnExitFunc)
    endmethod
    
endstruct

endlibrary
 

Attachments

  • Rectwraps.w3m
    28.8 KB · Views: 443

Kenny

Back for now.
Reaction score
202
I copied it manually, letter by letter, fitting it to work with regions instead. I had fun.

I was reading the scripts and i saw what looked to be linked lists, and i was like WOW, he learnt them fast. But it looks like you just copied :p. But still, using linked lists... nice!

Anywho this seems quite helpful for those who have trouble with rects and regions. And it would also be quite helpful for using them on a larger scale. So well done! :)

Also, just a quick question. Does the readonly keyword mean the member can accessed but not changed?
 

Azlier

Old World Ghost
Reaction score
461
Accessed but not reset, I believe. Which means that people might still be able to delete it via native. Ah well. Not my job to prevent user stupidity. Oh, and this leaks two triggers if you destroy a regionwrapper, at the moment.

Also going to have to get the triggering rectwrap, which I just devised a way to do. Fixing. Please wait.

Edit: Nevermind. Still working on the whole rectwrap deal. Trigger leaks are fixed, though.
 

Azlier

Old World Ghost
Reaction score
461
Update. Before, it didn't work at all. It works now. Oh, and I increased efficiency a bit in rectwraps. GetTriggeringRectwrap now exists, officially making this better than native rect and region handling. Couple that with some nice userdata on the rects.

All done with 0 efficiency loss, and uses no H2I.
 

Tom Jones

N/A
Reaction score
437
JASS:
        loop
            exitwhen i == 0
            call TriggerExecute(r.T1)
            call TriggerExecute(r.T2)
            set i = i - 1
        endloop
:D
At first I had a really hard time figuring out why you did that, and then I realized you're using it to pass the struct. Points for creativity.

JASS:
private function OnEnter takes nothing returns boolean
    set TrigRegW=GetTriggerExecCount(GetTriggeringTrigger())
    set TrigReg = GetTriggeringRegion()
    call TrigRegW.Enterpointer.execution() //Might as well pass TrigReg as argument?
    return false
endfunction

private function OnExit takes nothing returns boolean
    set TrigRegW=GetTriggerExecCount(GetTriggeringTrigger())
    set TrigReg = GetTriggeringRegion()
    call TrigRegW.Exitpointer.execution() //Same as above.
    return false
endfunction

regionwrap.theRegion
//The actual region within a regionwrap. Do NOT destroy this manually. Destroy the regionwrap instead.
Mind pointing out where this magic happens?

JASS:
    method registerEnter takes trigger trig, rectwrap which returns nothing
        local region re = CreateRegion()
        call RegionAddRect(re, which.theRect)
        call TriggerRegisterEnterRegion(.T1, re, null)
        call .Enterpointer.addNode(trig, re, which)
        set re = null
    endmethod
    
    method registerExit takes trigger trig, rectwrap which returns nothing
        local region re = CreateRegion()
        call RegionAddRect(re, which.theRect)
        call TriggerRegisterLeaveRegion(.T2, re, null)
        call .Exitpointer.addNode(trig, re, which)
        set re = null
    endmethod
I believe it would be more efficient to create one region, and then add rects to that region. What's the point in region wrappers if the user keeps creating regions for each rect he register anyways?
 

Azlier

Old World Ghost
Reaction score
461
>Points for creativity.
Key Triggers. All Jesus4Lyf.

>//Might as well pass TrigReg as argument?
I... see no point in that?

[EDIT] Oh, now I see. One less global. [/EDIT]

The original had all rects in one region. It fired the trigger each time for the amount of rects registered. :p

The only way around that was multiple regions. It still uses the same amount of regions as it would take to make a manual GetTriggeringRectwrap.

>regionwrap.theRegion
Yeah, that no longer exists and is no longer a danger. I should remove that.
 

Tom Jones

N/A
Reaction score
437
>Points for creativity.
Key Triggers. All Jesus4Lyf.

>//Might as well pass TrigReg as argument?
I... see no point in that?

[EDIT] Oh, now I see. One less global. [/EDIT]

The original had all rects in one region. It fired the trigger each time for the amount of rects registered. :p

The only way around that was multiple regions. It still uses the same amount of regions as it would take to make a manual GetTriggeringRectwrap.

>regionwrap.theRegion
Yeah, that no longer exists and is no longer a danger. I should remove that.
Indeed, and now that I think about it, you don't even have to give the function parameters, GetTriggeringRegion() should be carried to the function by the thread since it's just a regular call.
 

Azlier

Old World Ghost
Reaction score
461
It's being checked in the loop. If I just used GetTriggeringRegion(), that's more function calls. Unless I make a local. Which using it as an argument does anyway, but with one less line and no need for nulling.
 

wraithseeker

Tired.
Reaction score
122
What use does this serve? Doesn't the native does it's job itself?

I'm not sure by why are you using dynamic triggers? It can be fatal if you do not handle it correctly.
 

Azlier

Old World Ghost
Reaction score
461
Dynamic triggers are just fine if you use conditions instead of actions. I even disable them before destroying them. The main thing of this, however, is that you can get what rect was entered. Oh, and some operations like finding if a point is in a rect or not are made easier.

Oh, and there's user data. User data for attaching to a rect is always fun.
 

Jesus4Lyf

Good Idea™
Reaction score
397
I believe Darthfett wanted this. He kept saying "Do rect attaching without H2I!" And I kinda kept saying "I'll probably get around to it". But here it is...

Thanks for giving credit in regards to the "black magic" of execcount and linkedlists to avoid H2I. Appreciated! :thup:

Two points as I said in the PM:
User is likely to hit op-limit if they create 30 regionwraps unless you do some sort of SetTriggerData.evaluate(params), which is a good idea imo.
You leak the pointers of the linked lists as far as I saw at a glance. :thup:

But I'm very impressed to see another mapper using these crazy techniques. They're really quite cute, imo. Well done and congrats on learning linked-lists and ExecCount! I'd rep you, but I can't right now. XD

PS. For those who are curious, I think you'll find that GetTriggering?Wrap is more efficient than the native because it inlines to a single global reference (in fact, its more efficient to spam it than to save it to a local probably). But the event firing will inevitably be a fraction slower. But getting the user data off the wrap will probably be faster AND more reliable than H2I alternatives! :D

>What use does this serve? Doesn't the native does it's job itself?
That should probably be more clear. I'd say its data attachment to rects and regions.
 

Azlier

Old World Ghost
Reaction score
461
>User is likely to hit op-limit if they create 30 regionwraps
That's what I get for inlining SetTriggerData. Curses.

>GetTriggering?Wrap is more efficient than the native
Indeed. But saving it to a local is good for readability.

>You leak the pointers of the linked lists as far as I saw at a glance.
Onoz. Fixing.
 

Jesus4Lyf

Good Idea™
Reaction score
397
So, this too, could be clearned up quite a bit by using Event. :)

Also, I can't say I like that you used ExecuteFunc instead of .evaluate(params)... Personally I don't use ExecuteFunc in my maps (it's on my ban list). I still haven't read over all this code thoroughly, by the way.

I noticed a couple of oddities that would be cleaned up well using Event. For example, in execution(), you actually check the region ("if .reg == trigreg then")...? I'm sure if you look at it you can restructure things and increase efficiency, code readability, reliability and maintainability by using Event instead of a mutated trig chains. :D
 

Azlier

Old World Ghost
Reaction score
461
Meh, an extra trigger can't hurt. I'll switch it to .execute after I fix the regions.

Yeah, I know about the regions. It's... *sigh* ...a well hidden O(n) search :(. This is dead until I fix that, ya know.
 

Azlier

Old World Ghost
Reaction score
461
Update. Rewrote regionwraps, no more O(n) search.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top