• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[vJASS] LimitedSummon

A vjass System simples down limiting the amount of living summons at the same time by the same summoner down to a function call.
LimitedSummon does only operate when beeing called.

JASS:
library LimitedSummon
//Version 1.1
//LimitedSummon allows to limit the amount of units summoned by a summoner.
//The summons are splited into limitGroups, limits only affect 1 limitGroup.
//LimitSummon does not use any events, the data is updated everytime you call a function of LimitSummon.

//=======
//API
   //function LimitedSummon takes unit summoner, unit summon, integer limitGroup, integer limit returns boolean
       //summoner the summoning unit.
       //summon the unit summoned.
       //limitGroup (a number); summons with the same limitGroup (Nr) are sharing the same limit.
       //limit the amount of living summons allowed at the same time.
       //will kill when the amount of living summons of that group from that summoner exceeds the limit.
       //call with summon = null to do only a desummon based on limit.
       //returns true if units were desummoned with that call.
       //   >The desummoned Units are inside the unitGroup LimitedSummon__desummoned
   
   //function LimitedSummonEx takes integer limitGroup, integer limit returns boolean
       //Wrapper to be used inside a Unit Summon Event. Using GetSummoningUnit() and GetSummonedUnit() for the units.
   
   //function LimitedSummonGetOldest takes unit summoner, integer limitGroup returns unit
       //Returns the oldest living unit beeing summoned by summoner using limitGroup
//=======
globals
   private integer countReuse = 0
   private integer countData = 0
   private integer array reuse
   private unit array dataSummon
   private unit array dataSummoner
   private integer array dataGroup
   private integer array noteNext
   private integer array notePrev
 
   public string desummonArt = "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl" //Displayed below Units beeing Desummoned cause of Limit Exceeded.
   public boolean displayDesummonArt = true
   public group desummoned = CreateGroup() //Contains units beeing desummoned

endglobals

private function Remove takes integer index returns nothing
   set noteNext[notePrev[index]] = noteNext[index]
   set notePrev[noteNext[index]] = notePrev[index]
 
   //clean refs
   set dataSummon[index] = null
   set dataSummoner[index] = null

   //make index reuseable
   set reuse[countReuse] = index
   set countReuse = countReuse + 1
endfunction

function LimitedSummonGetOldest takes unit summoner, integer limitGroup returns unit
   local integer indexLoop = 0
 
   //loop all summons to count summons, finding the oldest of that limitGroup. And Purge the list.
   loop
       set indexLoop = noteNext[indexLoop]
       exitwhen indexLoop == 0
       if not IsUnitType(dataSummon[indexLoop], UNIT_TYPE_DEAD) and GetUnitTypeId(dataSummon[indexLoop]) != 0 then
           if dataGroup[indexLoop] == limitGroup and dataSummoner[indexLoop] == summoner then
               return dataSummon[indexLoop]
           endif
       else //This summon is dead or removed!
           call Remove(indexLoop)
           set indexLoop = notePrev[indexLoop]
       endif
   endloop
 
   return null
endfunction

function LimitedSummon takes unit summoner, unit summon, integer limitGroup, integer limit returns boolean
   local integer indexEnter
   local integer countOld = 0
   local integer indexLoop = 0
   local boolean desummonedSomthing = false
   call GroupClear(desummoned)

   if summon != null then
       if countReuse != 0 then
           set countReuse = countReuse - 1
           set indexEnter = reuse[countReuse]
       else
           set countData = countData + 1
           set indexEnter = countData
       endif
   
       set noteNext[indexEnter] = 0
       set noteNext[notePrev[0]] = indexEnter
       set notePrev[indexEnter] = notePrev[0]
       set notePrev[0] = indexEnter
   
       set dataSummon[indexEnter] = summon
       set dataSummoner[indexEnter] = summoner
       set dataGroup[indexEnter] = limitGroup
   endif

   //loop all summons to count summons, finding the oldest of that limitGroup. And Purge the list.
   loop
       set indexLoop = notePrev[indexLoop]
       exitwhen indexLoop == 0
       if not IsUnitType(dataSummon[indexLoop], UNIT_TYPE_DEAD) and GetUnitTypeId(dataSummon[indexLoop]) != 0 then
           if dataGroup[indexLoop] == limitGroup and dataSummoner[indexLoop] == summoner then
               set countOld = countOld + 1
               if countOld > limit then //limit was excedd?
                   set desummonedSomthing = true
                   if displayDesummonArt then
                       call DestroyEffect(AddSpecialEffect(desummonArt, GetUnitX(dataSummon[indexLoop]), GetUnitY(dataSummon[indexLoop])))
                   endif
                   call GroupAddUnit(desummoned, dataSummon[indexLoop])
                   call KillUnit(dataSummon[indexLoop])
               
                   call Remove(indexLoop)
                   set indexLoop = noteNext[indexLoop]
               endif
           endif
       else //This summon is dead or removed!
           call Remove(indexLoop)
           set indexLoop = noteNext[indexLoop]
       endif
   endloop
   return desummonedSomthing
endfunction

function LimitedSummonEx takes integer limitGroup, integer limit returns boolean
   return LimitedSummon(GetSummoningUnit(), GetSummonedUnit(), limitGroup, limit)
endfunction

endlibrary

changes:
V1.1
LimtedSummon handles summon = null, better.
Kills now all old summons exceeding the limit.
Reversed the iteration order inside LimitedSummon.
Removed the active boolean.
There is now "public group desummoned", after calling LimitedSummon it includes desummoned units.
LimitedSummon returns true, if someone was desummoned by that call.​
Added an boolean to toogle display desummonArt.
desummonArt is now public.​
Changed global variable names to match jass conventions.​
 
Last edited:
Level 15
Joined
Mar 25, 2016
Messages
1,327
You should name variables like this: variableName
You can read all conventions here: JPAG - JASS Proper Application Guide

Is desummonModelPath supposed to be configurable by the user? In general people shouldn't have to find where this variable is used and enable the function call DestroyEffect(AddSpecialEffect(...

You could use a constant boolean USE_SPECIAL_EFFECT to enable it. You can even use it in combination with a static if, if you don't want additional overhead.

Can you explain how the variable Active works? It seems to be active while the function LimitedSummon runs, but I don't see how it is affected by the desummoning of a unit.

The limit can be redefined in every function call, but if you reduce the limit from 5 to 2 and have just summoned the 4th summon, only the oldest one will be removed resulting in 3 summons, even though the new limit is 2.
 
Active tells Limited Summons is running, that allows to detect a desummon caused by limited Summon inside a death event with LimitedSummon__Active beeing true.

The limit can be redefined in every function call, but if you reduce the limit from 5 to 2 and have just summoned the 4th summon, only the oldest one will be removed resulting in 3 summons, even though the new limit is 2.
My Intention was that one can only desummon 1 with every call. But if you think that is a bad way, then I will change that.

wait i should filter "summon = null" better i think.

Edit:

@Jampion

Updated First posts jass content and added ChangeInfos.
 
Last edited:
Level 15
Joined
Mar 25, 2016
Messages
1,327
The system works as intended even in extreme test scenarios. There was no noticeable lag when 50+ units were desummoned at the same time.

Approved.
 
Top