14 years
edited 8 years
A library to manage units by indexing them.

Main library:
UnitIndexer UnitIndex:
UnitIndexer UnitIndexer:
UnitIndexer Pregame Event:
For further information related with installation and usage, please refer to the test map attached to this topic.
Main library:
1 library UnitIndexer /* v5.3.0.1
2 ************************************************************************************3 *4 * */ uses /*
5 *6 * */ WorldBounds /*
7 * */ Init /*
8 * */ AllocQ /*
9 * */ ErrorMessage /*
10 * */ StaticUniqueList /*
11 * */ UnitIndexerSettings /*
12 * */ Trigger /*
13 *14 ********************************************************************************15 *16 * struct UnitIndexer extends array17 *18 * Fields19 * -------------------------20 *21 * static boolean enabled22 * - is UnitIndexer onUnitIndex enabled?23 *24 * readonly static Trigger GlobalEvent.ON_INDEX25 * - this is a global event that runs whenever any unit is indexed26 *27 * Examples: UnitIndexer.GlobalEvent.ON_INDEX.reference(yourTrigger)28 * UnitIndexer.GlobalEvent.ON_INDEX.register(yourCode)29 *30 * Examples: unitIndex.indexer.Event.ON_DEINDEX.reference(yourTrigger)31 * unitIndex.indexer.Event.ON_DEINDEX.register(yourCode)32 *33 * readonly Trigger Event.ON_DEINDEX34 * - this is a local event that runs whenever a specific unit is deindexed35 *36 * Examples: unitIndex.indexer.Event.ON_DEINDEX.reference(yourTrigger)37 * unitIndex.indexer.Event.ON_DEINDEX.register(yourCode)38 *39 * readonly static Trigger GlobalEvent.ON_DEINDEX40 * - this is ON_DEINDEX, but global41 *42 * Examples: UnitIndexer.GlobalEvent.ON_DEINDEX.reference(yourTrigger)43 * UnitIndexer.GlobalEvent.ON_DEINDEX.register(yourCode)44 *45 * readonly static UnitIndex eventIndex46 * - when a unit is indexed or deindexed, this value stores47 * the index of that unit48 *49 * readonly static unit eventUnit50 * - when a unit is indexed or deindexed, this value stores51 * the unit52 *53 ************************************************************************************54 *55 * struct UnitIndex extends array56 *57 * Fields58 * -------------------------59 *60 * readonly unit unit61 * - converts a unit index into a unit62 *63 * readonly UnitIndexer indexer64 * - the indexer in charge of handling the unit65 * useful for deindex event, which is unit specific66 *67 * Operators68 * -------------------------69 *70 * static method operator [] takes unit whichUnit returns UnitIndex71 * - converts a unit into a UnitIndex72 *73 * Methods74 * -------------------------75 *76 * static method exists takes unit whichUnit returns boolean77 * - determines whether the unit is indexed or not78 *79 * static method isDeindexing takes unit whichUnit returns boolean80 * - determines whether the unit is in the process of being deindexed or not81 *82 ************************************************************************************83 *84 * module GlobalUnitIndex85 *86 * This has absolutely no module support87 *88 * Fields89 * -------------------------90 *91 * static constant boolean GLOBAL_UNIT_INDEX = true92 * - this is used to ensure that only one unit index module is implemented.93 *94 * readonly unit unit95 * - converts a unit index into a unit96 *97 * readonly boolean isUnitIndexed98 * - is the unit index indexed99 *100 * readonly UnitIndexer unitIndexer101 * - the indexer in charge of handling the unit102 * useful for deindex event, which is unit specific103 *104 * Methods105 * -------------------------106 *107 * static method exists takes unit whichUnit returns boolean108 * - determines whether the unit is indexed109 *110 * static method isDeindexing takes unit whichUnit returns boolean111 * - determines whether the unit is in the process of being deindexed or not112 *113 * Interface114 * -------------------------115 *116 * interface private method onUnitIndex takes nothing returns nothing117 * interface private method onUnitDeindex takes nothing returns nothing118 *119 * Operators120 * -------------------------121 *122 * static method operator [] takes unit whichUnit returns thistype123 * - converts a unit into thistype124 *125 ************************************************************************************126 *127 * module UnitIndex128 *129 * If you would like to create modules that work off of the UnitIndex module, implement130 * UnitIndex at the top of your module131 * 132 * Fields133 * -------------------------134 *135 * static constant boolean UNIT_INDEX = true136 * - this is used to ensure that only one unit index module is implemented.137 *138 * static boolean enabled139 * - is this UnitIndex struct enabled?140 * - this can only be disabed if onUnitIndex exists141 *142 * readonly unit unit143 * - converts a unit index into a unit144 *145 * readonly boolean isUnitIndexed146 * - is the unit index indexed for the struct?147 *148 * readonly UnitIndexer unitIndexer149 * - the indexer in charge of handling the unit150 * useful for deindex event, which is unit specific151 *152 * Operators153 * -------------------------154 *155 * static method operator [] takes unit whichUnit returns thistype156 * - converts a unit into thistype157 *158 * Methods159 * -------------------------160 *161 * static method exists takes unit whichUnit returns boolean162 * - determines whether the unit is indexed or not for the struct163 *164 * static method isDeindexing takes unit whichUnit returns boolean165 * - determines whether the unit is in the process of being deindexed or not166 *167 * Interface168 * -------------------------169 *170 * interface private method onUnitIndex takes nothing returns boolean171 * - if return true, index the unit for this struct172 *173 * interface private method onUnitDeindex takes nothing returns nothing174 * - only runs for units indexed for this struct175 * - if not onUnitIndex method is declared, it will run for all units176 *177 ************************************************************************************178 *179 * module UnitIndexEx180 *181 * If you would like to create modules that work off of the UnitIndexEx module, implement182 * UnitIndexEx at the top of your module183 * 184 * Fields185 * -------------------------186 *187 * static constant boolean UNIT_INDEX_EX = true188 * - this is used for modules that rely on local events189 * it allows these modules to differentiate between UnitIndex190 * and UnitIndexEx191 *192 * static boolean enabled193 * - is this UnitIndex struct enabled?194 * - this can only be disabed if onUnitIndex exists195 *196 * readonly unit unit197 * - converts a unit index into a unit198 *199 * readonly boolean isUnitIndexed200 * - is the unit index indexed for the struct?201 *202 * readonly UnitIndexer unitIndexer203 * - the indexer in charge of handling the unit204 * useful for deindex event, which is unit specific205 *206 * readonly static Trigger ON_INDEX207 * - this is a local event that runs whenever any unit is indexed for the struct208 * - this is primarily used for other resources that work off of your struct209 *210 * Examples: Struct.ON_INDEX.reference(yourTrigger)211 * Struct.ON_INDEX.register(yourCode)212 *213 * readonly Trigger Event.ON_DEINDEX214 * readonly static Trigger Event.ON_DEINDEX215 * - this is a unit specific event that runs when your local unit is deindexed216 * - this is static if onUnitIndex does not exist217 *218 * Examples: struct.ON_DEINDEX.reference(yourTrigger)219 * struct.ON_DEINDEX.register(yourCode)220 *221 * Operators222 * -------------------------223 *224 * static method operator [] takes unit whichUnit returns thistype225 * - converts a unit into thistype226 *227 * Methods228 * -------------------------229 *230 * static method exists takes unit whichUnit returns boolean231 * - determines whether the unit is indexed or not for the struct232 *233 * static method isDeindexing takes unit whichUnit returns boolean234 * - determines whether the unit is in the process of being deindexed or not235 *236 * Interface237 * -------------------------238 *239 * interface private method onUnitIndex takes nothing returns boolean240 * - if return true, index the unit for this struct241 *242 * interface private method onUnitDeindex takes nothing returns nothing243 * - only runs for units indexed for this struct244 * - if not onUnitIndex method is declared, it will run for all units245 *246 ************************************************************************************247 *248 * //! textmacro CREATE_LOCAL_UNIT_INDEX249 *250 * A macro was chosen because multiple modules utilizing this code may be251 * implemented into one struct. If this was a module, then all but one252 * of those modules would break.253 *254 * Interface255 * -------------------------256 *257 * interface private method onLocalUnitIndex takes nothing returns nothing258 * - runs whenever a unit is indexed for this struct259 *260 * interface private method onLocalUnitDeindex takes nothing returns nothing261 * - runs whenever a unit is deindexed for this struct262 *263 * interface private static method localInit takes nothing returns nothing264 * - the macro requires the usage of onInit. Declare this method if you265 * would like onInit.266 *267 ************************************************************************************/268 globals269 private UnitIndex p_eventIndex = 0
270 endglobals271 272 //! runtextmacro UNIT_INDEXER_UNIT_INDEX()273 //! runtextmacro UNIT_INDEXER_PREGAME_EVENT()274 //! runtextmacro UNIT_INDEXER_UNIT_INDEXER()275
276 module GlobalUnitIndex277 static if thistype.UNIT_INDEX then
278 elseif thistype.UNIT_INDEX_EX then
279 else280 static constant boolean GLOBAL_UNIT_INDEX = true
281
282 static method operator [] takes unit whichUnit returns thistype
283 return p_UnitIndex[whichUnit]
284 endmethod285 method operator unit takes nothing returns unit
286 return p_UnitIndex(this).unit
287 endmethod288 method operator unitIndexer takes nothing returns UnitIndexer
289 return p_UnitIndex(this).indexer
290 endmethod291 method operator isUnitIndexed takes nothing returns boolean
292 return p_UnitIndex(this).isAllocated
293 endmethod294 static method exists takes unit whichUnit returns boolean
295 return p_UnitIndex.exists(whichUnit)
296 endmethod297 static method isDeindexing takes unit whichUnit returns boolean
298 return p_UnitIndex.isDeindexing(whichUnit)
299 endmethod300
301 static if thistype.GLOBAL_UNIT_INDEX then
302 static if thistype.onUnitIndex.exists then
303 private static method onIndexEvent takes nothing returns boolean
304 call thistype(UnitIndexer.eventIndex).onUnitIndex()
305
306 return false
307 endmethod308 endif309 static if thistype.onUnitDeindex.exists then
310 private static method onDeindexEvent takes nothing returns boolean
311 call thistype(UnitIndexer.eventIndex).onUnitDeindex()
312
313 return false
314 endmethod315 endif316
317 static if thistype.onUnitIndex.exists then
318 private static method onInit takes nothing returns nothing
319 elseif thistype.onUnitDeindex.exists then
320 private static method onInit takes nothing returns nothing
321 endif322
323 static if thistype.onUnitIndex.exists then
324 call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onIndexEvent))
325 endif326
327 static if thistype.onUnitDeindex.exists then
328 call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onDeindexEvent))
329 endif330
331 static if thistype.onUnitIndex.exists then
332 endmethod333 elseif thistype.onUnitDeindex.exists then
334 endmethod335 endif336 endif337 endif338 endmodule339
340 module UnitIndex341 static if thistype.GLOBAL_UNIT_INDEX then
342 private static method error takes nothing returns nothing
343 A module requires UnitIndex to operate correctly.
344 This struct is currently implementing GlobalUnitIndex.
345 endmethod346 elseif thistype.UNIT_INDEX_EX then
347 else348 static constant boolean UNIT_INDEX = true
349
350 /*351 * [] is included because the struct automatically overrides it352 *353 * eventIndex is included to return thistype instead of UnitIndex354 */355 static method operator [] takes unit whichUnit returns thistype
356 return UnitIndex[whichUnit]
357 endmethod358 method operator unitIndexer takes nothing returns UnitIndexer
359 return this
360 endmethod361 method operator unit takes nothing returns unit
362 return UnitIndex(this).unit
363 endmethod364
365 static method isDeindexing takes unit whichUnit returns boolean
366 return UnitIndex.isDeindexing(whichUnit)
367 endmethod368
369 /*370 * the method is done in the second case because when there is no371 * onUnitIndex method, indexed depends on whether the actual372 * instance is allocated or not373 */374 static if thistype.onUnitIndex.exists then
375 readonly boolean isUnitIndexed
376 else377 method operator isUnitIndexed takes nothing returns boolean
378 return p_UnitIndex(this).isAllocated
379 endmethod380 endif381
382 static if thistype.onUnitIndex.exists then
383 static method exists takes unit whichUnit returns boolean
384 return UnitIndex.exists(whichUnit) and thistype(GetUnitUserData(whichUnit)).isUnitIndexed
385 endmethod386 else387 static method exists takes unit whichUnit returns boolean
388 return UnitIndex.exists(whichUnit)
389 endmethod390 endif391
392 /*393 * this is used to run local events394 */395 static if thistype.onUnitIndex.exists then
396 /*397 * this is where UnitIndex is located398 */399 private static TriggerCondition entryPoint
400
401 /*402 * this stores private onUnitIndex method403 */404 private static boolexpr onIndexExpression
405
406 /*407 * enable works with code inside of entryPoint here408 */409 private static boolean p_enabled = true
410 static method operator enabled takes nothing returns boolean
411 return p_enabled412 endmethod413 static method operator enabled= takes boolean enable returns nothing
414 set p_enabled = enable
415
416 if (enable) then
417 call entryPoint.replace(onIndexExpression)
418 else419 call entryPoint.replace(null)
420 endif421 endmethod422 else423 /*424 * if onUnitIndex does not exist, the struct can't be disabled425 */426 static method operator enabled takes nothing returns boolean
427 return true
428 endmethod429 static method operator enabled= takes boolean enable returns nothing
430 set enable = true
431 endmethod432 endif433
434 /*435 * onUnitDeindex436 *437 * This must be implemented if onUnitIndex exists to clear isUnitIndexed438 */439 static if thistype.onUnitDeindex.exists then
440 static if thistype.onUnitIndex.exists then
441 private static boolexpr onDeindexExpression
442 endif443
444 private static method onDeindexEvent takes nothing returns boolean
445 call thistype(UnitIndexer.eventIndex).onUnitDeindex()
446
447 static if thistype.onUnitIndex.exists then
448 set thistype(UnitIndexer.eventIndex).isUnitIndexed = false
449 endif450
451 return false
452 endmethod453 elseif thistype.onUnitIndex.exists then
454 static if thistype.onUnitIndex.exists then
455 private static boolexpr onDeindexExpression
456 endif457
458 private static method onDeindexEvent takes nothing returns boolean
459 set thistype(UnitIndexer.eventIndex).isUnitIndexed = false
460
461 return false
462 endmethod463 endif464
465 /*466 * onUnitIndex467 */468 static if thistype.onUnitIndex.exists then
469 private static method onIndexEvent takes nothing returns boolean
470 if (thistype(UnitIndexer.eventIndex).onUnitIndex()) then
471 set thistype(UnitIndexer.eventIndex).isUnitIndexed = true
472
473 /*474 * this is always registered to clear isUnitIndexed475 */476 call UnitIndexer(UnitIndexer.eventIndex).Event.ON_DEINDEX.register(onDeindexExpression)
477 endif478
479 return false
480 endmethod481 endif482
483 static if thistype.onUnitIndex.exists then
484 private static method onInit takes nothing returns nothing
485 set onIndexExpression = Condition(function thistype.onIndexEvent)
486 set onDeindexExpression = Condition(function thistype.onDeindexEvent)
487
488 set entryPoint = UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onIndexEvent))
489 endmethod490 elseif thistype.onUnitDeindex.exists then
491 private static method onInit takes nothing returns nothing
492 call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onDeindexEvent))
493 endmethod494 endif495 endif496 endmodule497
498 private struct UnitIndexList extends array
499 //! runtextmacro CREATE_TABLE_FIELD("public", "integer", "unitIndex2Node", "thistype")500 //! runtextmacro CREATE_TABLE_FIELD("public", "integer", "node2UnitIndex", "thistype")501
502 method add takes thistype index returns nothing
503 local thistype node = enqueue()
504
505 set node.node2UnitIndex = index
506 set index.unitIndex2Node = node
507 endmethod508
509 method delete takes nothing returns nothing
510 call unitIndex2Node.remove()
511 endmethod512
513 private static method init takes nothing returns nothing
514 //! runtextmacro INITIALIZE_TABLE_FIELD("unitIndex2Node")515 //! runtextmacro INITIALIZE_TABLE_FIELD("node2UnitIndex")516 endmethod517
518 implement NxListT519 implement Init520 endstruct521 private struct UnitIndexModuleTrigger extends array
522 method reference takes Trigger whichTrigger returns TriggerReference
523 local TriggerReference triggerReference = Trigger(this).reference(whichTrigger)
524
525 local UnitIndexList node = UnitIndexList(this).first
526 local integer prevIndexedUnitId = p_eventIndex
527
528 loop529 exitwhen node == UnitIndexList.sentinel or not whichTrigger.enabled
530
531 set p_eventIndex = node.node2UnitIndex
532 call whichTrigger.fire()
533
534 set node = node.next
535 endloop536
537 set p_eventIndex = prevIndexedUnitId
538
539 return triggerReference540 endmethod541
542 method register takes boolexpr whichExpression returns TriggerCondition
543 local TriggerCondition triggerCondition = Trigger(this).register(whichExpression)
544
545 local trigger triggerContainer = CreateTrigger()
546
547 local UnitIndexList node = UnitIndexList(this).first
548 local integer prevIndexedUnitId = p_eventIndex
549
550 call TriggerAddCondition(triggerContainer, whichExpression)
551
552 loop553 exitwhen node == UnitIndexList.sentinel
554
555 set p_eventIndex = node.node2UnitIndex
556 call TriggerEvaluate(triggerContainer)
557
558 set node = node.next
559 endloop560
561 call TriggerClearConditions(triggerContainer)
562 call DestroyTrigger(triggerContainer)
563 set triggerContainer = null
564
565 set p_eventIndex = prevIndexedUnitId
566
567 return triggerCondition568 endmethod569 endstruct570 module UnitIndexEx571 static if thistype.GLOBAL_UNIT_INDEX then
572 private static method error takes nothing returns nothing
573 A module requires UnitIndexEx to operate correctly.
574 This struct is currently implementing GlobalUnitIndex.
575 endmethod576 elseif thistype.UNIT_INDEX then
577 private static method error takes nothing returns nothing
578 A module requires UnitIndexEx to operate correctly.
579 This struct is currently implementing UnitIndex.
580 endmethod581 else582 static constant boolean UNIT_INDEX_EX = true
583
584 private static UnitIndex delegate unitIndex = 0
585
586 /*587 * [] is included because the struct automatically overrides it588 *589 * eventIndex is included to return thistype instead of UnitIndex590 */591 static method operator [] takes unit whichUnit returns thistype
592 return UnitIndex[whichUnit]
593 endmethod594 method operator unit takes nothing returns unit
595 return UnitIndex(this).unit
596 endmethod597 method operator unitIndexer takes nothing returns UnitIndexer
598 return this
599 endmethod600
601 static method isDeindexing takes unit whichUnit returns boolean
602 return UnitIndex.isDeindexing(whichUnit)
603 endmethod604
605 /*606 * the method is done in the second case because when there is no607 * onUnitIndex method, indexed depends on whether the actual608 * instance is allocated or not609 */610 static if thistype.onUnitIndex.exists then
611 readonly boolean isUnitIndexed
612 else613 method operator isUnitIndexed takes nothing returns boolean
614 return p_UnitIndex(this).isAllocated
615 endmethod616 endif617
618 static if thistype.onUnitIndex.exists then
619 static method exists takes unit whichUnit returns boolean
620 return UnitIndex.exists(whichUnit) and thistype(GetUnitUserData(whichUnit)).isUnitIndexed
621 endmethod622 else623 static method exists takes unit whichUnit returns boolean
624 return UnitIndex.exists(whichUnit)
625 endmethod626 endif627
628 /*629 * this is used to run local events630 */631 static if thistype.onUnitIndex.exists then
632 readonly static UnitIndexModuleTrigger ON_INDEX
633 else634 readonly static WrappedTrigger ON_INDEX
635 endif636
637 static if thistype.onUnitIndex.exists then
638 /*639 * this is where UnitIndex is located640 */641 private static TriggerCondition entryPoint
642
643 /*644 * this stores private onUnitIndex method645 */646 private static boolexpr onIndexExpression
647
648 /*649 * enable works with code inside of entryPoint here650 */651 private static boolean p_enabled = true
652 static method operator enabled takes nothing returns boolean
653 return p_enabled654 endmethod655 static method operator enabled= takes boolean enable returns nothing
656 set p_enabled = enable
657
658 if (enable) then
659 call entryPoint.replace(onIndexExpression)
660 else661 call entryPoint.replace(null)
662 endif663 endmethod664 else665 /*666 * if onUnitIndex does not exist, the struct can't be disabled667 */668 static method operator enabled takes nothing returns boolean
669 return true
670 endmethod671 static method operator enabled= takes boolean enable returns nothing
672 set enable = true
673 endmethod674 endif675
676 /*677 * this is here so that the module runs after code that relies on the module678 */679 static if thistype.onUnitIndex.exists then
680 readonly Trigger ON_DEINDEX681 else682 readonly static Trigger ON_DEINDEX
683 endif684
685 /*686 * onUnitDeindex687 */688 static if thistype.onUnitDeindex.exists then
689 static if thistype.onUnitIndex.exists then
690 private static boolexpr onDeindexExpression
691 endif692
693 private static method onDeindexEvent takes nothing returns boolean
694 call thistype(UnitIndexer.eventIndex).onUnitDeindex()
695
696 static if thistype.onUnitIndex.exists then
697 set thistype(UnitIndexer.eventIndex).isUnitIndexed = false
698
699 call thistype(UnitIndexer.eventIndex).ON_DEINDEX.destroy()
700
701 if (not PreGameEvent.isGameLoaded) then
702 call UnitIndexList(UnitIndexer.eventIndex).delete()
703 endif704 endif705
706 return false
707 endmethod708 elseif thistype.onUnitIndex.exists then
709 private static boolexpr onDeindexExpression
710
711 private static method onDeindexEvent takes nothing returns boolean
712 set thistype(UnitIndexer.eventIndex).isUnitIndexed = false
713
714 call thistype(UnitIndexer.eventIndex).ON_DEINDEX.destroy()
715
716 if (not PreGameEvent.isGameLoaded) then
717 call UnitIndexList(UnitIndexer.eventIndex).delete()
718 endif719
720 return false
721 endmethod722 endif723
724 /*725 * onUnitIndex726 */727 static if thistype.onUnitIndex.exists then
728 private static method onIndexEvent takes nothing returns boolean
729 if (thistype(UnitIndexer.eventIndex).onUnitIndex()) then
730 set thistype(UnitIndexer.eventIndex).isUnitIndexed = true
731
732 set thistype(UnitIndexer.eventIndex).ON_DEINDEX = Trigger.create(true)
733 call thistype(UnitIndexer.eventIndex).ON_DEINDEX.register(onDeindexExpression)
734 735 call UnitIndexer(UnitIndexer.eventIndex).Event.ON_DEINDEX.reference(thistype(UnitIndexer.eventIndex).ON_DEINDEX)
736
737 if (not PreGameEvent.isGameLoaded) then
738 call UnitIndexList(ON_INDEX).add(UnitIndexer.eventIndex)
739 endif740
741 call Trigger(thistype.ON_INDEX).fire()
742 endif743
744 return false
745 endmethod746 endif747
748 private static method destroyPregameUnitList takes nothing returns nothing
749 call DestroyTimer(GetExpiredTimer())
750
751 call UnitIndexList(ON_INDEX).destroy()
752 endmethod753
754 private static method onInit takes nothing returns nothing
755 set ON_INDEX = Trigger.create(false)
756
757 static if thistype.onUnitIndex.exists then
758 set onIndexExpression = Condition(function thistype.onIndexEvent)
759 set onDeindexExpression = Condition(function thistype.onDeindexEvent)
760
761 call UnitIndexList(ON_INDEX).clear()
762
763 call TimerStart(CreateTimer(), 0, false, function thistype.destroyPregameUnitList)
764
765 set entryPoint = UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onIndexEvent))
766 else767 set ON_DEINDEX = Trigger.create(true)
768 static if thistype.onUnitDeindex.exists then
769 call ON_DEINDEX.register(Condition(function thistype.onDeindexEvent))
770 endif771
772 call UnitIndexer.GlobalEvent.ON_DEINDEX.reference(ON_DEINDEX)
773 call UnitIndexer.GlobalEvent.ON_INDEX.reference(ON_INDEX)
774 endif775 endmethod776 endif777 endmodule778
779 //! textmacro CREATE_LOCAL_UNIT_INDEX780 /*781 * There are three cases782 *783 * Case 1: UnitIndex is implemented784 * Case 2: UnitIndexEx is implemented785 * Case 3: Nothing is implemented, go to Case 2786 */787 static if thistype.UNIT_INDEX then
788 /*789 * Here, UnitIndex is implemented790 */791
792 /*793 * There are two cases794 *795 * onUnitEvent exists, which means that events are conditionally local796 * onUnitEven does not exist, meaning all events are global797 */798 static if thistype.onUnitIndex.exists then
799 /*800 * Here, events are conditionally local801 */802
803 static if thistype.onLocalUnitDeindex.exists then
804 private static boolexpr onLocalUnitDeindexEventExpr
805 endif806
807 static if thistype.onLocalUnitIndex.exists then
808 /*809 * The user has a local unit index event810 */811 private static method onLocalUnitIndexEvent takes nothing returns boolean
812 /*813 * Here, the event is only run if the unit happened to be indexed814 */815 if (thistype(UnitIndexer.eventIndex).isUnitIndexed) then
816 static if thistype.onLocalUnitDeindex.exists then
817 call UnitIndexer.eventIndex.indexer.Event.ON_DEINDEX.register(onLocalUnitDeindexEventExpr)
818 endif819
820 call thistype(UnitIndexer.eventIndex).onLocalUnitIndex()
821 endif822
823 return false
824 endmethod825 elseif thistype.onLocalUnitDeindex.exists then
826 /*827 * The user did not declare a local unit index event828 *829 * onLocalUnitIndexEvent is still required because the deindex events are local830 */831 private static method onLocalUnitIndexEvent takes nothing returns boolean
832 if (thistype(UnitIndexer.eventIndex).isUnitIndexed) then
833 call UnitIndexer.eventIndex.indexer.Event.ON_DEINDEX.register(onLocalUnitDeindexEventExpr)
834 endif835
836 return false
837 endmethod838 endif839
840 static if thistype.onLocalUnitDeindex.exists then
841 private static method onLocalUnitDeindexEvent takes nothing returns boolean
842 call thistype(UnitIndexer.eventIndex).onLocalUnitDeindex()
843 return false
844 endmethod845 endif846
847 /*848 * onLocalUnitDeindexEvent is not registered globally here because these are local849 * events. It must be created inside of onLocalUnitIndexEvent whether or not850 * onLocalUnitIndex exists.851 */852 static if thistype.onLocalUnitIndex.exists then
853 private static method onInit takes nothing returns nothing
854 static if thistype.onLocalUnitDeindex.exists then
855 set onLocalUnitDeindexEventExpr = Condition(function thistype.onLocalUnitDeindexEvent)
856 endif857
858 call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
859
860 static if thistype.localInit.exists then
861 call localInit()
862 endif863 endmethod864 elseif thistype.onLocalUnitDeindex.exists then
865 private static method onInit takes nothing returns nothing
866 set onLocalUnitDeindexEventExpr = Condition(function thistype.onLocalUnitDeindexEvent)
867
868 call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
869
870 static if thistype.localInit.exists then
871 call localInit()
872 endif873 endmethod874 endif875 else876 /*877 * Here, all events are global878 */879 static if thistype.onLocalUnitIndex.exists then
880 private static method onLocalUnitIndexEvent takes nothing returns boolean
881 call thistype(UnitIndexer.eventIndex).onLocalUnitIndex()
882 return false
883 endmethod884 endif885
886 static if thistype.onLocalUnitDeindex.exists then
887 private static method onLocalUnitDeindexEvent takes nothing returns boolean
888 call thistype(UnitIndexer.eventIndex).onLocalUnitDeindex()
889 return false
890 endmethod891 endif892
893 static if thistype.onLocalUnitIndex.exists then
894 private static method onInit takes nothing returns nothing
895 static if thistype.onLocalUnitDeindex.exists then
896 call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onLocalUnitDeindexEvent))
897 endif898
899 call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
900
901 static if thistype.localInit.exists then
902 call localInit()
903 endif904 endmethod905 elseif thistype.onLocalUnitDeindex.exists then
906 private static method onInit takes nothing returns nothing
907 call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onLocalUnitDeindexEvent))
908
909 static if thistype.localInit.exists then
910 call localInit()
911 endif912 endmethod913 endif914 endif915 elseif thistype.GLOBAL_UNIT_INDEX then
916 private static method error takes nothing returns nothing
917 A module requires either UnitIndex or UnitIndexEx to operate correctly.
918 This struct is currently implementing GlobalUnitIndex.
919 endmethod920 else921 /*922 * Here, UnitIndexEx is either implemented or nothing is implemented923 *924 * Implement UnitIndexEx and work with its local events925 */926 implement UnitIndexEx927
928 static if thistype.onUnitIndex.exists then
929 /*930 * local events931 */932 static if thistype.onLocalUnitDeindex.exists then
933 private static boolexpr onLocalUnitDeindexEventExpr
934 endif935
936 /*937 * if onUnitIndex exists, then onLocalUnitDeindex is local938 *939 * this means that if onLocalUnitDeindex exists, the onLocalUnitIndexEvent must be940 * made so that it can register onLocalUnitDeindex locally941 */942 static if thistype.onLocalUnitIndex.exists then
943 private static method onLocalUnitIndexEvent takes nothing returns boolean
944 static if thistype.onLocalUnitDeindex.exists then
945 call thistype(UnitIndexer.eventIndex).ON_DEINDEX.register(onLocalUnitDeindexEventExpr)
946 endif947
948 call thistype(UnitIndexer.eventIndex).onLocalUnitIndex()
949
950 return false
951 endmethod952 elseif thistype.onLocalUnitDeindex.exists then
953 private static method onLocalUnitIndexEvent takes nothing returns boolean
954 call thistype(UnitIndexer.eventIndex).ON_DEINDEX.register(onLocalUnitDeindexEventExpr)
955
956 return false
957 endmethod958 endif959 elseif thistype.onLocalUnitIndex.exists then
960 /*961 * global events962 *963 * onLocalUnitDeindex is run globally, so it doesn't need onLocalUnitIndexEvent964 * anymore965 */966 private static method onLocalUnitIndexEvent takes nothing returns boolean
967 call thistype(UnitIndexer.eventIndex).onLocalUnitIndex()
968
969 return false
970 endmethod971 endif972
973 static if thistype.onLocalUnitDeindex.exists then
974 private static method onLocalUnitDeindexEvent takes nothing returns boolean
975 call thistype(UnitIndexer.eventIndex).onLocalUnitDeindex()
976
977 return false
978 endmethod979 endif980
981 /*982 * The reason why ON_INDEX is used is so that the module can be enabled/disabled983 * correctly984 */985 private static method onInit takes nothing returns nothing
986 static if thistype.onUnitIndex.exists then
987 /*988 * local events989 */990 static if thistype.onLocalUnitDeindex.exists then
991 set onLocalUnitDeindexEventExpr = Condition(function thistype.onLocalUnitDeindexEvent)
992 endif993
994 /*995 * onLocalUnitIndexEvent is registered for onLocalUnitdeindex because onLocalUnitDeindex996 * must be registered to each unit. This means that it must register as units are indexed.997 */998 static if thistype.onLocalUnitIndex.exists then
999 call thistype.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
1000 elseif thistype.onLocalUnitDeindex.exists then
1001 call thistype.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
1002 endif1003 else1004 /*1005 * global events1006 *1007 * ON_DEINDEX is used here instead of UnitIndexer.GlobalEvent.ON_DEINDEX for proper1008 * execution order1009 */1010
1011 static if thistype.onLocalUnitDeindex.exists then
1012 call thistype.ON_DEINDEX.register(Condition(function thistype.onLocalUnitDeindexEvent))
1013 endif1014
1015 static if thistype.onLocalUnitIndex.exists then
1016 call thistype.ON_INDEX.register(Condition(function thistype.onLocalUnitIndexEvent))
1017 endif1018 endif1019
1020 static if thistype.localInit.exists then
1021 call localInit()
1022 endif1023 endmethod1024 endif1025 //! endtextmacro1026 endlibrary
UnitIndexer UnitIndex:
1 /*2 * requires3 *4 * Alloc5 * ErrorMessage6 *7 * private struct p_UnitIndex extends array8 *9 * method operator isAllocated takes nothing returns boolean10 * debug static method calculateMemoryUsage takes nothing returns integer11 * debug static method getAllocatedMemoryAsString takes nothing returns string12 *13 * method operator indexer takes nothing returns UnitIndexer14 * method operator unit takes nothing returns unit15 * static method operator [] takes unit whichUnit returns thistype16 * static method exists takes unit whichUnit returns boolean17 *18 * struct UnitIndex extends array19 *20 * readonly unit unit21 * readonly UnitIndexer indexer22 *23 * static method operator [] takes unit whichUnit returns UnitIndex24 *25 * static method exists takes unit whichUnit returns boolean26 * static method isDeindexing takes unit whichUnit returns boolean27 */28 29 //! textmacro UNIT_INDEXER_UNIT_INDEX30 private struct p_UnitIndex extends array
31 implement AllocQ32 33 private unit p_unit
34
35 static method create takes unit whichUnit returns thistype
36 local thistype this = allocate()
37
38 set p_unit = whichUnit
39 call SetUnitUserData(whichUnit, this)
40 41 call UnitAddAbility(whichUnit, ABILITIES_UNIT_INDEXER)
42 call UnitMakeAbilityPermanent(whichUnit, true, ABILITIES_UNIT_INDEXER)
43
44 return this
45 endmethod46
47 method destroy takes nothing returns nothing
48 set p_unit = null
49
50 call deallocate()
51 endmethod52
53 method operator indexer takes nothing returns UnitIndexer
54 debug call ThrowWarning(not isAllocated, "UnitIndexer", "indexer", "thistype", this, "Getting indexer from a deallocated unit index.")
55
56 return this
57 endmethod58
59 method operator unit takes nothing returns unit
60 debug call ThrowWarning(not isAllocated, "UnitIndexer", "unit", "thistype", this, "Getting unit from a deallocated unit index.")
61
62 return p_unit63 endmethod64 static method operator [] takes unit whichUnit returns thistype
65 debug call ThrowWarning(GetUnitTypeId(whichUnit) == 0, "UnitIndexer", "[]", "thistype", 0, "Getting unit index of a null unit.")
66 debug call ThrowWarning(thistype(GetUnitUserData(whichUnit)).p_unit != whichUnit, "UnitIndexer", "[]", "thistype", 0, "Getting unit index of a unit that isn't indexed.")
67
68 return GetUnitUserData(whichUnit)
69 endmethod70
71 static method exists takes unit whichUnit returns boolean
72 debug call ThrowWarning(GetUnitTypeId(whichUnit) == 0, "UnitIndexer", "exists", "thistype", 0, "Checking for the existence of a null unit.")
73
74 return thistype(GetUnitUserData(whichUnit)).p_unit == whichUnit
75 endmethod76
77 static method isDeindexing takes unit whichUnit returns boolean
78 return GetUnitTypeId(whichUnit) != 0 and GetUnitAbilityLevel(whichUnit, ABILITIES_UNIT_INDEXER) == 0 and thistype(GetUnitUserData(whichUnit)).p_unit == whichUnit
79 endmethod80 endstruct81 82 struct UnitIndex extends array
83 method operator unit takes nothing returns unit
84 return p_UnitIndex(this).unit
85 endmethod86
87 static method operator [] takes unit whichUnit returns thistype
88 return p_UnitIndex[whichUnit]
89 endmethod90
91 static method exists takes unit whichUnit returns boolean
92 return p_UnitIndex.exists(whichUnit)
93 endmethod94
95 static method isDeindexing takes unit whichUnit returns boolean
96 return p_UnitIndex.isDeindexing(whichUnit)
97 endmethod98
99 method operator indexer takes nothing returns UnitIndexer
100 return p_UnitIndex(this).indexer
101 endmethod102 endstruct103 //! endtextmacro
UnitIndexer UnitIndexer:
1 /*2 * requires3 *4 * Event5 * WorldBounds6 *7 * struct UnitIndexer extends array8 *9 * static boolean enabled = true10 *11 * readonly static Trigger GlobalEvent.ON_INDEX12 * readonly static Trigger GlobalEvent.ON_DEINDEX13 * readonly Trigger Event.ON_DEINDEX14 *15 * readonly UnitIndex eventIndex = 016 * readonly unit eventUnit = null17 *18 * private struct WrappedTrigger extends array19 *20 * method reference takes Trigger whichTrigger returns nothing21 *22 * method register takes boolexpr whichExpression returns nothing23 *24 */25 26 //! textmacro UNIT_INDEXER_UNIT_INDEXER27 private struct WrappedTrigger extends array
28 static if DEBUG_MODE then
29 method reference takes Trigger whichTrigger returns TriggerReference
30 return reference_p(whichTrigger)
31 endmethod32
33 method register takes boolexpr whichExpression returns TriggerCondition
34 return register_p(whichExpression)
35 endmethod36
37 private method reference_p takes Trigger whichTrigger returns TriggerReference
38 local TriggerReference triggerReference = Trigger(this).reference(whichTrigger)
39
40 call PreGameEvent.fireTrigger(whichTrigger)
41
42 return triggerReference43 endmethod44
45 private method register_p takes boolexpr whichExpression returns TriggerCondition
46 local TriggerCondition triggerCondition = Trigger(this).register(whichExpression)
47
48 call PreGameEvent.fireExpression(whichExpression)
49
50 return triggerCondition51 endmethod52 else53 method reference takes Trigger whichTrigger returns TriggerReference
54 local TriggerReference triggerReference = Trigger(this).reference(whichTrigger)
55
56 call PreGameEvent.fireTrigger(whichTrigger)
57
58 return triggerReference59 endmethod60
61 method register takes boolexpr whichExpression returns TriggerCondition
62 local TriggerCondition triggerCondition = Trigger(this).register(whichExpression)
63
64 call PreGameEvent.fireExpression(whichExpression)
65
66 return triggerCondition67 endmethod68 endif69 endstruct70 71 private struct UnitIndexerTriggerGlobal extends array
72 readonly static WrappedTrigger ON_INDEX
73 readonly static Trigger ON_DEINDEX
74
75 private static method init takes nothing returns nothing
76 set ON_INDEX = Trigger.create(false)
77 set ON_DEINDEX = Trigger.create(true)
78 endmethod79
80 implement Init81 endstruct82 83 private keyword ON_DEINDEX_MAIN
84 private struct UnitIndexerTrigger extends array
85 readonly Trigger ON_DEINDEX86
87 method createDeindex takes nothing returns nothing
88 set ON_DEINDEX = Trigger.create(true)
89
90 call ON_DEINDEX.reference(UnitIndexerTriggerGlobal.ON_DEINDEX)
91 endmethod92
93 method destroyDeindex takes nothing returns nothing
94 call ON_DEINDEX.destroy()
95 endmethod96 endstruct97 98 struct UnitIndexer extends array
99 private trigger deindexTrigger
100 private static boolexpr onDeindexCondition
101 102 static method operator eventIndex takes nothing returns UnitIndex
103 return p_eventIndex104 endmethod105 static method operator eventUnit takes nothing returns unit
106 return eventIndex.unit
107 endmethod108
109 static method operator GlobalEvent takes nothing returns UnitIndexerTriggerGlobal
110 return 0
111 endmethod112 method operator Event takes nothing returns UnitIndexerTrigger
113 return this
114 endmethod115 116 static boolean enabled = true
117
118 private static method fire takes Trigger whichTrigger, integer whichIndex returns nothing
119 local integer prevIndexedUnit = p_eventIndex
120 set p_eventIndex = whichIndex
121 call whichTrigger.fire()
122 set p_eventIndex = prevIndexedUnit
123 endmethod124
125 private static method onIndex takes nothing returns boolean
126 local unit indexedUnit = GetFilterUnit()
127 local p_UnitIndex index128
129 if (enabled and not p_UnitIndex.exists(indexedUnit)) then
130 set index = p_UnitIndex.create(indexedUnit)
131
132 set thistype(index).deindexTrigger = CreateTrigger()
133 call TriggerRegisterUnitEvent(thistype(index).deindexTrigger, indexedUnit, EVENT_UNIT_ISSUED_ORDER)
134 call TriggerAddCondition(thistype(index).deindexTrigger, onDeindexCondition)
135
136 call PreGameEvent.addUnitIndex(index)
137
138 call thistype(index).Event.createDeindex()
139
140 call fire(GlobalEvent.ON_INDEX, index)
141 endif142
143 set indexedUnit = null
144
145 return false
146 endmethod147
148 private static method onDeindex takes nothing returns boolean
149 local p_UnitIndex index = GetUnitUserData(GetTriggerUnit())
150
151 if (GetUnitAbilityLevel(GetTriggerUnit(), ABILITIES_UNIT_INDEXER) == 0) then
152 call PreGameEvent.removeUnitIndex(index)
153
154 call fire(thistype(index).Event.ON_DEINDEX, index)
155
156 call thistype(index).Event.destroyDeindex()
157
158 call DestroyTrigger(thistype(index).deindexTrigger)
159 set thistype(index).deindexTrigger = null
160
161 call index.destroy()
162 endif163
164 return false
165 endmethod166
167 private static method init takes nothing returns nothing
168 local trigger indexTrigger = CreateTrigger()
169
170 local boolexpr onIndexCondition = Condition(function thistype.onIndex)
171
172 local group enumGroup = CreateGroup()
173
174 local integer currentPlayerId = 15
175 local player currentPlayer
176
177 set onDeindexCondition= Condition(function thistype.onDeindex)
178
179 call TriggerRegisterEnterRegion(indexTrigger, WorldBounds.worldRegion, onIndexCondition)
180
181 loop182 set currentPlayer = Player(currentPlayerId)
183
184 call SetPlayerAbilityAvailable(currentPlayer, ABILITIES_UNIT_INDEXER, false)
185 call GroupEnumUnitsOfPlayer(enumGroup, currentPlayer, onIndexCondition)
186
187 exitwhen currentPlayerId == 0
188 set currentPlayerId = currentPlayerId - 1
189 endloop190
191 call DestroyGroup(enumGroup)
192
193 set onIndexCondition = null
194
195 set enumGroup = null
196 set currentPlayer = null
197
198 set indexTrigger = null
199 endmethod200
201 implement Init202 endstruct203 //! endtextmacro
UnitIndexer Pregame Event:
1 /*2 * requires3 *4 * StaticUniqueList5 *6 * private struct PreGameEvent extends array7 *8 * Evaluates all triggers and functions registered to9 * Unit Indexer before game start for all indexed units.10 *11 *12 * static method fireTrigger takes trigger whichTrigger returns nothing13 * static method fireExpression takes boolexpr whichExpression returns nothing14 *15 * static method addUnitIndex takes integer whichUnitIndex returns nothing16 * static method removeUnitIndex takes integer whichUnitIndex returns nothing17 */18 19 //! textmacro UNIT_INDEXER_PREGAME_EVENT20 private struct PreGameEvent extends array
21 readonly static boolean isGameLoaded = false
22 23 implement StaticUniqueList24
25 private static method p_fireTrigger takes Trigger whichTrigger returns nothing
26 local thistype this = first
27 local integer prevIndexedUnitId = p_eventIndex
28
29 loop30 exitwhen this == sentinel or not whichTrigger.enabled
31
32 set p_eventIndex = this
33 call whichTrigger.fire()
34
35 set this = next
36 endloop37
38 set p_eventIndex = prevIndexedUnitId
39 endmethod40 static method fireTrigger takes Trigger whichTrigger returns nothing
41 if (first != 0) then
42 call p_fireTrigger(whichTrigger)
43 endif44 endmethod45
46 private static method p_fireExpression takes boolexpr whichExpression returns nothing
47 local trigger triggerContainer = CreateTrigger()
48 local thistype this = first
49 local integer prevIndexedUnitId = p_eventIndex
50
51 call TriggerAddCondition(triggerContainer, whichExpression)
52
53 loop54 exitwhen this == sentinel
55
56 set p_eventIndex = this
57 call TriggerEvaluate(triggerContainer)
58
59 set this = next
60 endloop61
62 call TriggerClearConditions(triggerContainer)
63 call DestroyTrigger(triggerContainer)
64 set triggerContainer = null
65
66 set p_eventIndex = prevIndexedUnitId
67 endmethod68 static method fireExpression takes boolexpr whichExpression returns nothing
69 if (first != 0) then
70 call p_fireExpression(whichExpression)
71 endif72 endmethod73
74 static method addUnitIndex takes integer whichUnitIndex returns nothing
75 if (isGameLoaded) then
76 return77 endif78
79 call enqueue(whichUnitIndex)
80 endmethod81
82 static method removeUnitIndex takes integer whichUnitIndex returns nothing
83 if (isGameLoaded) then
84 return85 endif86
87 call thistype(whichUnitIndex).remove()
88 endmethod89
90 private static method run takes nothing returns nothing
91 call DestroyTimer(GetExpiredTimer())
92
93 set isGameLoaded = true
94
95 call clear()
96 endmethod97 private static method init takes nothing returns nothing
98 call TimerStart(CreateTimer(), 0, false, function thistype.run)
99 endmethod100
101 implement Init102 endstruct103 //! endtextmacro
For further information related with installation and usage, please refer to the test map attached to this topic.