Spell Rain Of Footmen

gref

New Member
Reaction score
33
Rain Of Footmen

MUI: Yes.
Leakless: Yes.
Lagless: Yes.
JESP: Yes.
Jass/GUI: Jass

Screenshot:
RainOfFootmenScreen.jpg


Description:
Channeled: Footmen fall from the sky and explode, dealing damage.
Inspired by: http://www.thehelper.net/forums/showthread.php?t=80226

Made in Jass
JASS:

//===============================>
// Rain of Footmen by gref.
//===============================>

scope RainOfFootmen
    // Follows JESP
    
    //===========================>
    //Constants
    //===========================>
   globals
       private constant integer AbilCode = 'A000' //Name of triggering ability
       private constant integer UnitCode = 'h000' //Name of unit used for footman
       private constant real maxheight = 1200.0 //maximum height
       private constant real minheight = 1000.0 //minimum height
       private constant real range = 400.0 //range from center. ie 400 = 800 aoe.
       private constant real damagerange = 130.0 //range a unit has to be in to be hit by a footman's damage
       private constant real damagefactor = 50.0 //damage per level
       private constant real damagebase = 50.0 //constant damage
       private constant real footmenpersecond = 10 //number of footmen per second.
    endglobals          
    
 
    //===========================>
    //Data Types
    //===========================>
 
    struct FootmenStruct
        real x
        real y
        integer level
        unit caster 
                  
        static method create takes unit caster, real x, real y, integer level returns FootmenStruct
            local FootmenStruct f = FootmenStruct.allocate()
            
            set f.level = level 
            set f.x = x
            set f.y = y
            set f.caster = caster
             
            return f 
        endmethod    
    endstruct
    
    struct TimerStruct
        timer t
        method onDestroy takes nothing returns nothing
            local FootmenStruct f = GetAttachedInt(.t, "FootmenStruct")
            call FootmenStruct.destroy(f)
            call CleanAttachedVars(.t)
            call PauseTimer(.t)
            call DestroyTimer(.t)
        endmethod    
        static method create takes nothing returns TimerStruct
            local TimerStruct ts = TimerStruct.allocate()
            
            set ts.t = CreateTimer()
            
            return ts
        endmethod
    endstruct      
 
    //===========================>
    // Functions
    //===========================>                
    
    
    private function DamageFilter takes nothing returns boolean
        return (GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0) and not(IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE))
    endfunction
     
    private function TimerTick takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local FootmenStruct f = GetAttachedInt(t, "FootmenStruct")
        
        local real angle = GetRandomReal(0, 6.28318)
        local real distance = GetRandomReal(0, range)
        local real x = f.x + distance*Cos(angle)
        local real y = f.y + distance*Sin(angle)
                                                   
        local real tangle = GetRandomReal(0, 6.28318)
        local real tdistance = GetRandomReal(0, 200)
        
        local real tx = x + tdistance*Cos(tangle)
        local real ty = y + tdistance*Sin(tangle)
        
        local unit d = CreateUnit(GetOwningPlayer(f.caster), UnitCode, x, y, GetRandomReal(0, 360))
        local real height = GetRandomReal(minheight, maxheight)
        local real timedlife = height/(1500)
        
        call AttachInt(d, "FootmanLevel", f.level)
        call UnitApplyTimedLife(d, 'BTLF', timedlife) 
        call IssuePointOrder(d, "move", tx, ty)
        call UnitAddAbility(d, 'Arav')
        call UnitRemoveAbility(d, 'Arav')
        call SetUnitFlyHeight(d, height, 0) 
        call SetUnitFlyHeight(d, 0, (height/timedlife))
        
        set d = null
        set t = null
    endfunction

    private function RainOfFootmen_Actions takes nothing returns nothing 
         local TimerStruct ts 
         local FootmenStruct f 
         local unit u
         local group g
         local integer level
         local real x 
         local real y
         local player owner
         
         if(GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_EFFECT) then //Footman cast
             if(GetSpellAbilityId() == AbilCode) then
                 set ts = TimerStruct.create()
                 set f = FootmenStruct.create(GetTriggerUnit(), GetLocationX(GetSpellTargetLoc()), GetLocationY(GetSpellTargetLoc()), GetUnitAbilityLevel(GetTriggerUnit(), AbilCode))
         
                 call AttachInt(GetTriggerUnit(), "TimerStruct", ts)
                 call AttachInt(ts.t, "FootmenStruct", f)
                 call TimerStart(ts.t, 1/footmenpersecond, true, function TimerTick)
             endif
         elseif(GetTriggerEventId() == EVENT_PLAYER_UNIT_DEATH) then  //Footman dies  
             if (GetUnitTypeId(GetTriggerUnit()) == UnitCode) then
                 set g = CreateGroup()
                 set level = GetAttachedInt(GetTriggerUnit(), "FootmanLevel")
                 set x = GetUnitX(GetTriggerUnit())
                 set y = GetUnitY(GetTriggerUnit())       
                 set owner = GetOwningPlayer(GetTriggerUnit())                       
        
                 call CleanAttachedVars(GetTriggerUnit())
        
                 call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Human\\HumanLargeDeathExplode\\HumanLargeDeathExplode.mdl", x, y))
               
                 call GroupEnumUnitsInRange(g, x, y, damagerange, Condition(function DamageFilter))
                 loop
                     set u = FirstOfGroup(g)
                     exitwhen u == null
            
                     if(IsUnitEnemy(u, owner) == true) then            
                         call UnitDamageTarget(GetTriggerUnit(), u, damagebase+damagefactor*level, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
                         endif
            
                         call GroupRemoveUnit(g, u)
                endloop  
        
                call DestroyGroup(g)
            endif
             
         else  //stopped cast.       
             if(GetSpellAbilityId() == AbilCode) then
                 set ts = GetAttachedInt(GetTriggerUnit(), "TimerStruct")
        
                 call TimerStruct.destroy(ts)
                 call CleanAttachedVars(GetTriggerUnit()) 
             endif               
         endif
         
         
         set u = null
         set owner = null
         set g = null
    endfunction
    
    
//===========================================================================
    function InitTrig_RainOfFootmen takes nothing returns nothing
        local trigger t = CreateTrigger(  )     
        call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_DEATH )           
        call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_ENDCAST )
        call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddAction( t, function RainOfFootmen_Actions )      
         
        call Preload("Objects\\Spawnmodels\\Human\\HumanLargeDeathExplode\\HumanLargeDeathExplode.mdl")
       
        set t = null
    endfunction
endscope

How to Implement:
Spell Requirements:
1. A vJass preprocessor (If you don't have one you can download one from wc3campaigns.net)

How to implement this in your map:
1. Copy the CSCache and RainOfFootmen triggers to your map. (If you have CSCache, don't worry about it)
2. Copy the unit called Footman in the object editor.
3. Copy the ability called Rain Of Footmen in the object editor.
4. Make sure that the constants in the RainOfFootmen trigger match the ability and unit.
 

Attachments

  • RainOfFootmen.w3x
    155.5 KB · Views: 237

ReVolver

Mega Super Ultra Cool Member
Reaction score
609
This has to be the funniest spell I have ever seen, maybe better than sheepfall :p
 

Tom Jones

N/A
Reaction score
437
You should pause your timer before destroying it, destroying a running timer can horrible cripple a map. You could also clean the code a little if you used one trigger and then checked for the triggering event id. Other than that it's fine, keep it up.
 

gref

New Member
Reaction score
33
I won't lie, I kind of just made this for joke value. But I will go over and fix those things.

And I'm assuming you mean, add all events to one trigger, and just have a massive nested if then else, for the trigger event id part.
 
Reaction score
456
You don't have to null struct's members. So that method onDestroy can be removed.
 

gref

New Member
Reaction score
33
All comments taken into account, updated.

Footmen fall faster now because I felt they fell to slow.
It's actually attached as well. (I have 50 kilobytes left. :( )

Yes the footmen walk, I order them to move to get a more varied and interesting distribution. (And I've always found footmen moving makes jump animations look better too) It will look less strange now that the fall speed has been increased though.

@ nulling struct members: that would be alot easier for me to be comfortable about if I saw what happened to code afterwards --.

Also any more spells I release, I plan to release in spell packs. I hadn't realised I'd be this prolific.
 

Tinki3

Special Member
Reaction score
418
> I have 50 kilobytes left

Ask TH if you can have more space, I'm sure he'd be more than happy to give you some, since you're contributing helpful maps for other members to download and learn from.

Nice spell, though, I'll have to test this later :)

EDIT:

Tested the spell, so funny.
Though, to reduce lag, you should "remove" the units when they hit the ground.
There's not much point in leaving 100 Footmen there to rot, decay, and add to lag.

In the function "RainOfFootmen_Actions", this line leaks:
Code:
set f = FootmenStruct.create(GetTriggerUnit(), GetLocationX([COLOR="Red"]GetSpellTargetLoc()[/COLOR]), GetLocationY([COLOR="Red"]GetSpellTargetLoc()[/COLOR]), GetUnitAbilityLevel(GetTriggerUnit(), AbilCode))

And, I noticed, also, that you did this:
JASS:
call AttachInt(d, "FootmanLevel", f.level)

Is that attachment cleaned?
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Ghan Ghan:
    Howdy
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though
  • Ghan Ghan:
    Heard Houston got hit pretty bad by storms last night. Hope all is well with TH.
  • The Helper The Helper:
    Power back on finally - all is good here no damage
    +2
  • V-SNES V-SNES:
    Happy Friday!
    +1

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top