Arthur, I think this works for a 5e Sleep spell. Queries for spell level and rolls dice. Sorts tokens in ascending hp order and ignores undead, creatures immune to charm, and tokens with either no bar1 hp value (to ignore non-creatures) or less than 1hp (already unconscious). Then, "sleepy" condition markers are added to tokens under the remaining hp from the spell until it runs out of juice. It's really late so I didn't bother to deduct spell slots with a ChatSetAttr script call, but you could add this easily. Since it calculates distance from a token, I would use a "targeting" token (perhaps with an aura) to place the spell, and have your macro set up as a token action on that token. I would also probably use Spawn (not shown in this example - again it's late) to further speed up the process so you don't have to drag the targeting "character" token from the journal. !script {{
--#title|5e Sleep Spell
--:(0) QUERY SPELL LEVEL AND ROLL DICE|
--=SpellSlot|?{What Level Spell Slot?|1,1|2,2|3,3|4,4|5,5|6,6|7,7|8,8|9,9}
--#leftsub|Spell Level:[$SpellSlot]
--=NumDice|[$SpellSlot.Raw]-1*2 + 5
--&RollText|[$NumDice.Raw]d8
--#rightsub|HP Roll:[&RollText]
--=hpRemaining|[&RollText]
--+roll|[$hpRemaining]
--:(1) GET ALL TOKENS INTO THE "allTokens" ARRAY| will have blank 1st element to be removed later
--~|array;pagetokens;allTokens;@{selected|token_id}
--:(2) CREATE THE "inRange" ARRAY TO HOLD TOKENS IN RANGE|
--~|array;define;inRange;
--:(3) PREP ARRAY FOR LOOP| if no array elements then end macro
--~tokenid|array;getfirst;allTokens
--?[&tokenid] -eq ArrayError|endOutput
--:(4) FIND ALL TOKENS IN RANGE| add indexed roll variables for tokID, name, & hp
--=numToks|0
--=i|0
--:RangeLoop|
--:TOKEN MUST BE ON OBJECTS OR GMLAYER AND NOT UNDEAD OR IMMUNE TO CHARM|
--?[*[&tokenid]:t-layer] -ne objects -and [*[&tokenid]:t-layer] -ne gmlayer|NextToken
--?"X[*[&tokenid]:npc_condition_immunities]" -inc "charm" -or "X[*[&tokenid]:npc_type]" -inc "undead"|NextToken
--?"X[*[&tokenid]:t-bar1_value]" -eq "X"|NextToken
--?[*[&tokenid]:t-bar1_value] -lt 1|NextToken
--:CHECK DISTANCE IN UNITS. 20ft is 4UNITS|
--~dist|distance;@{selected|token_id};[&tokenid]
--?[$dist] -gt 4|NextToken
--:ADD TO THE "ARRAYS" OF VARIABLES|
--&tokID[$i.Raw]|[&tokenid]
--=hp[$i.Raw]|[*[&tokenid]:t-bar1_value]
--=numToks|[$numToks] + 1
--=i|[$i] + 1
--:NextToken|
--~tokenid|array;getnext;allTokens
--?[&tokenid] -ne ArrayError|RangeLoop
--:(5) SORT ALL "ARRAY" VARIABLES BY HP VALUE WITH A BUBBLE SORT|
--=max_i|[$i]-1
--=i|-1
--:OuterLoop|
--=i|[$i]+1
--=j|[$i]
--:InnerLoop|
--=j|[$j]+1
--?[$hp[$i.Raw]] -gt [$hp[$j.Raw]] |>BubbleUp;[$i.Raw];[$j.Raw]
--?[$j.Raw] -lt [$max_i.Raw]|InnerLoop
--?[$i.Raw] -lt [$max_i.Raw]|OuterLoop
--:(6) APPLY SLEEP DAMAGE TO SORTED TOKENS|
--=i|0
--:SortLoop|
--=ThisHP|[$hp[$i.Raw]]
--?[$ThisHP.Raw] -le [$hpRemaining.Raw]|>GoToSleep;[&tokID[$i.Raw]];sleepy;[$ThisHP.Raw]
--=i|[$i]+1
--?[$i.Raw] -lt [$numToks.Raw]|SortLoop
--:End|
--X|
--:PROCEDURES|
--:BubbleUp| accepts i, j as parameters. Swaps var[i] & var[j] for three variables
--=Temp|[$hp[%2%]]
--=hp[%2%]|[$hp[%1%]]
--=hp[%1%]|[$Temp]
--&Temp|[&tokID[%2%]]
--&tokID[%2%]|[&tokID[%1%]]
--&tokID[%1%]|[&Temp]
--<|
--:GoToSleep| accepts tokenID, condition marker, and hp to subtract as parameters
--@token-mod|_ignore-selected _ids [%1%] _set statusmarkers|[%2%]
--=hpRemaining|[$hpRemaining]-[%3%]
--<|
}} Click for example. Note the Skeleton and Flesh Golem are ignored due to immunities. The "sleepy" condition marker is applied to affected creatures.