//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Rectwraps ~~ By Azlier ~~ 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 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
method fire takes nothing returns nothing
local Event curr
// this = last.
loop
set curr=this.next
exitwhen curr==0
set .t=curr.trig
set .current=curr
endif
set this=curr
else
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?
//If you ever find yourself needing more of this, don't add more variables.
//Use the struct directly as an index in an array.
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 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 set .cenXR = .minXR + (.maxXR - .minXR) / 2
set .cenYR = .minYR + (.maxYR - .minYR) / 2
endmethod
method operator cenY=
takes real r
returns nothing 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 .cenXR = .minXR + (.maxXR - .minXR) / 2
set .cenYR = .minYR + (.maxYR - .minYR) / 2
if .theRect == null then
set .theRect =
Rect(.minXR, .minYR, .maxXR, .maxYR)
else
call SetRect(.theRect, .minXR, .minYR, .maxXR, .maxYR)
endif
return this
endmethod
//Creates a rectwrap out of nowhere. Uses recycled rects to minimize waste.
local thistype this = thistype.allocate()
if .theRect == null then
set .theRect =
Rect(x1, y1, x2, y2)
else
call SetRect(.theRect, x1, y1, x2, y2)
endif
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)
else
call SetRect(.theRect, x - width, y - height, x + width, y + height)
endif
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)
else
call SetRect(new.theRect, .minX, .minY, .maxX, .maxY)
endif
set new.minXR = .minXR
set new.minYR = .minYR
set new.maxXR = .maxXR
set new.maxYR = .maxYR
set new.cenXR = .cenXR
set new.cenYR = .cenYR
set new.userData = .userData
return new
endmethod
//Sets a rectwrap to an area, changing dimensions.
call SetRect(.theRect, x1, y1, x2, y2)
set .cenXR = .minXR + (.maxXR - .minXR) / 2
set .cenYR = .minYR + (.maxYR - .minYR) / 2
endmethod
//Moves a rectwrap, without changing dimensions.
method moveTo
takes real x,
real y
returns nothing set .cenXR = .minXR + (.maxXR - .minXR) / 2
set .cenYR = .minYR + (.maxYR - .minYR) / 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 thistype tempRW
private static method ReplaceTerrainB takes nothing returns nothing
loop
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 method SetPathingB takes nothing returns nothing
loop
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
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 >= .minXR and x <= .maxXR and y >= .minYR and y <= .maxYR")
//! 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
//The function fired when a unit enters the rectwrap.
private static method OnEnterFunc
takes nothing returns boolean 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 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
set i = i - 1
endloop
endmethod
//Readies a trigger to fire when the rectwrap is entered.
if .EnEv == 0 then
set .EnEv = Event.create()
endif
if .EnTrig == null then
call thistype.SetTrigData.execute(.EnTrig, this)
endif
call .EnEv.register(whichTrigger)
return whichTrigger
endmethod
//Does the same as above, but for when a unit leaves.
if .ExEv == 0 then
set .ExEv = Event.create()
endif
if .ExTrig == null then
call thistype.SetTrigData.execute(.ExTrig, this)
endif
call .ExEv.register(whichTrigger)
return whichTrigger
endmethod
//registerCode methods. They return the trigger in case the user wants to destroy it.
return .tempTrig
endmethod
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
endif
if .ExTrig != null then
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