Snippet EventResponses

Kenny

Back for now.
Reaction score
202
EventResponses

Version 1.0.1

Requirements:
- Jass NewGen

Documentation & Script:
JASS:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  ~~    EventResponses    ~~    By kenny!    ~~    Version 1.0.1    ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  What is EventResponses?
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//      - EventResponses is a system that allows users to easily access
//        the most common event response natives from spell and order events.
//      - It was created due to the repetitive nature of writing multiple scripts,
//        both for maps and for released spells and systems. The systems aims to
//        reduce the amount of time spent developing these spells and systems by
//        simplifying the tedious coding needed to write them.
//
//  Functions:
// ¯¯¯¯¯¯¯¯¯¯¯
//      - EventResp.create(boolean set2D, boolean set3D) --> returns EventResp
//
//        This creates a new event response struct that stores the event response
//        data for the current spell or order event. The first boolean argument is
//        used to decide if you want to set the 2D distance and angle between the
//        caster unit's x and y and the target x and y. The second boolean argument
//        is used to determine whether or not the 3D distance and angle between the
//        coordinates should be set. These are used as many spells do not need them.
//
//      - EventResp.replicate(EventResp resp) --> returns EventResp
//
//        This creates a new event response struct that stores the event response
//        data for the current spell or order event. This function, however, copies
//        a current EventResp struct and all of its data. The EventResp argument is
//        the EventResp instance that you wish to copy.
//
//      - .updateCaster(boolean updateZ) --> returns nothing
//
//        Updates the x, y and z locations of the caster. The boolean argument is
//        used to determine whether or not the z location should be updated.
//
//      - .updateTarget(boolean updateZ) --> returns nothing
//
//        Updates the x, y and z locations of the target. The boolean argument is
//        used to determine whether or not the z location should be updated.
//
//      - .updateDistances(boolean update3D) --> returns nothing
//
//        Updates the distance between the caster and target coordinates. The
//        boolean argument is used to determine whether or not the 3D distance
//        should be updated.
//
//      - .updateAngles(boolean update3D) --> returns nothing
//
//        Updates the angle between the caster and target coordinates. The
//        boolean argument is used to determine whether or not the 3D angle
//        should be updated.
//
//      - .destroy() --> returns nothing
//
//        Destroys the struct holding the variables.
//                      
//  Variables:
// ¯¯¯¯¯¯¯¯¯¯¯
//      - .casterUnit   --> Returns the unit that casted the spell, or the unit that
//                          was issued an order.
//      - .targetWidg   --> Returns the targeted widget of an order or spell. Does not
//                          return a unit, destructable or item.
//      - .targetUnit   --> Returns the targeted unit of an order or spell. Will return
//                          null if the target isn't a unit.
//      - .targetDest   --> Returns the targeted destructable of an order or spell.
//                          Will return null if the target isn't a destructable.
//      - .targetItem   --> Returns the targeted item of an order or spell. Will return
//                          null if the target isn't an item.
//      - .casterX      --> Returns the X coordinate of the casting unit or the ordered
//                          unit.
//      - .casterY      --> Returns the Y coordinate of the casting unit or the ordered
//                          unit.
//      - .casterZ      --> Returns the Z coordinate of the casting unit or the ordered
//                          unit.
//      - .targetX      --> Returns the X coordinate of the target of an order or 
//                          spell. Returns .casterX for immediate orders.
//      - .targetY      --> Returns the Y coordinate of the target of an order or 
//                          spell. Returns .casterY for immediate orders.
//      - .targetZ      --> Returns the Z coordinate of the target of an order or 
//                          spell. Returns .casterZ for immediate orders.
//      - .distXY       --> Returns the distance between the .casterUnit and the target
//                          widget or location of an order or spell.
//      - .distXYZ      --> Similar to the above variable, however .distXYZ will take
//                          into account the Z coordinate of the caster and target.
//      - .angle        --> Returns the angle between the caster and the target in
//                          radians.
//      - .pitch        --> Returns the angle between the caster and the target, also
//                          takes into account the Z location of both.
//      - .orderId      --> Returns the order id of the spell or order that the caster
//                          was issued in integer format.
//      - .orderStr     --> Returns the order string of the spell or order that the
//                          caster was issued.
//
//  Bonus Variables:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//      - .isTargetWidg --> Returns true if the target is a widget and false if there
//                          is no target (point or immediate order).
//      - .isTargetUnit --> Returns true if the target is a unit and false if it is
//                          either a destructable or item, or if there is no target.
//      - .isTargetDest --> Returns true if the target is a destructable and false if
//                          it is either a unit or item, or if there is no target.
//      - .isTargetItem --> Returns true if the target is an item and false if it is
//                          either a unit or destructable, or if there is no target.
//      - .isTargetLand --> Returns true if there is no target widget but still a
//                          target location, and false if there is a target.
//      - .isTargetNone --> Returns true if there is no target widget or location and
//                          false if there is (works for immediate orders).     
//
//  Details:
// ¯¯¯¯¯¯¯¯¯
//      - There are no configurables for this system, just import it and use it.
//      - Aquiring the Z coordinate of units uses GetLocationZ() which can desync.
//      - EventResponses will only work with some player unit and unit events,
//        these include:
//          - EVENT_PLAYER_UNIT_SPELL_CHANNEL
//          - EVENT_PLAYER_UNIT_SPELL_CAST
//          - EVENT_PLAYER_UNIT_SPELL_EFFECT
//          - EVENT_PLAYER_UNIT_SPELL_FINISH
//          - EVENT_PLAYER_UNIT_SPELL_ENDCAST
//          - EVENT_PLAYER_UNIT_ISSUED_ORDER
//          - EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER
//          - EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER
//          - EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER
//
//          - EVENT_UNIT_SPELL_CHANNEL
//          - EVENT_UNIT_SPELL_CAST
//          - EVENT_UNIT_SPELL_EFFECT
//          - EVENT_UNIT_SPELL_FINISH
//          - EVENT_UNIT_SPELL_ENDCAST
//          - EVENT_UNIT_ISSUED_ORDER
//          - EVENT_UNIT_ISSUED_TARGET_ORDER
//          - EVENT_UNIT_ISSUED_POINT_ORDER
//      - Only these events will work as they have common native responses. Other
//        Events have different responses, which would make this system messy if
//        it attempted to work for all of them.
//
//  How to import:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//      - Create a trigger named EventResponses.
//      - Convert it to custom text and replace the whole trigger text with this.
//
//  Thanks:
// ¯¯¯¯¯¯¯¯
//      - Jesus4Lyf for hopefully letting me use his method of determining
//        whether or not the spell or order has a target widget or location.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library EventResponses

    globals
        // Only configurable option available.
        private constant integer MAX_RESPONSES    = 8190
        
        // Different target types for boolean checks.
        private constant integer TARGET_TYPE_NONE = 1
        private constant integer TARGET_TYPE_UNIT = 2
        private constant integer TARGET_TYPE_DEST = 3
        private constant integer TARGET_TYPE_ITEM = 4
        private constant integer TARGET_TYPE_LAND = 5
        
        // Required for event initialisation.
        private constant integer MAXIMUM_EVENTS   = 17
        private constant integer MAX_SPELL_EVENTS = 9
    endglobals
    
    // Struct that stores preloaded events for the system.
    private struct EventId
    
        readonly boolean  isSpell = false // If it is a spell or order event.
        private  eventid  eventId = null  // The event itself.
        private  thistype next    = 0     // Next event in the list.
        
        private static timer tempTimer = null // Timer needed for initial registration.
        private static eventid array eventIds // Array to store the used events.
    
        // I kind of liked this interface, even though it requires a search.
        static method operator[] takes eventid id returns thistype
            local thistype this = thistype(0).next
            
            // Should still technically be 0(1) complexity as it is a constant search over 17 instances.
            loop
                exitwhen this == 0
                if id == this.eventId then
                    return this
                endif
                set this = this.next
            endloop
            
            return 0
        endmethod
        
        // Set up each event.
        private static method setEvent takes eventid id, integer i returns nothing
            local thistype this = thistype.allocate()
            
            set this.eventId = id // Set the eventid.
            
            if i <= MAX_SPELL_EVENTS then
                set this.isSpell = true // The first 9 events are spell events.
            endif
            
            // Lazy.
            set this.next=thistype(0).next
            set thistype(0).next=this
        endmethod
        
        // Register the events at 0.00 seconds of game time (It wouldn't work otherwise).
        private static method registerEvents takes nothing returns nothing
            local integer i = 0
            
            loop
                exitwhen i == MAXIMUM_EVENTS
                call thistype.setEvent(thistype.eventIds<i>,i)
                set i = i + 1
            endloop
            
            // Clean up the temporary timer.
            call PauseTimer(thistype.tempTimer)
            call DestroyTimer(thistype.tempTimer)
            set thistype.tempTimer = null
        endmethod
        
        // Initialise all the events used.
        private static method onInit takes nothing returns nothing
            // First 9 are spell events.
            set thistype.eventIds[0]  = EVENT_PLAYER_UNIT_SPELL_CHANNEL
            set thistype.eventIds[1]  = EVENT_PLAYER_UNIT_SPELL_CAST
            set thistype.eventIds[2]  = EVENT_PLAYER_UNIT_SPELL_EFFECT
            set thistype.eventIds[3]  = EVENT_PLAYER_UNIT_SPELL_FINISH
            set thistype.eventIds[4]  = EVENT_PLAYER_UNIT_SPELL_ENDCAST
            set thistype.eventIds[5]  = EVENT_UNIT_SPELL_CHANNEL
            set thistype.eventIds[6]  = EVENT_UNIT_SPELL_CAST
            set thistype.eventIds[7]  = EVENT_UNIT_SPELL_EFFECT
            set thistype.eventIds[8]  = EVENT_UNIT_SPELL_FINISH
            set thistype.eventIds[9]  = EVENT_UNIT_SPELL_ENDCAST
            
            // The rest are order events.
            set thistype.eventIds[10] = EVENT_PLAYER_UNIT_ISSUED_ORDER
            set thistype.eventIds[11] = EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER
            set thistype.eventIds[12] = EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER
            set thistype.eventIds[13] = EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER
            set thistype.eventIds[14] = EVENT_UNIT_ISSUED_ORDER
            set thistype.eventIds[15] = EVENT_UNIT_ISSUED_POINT_ORDER
            set thistype.eventIds[16] = EVENT_UNIT_ISSUED_TARGET_ORDER
            
            // Start the timer.
            set thistype.tempTimer = CreateTimer()
            call TimerStart(thistype.tempTimer,0.00,false,function thistype.registerEvents)
        endmethod
        
    endstruct

    // The exported EventResp struct.
    struct EventResp[MAX_RESPONSES]
    
        // All the accessible variables.
        readonly unit         casterUnit = null
        readonly widget       targetWidg = null
        readonly unit         targetUnit = null
        readonly destructable targetDest = null
        readonly item         targetItem = null
        readonly string       orderStr   = &quot;&quot;
        readonly real         casterX    = 0.00
        readonly real         casterY    = 0.00
        readonly real         casterZ    = 0.00
        readonly real         targetX    = 0.00
        readonly real         targetY    = 0.00
        readonly real         targetZ    = 0.00
        readonly real         distXY     = 0.00
        readonly real         distXYZ    = 0.00
        readonly real         angle      = 0.00
        readonly real         pitch      = 0.00
        readonly real         cosAng     = 0.00
        readonly real         sinAng     = 0.00
        readonly integer      orderId    = 0
        readonly integer      targetType = 0
        
        // Boolean checks.
        method operator isTargetWidg takes nothing returns boolean
            return this.targetType == TARGET_TYPE_UNIT or this.targetType == TARGET_TYPE_DEST or this.targetType == TARGET_TYPE_ITEM
        endmethod
        
        method operator isTargetUnit takes nothing returns boolean
            return this.targetType == TARGET_TYPE_UNIT
        endmethod
        
        method operator isTargetDest takes nothing returns boolean
            return this.targetType == TARGET_TYPE_DEST
        endmethod
        
        method operator isTargetItem takes nothing returns boolean
            return this.targetType == TARGET_TYPE_ITEM
        endmethod
        
        method operator isTargetLand takes nothing returns boolean
            return this.targetType == TARGET_TYPE_LAND
        endmethod
        
        method operator isTargetNone takes nothing returns boolean
            return this.targetType == TARGET_TYPE_NONE
        endmethod
        
        // Clean up.
        method destroy takes nothing returns nothing
            set this.casterUnit = null
            set this.targetWidg = null
            set this.targetUnit = null
            set this.targetDest = null
            set this.targetItem = null
            
            call this.deallocate()
        endmethod
        
        // Update the coordinates of the caster, with z coordinate if wanted.
        method updateCaster takes boolean updateZ returns nothing
            set this.casterX = GetUnitX(this.casterUnit)
            set this.casterY = GetUnitY(this.casterUnit)
            
            if updateZ then
                call MoveLocation(tempLoc,this.casterX,this.casterY)
                set this.casterZ = GetLocationZ(tempLoc) + GetUnitFlyHeight(this.casterUnit)
            endif
        endmethod
        
        // Update the coordinates of the target, with z coordinate if wanted.
        method updateTarget takes boolean updateZ returns nothing
            set this.targetX = GetUnitX(this.targetUnit)
            set this.targetY = GetUnitY(this.targetUnit)
            
            if updateZ then
                call MoveLocation(tempLoc,this.targetX,this.targetY)
                set this.targetZ = GetLocationZ(tempLoc) + GetUnitFlyHeight(this.targetUnit)
            endif
        endmethod
        
        // Update the 2D distance, and 3D if wanted.
        method updateDistances takes boolean set3D returns nothing
            local real x = this.targetX - this.casterX
            local real y = this.targetY - this.casterY
            local real z = this.targetZ - this.casterZ
                
            set this.distXY  = SquareRoot(x * x + y * y)
            
            if set3D then
                set this.distXYZ = SquareRoot(x * x + y * y + z * z)
            endif
        endmethod
        
        // Update the 2D angle, and 3D if wanted.
        method updateAngles takes boolean set3D returns nothing
            local real x = this.targetX - this.casterX
            local real y = this.targetY - this.casterY
            local real z = this.targetZ - this.casterZ
            
            set this.angle  = Atan2(y,x)
            set this.cosAng = Cos(this.angle)
            set this.sinAng = Sin(this.angle)
            
            if set3D then
                set this.pitch  = Atan2(SquareRoot(x * x + y * y),z)
            endif
        endmethod
        
        // Replicate a current EventResp instance and assign it to a new instance.
        static method replicate takes thistype resp returns thistype
            local thistype this = thistype.allocate()
            
            set this.casterUnit = resp.casterUnit
            set this.targetWidg = resp.targetWidg
            set this.targetUnit = resp.targetUnit
            set this.targetDest = resp.targetDest
            set this.targetItem = resp.targetItem
            set this.orderStr   = resp.orderStr
            set this.casterX    = resp.casterX
            set this.casterY    = resp.casterY
            set this.casterZ    = resp.casterZ
            set this.targetX    = resp.targetX
            set this.targetY    = resp.targetY
            set this.targetZ    = resp.targetZ
            set this.distXY     = resp.distXY
            set this.distXYZ    = resp.distXYZ
            set this.angle      = resp.angle
            set this.pitch      = resp.pitch
            set this.cosAng     = resp.cosAng
            set this.sinAng     = resp.sinAng
            set this.orderId    = resp.orderId
            set this.targetType = resp.targetType
            
            return this
        endmethod
        
        // Scabbed off Jesus4Lyf, hope you don&#039;t mind. <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite7" alt=":p" title="Stick Out Tongue    :p" loading="lazy" data-shortname=":p" />
        //! textmacro SetTargetMembers takes TYPE, LAND
            set this.targetUnit = Get$TYPE$TargetUnit()
            if this.targetUnit == null then
                set this.targetDest = Get$TYPE$TargetDestructable()
                if this.targetDest == null then
                    set this.targetItem = Get$TYPE$TargetItem()
                    if this.targetItem == null then
                        set this.targetWidg = null
                        set this.targetX    = Get$LAND$X()
                        set this.targetY    = Get$LAND$Y()
                        call MoveLocation(tempLoc,this.targetX,this.targetY)
                        set this.targetZ    = GetLocationZ(tempLoc)
                        if this.targetX != 0.00 or this.targetY != 0.00 or this.targetZ != 0.00 then
                            set this.targetType = TARGET_TYPE_LAND
                        else
                            set this.targetType = TARGET_TYPE_NONE
                            set this.targetX    = this.casterX
                            set this.targetY    = this.casterY
                            set this.targetZ    = this.casterZ
                        endif
                    else
                        set this.targetWidg = this.targetItem
                        set this.targetType = TARGET_TYPE_ITEM
                        set this.targetX    = GetItemX(this.targetItem)
                        set this.targetY    = GetItemY(this.targetItem)
                        call MoveLocation(tempLoc,this.targetX,this.targetY)
                        set this.targetZ    = GetLocationZ(tempLoc)
                    endif
                else
                    set this.targetWidg = this.targetDest
                    set this.targetItem = null
                    set this.targetType = TARGET_TYPE_DEST
                    set this.targetX    = GetDestructableX(this.targetDest)
                    set this.targetY    = GetDestructableY(this.targetDest)
                    call MoveLocation(tempLoc,this.targetX,this.targetY)
                    set this.targetZ    = GetLocationZ(tempLoc)
                endif
            else
                set this.targetWidg = this.targetUnit
                set this.targetDest = null
                set this.targetItem = null
                set this.targetType = TARGET_TYPE_UNIT
                set this.targetX    = GetUnitX(this.targetUnit)
                set this.targetY    = GetUnitY(this.targetUnit)
                call MoveLocation(tempLoc,this.targetX,this.targetY)
                set this.targetZ    = GetLocationZ(tempLoc) + GetUnitFlyHeight(this.targetUnit)
            endif
        //! endtextmacro
            
        // Create the event responses.
        static method create takes boolean set2D, boolean set3D returns thistype
            local EventId  id   = EventId[GetTriggerEventId()]
            local thistype this = 0
            local real     x    = 0.00
            local real     y    = 0.00
            local real     z    = 0.00
            
            // If the event responses were created for an unsupported event, show an error.
            if id == 0 then
                debug call BJDebugMsg(&quot;|cFFFF0000Error using EventResponses:|r Unsupported event type used.&quot;)
                return 0
            endif           
            
            // Assign all the members.
            set this            = thistype.allocate()
            set this.casterUnit = GetTriggerUnit()
            set this.casterX    = GetUnitX(this.casterUnit)
            set this.casterY    = GetUnitY(this.casterUnit)
            call MoveLocation(thistype.tempLoc,this.casterX,this.casterY)
            set this.casterZ    = GetUnitFlyHeight(this.casterUnit) - GetLocationZ(thistype.tempLoc)
            set this.orderId    = GetIssuedOrderId()
            set this.orderStr   = OrderId2String(this.orderId)
            
            if id.isSpell then
                //! runtextmacro SetTargetMembers(&quot;Spell&quot;,&quot;SpellTarget&quot;)
            else
                //! runtextmacro SetTargetMembers(&quot;Order&quot;,&quot;OrderPoint&quot;)
            endif
            
            // Set distances and angles if required.
            if set2D then
                set x = this.targetX - this.casterX
                set y = this.targetY - this.casterY
                set z = this.targetZ - this.casterZ
                
                set this.distXY  = SquareRoot(x * x + y * y)
                set this.angle   = Atan2(y,x)
                set this.cosAng  = Cos(this.angle)
                set this.sinAng  = Sin(this.angle)
            endif
            
            if set3D then
                set x = this.targetX - this.casterX
                set y = this.targetY - this.casterY
                set z = this.targetZ - this.casterZ
                
                set this.distXYZ = SquareRoot(x * x + y * y + z * z)
                set this.pitch   = Atan2(SquareRoot(x * x + y * y),z)
            endif
            
            return this
        endmethod
        
        // Initialisation of the temporary loc for Z coords.
        private static location tempLoc = Location(0.00,0.00)

    endstruct
        
endlibrary
</i>


Demonstration:
JASS:
private function Actions takes nothing returns boolean
    local EventResp er = EventResp.create(true,false) // Create an event response, setting 2D distance and angle, but not 3D.
    
    // Do stuff with the event response.
    if er.isTargetUnit then // Can check if the target is a unit.
        if er.distXY &gt;= 1000.00 then // No need for distance calculations.
            call SetUnitX(er.casterUnit,GetUnitX(er.targetUnit) + 50.00 * er.cosAng) // No need for angle calculations.
            call SetUnitY(er.casterUnit,GetUnitY(er.targetUnit) + 50.00 * er.sinAng)
            call SetUnitFacing(er.casterUnit,(er.angle * bj_RADTODEG) + 180.00)
            call UnitDamageTarget(er.casterUnit,er.targetUnit,100.00,false,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNIVERSAL,null)
        else
            // Do something awesome.
        endif
    else
        // Do some more awesome stuff.
    endif

    // You get the point by now.
    call SetWidgetLife(er.casterUnit,GetWidgetLife(er.casterUnit + 100.00))
    call DestroyEffect(AddSpecialEffectTarget(&quot;SomeCoolEffect.mdl&quot;,er.casterUnit,&quot;origin&quot;)

    call er.destroy() // Destroy the event response struct.

    return false
endfunction

Notes:
So this is basically a resource that helps maintain code readability and reduce bloating of scripts. It effectively reduces time spent maintaining, editing and producing spells and systems for personal or public use.

This snippet is aimed at those who, like me, prefer code simplicity and neatness. It has the downside of being quite simple, when compared to something like SpellStruct. However, it has a simple interface and is perfect for those who think systems like the above mentioned may be a bit much for themselves to understand.

Updates:
- Version 1.0.1: Removed the onInit method, initialised the location without it.
- Version 1.0.0: Initial release.
 

Azlier

Old World Ghost
Reaction score
461
Perhaps I'll do a through read through some day, but...

JASS:
// Initialisation and the temporary loc for Z coords.
    private static location tempLoc   = null
        
private static method onInit takes nothing returns nothing
    set thistype.tempLoc = Location(0.00,0.00)
endmethod


->
JASS:
private static location tempLoc = Location(0, 0)
 

Kenny

Back for now.
Reaction score
202
I am use to initialising global handles on Init instead of within a global block (and using periods for real values :p). I does not really make a difference, but I will change it if more people think I should.
 

Azlier

Old World Ghost
Reaction score
461
Well, not doing that leads to one more string leak and an ExecuteFunc. But okay. :p
 

Kenny

Back for now.
Reaction score
202
String leak?!? Never knew that one.. Fair enough. You have won me over, consider it changed. :p
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
Well, technically Azlier is right.
Strings are like boolexpr, one time they are created, they are reused.
So because of how Jasshelper handle struct/module and library initializers, yes you will have a kinda unique string, you won't ever use it in your map.

Though, i don't worry about this kind of think, i worry more about map crash with some functions used inside a global declaration, even if this one is safe, i tend to initialize all my globals inside an initializer.
 

Jesus4Lyf

Good Idea™
Reaction score
397
even if this one is safe, i tend to initialize all my globals inside an initializer.
Which will screw up when Vex makes yet another superior initialiser (like he recently did with modules), from which a user will try to use your system, resulting in a thread crash. :thup:
JASS:
//        The first boolean argument is
//        used to decide if you want to set the 2D distance and angle between the
//        caster unit&#039;s x and y and the target x and y.

I'd calculate this when you return the value, not when the event occurs... should clean up your interface a bit.
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
Which will screw up when Vex makes yet another superior initialiser (like he recently did with modules), from which a user will try to use your system, resulting in a thread crash.
I don't see how.
I just use a module initializer and if Vex plans to make a superior initializer it would be like that :

http://www.wc3c.net/showthread.php?t=108466

I can't believe it would break, else i trust on Vexorian to just don't change it and keep it in the current state, but maybe i'm naive.

Anyway it's fair enough, it was just a personal opinion.
 

Kenny

Back for now.
Reaction score
202
>I'd calculate this when you return the value, not when the event occurs... should clean up your interface a bit.

I actually thought about doing that originally. However, I found myself needing to use .distXY more than once for the majority of the times I used EventResponses. So instead of having to use SquareRoot() numerous times, I decided to do it like this.

Edit:

I am currently updating my Path of Shadows spell to use this, it has done exactly what I said it does. It reduced the length of the script by 50+ lines, standardised variable names, simplified the script and maintained readability. The bonus features (the .update methods) also come in handy for movement type spells.
 

Jesus4Lyf

Good Idea™
Reaction score
397
Where is this better than SpellEvent by Anitarf?
What advantage does this have over SpellEvent by Anitarf?
Wtf? Not everything is SpellEvent by Anitarf? Will you stop bringing up SpellEvent by Anitarf? You've brought it up in two systems now, neither of which are covered by that system.
 

Kenny

Back for now.
Reaction score
202
What I am thinking of doing next:

- Adding in ability level for spell events (will use GetSpellAbilityId(), so .level wont work if you want the level of another ability besides the one that was cast).
- Adding a method operator for .casterUnit, called .orderUnit (or .orderedUnit), so that people can use that for order events (looks better).
- Thinking of making new names for some struct members.
- Thinking of making all the EventResp members public, so that people can change them for more complex spells.

Okay, so I am looking for different names for:

- .distXY
- .distXYZ
- .angle
- .pitch

I am looking for some standardised names that are easy to type and understand (I'm not really a fan of XYZ at the end).
 

Deaod

Member
Reaction score
6
Wtf? Not everything is SpellEvent by Anitarf? Will you stop bringing up SpellEvent by Anitarf? You've brought it up in two systems now, neither of which are covered by that system.
How about you take few steps back and look at SpellEvent. SpellEvent DOES cover functionality of both systems ive mentioned it in. GTrigger is an event stack (or whatever youd call it), while this makes information associated to a certain event accessible inside nice wrappers, which is also something SpellEvent does (though SpellEvent only covers spell event responses).

So, DOES it do something important SpellEvent doesnt offer, or does it not?
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
How about you take few steps back and look at SpellEvent. SpellEvent DOES cover functionality of both systems ive mentioned it in. GTrigger is an event stack (or whatever youd call it), while this makes information associated to a certain event accessible inside nice wrappers, which is also something SpellEvent does (though SpellEvent only covers spell event responses).

So, DOES it do something important SpellEvent doesnt offer, or does it not?

GTrigger uses one event for each type of event. In other words, you will have faster starting triggers that run off of ANY event, not just spell events. SpellEvent doesn't cover every event, and so it is unrelated.

This system not only covers order events, but it also covers common/basic spell data, such as xy/xyz-location, angle/pitch, etc.

The systems are similar in that you can't/wouldn't use both, but they do cover completely different things.

Now, for the system:

I'm not a huge fan of the interface. I do feel that it's kind of like a sluggish spell event system, as it runs all those functions whether they're used or not. Then again, I never was a fan of using wrappers in strange situations. :p

However, nonetheless it's a useful system for people new to creating spells, and it does simplify things. I haven't gone through the code fully, yet (mostly just skimmed through the documentation), so I can't approve it right here and right now.
 

Deaod

Member
Reaction score
6
GTrigger uses one event for each type of event. In other words, you will have faster starting triggers that run off of ANY event, not just spell events. SpellEvent doesn't cover every event, and so it is unrelated.

This system not only covers order events, but it also covers common/basic spell data, such as xy/xyz-location, angle/pitch, etc.

The systems are similar in that you can't/wouldn't use both, but they do cover completely different things.
First off, youre contradicting yourself in your last sentence. How can something you wouldnt want to use at the same time NOT cover the same tasks?

Second, SpellEvent also covers basic spell data. Just not 3D location, angle and pitch (which are trivial to get anyway).
It does not cover orders, for which doing wrappers is totally pointless anyway.
Which made me notice something: This library is utterly pointless. Yes, its a wrapper library, but its just that: a wrapper. It doesnt offer any value, its just a bunch of code sitting on top of the natives (thus sucking performance) not doing anything useful in return (unless you see renaming natives as something useful).

Third, SpellEvent is not unrelated, those systems DO THE SAME FUCKING THING. How can they be unrelated?
 

Narks

Vastly intelligent whale-like being from the stars
Reaction score
90
First off, youre contradicting yourself in your last sentence. How can something you wouldnt want to use at the same time NOT cover the same tasks?

A safe SetUnitXY snippet and Vexorian's BoundSentinel? Similar uses, but they are definitely not the same and do not operate in the same way.

Which made me notice something: This library is utterly pointless. Yes, its a wrapper library, but its just that: a wrapper.
> So this is basically a resource that helps maintain code readability and reduce bloating of scripts. It effectively reduces time spent maintaining, editing and producing spells and systems for personal or public use.



its just a bunch of code sitting on top of the natives (thus sucking performance)
Aren't all systems basically code sitting on top of natives, sucking performance?


Third, SpellEvent is not unrelated, those systems DO THE SAME FUCKING THING. How can they be unrelated?
PERHAPS YOU SHOULD ACTUALLY CHECK WHAT GTRIGGER DOES, OR MAYBE READ OTHER PEOPLE'S POSTS: (ALSO CAPS LOCKS IS CRUISE CONTROL FOR COOL)
> GTrigger uses one event for each type of event. In other words, you will have faster starting triggers that run off of ANY event, not just spell events. SpellEvent doesn't cover every event, and so it is unrelated.
 

Jesus4Lyf

Good Idea™
Reaction score
397
GTrigger uses one event for each type of event. In other words, you will have faster starting triggers that run off of ANY event, not just spell events.
...
This system not only covers order events, but it also covers common/basic spell data, such as xy/xyz-location, angle/pitch, etc.
Darthfett is right, and the topic is now over. Further off-topic posts on this matter shall be deleted.
 

Kenny

Back for now.
Reaction score
202
>Just not 3D location, angle and pitch (which are trivial to get anyway)

For many people, getting angles and distances is not a trivial matter. It can actually be quite difficult for some, and for others it might just be a pian in the ass to do.

>Which made me notice something: This library is utterly pointless. Yes, its a wrapper library, but its just that: a wrapper. It doesnt offer any value, its just a bunch of code sitting on top of the natives (thus sucking performance) not doing anything useful in return (unless you see renaming natives as something useful).

This system just does what the user will eventually have to do anyway. For example:

My system: Sets the caster to a variable for later and repeated use.
What users will have to do: Define a local variable and set it to the caster unit for later and repeated use.

This system is here to simplify things.

And as of the next update, it will also fix the bugged blizzard event responses for ENDCAST and FINISH events.

It will also include .abilId and .level for spell events, and have .orderId and .orderStr for order events only. They will return 0 or null if used in the wrong events.

I will try to make some more intuitive names for some struct members if I can think of any, or I may just standardise them instead.

Edit:

Work in progress for next version (Still have to add better names for distances and angles and test the event responses for ENDCAST and FINISH):

JASS:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  ~~    EventResponses    ~~    By kenny!    ~~    Version 1.0.1    ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  What is EventResponses?
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//      - EventResponses is a system that allows users to easily access
//        the most common event response natives from spell and order events.
//      - It was created due to the repetitive nature of writing multiple scripts,
//        both for maps and for released spells and systems. The systems aims to
//        reduce the amount of time spent developing these spells and systems by
//        simplifying the tedious coding needed to write them.
//
//  Functions:
// ¯¯¯¯¯¯¯¯¯¯¯
//      - EventResp.create(boolean set2D, boolean set3D) --&gt; returns EventResp
//
//        This creates a new event response struct that stores the event response
//        data for the current spell or order event. The first boolean argument is
//        used to decide if you want to set the 2D distance and angle between the
//        caster unit&#039;s x and y and the target x and y. The second boolean argument
//        is used to determine whether or not the 3D distance and angle between the
//        coordinates should be set. These are used as many spells do not need them.
//
//      - EventResp.replicate(EventResp resp) --&gt; returns EventResp
//
//        This creates a new event response struct that stores the event response
//        data for the current spell or order event. This function, however, copies
//        a current EventResp struct and all of its data. The EventResp argument is
//        the EventResp instance that you wish to copy.
//
//      - .updateCaster(boolean updateZ) --&gt; returns nothing
//
//        Updates the x, y and z locations of the caster. The boolean argument is
//        used to determine whether or not the z location should be updated.
//
//      - .updateTarget(boolean updateZ) --&gt; returns nothing
//
//        Updates the x, y and z locations of the target. The boolean argument is
//        used to determine whether or not the z location should be updated.
//
//      - .updateDistances(boolean update3D) --&gt; returns nothing
//
//        Updates the distance between the caster and target coordinates. The
//        boolean argument is used to determine whether or not the 3D distance
//        should be updated.
//
//      - .updateAngles(boolean update3D) --&gt; returns nothing
//
//        Updates the angle between the caster and target coordinates. The
//        boolean argument is used to determine whether or not the 3D angle
//        should be updated.
//
//      - .destroy() --&gt; returns nothing
//
//        Destroys the struct holding the variables.
//                      
//  Variables:
// ¯¯¯¯¯¯¯¯¯¯¯
//      - .casterUnit   --&gt; Returns the unit that casted the spell, or the unit that
//                          was issued an order.
//      - .targetWidg   --&gt; Returns the targeted widget of an order or spell. Does not
//                          return a unit, destructable or item.
//      - .targetUnit   --&gt; Returns the targeted unit of an order or spell. Will return
//                          null if the target isn&#039;t a unit.
//      - .targetDest   --&gt; Returns the targeted destructable of an order or spell.
//                          Will return null if the target isn&#039;t a destructable.
//      - .targetItem   --&gt; Returns the targeted item of an order or spell. Will return
//                          null if the target isn&#039;t an item.
//      - .casterX      --&gt; Returns the X coordinate of the casting unit or the ordered
//                          unit.
//      - .casterY      --&gt; Returns the Y coordinate of the casting unit or the ordered
//                          unit.
//      - .casterZ      --&gt; Returns the Z coordinate of the casting unit or the ordered
//                          unit.
//      - .targetX      --&gt; Returns the X coordinate of the target of an order or 
//                          spell. Returns .casterX for immediate orders.
//      - .targetY      --&gt; Returns the Y coordinate of the target of an order or 
//                          spell. Returns .casterY for immediate orders.
//      - .targetZ      --&gt; Returns the Z coordinate of the target of an order or 
//                          spell. Returns .casterZ for immediate orders.
//      - .distXY       --&gt; Returns the distance between the .casterUnit and the target
//                          widget or location of an order or spell.
//      - .distXYZ      --&gt; Similar to the above variable, however .distXYZ will take
//                          into account the Z coordinate of the caster and target.
//      - .angle        --&gt; Returns the angle between the caster and the target in
//                          radians.
//      - .pitch        --&gt; Returns the angle between the caster and the target, also
//                          takes into account the Z location of both.
//      - .orderId      --&gt; Returns the order id of the spell or order that the caster
//                          was issued in integer format.
//      - .orderStr     --&gt; Returns the order string of the spell or order that the
//                          caster was issued.
//
//  Bonus Variables:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//      - .isTargetWidg --&gt; Returns true if the target is a widget and false if there
//                          is no target (point or immediate order).
//      - .isTargetUnit --&gt; Returns true if the target is a unit and false if it is
//                          either a destructable or item, or if there is no target.
//      - .isTargetDest --&gt; Returns true if the target is a destructable and false if
//                          it is either a unit or item, or if there is no target.
//      - .isTargetItem --&gt; Returns true if the target is an item and false if it is
//                          either a unit or destructable, or if there is no target.
//      - .isTargetLand --&gt; Returns true if there is no target widget but still a
//                          target location, and false if there is a target.
//      - .isTargetNone --&gt; Returns true if there is no target widget or location and
//                          false if there is (works for immediate orders).     
//
//  Details:
// ¯¯¯¯¯¯¯¯¯
//      - There are no configurables for this system, just import it and use it.
//      - Aquiring the Z coordinate of units uses GetLocationZ() which can desync.
//      - EventResponses will only work with some player unit and unit events,
//        these include:
//          - EVENT_PLAYER_UNIT_SPELL_CHANNEL
//          - EVENT_PLAYER_UNIT_SPELL_CAST
//          - EVENT_PLAYER_UNIT_SPELL_EFFECT
//          - EVENT_PLAYER_UNIT_SPELL_FINISH
//          - EVENT_PLAYER_UNIT_SPELL_ENDCAST
//          - EVENT_PLAYER_UNIT_ISSUED_ORDER
//          - EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER
//          - EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER
//          - EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER
//
//          - EVENT_UNIT_SPELL_CHANNEL
//          - EVENT_UNIT_SPELL_CAST
//          - EVENT_UNIT_SPELL_EFFECT
//          - EVENT_UNIT_SPELL_FINISH
//          - EVENT_UNIT_SPELL_ENDCAST
//          - EVENT_UNIT_ISSUED_ORDER
//          - EVENT_UNIT_ISSUED_TARGET_ORDER
//          - EVENT_UNIT_ISSUED_POINT_ORDER
//      - Only these events will work as they have common native responses. Other
//        Events have different responses, which would make this system messy if
//        it attempted to work for all of them.
//
//  How to import:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//      - Create a trigger named EventResponses.
//      - Convert it to custom text and replace the whole trigger text with this.
//
//  Thanks:
// ¯¯¯¯¯¯¯¯
//      - Jesus4Lyf for hopefully letting me use his method of determining
//        whether or not the spell or order has a target widget or location.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library EventResponses initializer Init requires AIDS

    globals
        // Only configurable option available.
        private constant integer MAX_RESPONSES    = 8190
        
        // Different target types for boolean checks.
        private constant integer TARGET_TYPE_NONE = 1
        private constant integer TARGET_TYPE_UNIT = 2
        private constant integer TARGET_TYPE_DEST = 3
        private constant integer TARGET_TYPE_ITEM = 4
        private constant integer TARGET_TYPE_LAND = 5
    endglobals
    
    private struct EventHandler extends array
        //! runtextmacro AIDS()
        
        EventResp eventResp
        
        private method AIDS_onCreate takes nothing returns nothing
            set this.eventResp = 0
        endmethod
        
        private method  AIDS_onDestroy takes nothing returns nothing
            set this.eventResp = 0
        endmethod
        
    endstruct
    
    // Struct that stores preloaded events for the system.
    private struct EventId
    
        readonly boolean  isSpell  = false // If it is a spell or order event.
        readonly boolean  isBroken = false // If the spell event is one of the broken ones (END_CAST and FINISH).
        private  eventid  eventId  = null  // The event itself.
        private  thistype next     = 0     // Next event in the list.
        
        private static timer tempTimer = null // Timer needed for initial registration.
        private static eventid array eventIds // Array to store the used events.
    
        // I kind of liked this interface, even though it requires a search.
        static method operator[] takes eventid id returns thistype
            local thistype this = thistype(0).next
            
            // Should still technically be 0(1) complexity as it is a constant search over 17 instances.
            loop
                exitwhen this == 0
                if id == this.eventId then
                    return this
                endif
                set this = this.next
            endloop
            
            return 0
        endmethod
        
        // Set up each event.
        private static method setEvent takes eventid id, integer i returns nothing
            local thistype this = thistype.allocate()
            
            set this.eventId = id // Set the eventid.
            
            if i &lt; 10 then
                set this.isSpell = true // The first 9 events are spell events.
                if i &gt; 5 then
                    set this.isBroken = true // There are 4 broken events.
                endif
            endif
            
            // Lazy.
            set this.next=thistype(0).next
            set thistype(0).next=this
        endmethod
        
        // Register the events at 0.00 seconds of game time (It wouldn&#039;t work otherwise).
        private static method registerEvents takes nothing returns nothing
            local integer i = 0
            
            loop
                exitwhen i == 17
                call thistype.setEvent(thistype.eventIds<i>,i)
                set i = i + 1
            endloop
            
            // Clean up the temporary timer.
            call PauseTimer(thistype.tempTimer)
            call DestroyTimer(thistype.tempTimer)
            set thistype.tempTimer = null
        endmethod
        
        // Initialise all the events used.
        private static method onInit takes nothing returns nothing
            // First 9 are spell events.
            set thistype.eventIds[0]  = EVENT_PLAYER_UNIT_SPELL_CHANNEL
            set thistype.eventIds[1]  = EVENT_PLAYER_UNIT_SPELL_CAST
            set thistype.eventIds[2]  = EVENT_PLAYER_UNIT_SPELL_EFFECT
            set thistype.eventIds[3]  = EVENT_UNIT_SPELL_CHANNEL
            set thistype.eventIds[4]  = EVENT_UNIT_SPELL_CAST
            set thistype.eventIds[5]  = EVENT_UNIT_SPELL_EFFECT
            set thistype.eventIds[6]  = EVENT_PLAYER_UNIT_SPELL_FINISH
            set thistype.eventIds[7]  = EVENT_PLAYER_UNIT_SPELL_ENDCAST
            set thistype.eventIds[8]  = EVENT_UNIT_SPELL_FINISH
            set thistype.eventIds[9]  = EVENT_UNIT_SPELL_ENDCAST
            
            // The rest are order events.
            set thistype.eventIds[10] = EVENT_PLAYER_UNIT_ISSUED_ORDER
            set thistype.eventIds[11] = EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER
            set thistype.eventIds[12] = EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER
            set thistype.eventIds[13] = EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER
            set thistype.eventIds[14] = EVENT_UNIT_ISSUED_ORDER
            set thistype.eventIds[15] = EVENT_UNIT_ISSUED_POINT_ORDER
            set thistype.eventIds[16] = EVENT_UNIT_ISSUED_TARGET_ORDER
            
            // Start the timer.
            set thistype.tempTimer = CreateTimer()
            call TimerStart(thistype.tempTimer,0.00,false,function thistype.registerEvents)
        endmethod
        
    endstruct

    // The exported EventResp struct.
    struct EventResp[MAX_RESPONSES]
    
        // All the accessible variables.
        readonly unit         casterUnit = null
        readonly widget       targetWidg = null
        readonly unit         targetUnit = null
        readonly destructable targetDest = null
        readonly item         targetItem = null
        readonly string       orderStr   = &quot;&quot;
        readonly real         casterX    = 0.00
        readonly real         casterY    = 0.00
        readonly real         casterZ    = 0.00
        readonly real         targetX    = 0.00
        readonly real         targetY    = 0.00
        readonly real         targetZ    = 0.00
        readonly real         distXY     = 0.00
        readonly real         distXYZ    = 0.00
        readonly real         angle      = 0.00
        readonly real         pitch      = 0.00
        readonly real         cosAng     = 0.00
        readonly real         sinAng     = 0.00
        readonly integer      orderId    = 0
        readonly integer      targetType = 0
        readonly integer      abilId     = 0
        readonly integer      level      = 0
        
        // For order events (looks nicer).
        method operator orderUnit takes nothing returns unit
            return this.casterUnit
        endmethod
        
        // Boolean checks.
        method operator isTargetWidg takes nothing returns boolean
            return this.targetType == TARGET_TYPE_UNIT or this.targetType == TARGET_TYPE_DEST or this.targetType == TARGET_TYPE_ITEM
        endmethod
        
        method operator isTargetUnit takes nothing returns boolean
            return this.targetType == TARGET_TYPE_UNIT
        endmethod
        
        method operator isTargetDest takes nothing returns boolean
            return this.targetType == TARGET_TYPE_DEST
        endmethod
        
        method operator isTargetItem takes nothing returns boolean
            return this.targetType == TARGET_TYPE_ITEM
        endmethod
        
        method operator isTargetLand takes nothing returns boolean
            return this.targetType == TARGET_TYPE_LAND
        endmethod
        
        method operator isTargetNone takes nothing returns boolean
            return this.targetType == TARGET_TYPE_NONE
        endmethod
        
        // Clean up.
        method destroy takes nothing returns nothing
            set this.casterUnit = null
            set this.targetWidg = null
            set this.targetUnit = null
            set this.targetDest = null
            set this.targetItem = null
            
            call this.deallocate()
        endmethod
        
        // Update the coordinates of the caster, with z coordinate if wanted.
        method updateCaster takes boolean updateZ returns nothing
            set this.casterX = GetUnitX(this.casterUnit)
            set this.casterY = GetUnitY(this.casterUnit)
            
            if updateZ then
                call MoveLocation(tempLoc,this.casterX,this.casterY)
                set this.casterZ = GetLocationZ(tempLoc) + GetUnitFlyHeight(this.casterUnit)
            endif
        endmethod
        
        // Update the coordinates of the target, with z coordinate if wanted.
        method updateTarget takes boolean updateZ returns nothing
            set this.targetX = GetUnitX(this.targetUnit)
            set this.targetY = GetUnitY(this.targetUnit)
            
            if updateZ then
                call MoveLocation(tempLoc,this.targetX,this.targetY)
                set this.targetZ = GetLocationZ(tempLoc) + GetUnitFlyHeight(this.targetUnit)
            endif
        endmethod
        
        // Update the 2D distance, and 3D if wanted.
        method updateDistances takes boolean set3D returns nothing
            local real x = this.targetX - this.casterX
            local real y = this.targetY - this.casterY
            local real z = this.targetZ - this.casterZ
                
            set this.distXY  = SquareRoot(x * x + y * y)
            
            if set3D then
                set this.distXYZ = SquareRoot(x * x + y * y + z * z)
            endif
        endmethod
        
        // Update the 2D angle, and 3D if wanted.
        method updateAngles takes boolean set3D returns nothing
            local real x = this.targetX - this.casterX
            local real y = this.targetY - this.casterY
            local real z = this.targetZ - this.casterZ
            
            set this.angle  = Atan2(y,x)
            set this.cosAng = Cos(this.angle)
            set this.sinAng = Sin(this.angle)
            
            if set3D then
                set this.pitch  = Atan2(SquareRoot(x * x + y * y),z)
            endif
        endmethod
        
        // Refreshes and updates all members at once.
        method refresh takes boolean updateZ, boolean set3D returns nothing
            call this.updateCaster(updateZ)
            call this.updateTarget(updateZ)
            call this.updateDistances(set3D)
            call this.updateAngles(set3D)
        endmethod
        
        // Replicate a current EventResp instance and assign it to a new instance.
        static method replicate takes thistype resp returns thistype
            local thistype this = thistype.allocate()
            
            set this.casterUnit = resp.casterUnit
            set this.targetWidg = resp.targetWidg
            set this.targetUnit = resp.targetUnit
            set this.targetDest = resp.targetDest
            set this.targetItem = resp.targetItem
            set this.orderStr   = resp.orderStr
            set this.casterX    = resp.casterX
            set this.casterY    = resp.casterY
            set this.casterZ    = resp.casterZ
            set this.targetX    = resp.targetX
            set this.targetY    = resp.targetY
            set this.targetZ    = resp.targetZ
            set this.distXY     = resp.distXY
            set this.distXYZ    = resp.distXYZ
            set this.angle      = resp.angle
            set this.pitch      = resp.pitch
            set this.cosAng     = resp.cosAng
            set this.sinAng     = resp.sinAng
            set this.orderId    = resp.orderId
            set this.targetType = resp.targetType
            set this.abilId     = resp.abilId
            set this.level      = resp.level
            
            return this
        endmethod
        
        // Scabbed off Jesus4Lyf, hope you don&#039;t mind. <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite7" alt=":p" title="Stick Out Tongue    :p" loading="lazy" data-shortname=":p" />
        //! textmacro SetTargetMembers takes TYPE, LAND
            set this.targetUnit = Get$TYPE$TargetUnit()
            if this.targetUnit == null then
                set this.targetDest = Get$TYPE$TargetDestructable()
                if this.targetDest == null then
                    set this.targetItem = Get$TYPE$TargetItem()
                    if this.targetItem == null then
                        set this.targetWidg = null
                        set this.targetX    = Get$LAND$X()
                        set this.targetY    = Get$LAND$Y()
                        call MoveLocation(tempLoc,this.targetX,this.targetY)
                        set this.targetZ    = GetLocationZ(tempLoc)
                        if this.targetX != 0.00 or this.targetY != 0.00 or this.targetZ != 0.00 then
                            set this.targetType = TARGET_TYPE_LAND
                        else
                            set this.targetType = TARGET_TYPE_NONE
                            set this.targetX    = this.casterX
                            set this.targetY    = this.casterY
                            set this.targetZ    = this.casterZ
                        endif
                    else
                        set this.targetWidg = this.targetItem
                        set this.targetType = TARGET_TYPE_ITEM
                        set this.targetX    = GetItemX(this.targetItem)
                        set this.targetY    = GetItemY(this.targetItem)
                        call MoveLocation(tempLoc,this.targetX,this.targetY)
                        set this.targetZ    = GetLocationZ(tempLoc)
                    endif
                else
                    set this.targetWidg = this.targetDest
                    set this.targetItem = null
                    set this.targetType = TARGET_TYPE_DEST
                    set this.targetX    = GetDestructableX(this.targetDest)
                    set this.targetY    = GetDestructableY(this.targetDest)
                    call MoveLocation(tempLoc,this.targetX,this.targetY)
                    set this.targetZ    = GetLocationZ(tempLoc)
                endif
            else
                set this.targetWidg = this.targetUnit
                set this.targetDest = null
                set this.targetItem = null
                set this.targetType = TARGET_TYPE_UNIT
                set this.targetX    = GetUnitX(this.targetUnit)
                set this.targetY    = GetUnitY(this.targetUnit)
                call MoveLocation(tempLoc,this.targetX,this.targetY)
                set this.targetZ    = GetLocationZ(tempLoc) + GetUnitFlyHeight(this.targetUnit)
            endif
        //! endtextmacro
            
        // Create the event responses.
        static method create takes boolean set2D, boolean set3D returns thistype
            local EventId  id   = EventId[GetTriggerEventId()]
            local thistype this = 0
            local real     x    = 0.00
            local real     y    = 0.00
            local real     z    = 0.00
            
            // If the event responses were created for an unsupported event, show an error.
            if id == 0 then
                debug call BJDebugMsg(&quot;|cFFFF0000Error using EventResponses:|r Unsupported event type used.&quot;)
                return 0
            elseif id.isBroken then
                return EventResp.replicate(EventHandler[GetTriggerUnit()].eventResp)
            endif
            
            // Assign all the members.
            set this            = thistype.allocate()
            set this.casterUnit = GetTriggerUnit()
            set this.casterX    = GetUnitX(this.casterUnit)
            set this.casterY    = GetUnitY(this.casterUnit)
            call MoveLocation(thistype.tempLoc,this.casterX,this.casterY)
            set this.casterZ    = GetUnitFlyHeight(this.casterUnit) - GetLocationZ(thistype.tempLoc)
            
            if id.isSpell then
                //! runtextmacro SetTargetMembers(&quot;Spell&quot;,&quot;SpellTarget&quot;)
                set this.abilId = GetSpellAbilityId()
                set this.level  = GetUnitAbilityLevel(this.casterUnit,this.abilId)
            else
                //! runtextmacro SetTargetMembers(&quot;Order&quot;,&quot;OrderPoint&quot;)
                set this.orderId    = GetIssuedOrderId()
                set this.orderStr   = OrderId2String(this.orderId)
            endif
            
            // Set 2D distances and angles if required.
            if set2D then
                set x = this.targetX - this.casterX
                set y = this.targetY - this.casterY
                set z = this.targetZ - this.casterZ
                
                set this.distXY  = SquareRoot(x * x + y * y)
                set this.angle   = Atan2(y,x)
                set this.cosAng  = Cos(this.angle)
                set this.sinAng  = Sin(this.angle)
            endif
            
            // Set 3D distances and angles if required.
            if set3D then
                set x = this.targetX - this.casterX
                set y = this.targetY - this.casterY
                set z = this.targetZ - this.casterZ
                
                set this.distXYZ = SquareRoot(x * x + y * y + z * z)
                set this.pitch   = Atan2(SquareRoot(x * x + y * y),z)
            endif
            
            return this
        endmethod
        
        // Initialisation of the temporary loc for Z coords.
        private static location tempLoc = Location(0.00,0.00)

    endstruct
    
    globals
        private trigger Trig = CreateTrigger()
        private timer   Time = CreateTimer()
        private unit    Unit = null
        private boolean Bool = false
    endglobals
    
    private function OnEndCastChild takes nothing returns boolean
        call EventHandler[Unit].eventResp.destroy()
        return false
    endfunction
    
    private function Recycle takes nothing returns nothing
        if Bool then
            call PauseTimer(Time)
            set Bool = false
            call TriggerEvaluate(Trig)
            call TriggerClearConditions(Trig)
        endif
    endfunction
    
    private function OnEffect takes nothing returns boolean
        set EventHandler[GetTriggerUnit()].eventResp = EventResp.create(true,true)
        return false
    endfunction
    
    private function OnEndCast takes nothing returns boolean
        set Bool = true
        set Unit = GetTriggerUnit()
        call ResumeTimer(Time)
        call TriggerAddCondition(Trig,Condition(function OnEndCastChild))
        return false
    endfunction
    
    private function Init takes nothing returns nothing
        local trigger trig = CreateTrigger()
        
        call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(trig,Condition(function OnEffect))
        
        set trig = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SPELL_ENDCAST)
        call TriggerAddCondition(trig,Condition(function OnEndCast))
        
        call TimerStart(Time,0.00,true,function Recycle)
        call PauseTimer(Time)
    endfunction
        
endlibrary
</i>
 
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