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,236
  • UnitCannon.w3x
    38.9 KB · Views: 454

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.
  • The Helper The Helper:
    Actually I was just playing with having some kind of mention of the food forum and recipes on the main page to test and see if it would engage some of those people to post something. It is just weird to get so much traffic and no engagement
  • The Helper The Helper:
    So what it really is me trying to implement some kind of better site navigation not change the whole theme of the site
  • Varine Varine:
    How can you tell the difference between real traffic and indexing or AI generation bots?
  • The Helper The Helper:
    The bots will show up as users online in the forum software but they do not show up in my stats tracking. I am sure there are bots in the stats but the way alot of the bots treat the site do not show up on the stats
  • Varine Varine:
    I want to build a filtration system for my 3d printer, and that shit is so much more complicated than I thought it would be
  • Varine Varine:
    Apparently ABS emits styrene particulates which can be like .2 micrometers, which idk if the VOC detectors I have can even catch that
  • Varine Varine:
    Anyway I need to get some of those sensors and two air pressure sensors installed before an after the filters, which I need to figure out how to calculate the necessary pressure for and I have yet to find anything that tells me how to actually do that, just the cfm ratings
  • Varine Varine:
    And then I have to set up an arduino board to read those sensors, which I also don't know very much about but I have a whole bunch of crash course things for that
  • Varine Varine:
    These sensors are also a lot more than I thought they would be. Like 5 to 10 each, idk why but I assumed they would be like 2 dollars
  • Varine Varine:
    Another issue I'm learning is that a lot of the air quality sensors don't work at very high ambient temperatures. I'm planning on heating this enclosure to like 60C or so, and that's the upper limit of their functionality
  • Varine Varine:
    Although I don't know if I need to actually actively heat it or just let the plate and hotend bring the ambient temp to whatever it will, but even then I need to figure out an exfiltration for hot air. I think I kind of know what to do but it's still fucking confusing
  • The Helper The Helper:
    Maybe you could find some of that information from AC tech - like how they detect freon and such
  • Varine Varine:
    That's mostly what I've been looking at
  • Varine Varine:
    I don't think I'm dealing with quite the same pressures though, at the very least its a significantly smaller system. For the time being I'm just going to put together a quick scrubby box though and hope it works good enough to not make my house toxic
  • Varine Varine:
    I mean I don't use this enough to pose any significant danger I don't think, but I would still rather not be throwing styrene all over the air
  • The Helper The Helper:
    New dessert added to recipes Southern Pecan Praline Cake https://www.thehelper.net/threads/recipe-southern-pecan-praline-cake.193555/
  • The Helper The Helper:
    Another bot invasion 493 members online most of them bots that do not show up on stats
  • Varine Varine:
    I'm looking at a solid 378 guests, but 3 members. Of which two are me and VSNES. The third is unlisted, which makes me think its a ghost.
    +1
  • The Helper The Helper:
    Some members choose invisibility mode
    +1
  • The Helper The Helper:
    I bitch about Xenforo sometimes but it really is full featured you just have to really know what you are doing to get the most out of it.
  • The Helper The Helper:
    It is just not easy to fix styles and customize but it definitely can be done
  • The Helper The Helper:
    I do know this - xenforo dropped the ball by not keeping the vbulletin reputation comments as a feature. The loss of the Reputation comments data when we switched to Xenforo really was the death knell for the site when it came to all the users that left. I know I missed it so much and I got way less interested in the site when that feature was gone and I run the site.
  • Blackveiled Blackveiled:
    People love rep, lol
    +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