Spell Footman Cannon

Gwypaas

hook DoNothing MakeGUIUsersCrash
Reaction score
50
Footmen Cannon

Footman Cannon

Jass: Yes.
MUI: Yes.
Laggless: Yes.
Leakless: Yes, I think so.
Requires: NewGen Editor, TT Credits to Cohadar, HSAS Credits to Pandamine

Description:
The Footman lord summons a random amount of Footmans around him and fires them at a target with some kind of mystical psychic power.

Lvl 1: Deals 10 damage per unit and summons 3-4 Footmans.
Lvl 2: Deals 20 damage per unit and summons 6-8 Footmans.
Lvl 3: Deals 30 damage per unit and summons 9-12 Footmans.

Code:
JASS:
// ==================================================================================================================================================================
//
//  Footman cannon created by: Gwypaas
//
// ==================================================================================================================================================================

// ==================================================================================================================================================================
//              How to import:
//
//  1. Create a spell named what you want this spell to be named and add the ID to the constants further down.
//  2. Create the dummy units for this spell and add the ID at the constants further down
//  3. Import the librarys TT made by Cohadar and HSAS made by Pandamine to your map
//  4. Change the rest of the values at the spell constants further down so the spell acts the way you want it to do.
//  
//  Not: if you really want to you can change the HSAS calls to ABC calls or another library that uses handle attaching.
//
// ==================================================================================================================================================================
 

scope UnitCannon   // Uses HSAS and TT
globals
    // The ID of the main ability.
    private constant integer ABILID = 'A000'  
    // The ID of the dummy unit used in this spell.
    private constant integer DUMMYID = 'h000'
    // The ID of the eye candy dummy used when summoning
    private constant integer EYECANDYDUMMY = 'h001'
    // How fast they travels.
    private constant real SPEED = 40
    // How long time it takes to summon all units.
    private constant real TOTALTIMESUMMONING = 1.25
    // The radius of the circle the units are summoned in.
    private constant real CIRCLERADIUS = 400
    // The radius of the circle it damages in.
    private constant real DAMAGERADIUS = 200
    // The ID of the ability called Crow Form, used in this spell to cause the units flying.
    private constant integer CROWFORMID = 'Amrf'
    // The max height the units are able to be on.
    private constant real MAXHEIGHT = 2 // This value is used like this: Total Distance / This.
    // The damage is calculated by this formula lvl*YourValue so change YourValue here to the value you want.
    private constant real DAMAGE = 10
    // The unit amount is calculated like this: A random integer between lvl*MINAMOUNT and lvl*MAXAMOUNT
    private constant integer MINAMOUNT = 3
    private constant integer MAXAMOUNT = 4
endglobals

// ===========   DO NOT EDIT ANYTHING AFTER THIS LINE!   ===========
// ===========   DO NOT EDIT ANYTHING AFTER THIS LINE!   ===========
// ===========   DO NOT EDIT ANYTHING AFTER THIS LINE!   ===========

private function H2I takes handle h returns integer 
    return h
    return 0
endfunction

//! runtextmacro HSAS_Static("Cannon")
//! runtextmacro HSAS_Static("Fire")


private struct Data
    unit caster
    unit array dummies[11]
    integer dummyAmount
    integer currentdummies = 0
    integer unitsFired = 0
    integer level
    real targetX
    real targetY

endstruct

private struct SlideData
    unit damager // The hero that casts the spell
    unit whichUnit
    real totalDist
    real distDone = 0
    real startX
    real startY
    real targetX
    real targetY
    real cX
    real cY
    real angle
    real speed
    real maxHeight
endstruct

private function RandomPointCircle takes real x, real y, real d returns location // Credits to Vexorian!
    local real cx = GetRandomReal(-d,d)
    local real ty = SquareRoot(d*d-cx*cx)
    return Location(x+cx, y+ GetRandomReal(-ty,ty) )
endfunction

private function ParabolicMovement takes real h, real d, real x returns real // h Height, d total distance, x dist to add.
    // thanks to moyack for this function!
    return (-4*h/(3*d*d))*x*x + (4*h/(3*d))*x
endfunction

private function DamageAmount takes integer lvl returns real
    return lvl*DAMAGE
endfunction

private function UnitAmount takes integer lvl returns integer
    return GetRandomInt(lvl*MINAMOUNT, lvl*MAXAMOUNT)
endfunction
private function DamageFilter takes unit caster, unit target returns boolean
    return (IsUnitEnemy(target, GetOwningPlayer(caster))) and (IsUnitType(target, UNIT_TYPE_GROUND)) and (GetUnitState(target, UNIT_STATE_LIFE) > 0.405)
endfunction 

private function SlideCallback takes nothing returns boolean
    local SlideData SD = TT_GetData()
    local group g = CreateGroup()
    local unit u 
    local real z = ParabolicMovement(SD.maxHeight, SD.totalDist, SD.distDone)
    if SD.distDone >= SD.totalDist then
        call GroupEnumUnitsInRange(g, GetUnitX(SD.whichUnit), GetUnitY(SD.whichUnit), DAMAGERADIUS, null)
        loop
            set u = FirstOfGroup(g)
            exitwhen u == null
            if DamageFilter(SD.damager, u) == true then
                call UnitDamageTarget(SD.damager, u, DamageAmount(GetUnitAbilityLevel(SD.damager, ABILID)) , FALSE, FALSE, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNIVERSAL, null)
            endif
            call GroupRemoveUnit(g, u)
            set u = null
        endloop
        set SD.damager = null
        call SetUnitExploded(SD.whichUnit, true)
        call KillUnit(SD.whichUnit)
        set SD.whichUnit = null
        call SD.destroy()
        return true
    else
        set SD.cX = SD.cX + SD.speed * Cos(SD.angle)
        set SD.cY = SD.cY + SD.speed * Sin(SD.angle)
        call SetUnitX(SD.whichUnit, SD.cX)
        call SetUnitY(SD.whichUnit, SD.cY)
        call SetUnitFlyHeight(SD.whichUnit, z, 0)
        set SD.distDone = SD.distDone + SD.speed
    endif
    set u = null
    call DestroyGroup(g)
    set g = null
    return false
endfunction

private function Slide takes unit whichUnit, real startX, real startY, real targetX, real targetY, real speed, unit damager returns nothing
    local SlideData SD = SlideData.create()
    set SD.damager = damager
    set SD.startX = startX
    set SD.startY = startY
    set SD.targetX = targetX
    set SD.targetY = targetY
    set SD.cX = startX
    set SD.cY = startY
    set SD.whichUnit = whichUnit
    set SD.angle = Atan2((SD.targetY-SD.startY),(SD.targetX-SD.startX))
    set SD.speed = speed
    set SD.totalDist = SquareRoot(Pow((SD.targetX-SD.startX), 2) + Pow((SD.targetY-SD.startY), 2))
    set SD.maxHeight = SD.totalDist/MAXHEIGHT
    call TT_Start(function SlideCallback, SD)

endfunction


private function FireUnitsCallback takes nothing returns nothing
    local timer t2 = GetExpiredTimer()
    local Data data = GetAttachedStructFire(t2)
    local integer i = 0

    if data.unitsFired >= data.dummyAmount then
        call PauseTimer(t2)
        call DestroyTimer(t2)
        set data.caster = null
        loop
            exitwhen i == 11
            set data.dummies<i> = null
            set i = i+1
        endloop
        call data.destroy()
    else
        call Slide(data.dummies[data.unitsFired], GetUnitX(data.dummies[data.unitsFired]), GetUnitY(data.dummies[data.unitsFired]), data.targetX, data.targetY, SPEED, data.caster)
        set data.unitsFired = data.unitsFired + 1
    endif
    set t2 = null
endfunction
private function CreateUnitAndRemoveAfter takes integer ID, real X, real Y, real time, boolean kill, player whichPlayer returns nothing
    local unit u = CreateUnit(whichPlayer, ID, X, Y, GetRandomReal(0, 360))
    
    if kill == true then
        call TriggerSleepAction(time)
        call KillUnit(u)
    else
        call TriggerSleepAction(time)
        call RemoveUnit(u)
    endif
    set u = null
endfunction
private function CreateUnitCallback takes nothing returns nothing 
    local timer t = GetExpiredTimer()
    local Data data = GetAttachedStructCannon(t)
    local integer i = 0
    local real casterX = GetUnitX(data.caster)
    local real casterY = GetUnitY(data.caster)
    local location l = Location(0,0)
    if data.currentdummies == data.dummyAmount then

        call PauseTimer(t)
        call DestroyTimer(t)
    else
        set l = RandomPointCircle(casterX, casterY, CIRCLERADIUS)
        set data.dummies[data.currentdummies] = CreateUnit(GetOwningPlayer(data.caster), DUMMYID, GetLocationX(l), GetLocationY(l), GetRandomReal(0, 360))
        call UnitApplyTimedLife( data.dummies[data.currentdummies], &#039;BTLF&#039;, TOTALTIMESUMMONING*5 )
        call UnitAddAbility(data.dummies[data.currentdummies], CROWFORMID)
        call UnitRemoveAbility(data.dummies[data.currentdummies], CROWFORMID)
        call CreateUnitAndRemoveAfter.execute(EYECANDYDUMMY, GetLocationX(l), GetLocationY(l), TOTALTIMESUMMONING*2, false, GetOwningPlayer(data.caster))
        set data.currentdummies = data.currentdummies+1
    endif
    set t = null
    call RemoveLocation(l)
    set l = null
endfunction

private function Actions takes nothing returns nothing
    local Data data = Data.create()
    local integer i = 0
    local real waitBetween

    local timer t = CreateTimer()
    local timer t2 = CreateTimer()
    local location targ = GetSpellTargetLoc()


    set data.caster = GetSpellAbilityUnit()
    set data.dummyAmount = UnitAmount(GetUnitAbilityLevel(data.caster, ABILID))
    set waitBetween = TOTALTIMESUMMONING/data.dummyAmount
    set data.level = GetUnitAbilityLevel(data.caster, ABILID)
    set data.targetX = GetLocationX(targ)
    set data.targetY = GetLocationY(targ)
    call AttachStructCannon(t, data)
    
    call TimerStart(t, waitBetween, true, function CreateUnitCallback)
    call TriggerSleepAction(TOTALTIMESUMMONING+TOTALTIMESUMMONING/3)
    
    call AttachStructFire(t2, data)
    call TimerStart(t2, waitBetween, true, function FireUnitsCallback)
    

    set t = null
    set t2 = null
    call RemoveLocation(targ)
    set targ  = null
endfunction

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == ABILID
endfunction

//===========================================================================
public function InitTrig takes nothing returns nothing
    local trigger Trig = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( Trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition(Trig, Condition(function Conditions))
    call TriggerAddAction( Trig, function Actions )
    set Trig = null
endfunction
endscope</i>


Screenshot: (It looks better ingame! :))
attachment.php
Changelog:
Added a special effect when summoning, speeded up a bit.
 

Attachments

  • FootmanCannonNew.jpg
    FootmanCannonNew.jpg
    195.6 KB · Views: 2,241
  • UnitCannon.w3x
    38.9 KB · Views: 461

GoGo-Boy

You can change this now in User CP
Reaction score
40
Hmm, like the idea but the result isn't that great in my opinion. I think it looks so unrealistic (even for wc3 ;) ) and boring. Since this is somewhat a telekinesis spell how about let the units flow in a certain high? And please add special effects whenever the footies are created. And you perhaps should increase the speed of at least the footmen creating.
I really like the idea, but think you should improve it in the stated points to make it more attractive^^

Edit: Ahh... now I knew your name. You're from mutedvision :s

Edit2: At least the speed issue is customizable for sure... globals ftw :D
 

Gwypaas

hook DoNothing MakeGUIUsersCrash
Reaction score
50
I was thinking about doing something like he raises them from the ground to different heights but I scrapped that idea because I didn't really know how move their height down, so I added a parabola so it would look better :p.

But i'll add some spawning effect!
Yes I am from Mutedvision, who are you there? I can't find your name. :p

Edit: Updated now with a effect when the units summons, also speeded up a bit.
 

PurgeandFire

zxcvmkgdfg
Reaction score
509
Oh noes! =O
TriggerSleepActionSuxorz said:
"Look mommy, I spy a TriggerSleepAction!" said Little Timmy.
"Stay away from those, dear. And we call it TSA... Your grounded for even calling it by its real name," said the mother.
"Aw... Sh*t!" said Little Timmy.

Other than that little TriggerSleepAction, it seems fine. :D

Great job Gwypaas, +rep.

Nice coding.
 

Gwypaas

hook DoNothing MakeGUIUsersCrash
Reaction score
50
Yeah I know about the TriggerSleepAction's but they are there to make the spell look better, there's 3 parts in the spell and the SleepActions separates them :p. I could always make a timer but that would just make the code less readable so I think it will stay this way, but if someone really thinks that the SleepActions must be removed I could do it :p
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • 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 The Helper:
    New recipe is another summer dessert Berry and Peach Cheesecake - https://www.thehelper.net/threads/recipe-berry-and-peach-cheesecake.194169/

      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