Snippet EventResponses

Jesus4Lyf

Good Idea™
Reaction score
397
JASS:
//        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.

I'd calculate this when you return the value, not when the event occurs... should clean up your interface a bit.
If efficiency matters, these functions shouldn't be there. If efficiency does not matter, they should calculate the value when called, if possible. For a system without any efficiency focus to be more than just a personal system, it must have an intuitive and helpful interface (ie. not [LJASS]boolean set2D, boolean set3D[/LJASS] in my opinion).
 

Kenny

Back for now.
Reaction score
202
Fair enough. I have attempted to clean up the interface and script. I think this should be more to your liking...

I removed the boolean arguments from the methods, removed some methods and fixed up a few things.

Unfortunately, I had to lose .cosAng and .sinAng, as I see no way of making them work properly without an angle member to base them off.

JASS:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  ~~    EventResponses    ~~    By kenny!    ~~    Version 1.0.2    ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  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.
//      - EventResponses also fixes the broken blizzard event responses for ENDCAST
//        and FINISH spell events, allowing all native event responses to be used
//        for the events.
//
//  Requires:
// ¯¯¯¯¯¯¯¯¯¯
//      - AIDS by Jesus4Lyf.
//      - Jass NewGen.
//
//  Methods:
// ¯¯¯¯¯¯¯¯¯
//      - EventResp.create() --> returns EventResp
//
//        This creates a new event response struct that stores the event response
//        data for the current spell or order event.
//
//      - .replicate()       --> returns EventResp
//
//        This copies an existing EventResp struct and all the data into a new
//        EventResp struct instance. This can be useful for some spells.
//
//      - .updateCaster()    --> returns nothing
//
//        Updates the x, y and z locations of the caster.
//
//      - .updateTarget()    --> returns nothing
//
//        Updates the x, y and z locations of the target.
//
//      - .destroy()         --> returns nothing
//
//        Destroys the struct holding the variables.
//                      
//  Members:
// ¯¯¯¯¯¯¯¯¯
//      - .casterUnit   --> Returns the unit that casted the spell, or the unit that
//                          was issued an order.
//      - .orderUnit    --> Returns the same unit as .casterUnit. This can be used for
//                          order events so that the script makes more sense.
//      - .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.
//      - .orderId      --> Returns the order id of the order that the unit was
//                          issued in integer format. Only works for order events.
//      - .orderStr     --> Returns the order string of the order that the
//                          unit was issued. Only works for order events.
//      - .abilId       --> Returns the ability id of the spell that the unit casted.
//                          Only works for spell events.
//      - .level        --> Returns the level of the spell casted as an integer.
//                          Only works for spell events.
//
//  Distances and Angles:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//      - .distance     --> Returns the distance between the caster and the target.
//                          Does not account for the z coordinate of the units/locations.
//      - .distanceZ    --> Returns the distance between the caster and the target.
//                          Takes into account the z coordinate of the units/locations.
//      - .angle        --> Returns the angle between the caster and the target in radians.
//                          Does not account for the z coordinate of the units/locations.
//      - .angleZ       --> Returns the angle between the caster and the target in radians.
//                          Takes into account the z coordinate of the units/locations.
//
//  Boolean Checks:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//      - .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.
//      - Make sure you have the requirements for this system installed as well.
//
//  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
    
    // The event handler for fixing broken event responses.
    private struct EventHandler extends array
        //! runtextmacro AIDS()
        
        readonly EventResp curr
        readonly EventResp prev
        
        method attach takes EventResp er returns nothing
            if this.curr != 0 then
                set this.prev = this.curr
            endif
            set this.curr = er
        endmethod
        
        method detach takes nothing returns nothing
            if this.curr != 0 then
                call this.curr.destroy()
                if this.prev != 0 then
                    set this.curr = this.prev
                    set this.prev = 0
                else
                    set this.curr = 0
                endif
            endif
        endmethod
        
        private method AIDS_onCreate takes nothing returns nothing
            set this.curr = 0
            set this.prev = 0
        endmethod
        
        private method  AIDS_onDestroy takes nothing returns nothing
            set this.curr = 0
            set this.prev = 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 < 10 then
                set this.isSpell = true // The first 9 events are spell events.
                if i > 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'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 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
        
        // Distance and angle method operators.
        method operator distance takes nothing returns real
            local real x = this.targetX - this.casterX
            local real y = this.targetY - this.casterY
            return SquareRoot(x * x + y * y)
        endmethod
        
        method operator distanceZ takes nothing returns real
            local real x = this.targetX - this.casterX
            local real y = this.targetY - this.casterY
            local real z = this.targetZ - this.casterZ
            return SquareRoot(x * x + y * y + z * z)
        endmethod
        
        method operator angle takes nothing returns real
            return Atan2(this.targetY - this.casterY,this.targetX - this.casterX)
        endmethod
        
        method operator angleZ takes nothing returns real
            local real x = this.targetX - this.casterX
            local real y = this.targetY - this.casterY
            return Atan2(SquareRoot(x * x + y * y),this.targetZ - this.casterZ)
        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.
        method updateCaster takes nothing returns nothing
            set this.casterX = GetUnitX(this.casterUnit)
            set this.casterY = GetUnitY(this.casterUnit)
            call MoveLocation(tempLoc,this.casterX,this.casterY)
            set this.casterZ = GetUnitFlyHeight(this.casterUnit) - GetLocationZ(tempLoc)
        endmethod
        
        // Update the coordinates of the target.
        method updateTarget takes nothing returns nothing
            set this.targetX = GetUnitX(this.targetUnit)
            set this.targetY = GetUnitY(this.targetUnit)
            call MoveLocation(tempLoc,this.targetX,this.targetY)
            set this.targetZ = GetUnitFlyHeight(this.targetUnit) - GetLocationZ(tempLoc)
        endmethod
        
        // Replicate a current EventResp instance and assign it to a new instance.
        method replicate takes nothing returns thistype
            local thistype that = thistype.allocate()
            
            set that.casterUnit = this.casterUnit
            set that.targetWidg = this.targetWidg
            set that.targetUnit = this.targetUnit
            set that.targetDest = this.targetDest
            set that.targetItem = this.targetItem
            set that.orderStr   = this.orderStr
            set that.casterX    = this.casterX
            set that.casterY    = this.casterY
            set that.casterZ    = this.casterZ
            set that.targetX    = this.targetX
            set that.targetY    = this.targetY
            set that.targetZ    = this.targetZ
            set that.orderId    = this.orderId
            set that.targetType = this.targetType
            set that.abilId     = this.abilId
            set that.level      = this.level
            
            return that
        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    = GetUnitFlyHeight(this.targetUnit) - GetLocationZ(tempLoc)
            endif
        //! endtextmacro
            
        // Create the event responses.
        static method create takes nothing returns thistype
            local EventId  id   = EventId[GetTriggerEventId()]
            local thistype this = 0
            
            // 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
                call BJDebugMsg(&quot;Broken event fixed.&quot;)
                return EventHandler[GetTriggerUnit()].curr.replicate()
            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
            
            return this
        endmethod
        
        // Initialisation of the temporary loc for Z coords.
        private static location tempLoc = Location(0.00,0.00)

    endstruct
    
    // Below fixes the broken blizzard event responses.
    globals
        private trigger Trig = CreateTrigger()
        private timer   Time = CreateTimer()
        private unit    Unit = null
        private boolean Bool = false
    endglobals
    
    private function Recycle takes nothing returns nothing
        if Bool then
            call PauseTimer(Time)
            call TriggerEvaluate(Trig)
            call TriggerClearConditions(Trig)
            set Bool = false
            set Unit = null
        endif
    endfunction
    
    private function OnEndCastChild takes nothing returns boolean
        call EventHandler[Unit].detach()
        return false
    endfunction
    
    private function OnEffect takes nothing returns boolean
        call EventHandler[GetTriggerUnit()].attach(EventResp.create())
        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>
 

tooltiperror

Super Moderator
Reaction score
231
It came with its own (read the first post) but here's one anyways?
JASS:

//! zinc
library KillSpell {
    constant integer SPELL_ID = &#039;A000&#039;;
    struct Data {
        static method onEffect() -&gt; boolean {
            EventResp resp;
            if (GetSpellAbilityId()!=SPELL_ID) { return false; }
            resp=EventResp.create(); // we can now use the resp variable to get common responses
            // Since this IS the spell casted, now set the variable to something we can use.
            if (resp.isTargetUnit(resp.targetUnit)) { KillUnit(resp.targetUnit);
            // This above line is really special. We use resp.targetUnit twice, and we save a line
            // for readability, and use a variable so we&#039;re not wasting CPU power.
            resp.destroy();
            // Recycle it.
            return false;
        }
        static method onInit() {
            trigger t=CreateTrigger();
            TriggerAddCondition(t,Condition(function thistype.onEffect));
            TriggerRegisterWhateverGenericUnitSpellEffectEvent(t); // because I forget what its called
        }
    }
}
//! endzinc
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top