vJASS & Zinc Documentation
For the latest documentation about how it works vJASS and Zinc language layers for Warcraft III, please follow these links:
Jasshelper documentation - Zinc documentation - WC3 Optimizer documentation

AutoEvents

moyack · 456

0 Members and 1 Guest are viewing this topic.

Rating

Average Score - 5 / 5

« Created: December 25, 2017, 09:56:13 PM by moyack »

AutoEvents
on: March 09, 2012, 10:37:07 PM
Category: Execution, Units
Language: vJASS

Related Topics or Resources



by

AutoEvents is an add-on library for AutoIndex. It gives you events that detect the following things: when units resurrect, when units are raised with Animate Dead, when units begin reincarnating, when units finish reincarnatinging, and when transports load and unload units. It also provides other useful functions. You can check if a unit is currently raised with Animate Dead, get the transport carrying a unit, get the number of a units in a transport, get the passenger in a specific slot of a transport, and enumerate through all of the units in a transport.

Code: jass
  1. library AutoEvents requires AutoIndex
  2. //===========================================================================
  3. // Information:
  4. //==============
  5. //
  6. //     AutoEvents is an add-on library for AutoIndex. It gives you events that
  7. // detect the following things: when units resurrect, when units are raised with
  8. // Animate Dead, when units begin reincarnating, when units finish reincarnating,
  9. // when transports load units, and when transports unload units. It also provides
  10. // other useful functions: you can check if a unit is currently raised with Ani-
  11. // mate Dead, get the transport carrying a unit, get the number of a units in a
  12. // transport, get the passenger in a specific slot of a transport, and enumerate
  13. // through all of the units in a transport.
  14. //
  15. //===========================================================================
  16. // How to use AutoEvents:
  17. //========================
  18. //
  19. //     You can use the events in this library to run specific functions when
  20. // an event occurs. Unit-related events require a function matching the Stat-
  21. // usEvent function interface, and transport-related events require a function
  22. // matching the TransportEvent function interface:
  23. //
  24. // function interface AutoEvent takes unit u returns nothing
  25. // function interface TransportEvent takes unit transport, unit passenger returns nothing
  26. //
  27. //     The following examples use the AutoEvent function interface:
  28. /*
  29.     function UnitDies takes unit u returns nothing
  30.         call BJDebugMsg(GetUnitName(u)+" has died.")
  31.     endfunction
  32.  
  33.     function UnitResurrects takes unit u returns nothing
  34.         call BJDebugMsg(GetUnitName(u)+" has been resurrected.")
  35.     endfunction
  36.  
  37.     function Init takes nothing returns nothing
  38.         call OnUnitDeath(UnitDies)
  39.         call OnUnitResurrect(UnitResurrects)
  40.     endfunction
  41. */
  42. //     And the following examples use the TransportEvents function interface:
  43. /*
  44.     function UnitLoads takes unit transport, unit passenger returns nothing
  45.         call BJDebugMsg(GetUnitName(transport)+" loaded "+GetUnitName(passenger))
  46.     endfunction
  47.  
  48.     function UnitUnloads takes unit transport, unit passenger returns nothing
  49.         call BJDebugMsg(GetUnitName(transport)+" unloaded "+GetUnitName(passenger))
  50.     endfunction
  51.  
  52.     function Init takes nothing returns nothing
  53.         call OnUnitLoad(UnitLoads)
  54.         call OnUnitUnload(UnitUnloads)
  55.     endfunction
  56. */
  57. //     Here is an example of using ForPassengers to enumerate each unit in
  58. // a transport and heal them for 100 life:
  59. /*
  60.     function HealPassenger takes unit transport, unit passenger returns nothing
  61.         call SetWidgetLife(passenger, GetWidgetLife(passenger) + 100.)
  62.     endfunction
  63.     function HealAllPassengers takes unit transport returns nothing
  64.         call ForPassengers(transport, HealPassenger)
  65.     endfunction
  66. */
  67. //     GetPassengerBySlot provides an alternative way to enumerate the
  68. // units within a transport. (The following example would heal a unit
  69. // that occupies multiple slots in the transport only one time, since
  70. // GetPassengerBySlot assumes that each unit occupies only one slot.)
  71. /*
  72.     function HealAllPassengers takes unit transport returns nothing
  73.         local integer slot = 1 //Start at slot 1.
  74.         local unit passenger
  75.             loop
  76.                 set passenger = GetPassengerBySlot(transport, slot)
  77.                 exitwhen passenger == null
  78.                 call SetWidgetLife(passenger, GetWidgetLife(passenger) + 100.)
  79.                 set slot = slot + 1
  80.             endloop
  81.     endfunction
  82. */
  83. //===========================================================================
  84. // AutoEvents API:
  85. //=================
  86. //
  87. // OnUnitDeath(AutoEvent)
  88. //   This event runs when any unit dies. It fires after the unit is dead, but
  89. //   before any death triggers fire.
  90. //
  91. // OnUnitResurrect(AutoEvent)
  92. //   This event runs when any unit is resurrected. It also fires when units
  93. //   are raised with Animate Dead or Reincarnation, as those are forms of
  94. //   resurrection as well.
  95. //
  96. // OnUnitAnimateDead(AutoEvent)
  97. //   This event runs when any unit is raised with Animate Dead. It fires after
  98. //   the resurrection event.
  99. //
  100. // IsUnitAnimateDead(unit) -> boolean
  101. //   This function returns a boolean that indicates if the specified unit
  102. //   has been raised with Animate Dead.
  103. //
  104. // OnUnitReincarnateStart(AutoEvent)
  105. //   This event runs when any unit begins reincarnating. The OnUnitDeath event
  106. //   will run first.
  107. //
  108. // OnUnitReincarnateEnd(AutoEvent)
  109. //   This event runs when any unit finishes reincarnating. The OnUnitResurrect
  110. //   event will occur immediately after.
  111. //
  112. // OnUnitLoad(TransportEvent)
  113. //   This event runs when any transport loads a passenger.        
  114. //
  115. // OnUnitUnload(TransportEvent)
  116. //   This event runs when any transport unloads a passenger.
  117. //
  118. // GetUnitTransport(unit)
  119. //   Returns the transport that a unit is loaded in. Returns null if the
  120. //   unit is not riding in any transport.
  121. //
  122. // CountPassengers(transport) -> integer
  123. //   Returns the number of passengers in the specified transport.
  124. //
  125. // GetPassengerBySlot(transport, slot) -> unit
  126. //   Returns the passenger in the given slot of the specified transport.
  127. //   However, if a unit takes  more than one transport slot, it will only be
  128. //   treated as occupying one transport slot.
  129. //
  130. // ForPassengers(transport, TransportEvent)
  131. //   This function runs a TransportEvent immediately for each passenger in
  132. //   the specified transport.
  133. //
  134. //===========================================================================
  135.  
  136. function interface AutoEvent takes unit u returns nothing
  137.  
  138. //! textmacro RunAutoEvent takes EVENT
  139.     set n = 0
  140.     loop
  141.         exitwhen n > $EVENT$funcs_n
  142.         call $EVENT$funcs[n].evaluate(u)
  143.         set n = n + 1
  144.     endloop
  145. //! endtextmacro
  146.  
  147. //Injecting this textmacro into AutoIndex will cause the events to actually run.
  148.  
  149. //! textmacro AutoEvent takes EVENT, EVENTTYPE
  150.     globals
  151.         $EVENTTYPE$ array $EVENT$funcs
  152.         integer $EVENT$funcs_n = -1
  153.     endglobals
  154.     function OnUnit$EVENT$ takes $EVENTTYPE$ func returns nothing
  155.         set $EVENT$funcs_n = $EVENT$funcs_n + 1
  156.         set $EVENT$funcs[$EVENT$funcs_n] = func
  157.     endfunction
  158. //! endtextmacro
  159.  
  160. //Instantiate the function to register events of each type.
  161. //! runtextmacro AutoEvent("Death", "AutoEvent")
  162. //! runtextmacro AutoEvent("Resurrect", "AutoEvent")
  163. //! runtextmacro AutoEvent("AnimateDead", "AutoEvent")
  164.  
  165. //===========================================================================
  166. //The code below this point adds Reincarnation support to AutoEvents.
  167. //Credit to ToukoAozaki for the idea behind this detection method.
  168.  
  169. //! runtextmacro AutoEvent("ReincarnationStart", "AutoEvent")
  170. //! runtextmacro AutoEvent("ReincarnationFinish", "AutoEvent")
  171. //Create registration functions for reincarnation start and stop events.
  172.  
  173. globals
  174.     private timer ReincarnateTimer = CreateTimer()
  175.     private boolean array Reincarnated
  176.     private unit array Reincarnating
  177.     private integer Reincarnating_N = -1
  178. endglobals
  179.  
  180. private function OnResurrect takes unit u returns nothing
  181.     local integer index = GetUnitId(u)
  182.     local integer n
  183.         if Reincarnated[index] then
  184.             set Reincarnated[index] = false
  185.             //If a resurrecting unit is flagged as reincarnating,
  186.             //it's time to run the ReincarnationFinish event.
  187.             //! runtextmacro RunAutoEvent("ReincarnationFinish")
  188.         endif
  189. endfunction
  190.  
  191. private function ReincarnateCheck takes nothing returns nothing
  192.     local integer n = Reincarnating_N
  193.     local unit u
  194.         loop
  195.             exitwhen n < 0
  196.             set u = Reincarnating[n]
  197.             if GetUnitTypeId(u) != 0 and Reincarnated[GetUnitId(u)] then
  198.                 //If the unit is still flagged as reincarnating, it means DeathDetect didn't run.
  199.                 //The unit is actually reincarnating, so run the ReincarnationStart event.
  200.                 //! runtextmacro RunAutoEvent("ReincarnationStart")
  201.             endif
  202.             set Reincarnating[n] = null
  203.             set n = n - 1
  204.         endloop
  205.         set Reincarnating_N = -1
  206.     set u = null
  207. endfunction
  208.  
  209. private function OnDeath takes unit u returns nothing
  210.     set Reincarnated[GetUnitId(u)] = true
  211.     //Assume any unit that dies is going to reincarnate, unless this
  212.     //flag is set to false later by the DeathDetect function.
  213.     set Reincarnating_N = Reincarnating_N + 1 //Add the dying unit to a stack and
  214.     set Reincarnating[Reincarnating_N] = u    //check the flag 0. seconds later.
  215.     call TimerStart(ReincarnateTimer, 0., false, function ReincarnateCheck)
  216. endfunction
  217.    
  218. private function DeathDetect takes nothing returns boolean
  219.         set Reincarnated[GetUnitId(GetTriggerUnit())] = false
  220.     return false //Set the Reincarnated flag to false if the unit will not reincarnate.
  221. endfunction
  222.  
  223. private function OnEnter takes unit u returns nothing
  224.     set Reincarnated[GetUnitId(u)] = false
  225.     //When a unit enters the map, initialize its Reincarnated flag to false.
  226. endfunction
  227.    
  228. private struct ReincarnationInit extends array
  229.     private static method onInit takes nothing returns nothing
  230.         local trigger deathdetect = CreateTrigger()
  231.             call TriggerRegisterAnyUnitEventBJ(deathdetect, EVENT_PLAYER_UNIT_DEATH)
  232.             call TriggerAddCondition(deathdetect, function DeathDetect)
  233.             //This trigger runs 0. seconds after OnUnitDeath events,
  234.             //but does not fire if the unit is going to Reincarnate.
  235.             call OnUnitIndexed(OnEnter)
  236.             call OnUnitDeath(OnDeath)
  237.             call OnUnitResurrect(OnResurrect)
  238.     endmethod
  239. endstruct
  240.  
  241. //===========================================================================
  242. // All of the remaining code deals with transports.
  243.  
  244. function interface TransportEvent takes unit transport, unit passenger returns nothing
  245.  
  246. //! runtextmacro AutoEvent("Load", "TransportEvent")
  247. //! runtextmacro AutoEvent("Unload", "TransportEvent")
  248. //Create registration functions for load and unload events.
  249.  
  250. //! textmacro RunTransportEvent takes EVENT
  251.     set n = 0
  252.     loop
  253.         exitwhen n > $EVENT$funcs_n
  254.         call $EVENT$funcs[n].evaluate(transport, passenger)
  255.         set n = n + 1
  256.     endloop
  257. //! endtextmacro
  258. //The above textmacro is used to run the Load/Unload events in the Transport struct below.
  259.  
  260. //===========================================================================
  261. //A transport struct is created and attached to any unit detected loading another unit.
  262. //It keeps track of the units within a transport and updates when they load or unload.
  263.  
  264. private keyword getUnitTransport
  265. private keyword countPassengers
  266. private keyword getPassengerBySlot
  267. private keyword forPassengers
  268.  
  269. struct Transport
  270.     private static unit array loadedin
  271.     private static Transport array transports
  272.     private static integer array loadedindex
  273.     private static group array groups
  274.     private static integer groups_n = -1
  275.     private static real MaxX
  276.     private static real MaxY
  277.    
  278.     private unit array loaded[10] //Transports can only carry 10 units.
  279.     private integer loaded_n = -1
  280.    
  281.     //===========================================================================
  282.    
  283.     static method getUnitTransport takes unit u returns unit
  284.         return loadedin[GetUnitId(u)]
  285.     endmethod
  286.    
  287.     static method countPassengers takes unit transport returns integer
  288.         return transports[GetUnitId(transport)].loaded_n + 1
  289.     endmethod
  290.    
  291.     static method getPassengerBySlot takes unit transport, integer slot returns unit
  292.             if slot < 1 or slot > 10 then
  293.                 return null
  294.             endif
  295.         return transports[GetUnitId(transport)].loaded[slot - 1]
  296.     endmethod
  297.    
  298.     static method forPassengers takes unit transport, TransportEvent func returns nothing
  299.         local Transport this = transports[GetUnitId(transport)]
  300.         local integer n = 0
  301.             if loaded_n == -1 then
  302.                 return //Return if transport has no units loaded inside.
  303.             endif
  304.             loop
  305.                 exitwhen n > loaded_n
  306.                 call func.evaluate(transport, loaded[n])
  307.                 //Loop through each passenger and call the TransportEvent func on it.
  308.                 set n = n + 1
  309.             endloop
  310.     endmethod
  311.    
  312.     //===========================================================================
  313.  
  314.     static method loadUnit takes nothing returns boolean
  315.         local unit transport = GetTransportUnit()
  316.         local unit passenger = GetTriggerUnit()
  317.         local Transport this = transports[GetUnitId(transport)]
  318.         local integer n
  319.             if this == 0 then        //If this is the first unit loaded by this transport...
  320.                 set this = allocate()                       //allocate a Transport struct,
  321.                 set transports[GetUnitId(transport)] = this //and attach it to the transport.
  322.             endif
  323.             set loaded_n = loaded_n + 1      //Increment the passenger counter.
  324.             set loaded[loaded_n] = passenger //Put the passenger in the unit array.
  325.             set loadedindex[GetUnitId(passenger)] = loaded_n //Attach the index to the passenger.
  326.             set loadedin[GetUnitId(passenger)] = transport   //Attach the transport struct to the transport.
  327.             //! runtextmacro RunTransportEvent("Load") //Run the OnUnitLoad events.
  328.             call SetUnitX(passenger, MaxX) //Move the passenger to the edge of the map so that
  329.             call SetUnitY(passenger, MaxY) //unloading will trigger a "unit enters region" event.
  330.         set transport = null
  331.         set passenger = null
  332.         return false
  333.     endmethod
  334.    
  335.     static method unloadUnit takes unit passenger returns nothing
  336.         local unit transport = getUnitTransport(passenger)      //Get the transport unit.
  337.         local Transport this = transports[GetUnitId(transport)] //Get the transport struct.
  338.         local integer n = loadedindex[GetUnitId(passenger)]     //Get the passenger's index.
  339.             loop
  340.                 exitwhen n == loaded_n
  341.                 set loaded[n] = loaded[n + 1]
  342.                 set loadedindex[GetUnitId(loaded[n])] = n
  343.                 set n = n + 1 //Starting from the position of the removed unit,
  344.             endloop           //shift everything down by one and update the index.
  345.             set loaded[n] = null
  346.             set loaded_n = loaded_n - 1                  //Decrement the passenger counter.
  347.             set loadedin[GetUnitId(passenger)] = null    //Null the unloaded unit's transport.
  348.             //! runtextmacro RunTransportEvent("Unload") //Run the OnUnitUnload events.
  349.             if loaded_n == -1 then                       //If the transport is now empty...
  350.                 call destroy()                           //Destroy the transport struct.
  351.                 set transports[GetUnitId(transport)] = 0 //Disassociate it from the unit.
  352.             endif
  353.         set transport = null
  354.     endmethod
  355.    
  356.     //===========================================================================
  357.    
  358.     private static method unitEntersMap takes nothing returns boolean
  359.             if getUnitTransport(GetFilterUnit()) != null then //If the entering unit is in a transport...
  360.                 call unloadUnit(GetFilterUnit())              //The unit was unloaded.
  361.             endif
  362.         return false
  363.     endmethod
  364.    
  365.     private static method unitDies takes nothing returns boolean
  366.             if getUnitTransport(GetTriggerUnit()) != null then //If the dying unit is in a transport...
  367.                 call unloadUnit(GetTriggerUnit())              //Unload the unit from its transport.
  368.             endif
  369.         return false
  370.     endmethod
  371.    
  372.     private static method onInit takes nothing returns nothing
  373.         local region maparea = CreateRegion()
  374.         local rect bounds = GetWorldBounds()
  375.         local trigger unload = CreateTrigger()
  376.         local trigger load = CreateTrigger()
  377.         local trigger death = CreateTrigger()
  378.             call RegionAddRect(maparea, bounds)
  379.             call TriggerRegisterEnterRegion(unload, maparea, function Transport.unitEntersMap) //When a unit enters the map area,
  380.             call TriggerRegisterAnyUnitEventBJ(load, EVENT_PLAYER_UNIT_LOADED)                 //it may have been unloaded.
  381.             call TriggerAddCondition(load, function Transport.loadUnit) //When a unit loads a unit, run the loadUnit method.
  382.             call TriggerRegisterAnyUnitEventBJ(death, EVENT_PLAYER_UNIT_DEATH)
  383.             call TriggerAddCondition(death, function Transport.unitDies) //Detect when a unit dies in order to unload it.
  384.             call OnUnitDeindexed(Transport.unloadUnit) //When a unit leaves the game, unload it from its transport.
  385.             set Transport(0).loaded_n = -1 //Initialize this to -1 to make CountUnitsInTransport work properly.
  386.             set MaxX = GetRectMaxX(bounds) //Record the coordinates of a corner of the map so
  387.             set MaxY = GetRectMaxY(bounds) //that loaded units can be moved to that location.
  388.         call RemoveRect(bounds)
  389.         set bounds = null
  390.     endmethod
  391.    
  392. endstruct
  393.  
  394. //===========================================================================
  395. // User functions:
  396. //=================
  397.  
  398. function IsUnitAnimateDead takes unit u returns boolean
  399.     return AutoIndex.isUnitAnimateDead(u)
  400. endfunction
  401.  
  402. function GetUnitTransport takes unit u returns unit
  403.     return Transport.getUnitTransport(u)
  404. endfunction
  405.  
  406. function CountPassengers takes unit transport returns integer
  407.     return Transport.countPassengers(transport)
  408. endfunction
  409.  
  410. function GetPassengerBySlot takes unit transport, integer slot returns unit
  411.     return Transport.getPassengerBySlot(transport, slot)
  412. endfunction
  413.  
  414. function ForPassengers takes unit transport, TransportEvent func returns nothing
  415.     call Transport.forPassengers(transport, func)
  416. endfunction
  417.  
  418. endlibrary
« Last Edit: December 25, 2017, 09:56:46 PM by moyack »



 

Vivir aprendiendo.co - A place for learning stuff, in Spanish   Chaos Realm - The world of Game modders and wc3 addicts   Diplo, a gaming community   WC3JASS.com - The JASS Vault + vJASS and Zinc   Jetcraft - A Starcraft II mod