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