• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Spell - Attribute Scaling Summoning Spell

Status
Not open for further replies.
Level 4
Joined
Sep 25, 2018
Messages
81
I have been trying to create a spell which has a max number of summons based on your primary attribute.

I have based it on Summon Water Elemental. So the stats of the summon are based on the level of the spell (e.g. level 1 summon has 500 health, 40 damage. level 2 summon has 600 health, 50 damage.).

So basically, if you have 25 intelligence, you can only have one summon spawned at a time. If you have 50 intelligence, you can have 2 and so on.

Just wondering how I would trigger this.

Obviously if you go over the amount of summons you can have, the first one will die to make room for the new one.

(I was also hoping to make the duration of the summons scale as well. That would be ideal)
 
Level 24
Joined
Feb 9, 2009
Messages
1,787
Triggered summons
Unit - Set Expiration - ((Hero - Attribute Int) x 10)
Unit - Set Classification - (Summoned)
Unit - Set Max HP ((Hero - Attribute Int) x 20)
Unit - Set Attack Damage ((Hero - Attribute Int) x 4)
Etc

As for limited number you need a variable that follows the specific unit, I would use Bribe's indexing that uses the custom unit value or hastables.

I'll take a whack at making it but no promises.

ETA: I wasn't able to limit the summons unfortunately, otherwise it fits the rest of your description.
 

Attachments

  • Stat Based Summon.w3x
    75.7 KB · Views: 72
Last edited:
Level 39
Joined
Feb 27, 2007
Messages
5,011
If only a few units on the map need to be able to cast this spell then you can keep track of them all with their own variables (or an array: see the Dynamic Indexing tutorial). Pretty easy to do as Devalut described above.
 
Level 24
Joined
Feb 9, 2009
Messages
1,787
Yes absolutely simple, I was just testing you...
@Pyrogasm you should do an example case anyone doesn't fully understand.
giphy-gif.317479
 
Maybe this ones might help to archive the wanted summon limit.

Option: Time Stamps
For each summon the time elapsed since starting the game is saved. On summon get all the summoners summons, count them and if the limit was exceed remove the one with the lowest time stamp.

Option: Linked List
One saves all summons and their summoner in a linked list, by using a linked list the units are ordered they way they were added. On summon loop the list find summons of that unit and remember oldest, kill the oldest if the limit is exceed.
 
Level 39
Joined
Feb 27, 2007
Messages
5,011
Linked list and dynamically allocated 2-D arrays were actually much harder to work with in GUI than I thought/remembered. Via PM to Devalut I wrote out this possible solution using a hashtable and timestamps as Tasyen suggested.

  • Events
    • Time - Elapsed game time is 0.00 seconds
  • Conditions
  • Actions
    • -------- set up hashtable --------
    • -------- start a repeating countdown timer with max duration that you'll never stop --------
  • Events
    • Unit - A unit spawns a summoned unit
  • Conditions
    • -------- can filter by unit type of summon here --------
  • Actions
    • Set CasterKey = Key(Summoning Unit)
    • Set SummonKey = Key(Summoned Unit)
    • Set SummonTime = (Elapsed time for TIMER)
    • If (conditions) then (actions) else (actions)
      • If - Conditions
        • (Load boolean (CasterKey, 0) from HASH) equal to false //boolean for was it previously cast? no GUI way to check if the group is null
      • Then - Actions
        • Custom script: set udg_SummonGroup = CreateGroup() //note that these groups have to be initialized when a caster casts for the first time
          • Hashtable - Save SummonGroup as (CasterKey, 1) in HASH
          • Hashtable - Save true as (CasterKey, 0) in HASH
      • Else - Actions
        • Set SummonGroup = Load unit group handle (CasterKey, 1) from HASH
    • If (conditions) then (actions) else (actions)
      • If - Conditions
        • (Number of units in SummonGroup) greater than or equal to LIMIT //set the limit however you want
      • Then - Actions
        • -------- search for oldest and remove it --------
        • Set MaxDuration = 0.00
        • Unit Group - Pick every unit in SummonGroup and do (Actions)
          • Loop - Actions
            • Set TempReal = SummonTime - Load real handle (Key(Picked Unit), 1) in HASH
            • If (conditions) then (actions) else (actions)
              • If - Conditions
                • TempReal Greater than MaxDuration
              • Then - Actions
                • Set MaxDuration = TempReal
                • Set TempUnit = (Picked Unit)
              • Else - Actions
        • Unit - Kill TempUnit //this runs cleanup in the third trigger so we don't have to do it here
      • Else - Actions
    • Unit Group - Add (Summoned Unit) to SummonGroup
    • Hashtable - Save CasterKey as (SummonKey, 0) in HASH //so we can figure out who the caster was that spawned a summoned unit that dies
    • Hashtable - Save SummonTime as (SummonKey, 1) in HASH
  • Events
    • Unit - A unit dies //god forbid if this doesn't run on summoned unit dispel or life expiration
  • Conditions
    • -------- don't actually need anything here --------
  • Actions
    • If (conditions) then (actions) else (actions)
      • If - Conditions
        • -------- check for summoned unit types here --------
      • Then - Actions
        • Set SummonKey = Key(Triggering Unit)
        • Set CasterKey = Load integer (SummonKey, 0) from HASH
        • Unit Group - Remove (Triggering Unit) from (Load group (CasterKey, 1)
        • Hashtable - Flush all children of SummonKey in HASH //data cleanup
      • Else - Actions
    • If (conditions) then (actions) else (actions)
      • If - Conditions
        • (Level of SPELL for (Triggering Unit)) greater than 0
      • Then - Actions
        • Set CasterKey = Key(Triggering Unit)
        • -------- what you do here is up to you, the group needs to be removed and the hashtable needs to have its caster stuff flushed --------
          • -------- you have to decide what to do with the extant summons: do they get killed? do they live out their lifetime? if the caster can be revived while some of them are still alive, what then? --------
            • -------- I'd say just kill them all, but in any case something like the following needs to be done at the right time if the same unit is not ever expected to create more summons --------
          • Set SummonGroup = Load group handle (CasterKey, 1) in HASH
          • Custom script: call DestroyGroup(udg_SummonGroup)
          • Hashtable - Flush all children of CasterKey in HASH
 
Level 39
Joined
Feb 27, 2007
Messages
5,011
(I was also hoping to make the duration of the summons scale as well. That would be ideal)
Just noticed this part. I wrote my example above presuming that you specifically wanted to spawn the summons with a summoning ability. With this in mind, however, it makes way more sense run a spellcast trigger (instead of a summoned unit trigger) and create the summons manually with that trigger. Then you can apply whatever duration timed life you want, just remember to also give the units the 'summoned' classification after you make them else they can't be dispelled.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,537
I was bored and this seemed like a fun challenge. I like Pyrogasm's method, but I figured why not so here's my take on it. Let me know how I can improve it if anyone sees anything.

I store the Water Elementals using a Unit Indexer/Hashtable and then store them in the order in which they were summoned (I assume similar to like a Linked List as Taysen said). There's most likely a better way to do this but this way made the most sense to me :p

Edit: Fixed some issues with Intelligence loss/gain breaking the Summon Limit.

  • Summon Water Ele MUI
    • Events
      • Unit - A unit Spawns a summoned unit
    • Conditions
      • Or - Any (Conditions) are true
        • Conditions
          • (Unit-type of (Summoned unit)) Equal to SummonType[1]
          • (Unit-type of (Summoned unit)) Equal to SummonType[2]
          • (Unit-type of (Summoned unit)) Equal to SummonType[3]
    • Actions
      • -------- Variables --------
      • -------- - --------
      • Set Spawn = (Summoned unit)
      • Set Caster = (Summoning unit)
      • Set CastingPlayer = (Owner of (Summoning unit))
      • Set Index = (Custom value of Caster)
      • -------- Set Ability Modifiers --------
      • -------- - --------
      • Set AbilityLevel = (Level of (Ability being cast) for Caster)
      • Set HeroInt = ((Intelligence of Caster (Include bonuses)) / 25)
      • Set Summon_Limit[Index] = (1 x (1 + HeroInt))
      • Unit - Add a ((Real(45)) + ((Real(15)) x (Real(HeroInt)))) second Water Elemental expiration timer to Spawn
      • -------- Set the summon order of the Water Elemental (Summon_Open represents which # the next Ele will be) --------
      • -------- - --------
      • Set Summon_Open[Index] = ((Number of units in Summon_UG[Index]) + 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Summon_Open[Index] Greater than Summon_Limit[Index]
        • Then - Actions
          • Set Summon_Open[Index] = Summon_Limit[Index]
        • Else - Actions
      • -------- Kill extra Water Elementals if your Summon Limit has changed (Lost Intelligence for example) --------
      • -------- - --------
      • Set SummonCount = (Number of units in Summon_UG[Index])
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • SummonCount Greater than Summon_Limit[Index]
        • Then - Actions
          • Set TempInt = ((SummonCount + 1) - Summon_Limit[Index])
          • For each (Integer A) from 1 to TempInt, do (Actions)
            • Loop - Actions
              • Unit Group - Add (Load (Integer A) of Index in SummonHash) to SummonExcess
          • Unit Group - Pick every unit in SummonExcess and do (Actions)
            • Loop - Actions
              • Unit - Kill (Picked unit)
        • Else - Actions
      • -------- Replace Oldest Elemental (If new one is over the limit) --------
      • -------- - --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • SummonCount Equal to Summon_Limit[Index]
        • Then - Actions
          • Unit - Kill (Load 1 of Index in SummonHash)
        • Else - Actions
      • -------- Add the new Elemental to the UG and store it and the caster to the Hashtable --------
      • -------- - --------
      • Unit Group - Add Spawn to Summon_UG[Index]
      • Hashtable - Save Handle OfSpawn as Summon_Open[Index] of Index in SummonHash
      • Set SummonIndex = (Custom value of Spawn)
      • Hashtable - Save Handle OfCaster as Summon_Open[SummonIndex] of SummonIndex in SummonHash
  • Water Ele Death MUI
    • Events
      • Unit - A unit Dies
    • Conditions
      • Or - Any (Conditions) are true
        • Conditions
          • (Unit-type of (Triggering unit)) Equal to SummonType[1]
          • (Unit-type of (Triggering unit)) Equal to SummonType[2]
          • (Unit-type of (Triggering unit)) Equal to SummonType[3]
    • Actions
      • -------- - --------
      • -------- We get the Index (Custom Value) of the dying Summon and use that to find the Caster associated with it --------
      • -------- - --------
      • Set SummonIndex = (Custom value of (Triggering unit))
      • Set Index = (Custom value of (Load Summon_Open[SummonIndex] of SummonIndex in SummonHash))
      • Unit Group - Remove (Triggering unit) from Summon_UG[Index]
      • -------- - --------
      • -------- This first Loop is just to find which Water Ele died (1, 2, 3, etc...) --------
      • -------- - --------
      • For each (Integer A) from 1 to Summon_Limit[Index], do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Load (Integer A) of Index in SummonHash) Equal to (Triggering unit)
            • Then - Actions
              • Set SummonFind = (Integer A)
            • Else - Actions
      • -------- - --------
      • -------- All of the Water Elementals are stored in order as 1, 2, 3, 4, 5, etc... And this loop organizes -> --------
      • -------- the Water Elementals so that if #2 died for example, then 3 becomes 2, 4 becomes 3, 5 becomes 4, etc.... --------
      • -------- This is why we Kill Water Elemental #1 in our other trigger, because it's always going to be the Oldest one --------
      • -------- - --------
      • For each (Integer A) from SummonFind to Summon_Limit[Index], do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Load (Integer A) of Index in SummonHash) Not equal to No unit
              • ((Load (Integer A) of Index in SummonHash) is alive) Equal to True
              • (Integer A) Greater than SummonFind
            • Then - Actions
              • Hashtable - Save Handle Of(Load (Integer A) of Index in SummonHash) as ((Integer A) - 1) of Index in SummonHash
              • Set Summon_Open[Index] = (Integer A)
            • Else - Actions
  • Setup
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • Set SummonType[1] = Water Elemental (Level 1)
      • Set SummonType[2] = Water Elemental (Level 2)
      • Set SummonType[3] = Water Elemental (Level 3)
      • Hashtable - Create a hashtable
      • Set SummonHash = (Last created hashtable)
 

Attachments

  • Summon.w3x
    26.6 KB · Views: 50
Last edited:
Status
Not open for further replies.
Top