• 🏆 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!

[Spell] Rolling Stone Spell

Status
Not open for further replies.
Level 20
Joined
Jul 10, 2009
Messages
479
Hey guys!

I am working on a tower defense and want to implement a tower that attacks with a "projectile line".
He shall "shoot" a gigantous rolling stone that damages all units that he passes.
You can probably compare it with a very slow (and straight-line moving) shockwave.

Which possibilities are out there to do that? Is there an easy way?

Thanks in Advance!
Eikonium
 
Level 20
Joined
Jul 10, 2009
Messages
479
That's quite good already!
I need two more things in there:
  • The stone should actually roll! How can I get the stone to roll? This feature can be seen in many minigame maps (Rolling Stone Evasion) and in Warlock (Meteor 2nd modus).
  • I urgently need the attack to respect damage and armor types. That means, I want the attack (which is obviously based on the carrion swarm ability) to be a special damage type (Pierce for example). How can I do that?
 
Level 1
Joined
Jun 13, 2008
Messages
132
Thats great! Thank you very much!
One last thing: It is possible to change the missile speed of the boulders? It looks weird when such big ones roll so fast ;)

Of course you can, just search for the ability, missile speed field, it has 600 ms right now, change it to your desided speed. Also I forgot to add expiration time to the dummy units, so they get removed, use this map: View attachment Tutorial 15 (Boulder tower).w3x
 
Level 1
Joined
Jun 13, 2008
Messages
132
You are the owner of the dummy unit, so the one who kills is the one who deals the triggered damage. You could add the ability to the tower, but the boulder will be smaller, the boulder size depends on the unit's size. A more complex triggering will be needed in order to make the tower get the credit for the kill.
 
Level 10
Joined
Jun 6, 2007
Messages
392
I made this spell long ago, I think you might find it useful. Simply create a dummy unit based on an ancient protector missile model. The benefits are that the correct unit gets the credit and you can easily change the dummy size, speed etc.. As a drawback (?), it is in vJASS, and unit may be damaged more than once (that could be changed with a simple fix). So here's the code:
JASS:
scope RockSlide initializer init

//#####################
//### CONFIGURABLES ###
//#####################
globals
    //speed is MOVEMENT_PER_ITERATION / TIMEOUT, = 500 with example values 20 and 0.04
    private constant real MOVEMENT_PER_ITERATION = 20
    private constant real TIMEOUT = 0.04
    private constant integer ABIL_CODE = 'A027'
    private constant real DISTANCE = 800
    private constant integer DUMMY_ID = 'h00K'
    //area, which is damaged around the boulder
    private constant real AREA = 100
endglobals

private function CalculateDamage takes unit caster returns real
    return 5.0 * (30 * GetUnitAbilityLevel(caster, ABIL_CODE) + GetHeroStr(caster,true))
endfunction

private function DamageConditions takes unit caster, unit matching returns boolean
    return  IsPlayerEnemy(GetOwningPlayer(matching), GetOwningPlayer(caster)) /*
*/  and not IsUnitType(matching, UNIT_TYPE_STRUCTURE)
endfunction

//#########################
//### CONFIGURABLES END ###
//#########################

private struct Data
    unit caster
    unit dummy
    real damage
    real x
    real y
    real xd
    real yd
    integer executions
endstruct

globals
    private Data array DataList
    private integer Count = 0
    private timer T = CreateTimer()
endglobals

private function True takes nothing returns boolean
    return true
endfunction

private function Loop takes nothing returns nothing
    local Data dat
    local integer i = 0
    local location p
    local group g
    local unit u
    loop
        exitwhen i >= Count
        set dat = DataList[i]
        set dat.x = dat.x + dat.xd
        set dat.y = dat.y + dat.yd
        call SetUnitX(dat.dummy, dat.x)
        call SetUnitY(dat.dummy, dat.y)
        
        call BJDebugMsg("Count = " + I2S(Count) + ", heroloc = (" + R2S(GetUnitX(dat.caster)) + ", " + R2S(GetUnitY(dat.caster)) + /*
        */  "), dummyloc = (" + R2S(dat.x) + ", " + R2S(dat.y) + ")")
                
        set p = Location(dat.x, dat.y)
        set g = GetUnitsInRangeOfLocMatching(AREA, p, Filter(function True))
        loop
            set u = FirstOfGroup(g)
            exitwhen u == null
            if DamageConditions(dat.caster, u) then
                call UnitDamageTarget(dat.caster, u, dat.damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
            endif  
            call GroupRemoveUnit(g, u)
        endloop
        call RemoveLocation(p)
        call DestroyGroup(g)
        
        set dat.executions = dat.executions - 1
        if dat.executions == 0 then
            call KillUnit(dat.dummy)
            call dat.destroy()
            set Count = Count - 1
            set DataList[i] = DataList[Count]
        endif
        if Count == 0 then
            call PauseTimer(T)
        endif
        set i = i + 1
    endloop
    
    set u = null
    set p = null
    set g = null
endfunction

private function Actions takes nothing returns nothing
    local location loc = GetSpellTargetLoc()
    local real xTarget= GetLocationX(loc)
    local real yTarget = GetLocationY(loc)
    local real a
    local Data dat = Data.create()
    set DataList[Count] = dat
    set dat.caster = GetTriggerUnit()
    set dat.executions = R2I(DISTANCE / MOVEMENT_PER_ITERATION)
    set dat.x = GetUnitX(dat.caster)
    set dat.y = GetUnitY(dat.caster)
    set a = Atan2((yTarget-dat.y), (xTarget-dat.x))
    set dat.xd = MOVEMENT_PER_ITERATION*Cos(a)
    set dat.yd = MOVEMENT_PER_ITERATION*Sin(a)
    set dat.damage = CalculateDamage(dat.caster)
    set dat.dummy = CreateUnit(GetOwningPlayer(dat.caster), DUMMY_ID, dat.x, dat.y, Rad2Deg(a))
    set Count = Count + 1
    if Count == 1 then
        call TimerStart(T, TIMEOUT, true, function Loop)
    endif

    call RemoveLocation(loc)
    set loc = null
endfunction

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

private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function Conditions))
    call TriggerAddAction(t, function Actions)
endfunction

endscope

EDIT: If you find this useful and are unfamiliar with vJASS and want some modifications to it (e.g. cast on attack instead of spell or damage each unit only once), just ask me.
 
Level 20
Joined
Jul 10, 2009
Messages
479
Works perfectly!
  • It is true that both - the mana of the tower and the condition in the trigger "Boulder Tower 1" that the mana of the attacking unit has to be 10 - are not needed?
  • There is one weird line in the "Display Damage" trigger that seems to be incomplete:
    • Display Damage
      • Events
        • Spiel - GDD_Event becomes Equal to 0.00
      • Conditions
      • Actions
        • For each (Integer A) from 1 to 6, do (Actions)
          • Loop - Actions
            • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • 'IF'-Conditions
                • ((This trigger) is on) Equal to True
                • GDD_Damage Bigger Than 0.00
                • WEIRD: -> (Item-type of (Item carried by GDD_DamageSource in slot (Integer A))) Equal to
              • 'THEN'-Actions
                • Set GDD_TempInteger = (Random integer number between 0 and 100)
                • etc...
 
Last edited:
Level 1
Joined
Jun 13, 2008
Messages
132
Works perfectly!
  • It is true that both - the mana of the tower and the condition in the trigger "Boulder Tower 1" that the mana of the attacking unit has to be 10 - are not needed?
  • There is one weird line in the "Display Damage" trigger that seems to be incomplete:
    • Display Damage
      • Events
        • Spiel - GDD_Event becomes Equal to 0.00
      • Conditions
      • Actions
        • For each (Integer A) from 1 to 6, do (Actions)
          • Loop - Actions
            • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • 'IF'-Conditions
                • ((This trigger) is on) Equal to True
                • GDD_Damage Bigger Than 0.00
                • WEIRD: -> (Item-type of (Item carried by GDD_DamageSource in slot (Integer A))) Equal to
              • 'THEN'-Actions
                • Set GDD_TempInteger = (Random integer number between 0 and 100)
                • etc...

Yes sorry, I copied the code I use in another map, that part isn't useful for you.
 
Status
Not open for further replies.
Top