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

Spells & Systems Mini-Contest #19

Status
Not open for further replies.
Level 10
Joined
Jun 1, 2008
Messages
485
ok, I think I'll join this one.... Have been ages since the last Spell Contest I joined....

Some Ideas comes to my mind:

Fireworks 3000
Hero drop a fireworks in the ground that release beautiful fireworks which attracts nearby unit to come close. After a while, the Fireworks explode and damage all nearby unit.

Honey Shower
Hero shower an area with honey. Honey only reduce enemy unit's movement that come to the area for a bit and summon some bees to attack unit that covered with it. The Bees only deal minor damage (1-5 dmg). Sometimes, the honey also attracts a bear which dealt devastating damage.

Critter'splode (Can't think a better name ==a)
Summon an invulnerable and controllable slow movement critter. After some times, critter will explode and deal damage to minor range. Classic...

Fart
The hero fart, releasing cloud on the area. Fart's cloud will damage unit(enemy and friendly) inside it over time. Hero will unaffected by fart, but will lost hp for use it.

Throw Stick
Hero throw stick to enemy, dealing really small damage. But sometimes, hero will throw a summoning stick, which summon a random high level monster to attack the target once, dealing high damage.

well, These are all easy to do...i think I'll do either Honey Shower or Fireworks 3000.

EDIT:
btw, [thread=118480]S&SMC#18[/thread] already done before (well, only the winner is given though). So... I think this one should be S&SMC#19.

EDIT 2:
Nice work Weep. Simple spell, though. Maybe u should add timed life to these critter summoned by this, because sometimes, it can kill a map reason by having too many critter wandering... and maybe make the flower effect disappear when the spell effect end maybe? It'll give the impression that the flower is really that spell's effect and not just random doodad appeared if u know what i mean...
 
Last edited:
Level 17
Joined
Jun 17, 2010
Messages
2,275
Heres part of my entry, i will turn the rest in later.

Flaming Hot Burrito
flamingburrito.jpg
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
You don't have to post the spell idea, you can just post the map any time between now and the end of the month.

@InfinateAnswers, that's awesome!

@MageGoo, Honey Shower is my choice of that group. I can imagine a random bear popping out every once in a while would be great lulz!

@Magtheridon96, "A spell in which the caster says a lame joke and suddenly all units in range are asleep :p" - I like that one!
 
Last edited:
Level 8
Joined
Aug 2, 2008
Messages
193
Soo, here is my spell:


attachment.php





attachment.php

attachment.php




JASS:
 /*=====================================================================*\
//======                      SUICIDE SQUAD                        =====*\\
\\======                       Version 1.0                         ======//
 \\======                        by Kricz                         ======//
 ||                                                                     ||
 ||                                                                     ||
 ||                              Requires:                              ||
 \\                          Table [Vexorian]                          //  
  \\                       ListModule [grim001]                       //
   \\              xebasic, xedamage & xefx [Vexorian]               //
    \\                       ARGB [Vexorian]                        //
    ||                  SoundUtils [Rising_Dusk]                   ||
    ||                  GroupUtils [Rising_Dusk]                   ||
    ||                       Z-Utils [Kricz]                       ||
   //                                                              \\
  //                           Optional:                            \\
  ||              AutoFly [Kricz] (requires AutoIndex)              ||
  ||                    AbilityPreload [grim001]                    ||
  ||                                                                ||
  ||    Please give credits if you use this spell in your map.      ||
  ||                                                                ||
  \*==============================================================?=*/
                    
scope SuicideSquad initializer onInit

    /*Main Setup*/
    globals
        
        //The Spell-Id of the SuicideSquad Ability
        private constant integer SPELL_ID                       = 'A000'
        
        //The Timer-Interval of timers for movements and checks
        //Default Value: 0.03125
        private constant real TIMER_INTERVAL                    = 0.03125
        
        //If true, the system will use sounds using Rising_Dusk's SoundUtils Library.
        //You can manually disable specific sounds, by setting their path to "".
        private constant boolean USE_SOUNDS                     = true         

    endglobals
    
    /*Sapper Setup*/
    globals
    
        //The Unit-Id of the Sapper
        private constant integer SAPPER_UNIT_ID                     = 'sapp'
        
        //The speed of the down-falling sappers
        //Default Value: 225.00
        private constant real SAPPER_DROP_SPEED                     = 225.00
        
        //The radius, in where sappers search valid targets
        //Default Value: 550.00
        private constant real SAPPER_TARGET_SEARCH_AREA             = 550.00
        
        //If this is true, the sapper will walk to the position of the target unit once it dies
        //and search for new targets while walking. If false, the sapper will stop walking and
        //then search for new targets
        //Default Value: false
        private constant boolean SAPPER_STOP_WHEN_TARGET_DIES       = false
        
        //This is the distance a sapper has to be with its target to make suicide.
        //Default Value: 100.00
        private constant real SAPPER_SUICIDE_RANGE                  = 100.00
        
        //This is the animation-id which is played indstead of the normal death-animation.
        //Information: 3 is the "spell death" animation, which shows, that the sapper does suicide
        //4 is the normal death animation. Ofcourse you could use any other number, if you are funny :D
        //Default Value: 3
        private constant integer SAPPER_SUICIDE_ANIMATION_ID        = 3
        
        //This is the effect that is created when a sapper is dropped by a zeppeling and falling down
        //Use "" for no effect.
        //Default Value: "Abilities\\Spells\\Other\\Tornado\\Tornado_Target.mdl"
        private constant string SAPPER_DROP_EFFECT                  = "Abilities\\Spells\\Other\\Tornado\\Tornado_Target.mdl"
        
        //This is the attachment point of the drop effect above.
        //Default Value: "chest"
        private constant string SAPPER_DROP_EFFECT_ATTACHPOINT          = "chest"
        
        //This is the effect that is created once a sapper reaches the ground and kindles himself
        //Default Value: "Abilities\\Spells\\Other\\BreathOfFire\\BreathOfFireDamage.mdl"
        private constant string SAPPER_BURN_EFFECT                  = "Abilities\\Spells\\Other\\BreathOfFire\\BreathOfFireDamage.mdl"
        
        //This is the attachment point of the burn effect above
        //Default Value: "chest"
        private constant string SAPPER_BURN_EFFECT_ATTACHPOINT          = "chest"
        
        //This is the effect that is displayed, when a sapper found a target
        //Set it to "" if you want no effect.
        //Default Value: "Abilities\\Spells\\Other\\TalkToMe\\TalkToMe.mdl"
        private constant string SAPPER_TARGET_FOUND_EFFECT          = "Abilities\\Spells\\Other\\TalkToMe\\TalkToMe.mdl"
        
        //This is the attachment point of the target-found effect above
        //Default Value: "overhead"
        private constant string SAPPER_TARGET_FOUND_EFFECT_ATTACHPOINT  = "overhead"
        
        //The effect created by the explosion. Set it to "" for no effect
        //Default Value: "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
        private constant string SAPPER_EXPLOSION_EFFECT             = "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
        
        
        //This boolean decides, whether the movespeed of a sapper should be changed using
        //the native SetUnitMoveSpeed or not. In some maps, changing the movespeed via trigger
        //may cause some bugs with other systems/spells.
        //If you dont want, that the movespeed is changed using SetUnitMoveSpeed, change it in the OE.
        //Default Value: true
        private constant boolean SAPPER_ENABLE_MOVESPEED_CHANGE     = true
        
        //This is the movespeed of sappers. It's only used, if the value above is set to true
        //Default Value: 225.00
        private constant real SAPPER_MOVEMENT_SPEED                     = 225.00
        
        //If this boolean is set a true, a texttag is created above each sapper, showing when it will
        //explode. Please note, that you can only have max. 100 Texttags active at the same time, so
        //disable it, when you think you could reach more than 100.
        //Default Value: true
        private constant boolean SAPPER_SHOW_EXPLOSION_INDICATOR    = true
        
        //This is the color of the texttag. Read the ARGB Readme for mroe information about how to use it.
        //Default Value: 0xFFFF0000 (red)
        private ARGB SAPPER_EXPLOSION_TIME_INDICATOR_COLOR              = 0xFFFF0000
            
        //This is the size of the texttag.
        //Default Value: 10.00
        private constant real SAPPER_EXPLOSION_TIME_INDICATOR_SIZE      = 10.00
            
        //This is the height of the texttag.
        //Default Value: 75.00
        private constant real SAPPER_EXPLOSION_TIME_INDICATOR_HEIGHT    = 75.00
        
        //This is the attack type which xedamage uses once a sapper does suicide or explodes
        //Default Value: ATTACK_TYPE_MAGIC
        private constant attacktype SAPPER_EXPLOSION_ATTACK_TYPE    = ATTACK_TYPE_MAGIC
        
        //This is the damage type which xedamage uses once a sapper does suicide or explodes
        //Default Value: DAMAGE_TYPE_FIRE
        private constant damagetype SAPPER_EXPLOSION_DAMAGE_TYPE    = DAMAGE_TYPE_FIRE
        
        //This is the radius of the explosion.
        //Default Value: 250.00
        private constant real SAPPER_EXPLOSION_RADIUS               = 250.00
        
        //If this boolean is set to true, the explosion will also damage allied unit.
        //Default Value: false
        private constant boolean SAPPER_EXPLOSION_DAMAGE_ALLIED     = false
        
        //If this boolean is true, sappers will play a random sound, 
        //which you can add/remove/change in the SAPPER_INIT_SOUNDS textmacro below
        //Default Value: true
        private constant boolean SAPPER_ENABLE_FUNNY_SOUNDS         = true
        
        //This value is only important, if funny sounds of sappers are enabled.
        //Because it may sounds stupid, when 5 sappers speak at the same time, 
        //there is this possibility to give each sapper only a chance to tell something
        //which you can setup with this value.
        //Default Value: 0.33 (33%)
        private constant real SAPPER_FUNNY_SOUND_CHANCE             = 0.30
        
        
    endglobals
    
    
    //in this macro, you can add funny sounds for sappers. 
    //the function you have to call is:
    //call addSapperSound(string soundHandle, real duration)
    //soundHandle is the path of the sound, you can get them i.e from the SoundEditor (F5)
    //duration is the duration of the sound, you can also get this information in the SoundEditor
    //Example: call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperYes1.wav", 1.463)
    //! textmacro SAPPER_INIT_SOUNDS
        
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperYes1.wav", 1.463)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperYes5.wav", 1.434)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperWhat2.wav", 1.694)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperYesAttack3.wav", 2.026)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperYesAttack4.wav", 1.091)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed1.wav", 1.515)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed2.wav", 2.776)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed4.wav", 2.554)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed5.wav", 0.592)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed6.wav", 2.201)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed7.wav", 2.374)
    
    //! endtextmacro
    
    //This is the amount of sappers dropped each level.
    //Default Value: 3 + lvl
    private constant function SAPPER_AMOUNT takes integer lvl returns integer
        return 3 + lvl
    endfunction
    
    //This is the time, a sapper has until it will explode
    //Default Value: 6.00 + lvl
    private constant function SAPPER_EXPLOSION_TIMER takes integer lvl returns real
        return 6.00 + lvl
    endfunction
    
    //This is the damage a explosion deals.
    //Default Value: 25.00 + 25.00 * lvl
    private constant function SAPPER_EXPLOSION_DAMAGE takes integer lvl returns real
        return 15.00 * lvl
    endfunction
    
    //This is the filter used to get valid targets for sappers.
    //Default Value: not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and IsUnitType(u, UNIT_TYPE_GROUND) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and IsUnitVisible(u, GetOwningPlayer(sapper)) and IsUnitEnemy(u, GetOwningPlayer(sapper)) 
    private constant function SAPPER_TARGET_SEARCH_FILTER takes unit u, unit sapper returns boolean
        return not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and IsUnitType(u, UNIT_TYPE_GROUND) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and IsUnitVisible(u, GetOwningPlayer(sapper)) and IsUnitEnemy(u, GetOwningPlayer(sapper)) 
    endfunction
    
    
    /*Zeppelin Setup*/
    globals
    
        //The model of the zeppelin that drops the sappers
        //Default Value: "units\\creeps\\GoblinZeppelin\\GoblinZeppelin.mdl"
        private constant string ZEPPELIN_MODEL                  = "units\\creeps\\GoblinZeppelin\\GoblinZeppelin.mdl"
        
        //The height of the zeppelin. Please note, that the higher this value is, the longer a sapper requires
        //to reach the ground. If you change this value, you may should change the drop speed of the sappers too.
        //Default Value: 350.00
        private constant real ZEPPELIN_HEIGHT                   = 350.00
        
        //The model-size of the zeppelin.
        //Default Value: 0.80
        private constant real ZEPPELIN_SIZE                     = 0.80
        
        //The speed the zeppelin is moving with. This does not effect the distance, when a sapper is dropped
        //The formula for the distance for a sapper drop is:
        //ZEPPELIN_MOVE_DISTANCE / (SAPPER_DROP_AMOUNT(lvl) + 1)
        //Default Value: 450.00
        private constant real ZEPPELIN_SPEED                    = 450.00
        
        //This is the distance the zeppelin moves until is expires.
        //Default Value: 1000.00
        private constant real ZEPPELIN_MOVE_DISTANCE            = 1000.00
        
        //If this boolean is set to true, the zeppelin will display its death animation
        //If false, it will be just removed without any animation
        //Default Value: false
        private constant boolean ZEPPELIN_DESTROY_ON_END        = false
        
        //Zeppelin Sounds
        //This is the sound which is played when the spell is cast. Set this to "" if you want no sound.
        //Default Value: "Units\\Creeps\\GoblinZeppelin\\GoblinZeppelinWhat3.wav"
        private constant string ZEPPELIN_SUMMON_SOUND           = "Units\\Creeps\\GoblinZeppelin\\GoblinZeppelinWhat3.wav"
    
        //This is the duration of the sound above
        //Default Value: 1.838
        private constant real ZEPPELIN_SUMMON_SOUND_DUR         = 1.838
        
        //This sound is played whenever a zeppelin drops a sapper. Set it to "" if you want no sound.
        //Default Value: "Abilities\\Spells\\Other\\LoadUnload\\Loading.wav"
        private constant string ZEPPELIN_SAPPER_DROP_SOUND      = "Abilities\\Spells\\Other\\LoadUnload\\Loading.wav"
    
        //This is the duration of the sound above
        //Default Value: 0.74
        private constant real ZEPPELIN_SAPPER_DROP_SOUND_DUR    = 0.74
    
    endglobals
    
  //=================================================================//
 // Do not touch anything below unless you know what you are doing! //
//=================================================================//
    
    private keyword Main
    private keyword Zeppelin
    private keyword Sapper
    
    private struct Sapper
        unit caster = null
        unit target = null
        unit sapper = null
        
        real time = 0.00
        real x = 0.00
        real y = 0.00
        real tx = 0.00
        real ty = 0.00
        real z = 0.00
        real explosion = 0.00
        
        texttag explosionIndicator = null
        
        integer lvl = 0
        
        effect dropEffect = null
        effect burnEffect = null
        
        boolean onGround = false
        
        static trigger onDeath = CreateTrigger()
        static timer ticker = CreateTimer()
        static thistype temp = 0
        static HandleTable table = 0
        static delegate xedamage dmg = 0
        static real dropSpeed = SAPPER_DROP_SPEED * TIMER_INTERVAL
        
        static integer array sapperSound
        static integer sapperSoundAmount = 0
        
        implement List
        
        static method addSapperSound takes string soundHandle, real duration returns nothing
            set sapperSound[sapperSoundAmount] = DefineSound(soundHandle, R2I(duration * 1000), false, true)
            set sapperSoundAmount = sapperSoundAmount + 1
        endmethod
        
        static method unitFilter takes nothing returns boolean
            return SAPPER_TARGET_SEARCH_FILTER(GetFilterUnit(), temp.sapper)
        endmethod
        
        method onDestroy takes nothing returns nothing
            call table.flush(sapper)
        
            call listRemove()
            if count == 0 then
                call PauseTimer(ticker)
            endif
            
            static if SAPPER_SHOW_EXPLOSION_INDICATOR then
                call DestroyTextTag(explosionIndicator)
            endif
        endmethod
        
        static method onLoop takes nothing returns nothing
            local thistype this = first
            local real dx = 0.00
            local real dy = 0.00
            
            loop
                exitwhen this == 0
                if not onGround then
                    call SetUnitZ(sapper, GetUnitZ(sapper) - dropSpeed)
                    if GetUnitZ(sapper) <= 0.01 then
                        if dropEffect != null then
                            call DestroyEffect(dropEffect)
                        endif
                        
                        if SAPPER_BURN_EFFECT != "" then
                            set burnEffect = AddSpecialEffectTarget(SAPPER_BURN_EFFECT, sapper, SAPPER_BURN_EFFECT_ATTACHPOINT)
                        endif
                        
                        static if SAPPER_SHOW_EXPLOSION_INDICATOR then
                            set explosionIndicator = CreateTextTag()
                            call SetTextTagVisibility(explosionIndicator, true)
                            call SetTextTagPermanent(explosionIndicator, true)
                            call SetTextTagText(explosionIndicator, I2S(R2I(explosion + 0.5)), SAPPER_EXPLOSION_TIME_INDICATOR_SIZE * 0.0023)
                            call SetTextTagColor(explosionIndicator, SAPPER_EXPLOSION_TIME_INDICATOR_COLOR.red, SAPPER_EXPLOSION_TIME_INDICATOR_COLOR.green, SAPPER_EXPLOSION_TIME_INDICATOR_COLOR.blue, SAPPER_EXPLOSION_TIME_INDICATOR_COLOR.alpha)
                            call SetTextTagPos(explosionIndicator, x, y, GetUnitZ(sapper) + SAPPER_EXPLOSION_TIME_INDICATOR_HEIGHT)
                        endif
            
                        set onGround = true
                    endif
                else
                    set x = GetUnitX(sapper)
                    set y = GetUnitY(sapper)
                    
                    set explosion = explosion - TIMER_INTERVAL
                    
                    static if SAPPER_SHOW_EXPLOSION_INDICATOR then
                        call SetTextTagPos(explosionIndicator, x, y, GetUnitZ(sapper) + SAPPER_EXPLOSION_TIME_INDICATOR_HEIGHT)
                        call SetTextTagText(explosionIndicator, I2S(R2I(explosion + 0.5)), SAPPER_EXPLOSION_TIME_INDICATOR_SIZE * 0.0023)
                    endif
                    
                    if explosion <= 0 then
                        call SetUnitExploded(sapper, true)
                        call KillUnit(sapper)
                        call SetUnitAnimationByIndex(sapper, SAPPER_SUICIDE_ANIMATION_ID)
                        call destroy()
                    endif
                    
                    if target == null then
                        set temp = this
                        call GroupEnumUnitsInArea(ENUM_GROUP, x, y, SAPPER_TARGET_SEARCH_AREA, Condition(function thistype.unitFilter))
                        //These are valid BJ's which SHOULD be used...
                        if CountUnitsInGroup(ENUM_GROUP) > 0 then
                            set target = GroupPickRandomUnit(ENUM_GROUP)
                            set tx = GetUnitX(target)
                            set ty = GetUnitY(target)
                            call IssuePointOrder(sapper, "smart", tx, ty)
                            
                            if SAPPER_TARGET_FOUND_EFFECT != "" then
                                call DestroyEffect(AddSpecialEffectTarget(SAPPER_TARGET_FOUND_EFFECT, sapper, SAPPER_TARGET_FOUND_EFFECT_ATTACHPOINT))
                            endif
                            
                            static if SAPPER_ENABLE_FUNNY_SOUNDS then
                                if GetRandomReal(0.00, 1.00) <= SAPPER_FUNNY_SOUND_CHANCE then
                                    call RunSoundOnUnit(sapperSound[GetRandomInt(0, sapperSoundAmount - 1)], sapper)
                                endif
                            endif
                        endif
                    else
                        set tx = GetUnitX(target)
                        set ty = GetUnitY(target)
                        
                        if IsUnitType(target, UNIT_TYPE_DEAD) then
                            static if not SAPPER_STOP_WHEN_TARGET_DIES then
                                call IssuePointOrder(sapper, "smart", tx, ty)
                            else
                                call IssueImmediateOrder(sapper, "stop")
                            endif
                            set target = null
                            
                        else
                        
                            //This here is a problem... If the target moves, the sapper will stuck a little bit
                            //when i reorder smart or move each interval.
                            //So i made a check with the position of the target to only reorder the smart order
                            //once the target changed its position, dunno what else i could do...
                            if tx != GetUnitX(target) or ty != GetUnitY(target) then
                                set tx = GetUnitX(target)
                                set ty = GetUnitY(target)
                                call IssuePointOrder(sapper, "smart", tx, ty)
                            endif
                            
                            set dx = x - tx
                            set dy = y - ty
                            if (dx * dx + dy * dy) <= SAPPER_SUICIDE_RANGE * SAPPER_SUICIDE_RANGE then
                                call SetUnitExploded(sapper, true)
                                call KillUnit(sapper)
                                call SetUnitAnimationByIndex(sapper, SAPPER_SUICIDE_ANIMATION_ID)
                                call destroy()
                            endif
                        endif
                    endif
                        
                endif
                    
                set this = next
            endloop
        endmethod
        
        static method create takes Zeppelin data returns thistype
            local thistype this = allocate()
            set caster = data.caster
            set y = data.y
            set x = data.x
            set z = data.z
            set lvl = data.lvl
            set explosion = SAPPER_EXPLOSION_TIMER(lvl)
            
            set sapper = CreateUnit(GetOwningPlayer(caster), SAPPER_UNIT_ID, x, y, data.xyangle * bj_RADTODEG)
            
            static if not LIBRARY_AutoFly then
                call UnitAddAbility(sapper, XE_HEIGHT_ENABLER)
                call UnitRemoveAbility(sapper, XE_HEIGHT_ENABLER)
            endif
            
            if SAPPER_DROP_EFFECT != "" then
                set dropEffect = AddSpecialEffectTarget(SAPPER_DROP_EFFECT, sapper, SAPPER_DROP_EFFECT_ATTACHPOINT)
            endif
            
            call SetUnitFlyHeight(sapper, GetTerrainZ(x, y) + z, 0.00)
            call UnitAddAbility(sapper, 'Aloc')
            call TriggerRegisterUnitEvent(onDeath, sapper, EVENT_UNIT_DEATH)
            
            set table[sapper] = integer(this)
            
            call listAdd()
            if count == 1 then
                call TimerStart(ticker, TIMER_INTERVAL, true, function thistype.onLoop)
            endif
            return this
        endmethod
        
        static method onUnitDeath takes nothing returns boolean
            local thistype this = thistype(table[GetDyingUnit()])
            if this != 0 then
                call damageAOE(sapper, x, y, SAPPER_EXPLOSION_RADIUS, SAPPER_EXPLOSION_DAMAGE(lvl))
                if SAPPER_EXPLOSION_EFFECT != "" then
                    call DestroyEffect(AddSpecialEffect(SAPPER_EXPLOSION_EFFECT, x, y))
                endif
            endif
            return false
        endmethod
        
        static method onInit takes nothing returns nothing
            set table = HandleTable.create()
            
            set dmg = xedamage.create()
            set dtype = SAPPER_EXPLOSION_DAMAGE_TYPE
            set atype = SAPPER_EXPLOSION_ATTACK_TYPE
            set damageAllies = SAPPER_EXPLOSION_DAMAGE_ALLIED
            
            //! runtextmacro SAPPER_INIT_SOUNDS()
            
            call TriggerAddCondition(onDeath, Condition(function thistype.onUnitDeath))
        endmethod
        
    endstruct
            
    private struct Zeppelin
        
        unit caster = null
        
        real cos = 0.00
        real sin = 0.00
        real moved = 0.00
        
        delegate xefx model = 0
        
        sound summonSound = null
        
        integer lvl = 0
        integer sapperDropped = 0
        integer sapperToDrop = 0
        
        real sapperDropCounter = 0.00
        
        static integer zeppelinSummonSound = 0
        static integer zeppelinDropSound = 0
        
        static timer ticker = CreateTimer()
        static real speed = TIMER_INTERVAL * ZEPPELIN_SPEED
        
        implement List
        
        
        method onDestroy takes nothing returns nothing
        
            static if not ZEPPELIN_DESTROY_ON_END then
                call model.hiddenDestroy()
            else
                call model.destroy()
            endif
        
            call listRemove()
            if count == 0 then
                call PauseTimer(ticker)
            endif
        endmethod
        
        static method onLoop takes nothing returns nothing
            local thistype this = first
            
            loop
                exitwhen this == 0
                set x = x + cos
                set y = y + sin
                
                static if USE_SOUNDS then
                    if summonSound != null then
                        call SetSoundPosition(summonSound, x, y, z)
                    endif
                endif
                
                set moved = moved + speed
                set sapperDropCounter = sapperDropCounter + speed
                
                if sapperDropCounter >= ZEPPELIN_MOVE_DISTANCE / (sapperToDrop + 1) then
                    set sapperDropCounter = 0.00
                    call Sapper.create(this)
                    
                    static if USE_SOUNDS then
                        if zeppelinDropSound != 0 then
                            call RunSoundAtPoint(zeppelinDropSound, x, y, z)
                        endif
                    endif
                endif

                if moved >= ZEPPELIN_MOVE_DISTANCE then
                    call destroy()
                endif
                
                set this = next
            endloop
            
        endmethod
        
        static method create takes Main data returns thistype
            local thistype this = allocate()
            
            set sin = ZEPPELIN_SPEED * TIMER_INTERVAL * Sin(data.angle)
            set cos = ZEPPELIN_SPEED * TIMER_INTERVAL * Cos(data.angle)
            set caster = data.caster
            set lvl = GetUnitAbilityLevel(caster, SPELL_ID)
            set sapperToDrop = SAPPER_AMOUNT(lvl)
            
            set model = xefx.create(data.cx, data.cy, data.angle)
            set fxpath = ZEPPELIN_MODEL
            set z = ZEPPELIN_HEIGHT
            set scale = ZEPPELIN_SIZE 
            set teamcolor = GetPlayerColor(GetOwningPlayer(caster))
            set owner = GetOwningPlayer(caster)
            
            static if USE_SOUNDS then
                if ZEPPELIN_SUMMON_SOUND != "" then
                    call RunSoundAtPoint(zeppelinSummonSound, x, y, z)
                endif
            endif
            
            call listAdd()
            if count == 1 then
                call TimerStart(ticker, TIMER_INTERVAL, true, function thistype.onLoop)
            endif
            return this
        endmethod
        
        static method onInit takes nothing returns nothing
            static if USE_SOUNDS then
                if ZEPPELIN_SUMMON_SOUND != "" then
                    set zeppelinSummonSound = DefineSound(ZEPPELIN_SUMMON_SOUND, R2I(ZEPPELIN_SUMMON_SOUND_DUR * 1000), false, true)
                endif
                
                if ZEPPELIN_SAPPER_DROP_SOUND != "" then
                    set zeppelinDropSound = DefineSound(ZEPPELIN_SAPPER_DROP_SOUND, R2I(ZEPPELIN_SAPPER_DROP_SOUND_DUR * 1000), false, true)
                endif
            endif
        endmethod
        
    endstruct
    
    private struct Main 
    
        unit caster = null
        integer lvl = 0
        real cx = 0.00
        real cy = 0.00
        real angle = 0.00
        
        static method onCast takes nothing returns boolean
            local thistype this = 0
            if GetSpellAbilityId() != SPELL_ID then
                return false
            endif
            set this = allocate()
            set caster = GetSpellAbilityUnit()
            set lvl = GetUnitAbilityLevel(caster, SPELL_ID)
            set cx = GetUnitX(caster)
            set cy = GetUnitY(caster)
            
            set angle = Atan2(GetSpellTargetY() - cy, GetSpellTargetX() - cx)
            
            call Zeppelin.create(this)
            
            call destroy()
            return false
        endmethod
        
        private static trigger cast = CreateTrigger()
        
        static method onInit takes nothing returns nothing
            call TriggerRegisterAnyUnitEventBJ(cast, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(cast, Condition(function thistype.onCast))
        endmethod
        
    endstruct
    
    
endscope



Please give credits if you use this awesome terrain :ogre_haosis:
 

Attachments

  • SuicideSquaScreenshot1.png
    SuicideSquaScreenshot1.png
    873.3 KB · Views: 242
  • SuicideSquaScreenshot2.png
    SuicideSquaScreenshot2.png
    832.8 KB · Views: 213
  • SuicideSquadTooltip.png
    SuicideSquadTooltip.png
    47.8 KB · Views: 220
  • SuicideSquad.w3x
    157.7 KB · Views: 52
Level 8
Joined
Aug 2, 2008
Messages
193
I think it should reduce points for coding.. cause it sucks if a spell can only be casted one single time by one single unit... And its not that hard to make a spell MUI...


Going to update my spell tomorrow, removing Locust from the sappers. They then have 100 hit points each, making them killable (which also makes them blow up!) for bounty/exp.
Also fixed some things with my Z-Utils Library and tweaked some values inside of the spell. Also added some new code and setups to fix some bugs with ordering of sappers...
The spell got 700 lines of code at the moment ~.~ :D
 
Level 10
Joined
Jul 12, 2009
Messages
318
Nice work Weep. Simple spell, though. Maybe u should add timed life to these critter summoned by this, because sometimes, it can kill a map reason by having too many critter wandering... and maybe make the flower effect disappear when the spell effect end maybe? It'll give the impression that the flower is really that spell's effect and not just random doodad appeared if u know what i mean...

Thanks. Timed life added, decided against making the flowers expire with the buff because they're supposed to be grown in place like the critters.

Nah...you don't get points deducted for that,you just get instantly disqualified.
Well, maybe it is so. After all, that's in the site rules for spell resources... :huh:
 
Level 8
Joined
Aug 2, 2008
Messages
193
What i meant with that is, that its not allowed to use them or am I wrong? :D

Updating my Spell soon, terraining a bit atm..

Edit:

Updated Spell!


Removed Locust (Sapper have 100 life and magic immunity)
Changed some movement-things (now orders attack on target instead of "smart" to their position)
Added option to make sapper invulnerable while falling down.
Tweaked some values.
Fixed a bug with in my Z-Utils lib.
Added option to decide whether the sappers or the caster deals the damage.
New testmap.
Added preloading of ability...
Fixed a bug where targets wont get added to the onDeath-Trigger.
Added Visible-Check for sappers:
Once the target becomes invisible or gets out of sight, sappers will walk to the position, where the target has been seen the last time. Cannot suicides targets that are invisible (means, that even if the targets stands invisible in front of the sapper, it wont blow its ass up).




JASS:
 /*=====================================================================*\
//======                      SUICIDE SQUAD                        =====*\\
\\======                       Version 1.0b                        ======//
 \\======                        by Kricz                         ======//
 ||                                                                     ||
 ||                                                                     ||
 ||                              Requires:                              ||
 \\                          Table [Vexorian]                          //  
  \\                       ListModule [grim001]                       //
   \\              xebasic, xedamage & xefx [Vexorian]               //
    \\                       ARGB [Vexorian]                        //
    ||                  SoundUtils [Rising_Dusk]                   ||
    ||                  GroupUtils [Rising_Dusk]                   ||
    ||                       Z-Utils [Kricz]                       ||
   //                                                              \\
  //                           Optional:                            \\
  ||              AutoFly [Kricz] (requires AutoIndex)              ||
  ||                    AbilityPreload [grim001]                    ||
  ||                                                                ||
  ||    Please give credits if you use this spell in your map.      ||
  ||                                                                ||
  \*==============================================================?=*/
                    
scope SuicideSquad initializer onInit

    /*Main Setup*/
    globals
        
        //The Spell-Id of the SuicideSquad Ability
        private constant integer SPELL_ID                       = 'A000'
        
        //The Timer-Interval of timers for movements and checks
        //Default Value: 0.05
        private constant real TIMER_INTERVAL                    = 0.05
        
        //If true, the system will use sounds using Rising_Dusk's SoundUtils Library.
        //You can manually disable specific sounds, by setting their path to "".
        private constant boolean USE_SOUNDS                     = true         

    endglobals
    
    /*Sapper Setup*/
    globals
    
        //The Unit-Id of the Sapper
        private constant integer SAPPER_UNIT_ID                     = 'sapp'
        
        //The speed of the down-falling sappers
        //Default Value: 375.00
        private constant real SAPPER_DROP_SPEED                     = 375.00
        
        //The radius, in where sappers search valid targets
        //Default Value: 700.00
        private constant real SAPPER_TARGET_SEARCH_AREA             = 700.00
        
        //If this is true, the sapper will walk to the position of the target unit once it dies
        //and search for new targets while walking. If false, the sapper will stop walking and
        //then search for new targets
        //Default Value: false
        private constant boolean SAPPER_STOP_WHEN_TARGET_DIES       = false
        
        //This is the distance a sapper has to be with its target to make suicide.
        //Default Value: 150.00
        private constant real SAPPER_SUICIDE_RANGE                  = 150.00
        
        //If true, the sappers are invulnerable while falling down and become normal once reaching the gorund
        //Default Value: true
        private constant boolean SAPPER_INVULNERABLE_WHILE_FALLING  = true
        
        //This is the animation-id which is played indstead of the normal death-animation.
        //Information: 3 is the "spell death" animation, which shows, that the sapper does suicide
        //4 is the normal death animation. Ofcourse you could use any other number, if you are funny :D
        //Default Value: 3
        private constant integer SAPPER_SUICIDE_ANIMATION_ID        = 3
        
        //This is the effect that is created when a sapper is dropped by a zeppeling and falling down
        //Use "" for no effect.
        //Default Value: "Abilities\\Spells\\Other\\Tornado\\Tornado_Target.mdl"
        private constant string SAPPER_DROP_EFFECT                  = "Abilities\\Spells\\Other\\Tornado\\Tornado_Target.mdl"
        
        //This is the attachment point of the drop effect above.
        //Default Value: "chest"
        private constant string SAPPER_DROP_EFFECT_ATTACHPOINT          = "chest"
        
        //This is the effect that is created once a sapper reaches the ground and kindles himself
        //Default Value: "Abilities\\Spells\\Other\\BreathOfFire\\BreathOfFireDamage.mdl"
        private constant string SAPPER_BURN_EFFECT                  = "Abilities\\Spells\\Other\\BreathOfFire\\BreathOfFireDamage.mdl"
        
        //This is the attachment point of the burn effect above
        //Default Value: "chest"
        private constant string SAPPER_BURN_EFFECT_ATTACHPOINT          = "chest"
        
        //This is the effect that is displayed, when a sapper found a target
        //Set it to "" if you want no effect.
        //Default Value: "Abilities\\Spells\\Other\\TalkToMe\\TalkToMe.mdl"
        private constant string SAPPER_TARGET_FOUND_EFFECT          = "Abilities\\Spells\\Other\\TalkToMe\\TalkToMe.mdl"
        
        //This is the attachment point of the target-found effect above
        //Default Value: "overhead"
        private constant string SAPPER_TARGET_FOUND_EFFECT_ATTACHPOINT  = "overhead"
        
        //The effect created by the explosion. Set it to "" for no effect
        //Default Value: "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
        private constant string SAPPER_EXPLOSION_EFFECT             = "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
        
        
        //This boolean decides, whether the movespeed of a sapper should be changed using
        //the native SetUnitMoveSpeed or not. In some maps, changing the movespeed via trigger
        //may cause some bugs with other systems/spells.
        //If you dont want, that the movespeed is changed using SetUnitMoveSpeed, change it in the OE.
        //Default Value: true
        private constant boolean SAPPER_ENABLE_MOVESPEED_CHANGE     = true
        
        //This is the movespeed of sappers. It's only used, if the value above is set to true
        //Default Value: 250.00
        private constant real SAPPER_MOVEMENT_SPEED                     = 250.00
        
        //If this boolean is set a true, a texttag is created above each sapper, showing when it will
        //explode. Please note, that you can only have max. 100 Texttags active at the same time, so
        //disable it, when you think you could reach more than 100.
        //Default Value: true
        private constant boolean SAPPER_SHOW_EXPLOSION_INDICATOR    = true
        
        //This is the color of the texttag. Read the ARGB Readme for mroe information about how to use it.
        //Default Value: 0xFFFF0000 (red)
        private ARGB SAPPER_EXPLOSION_TIME_INDICATOR_COLOR              = 0xFFFF0000
            
        //This is the size of the texttag.
        //Default Value: 10.00
        private constant real SAPPER_EXPLOSION_TIME_INDICATOR_SIZE      = 10.00
            
        //This is the height of the texttag.
        //Default Value: 75.00
        private constant real SAPPER_EXPLOSION_TIME_INDICATOR_HEIGHT    = 75.00
        
        //If this boolean is set to true, the damage will be done by the caster, not by the sapper
        //that exploded. Result of that is, the each unit, that received damage through the explosion
        //will attack the caster. If false, they will just do like nothing, cause they cannnot attack
        //dead units (the sapper).
        //Default Value: true
        private constant boolean SAPPER_EXPLOSION_USE_CASTER_AS_SOURCE  = true
        
        //This is the attack type which xedamage uses once a sapper does suicide or explodes
        //Default Value: ATTACK_TYPE_MAGIC
        private constant attacktype SAPPER_EXPLOSION_ATTACK_TYPE    = ATTACK_TYPE_MAGIC
        
        //This is the damage type which xedamage uses once a sapper does suicide or explodes
        //Default Value: DAMAGE_TYPE_FIRE
        private constant damagetype SAPPER_EXPLOSION_DAMAGE_TYPE    = DAMAGE_TYPE_FIRE
        
        //This is the radius of the explosion.
        //Default Value: 250.00
        private constant real SAPPER_EXPLOSION_RADIUS               = 250.00
        
        //If true, the explosion will also deal damage to destructables in the explosion area
        //Default Value: true
        private constant boolean SAPPER_EXPLOSION_DAMAGE_DESTRUCTS  = true
        
        //If this boolean is set to true, the explosion will also damage allied unit.
        //Default Value: false
        private constant boolean SAPPER_EXPLOSION_DAMAGE_ALLIED     = false
        
        //If this boolean is true, sappers will play a random sound, 
        //which you can add/remove/change in the SAPPER_INIT_SOUNDS textmacro below
        //Default Value: true
        private constant boolean SAPPER_ENABLE_FUNNY_SOUNDS         = true
        
        //This value is only important, if funny sounds of sappers are enabled.
        //Because it may sounds stupid, when 5 sappers speak at the same time, 
        //there is this possibility to give each sapper only a chance to tell something
        //which you can setup with this value.
        //Default Value: 0.33 (33%)
        private constant real SAPPER_FUNNY_SOUND_CHANCE             = 0.30
        
        
    endglobals
    
    
    //in this macro, you can add funny sounds for sappers. 
    //the function you have to call is:
    //call addSapperSound(string soundHandle, real duration)
    //soundHandle is the path of the sound, you can get them i.e from the SoundEditor (F5)
    //duration is the duration of the sound, you can also get this information in the SoundEditor
    //Example: call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperYes1.wav", 1.463)
    //! textmacro SAPPER_INIT_SOUNDS
        
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperYes1.wav", 1.463)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperYes5.wav", 1.434)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperWhat2.wav", 1.694)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperYesAttack3.wav", 2.026)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperYesAttack4.wav", 1.091)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed1.wav", 1.515)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed2.wav", 2.776)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed4.wav", 2.554)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed5.wav", 0.592)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed6.wav", 2.201)
        call addSapperSound("Units\\Creeps\\GoblinSapper\\GoblinSapperPissed7.wav", 2.374)
    
    //! endtextmacro
    
    //This is the amount of sappers dropped each level.
    //Default Value: 3 + lvl
    private constant function SAPPER_AMOUNT takes integer lvl returns integer
        return 3 + lvl
    endfunction
    
    //This is the time, a sapper has until it will explode
    //Default Value: 6.00 + lvl
    private constant function SAPPER_EXPLOSION_TIMER takes integer lvl returns real
        return 6.00 + lvl
    endfunction
    
    //This is the damage a explosion deals.
    //Default Value: 25.00 + 25.00 * lvl
    private constant function SAPPER_EXPLOSION_DAMAGE takes integer lvl returns real
        return 15.00 * lvl
    endfunction
    
    //This is the filter used to get valid targets for sappers.
    //Default Value: not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and IsUnitType(u, UNIT_TYPE_GROUND) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and IsUnitVisible(u, GetOwningPlayer(sapper)) and IsUnitEnemy(u, GetOwningPlayer(sapper)) 
    private constant function SAPPER_TARGET_SEARCH_FILTER takes unit u, unit sapper returns boolean
        return not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and IsUnitType(u, UNIT_TYPE_GROUND) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and IsUnitVisible(u, GetOwningPlayer(sapper)) and IsUnitEnemy(u, GetOwningPlayer(sapper)) 
    endfunction
    
    
    /*Zeppelin Setup*/
    globals
    
        //The model of the zeppelin that drops the sappers
        //Default Value: "units\\creeps\\GoblinZeppelin\\GoblinZeppelin.mdl"
        private constant string ZEPPELIN_MODEL                  = "units\\creeps\\GoblinZeppelin\\GoblinZeppelin.mdl"
        
        //The height of the zeppelin. Please note, that the higher this value is, the longer a sapper requires
        //to reach the ground. If you change this value, you may should change the drop speed of the sappers too.
        //Default Value: 500.00
        private constant real ZEPPELIN_HEIGHT                   = 500.00
        
        //The model-size of the zeppelin.
        //Default Value: 0.80
        private constant real ZEPPELIN_SIZE                     = 0.80
        
        //The speed the zeppelin is moving with. This does not effect the distance, when a sapper is dropped
        //The formula for the distance for a sapper drop is:
        //ZEPPELIN_MOVE_DISTANCE / (SAPPER_DROP_AMOUNT(lvl) + 1)
        //Default Value: 400.00
        private constant real ZEPPELIN_SPEED                    = 400.00
        
        //This is the distance the zeppelin moves until is expires.
        //Default Value: 1000.00
        private constant real ZEPPELIN_MOVE_DISTANCE            = 1000.00
        
        //If this boolean is set to true, the zeppelin will display its death animation
        //If false, it will be just removed without any animation
        //Default Value: false
        private constant boolean ZEPPELIN_DESTROY_ON_END        = false
        
        //Zeppelin Sounds
        //This is the sound which is played when the spell is cast. Set this to "" if you want no sound.
        //Default Value: "Units\\Creeps\\GoblinZeppelin\\GoblinZeppelinWhat3.wav"
        private constant string ZEPPELIN_SUMMON_SOUND           = "Units\\Creeps\\GoblinZeppelin\\GoblinZeppelinWhat3.wav"
    
        //This is the duration of the sound above
        //Default Value: 1.838
        private constant real ZEPPELIN_SUMMON_SOUND_DUR         = 1.838
        
        //This sound is played whenever a zeppelin drops a sapper. Set it to "" if you want no sound.
        //Default Value: "Abilities\\Spells\\Other\\LoadUnload\\Loading.wav"
        private constant string ZEPPELIN_SAPPER_DROP_SOUND      = "Abilities\\Spells\\Other\\LoadUnload\\Loading.wav"
    
        //This is the duration of the sound above
        //Default Value: 0.74
        private constant real ZEPPELIN_SAPPER_DROP_SOUND_DUR    = 0.74
    
    endglobals
    
  //=================================================================//
 // Do not touch anything below unless you know what you are doing! //
//=================================================================//
    
    private keyword Main
    private keyword Zeppelin
    private keyword Sapper
    
    private struct Sapper
        unit caster = null
        unit target = null
        unit sapper = null
        
        real time = 0.00
        real x = 0.00
        real y = 0.00
        real tx = 0.00
        real ty = 0.00
        real z = 0.00
        real explosion = 0.00
        
        texttag explosionIndicator = null
        
        integer lvl = 0
        
        effect dropEffect = null
        effect burnEffect = null
        
        player owner = null
        
        boolean onGround = false
        boolean oldTargetDied = false
        
        static trigger onDeath = CreateTrigger()
        static trigger onOrder = CreateTrigger()
        static timer ticker = CreateTimer()
        static thistype temp = 0
        static HandleTable sapperTable = 0
        static HandleTable targetTable = 0
        static delegate xedamage dmg = 0
        static boolean ignoreOrders = false
        static real dropSpeed = SAPPER_DROP_SPEED * TIMER_INTERVAL
        
        static integer array sapperSound
        static integer sapperSoundAmount = 0
        
        implement List
        
        static method addSapperSound takes string soundHandle, real duration returns nothing
            set sapperSound[sapperSoundAmount] = DefineSound(soundHandle, R2I(duration * 1000), false, true)
            set sapperSoundAmount = sapperSoundAmount + 1
        endmethod
        
        static method unitFilter takes nothing returns boolean
            return SAPPER_TARGET_SEARCH_FILTER(GetFilterUnit(), temp.sapper)
        endmethod
        
        method onDestroy takes nothing returns nothing
            call sapperTable.flush(sapper)
        
            call listRemove()
            if count == 0 then
                call PauseTimer(ticker)
            endif
            
            static if SAPPER_SHOW_EXPLOSION_INDICATOR then
                call DestroyTextTag(explosionIndicator)
            endif
        endmethod
        
        method searchForTarget takes nothing returns boolean
            set temp = this
            call GroupEnumUnitsInArea(ENUM_GROUP, x, y, SAPPER_TARGET_SEARCH_AREA, Condition(function thistype.unitFilter))
            //These are valid BJ's which SHOULD be used...
            if CountUnitsInGroup(ENUM_GROUP) > 0 then
                set target = GroupPickRandomUnit(ENUM_GROUP)
                //Using the table to save whether a unit is already registred to the trigger or not
                if targetTable[target] == 0 then
                    call TriggerRegisterUnitEvent(onDeath, target, EVENT_UNIT_DEATH)
                    set targetTable[target] = 1
                endif
                set tx = GetUnitX(target)
                set ty = GetUnitY(target)
                call IssueTargetOrder(sapper, "attack", target)
                            
                if SAPPER_TARGET_FOUND_EFFECT != "" then
                    call DestroyEffect(AddSpecialEffectTarget(SAPPER_TARGET_FOUND_EFFECT, sapper, SAPPER_TARGET_FOUND_EFFECT_ATTACHPOINT))
                endif
                            
                static if SAPPER_ENABLE_FUNNY_SOUNDS then
                    if GetRandomReal(0.00, 1.00) <= SAPPER_FUNNY_SOUND_CHANCE then
                        call RunSoundOnUnit(sapperSound[GetRandomInt(0, sapperSoundAmount - 1)], sapper)
                    endif
                endif
            else
                set target = null
            endif
            return target != null
        endmethod
        
        
        method moveSapper takes nothing returns nothing
            if target == null then
                static if not SAPPER_STOP_WHEN_TARGET_DIES then
                    if oldTargetDied then
                        call IssuePointOrder(sapper, "smart", tx, ty)
                    else
                        call PauseUnit(sapper, true)
                        call IssueImmediateOrder(sapper, "stop")
                        call PauseUnit(sapper, false)
                    endif
                else
                    call PauseUnit(sapper, true)
                    call IssueImmediateOrder(sapper, "stop")
                    call PauseUnit(sapper, false)
                endif
            else
                if not IsUnitVisible(target, owner) then
                        
                    if GetUnitCurrentOrder(sapper) == 851983 then
                        //if target becomes invisible or gets out of sight, the sapper will
                        //run to the position, where the target was last seen.
                        call IssuePointOrder(sapper, "smart", tx, ty)
                    endif
                            
                else                            
                    if IsUnitType(target, UNIT_TYPE_DEAD) then
                        if not searchForTarget() then
                            set oldTargetDied = true
                            static if not SAPPER_STOP_WHEN_TARGET_DIES then
                                call IssuePointOrder(sapper, "smart", tx, ty)
                            else
                                call PauseUnit(sapper, true)
                                call IssueImmediateOrder(sapper, "stop")
                                call PauseUnit(sapper, false)
                            endif
                        else
                            set oldTargetDied = false
                        endif
                    elseif GetUnitCurrentOrder(sapper) != 851983 then
                        call IssueTargetOrder(sapper, "attack", target)
                    endif
                endif
            endif
        endmethod
        
        static method onLoop takes nothing returns nothing
            local thistype this = first
            local real dx = 0.00
            local real dy = 0.00
            
            set ignoreOrders = true
            loop
                exitwhen this == 0
                if not onGround then
                    call SetUnitZ(sapper, GetUnitZ(sapper) - dropSpeed)
                    if GetUnitZ(sapper) <= 0.01 then
                    
                        static if SAPPER_INVULNERABLE_WHILE_FALLING then
                            call SetUnitInvulnerable(sapper, false)
                        endif
                        
                        if dropEffect != null then
                            call DestroyEffect(dropEffect)
                        endif
                        
                        if SAPPER_BURN_EFFECT != "" then
                            set burnEffect = AddSpecialEffectTarget(SAPPER_BURN_EFFECT, sapper, SAPPER_BURN_EFFECT_ATTACHPOINT)
                        endif
                        
                        static if SAPPER_SHOW_EXPLOSION_INDICATOR then
                            set explosionIndicator = CreateTextTag()
                            call SetTextTagVisibility(explosionIndicator, true)
                            call SetTextTagPermanent(explosionIndicator, true)
                            call SetTextTagText(explosionIndicator, I2S(R2I(explosion + 0.5)), SAPPER_EXPLOSION_TIME_INDICATOR_SIZE * 0.0023)
                            call SetTextTagColor(explosionIndicator, SAPPER_EXPLOSION_TIME_INDICATOR_COLOR.red, SAPPER_EXPLOSION_TIME_INDICATOR_COLOR.green, SAPPER_EXPLOSION_TIME_INDICATOR_COLOR.blue, SAPPER_EXPLOSION_TIME_INDICATOR_COLOR.alpha)
                            call SetTextTagPos(explosionIndicator, x, y, GetUnitZ(sapper) + SAPPER_EXPLOSION_TIME_INDICATOR_HEIGHT)
                        endif
            
                        set onGround = true
                    endif
                else
                    set x = GetUnitX(sapper)
                    set y = GetUnitY(sapper)
                    
                    set explosion = explosion - TIMER_INTERVAL
                    
                    static if SAPPER_SHOW_EXPLOSION_INDICATOR then
                        call SetTextTagPos(explosionIndicator, x, y, GetUnitZ(sapper) + SAPPER_EXPLOSION_TIME_INDICATOR_HEIGHT)
                        call SetTextTagText(explosionIndicator, I2S(R2I(explosion + 0.5)), SAPPER_EXPLOSION_TIME_INDICATOR_SIZE * 0.0023)
                    endif
                    
                    if explosion <= 0 then
                        call SetUnitExploded(sapper, true)
                        call KillUnit(sapper)
                        call SetUnitAnimationByIndex(sapper, SAPPER_SUICIDE_ANIMATION_ID)
                        call destroy()
                    endif
                    
                    if target == null then
                        call searchForTarget()
                    else
                        call moveSapper()
                        
                        if IsUnitVisible(target, owner) then
                            set tx = GetUnitX(target)
                            set ty = GetUnitY(target)
                            
                            set dx = x - tx
                            set dy = y - ty
                            if (dx * dx + dy * dy) <= SAPPER_SUICIDE_RANGE * SAPPER_SUICIDE_RANGE then
                                call SetUnitExploded(sapper, true)
                                call KillUnit(sapper)
                                call SetUnitAnimationByIndex(sapper, SAPPER_SUICIDE_ANIMATION_ID)
                                call destroy()
                            endif
                        endif
                    endif
                        
                endif
                    
                set this = next
            endloop
            set ignoreOrders = false
        endmethod
        
        static method create takes Zeppelin data returns thistype
            local thistype this = allocate()
            set caster = data.caster
            set y = data.y
            set x = data.x
            set z = data.z
            set lvl = data.lvl
            set explosion = SAPPER_EXPLOSION_TIMER(lvl)
            
            set sapper = CreateUnit(GetOwningPlayer(caster), SAPPER_UNIT_ID, x, y, data.xyangle * bj_RADTODEG)
            set owner = GetOwningPlayer(sapper)
            
            static if not LIBRARY_AutoFly then
                call UnitAddAbility(sapper, XE_HEIGHT_ENABLER)
                call UnitRemoveAbility(sapper, XE_HEIGHT_ENABLER)
            endif
            
            static if SAPPER_INVULNERABLE_WHILE_FALLING then
                call SetUnitInvulnerable(sapper, true)
            endif
            
            if SAPPER_DROP_EFFECT != "" then
                set dropEffect = AddSpecialEffectTarget(SAPPER_DROP_EFFECT, sapper, SAPPER_DROP_EFFECT_ATTACHPOINT)
            endif
            
            call SetUnitZ(sapper, z)
            call TriggerRegisterUnitEvent(onDeath, sapper, EVENT_UNIT_DEATH)
            
            set sapperTable[sapper] = integer(this)
            
            call listAdd()
            if count == 1 then
                call TimerStart(ticker, TIMER_INTERVAL, true, function thistype.onLoop)
            endif
            return this
        endmethod
        
        static method onUnitDeath takes nothing returns boolean
            local unit killed = GetDyingUnit()
            local thistype this = thistype(sapperTable[killed])
            if this != 0 then
            
                static if SAPPER_EXPLOSION_USE_CASTER_AS_SOURCE then
                    call damageAOE(caster, x, y, SAPPER_EXPLOSION_RADIUS, SAPPER_EXPLOSION_DAMAGE(lvl))
                else
                    call damageAOE(sapper, x, y, SAPPER_EXPLOSION_RADIUS, SAPPER_EXPLOSION_DAMAGE(lvl))
                endif
                    
                static if SAPPER_EXPLOSION_DAMAGE_DESTRUCTS then
                    call damageDestructablesAOE(caster, x, y, SAPPER_EXPLOSION_RADIUS, SAPPER_EXPLOSION_DAMAGE(lvl))
                endif
                if SAPPER_EXPLOSION_EFFECT != "" then
                    call DestroyEffect(AddSpecialEffect(SAPPER_EXPLOSION_EFFECT, x, y))
                endif
            else
                //loop through everything and check targets. if the dying unit is a target of any sapper, find a new one
                //or order it to move to the target's location if enabled
                set this = first
                loop
                    exitwhen this == 0
                    if killed == target then
                        set oldTargetDied = true
                        if not searchForTarget() then
                            static if not SAPPER_STOP_WHEN_TARGET_DIES then
                                set tx = GetUnitX(killed)
                                set ty = GetUnitY(killed)
                                call IssuePointOrder(sapper, "smart", tx, ty)
                            else
                                call PauseUnit(sapper, true)
                                call IssueImmediateOrder(sapper, "stop")
                                call PauseUnit(sapper, false)
                            endif
                        endif
                    endif
                    set this = next
                endloop
            endif
            set killed = null
            return false
        endmethod
        
        static method onUnitOrder takes nothing returns boolean
            local thistype this = thistype(sapperTable[GetOrderedUnit()])
            if this != 0 and not ignoreOrders then
                set ignoreOrders = true
                call moveSapper()
                set ignoreOrders = false
            endif
            return false
        endmethod
        
        static method onInit takes nothing returns nothing
            set sapperTable = HandleTable.create()
            set targetTable = HandleTable.create()
            
            set dmg = xedamage.create()
            set dtype = SAPPER_EXPLOSION_DAMAGE_TYPE
            set atype = SAPPER_EXPLOSION_ATTACK_TYPE
            set damageAllies = SAPPER_EXPLOSION_DAMAGE_ALLIED
            
            //! runtextmacro SAPPER_INIT_SOUNDS()
            
            call TriggerAddCondition(onDeath, Condition(function thistype.onUnitDeath))
            
            call TriggerRegisterAnyUnitEventBJ(onOrder, EVENT_PLAYER_UNIT_ISSUED_ORDER)
            call TriggerRegisterAnyUnitEventBJ(onOrder, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
            call TriggerRegisterAnyUnitEventBJ(onOrder, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
            call TriggerRegisterAnyUnitEventBJ(onOrder, EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER)
            call TriggerAddCondition(onOrder, Condition(function thistype.onUnitOrder))
        endmethod
        
    endstruct
            
    private struct Zeppelin
        
        unit caster = null
        
        real cos = 0.00
        real sin = 0.00
        real moved = 0.00
        
        delegate xefx model = 0
        
        sound summonSound = null
        
        integer lvl = 0
        integer sapperDropped = 0
        integer sapperToDrop = 0
        
        real sapperDropCounter = 0.00
        
        static integer zeppelinSummonSound = 0
        static integer zeppelinDropSound = 0
        
        static timer ticker = CreateTimer()
        static real speed = TIMER_INTERVAL * ZEPPELIN_SPEED
        
        implement List
        
        
        method onDestroy takes nothing returns nothing
        
            static if not ZEPPELIN_DESTROY_ON_END then
                call model.hiddenDestroy()
            else
                call model.destroy()
            endif
        
            call listRemove()
            if count == 0 then
                call PauseTimer(ticker)
            endif
        endmethod
        
        static method onLoop takes nothing returns nothing
            local thistype this = first
            
            loop
                exitwhen this == 0
                set x = x + cos
                set y = y + sin
                
                static if USE_SOUNDS then
                    if summonSound != null then
                        call SetSoundPosition(summonSound, x, y, z)
                    endif
                endif
                
                set moved = moved + speed
                set sapperDropCounter = sapperDropCounter + speed
                
                if sapperDropCounter >= ZEPPELIN_MOVE_DISTANCE / (sapperToDrop + 1) then
                    set sapperDropCounter = 0.00
                    call Sapper.create(this)
                    
                    static if USE_SOUNDS then
                        if zeppelinDropSound != 0 then
                            call RunSoundAtPoint(zeppelinDropSound, x, y, z)
                        endif
                    endif
                endif

                if moved >= ZEPPELIN_MOVE_DISTANCE then
                    call destroy()
                endif
                
                set this = next
            endloop
            
        endmethod
        
        static method create takes nothing returns thistype
            local thistype this = allocate()
            
            set sin = ZEPPELIN_SPEED * TIMER_INTERVAL * Sin(Main.angle)
            set cos = ZEPPELIN_SPEED * TIMER_INTERVAL * Cos(Main.angle)
            set caster = Main.caster
            set lvl = GetUnitAbilityLevel(caster, SPELL_ID)
            set sapperToDrop = SAPPER_AMOUNT(lvl)
            
            set model = xefx.create(Main.cx, Main.cy, Main.angle)
            set fxpath = ZEPPELIN_MODEL
            set z = ZEPPELIN_HEIGHT
            set scale = ZEPPELIN_SIZE 
            set teamcolor = GetPlayerColor(GetOwningPlayer(caster))
            set owner = GetOwningPlayer(caster)
            
            static if USE_SOUNDS then
                if ZEPPELIN_SUMMON_SOUND != "" then
                    call RunSoundAtPoint(zeppelinSummonSound, x, y, z)
                endif
            endif
            
            call listAdd()
            if count == 1 then
                call TimerStart(ticker, TIMER_INTERVAL, true, function thistype.onLoop)
            endif
            return this
        endmethod
        
        static method onInit takes nothing returns nothing
            static if USE_SOUNDS then
                if ZEPPELIN_SUMMON_SOUND != "" then
                    set zeppelinSummonSound = DefineSound(ZEPPELIN_SUMMON_SOUND, R2I(ZEPPELIN_SUMMON_SOUND_DUR * 1000), false, true)
                endif
                
                if ZEPPELIN_SAPPER_DROP_SOUND != "" then
                    set zeppelinDropSound = DefineSound(ZEPPELIN_SAPPER_DROP_SOUND, R2I(ZEPPELIN_SAPPER_DROP_SOUND_DUR * 1000), false, true)
                endif
            endif
        endmethod
        
    endstruct
    
    private struct Main extends array
    
        static unit caster = null
        static integer lvl = 0
        static real cx = 0.00
        static real cy = 0.00
        static real angle = 0.00
        
        static method onCast takes nothing returns boolean
            if GetSpellAbilityId() != SPELL_ID then
                return false
            endif
            set caster = GetSpellAbilityUnit()
            set lvl = GetUnitAbilityLevel(caster, SPELL_ID)
            set cx = GetUnitX(caster)
            set cy = GetUnitY(caster)
            
            set angle = Atan2(GetSpellTargetY() - cy, GetSpellTargetX() - cx)
            
            call Zeppelin.create()
            return false
        endmethod
        
        private static trigger cast = CreateTrigger()
        
        static method onInit takes nothing returns nothing
            call TriggerRegisterAnyUnitEventBJ(cast, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(cast, Condition(function thistype.onCast))
            
            static if LIBRARY_AbilityPreload then
                call AbilityPreload(SPELL_ID)
            endif
        endmethod
        
    endstruct
    
    
endscope


Edit No.2:
Fixed a small bug in the moveSapper method, updated map and code.
 

Attachments

  • SuicideSquad.w3x
    190.1 KB · Views: 82
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
The rules should be clarified it looks like.

The dummy model is the "dummy.mdx" model from Vexorian and Anitarf.

MUI is not a requirement for spells (probably why it was not listed) but might significantly if not entirely lower the score of the "triggering" aspect. I should refine the rules to establish what types of triggering I'm referring to.
 

Cokemonkey11

Code Reviewer
Level 29
Joined
May 9, 2006
Messages
3,522
epic historical post

Happiness Overload

Well, I decided I think I'm ready to submit it. I'd like to spend more time commenting my code to help people learn it, but I'm very happy with what I have now so I'll just submit it. This is the most code I think I've ever written for a spell. It's all perfect in my eyes.


z6Bdk.png






libGetFlowerID:
JASS:
library getFlowerID
    globals
        private integer rand
        private constant integer HAPPINESSONE='e001'
        private constant integer HAPPINESSTWO='e002'
        private constant integer HAPPINESSTHR='e003'
        private constant integer HAPPINESSFOU='e004'
    endglobals
    
    function getFlower takes nothing returns integer
        set rand=GetRandomInt(0,3)
        if rand==0 then
            return HAPPINESSONE
        elseif rand==1 then
            return HAPPINESSTWO
        elseif rand==2 then
            return HAPPINESSTHR
        elseif rand==3 then
            return HAPPINESSFOU
        endif
        return 0
    endfunction
endlibrary

libLaunchUnit:
JASS:
//this is the only script I made that requires a third party library. Generally I integrate only the parts of libs I need into my systems, but IsTerrainWalkable is one of my favorites.

library launchUnit requires IsTerrainWalkable
    private struct dat
        unit u
        real xV
        real yV
        real zPrime
    endstruct
    
    globals
        private constant real GRAVITY=4*9.8*.03
        private integer dbIndex=-1
        private dat array datDB
        private timer time=CreateTimer()
    endglobals
    
    private function p takes nothing returns nothing
        local integer index=0
        local effect fx
        local dat tempDat
        local real dir
        loop
            exitwhen index>dbIndex
            set tempDat=datDB[index]
            call SetUnitX(tempDat.u,GetUnitX(tempDat.u)+tempDat.xV)
            call SetUnitY(tempDat.u,GetUnitY(tempDat.u)+tempDat.yV)
            call SetUnitFlyHeight(tempDat.u,GetUnitFlyHeight(tempDat.u)+tempDat.zPrime,0)
            set tempDat.zPrime=tempDat.zPrime-GRAVITY
            if GetUnitFlyHeight(tempDat.u)<25 then
                set fx=AddSpecialEffect("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl",GetUnitX(tempDat.u),GetUnitY(tempDat.u))
                call DestroyEffect(fx)
                if IsTerrainWalkable(GetUnitX(tempDat.u),GetUnitY(tempDat.u))==false then
                    set dir=Atan(tempDat.yV/tempDat.xV)
                    call SetUnitX(tempDat.u,GetUnitX(tempDat.u)-128*Cos(dir))
                    call SetUnitY(tempDat.u,GetUnitY(tempDat.u)-128*Sin(dir))
                    set fx=AddSpecialEffect("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl",GetUnitX(tempDat.u),GetUnitY(tempDat.u))
                    call DestroyEffect(fx)
                endif
                set datDB[index]=datDB[dbIndex]
                set dbIndex=dbIndex-1
                call UnitRemoveAbility(tempDat.u,'Arav')
                call PauseUnit(tempDat.u,false)
                if dbIndex<0 then
                    call PauseTimer(time)
                endif
            endif
            set index=index+1
        endloop
    endfunction
    
    function launch takes unit u, real dir, real zTheta, real power returns nothing
        local dat tempDat=dat.create()
        local real pow=power-(GetUnitState(u,UNIT_STATE_MAX_LIFE)*.01)
        call UnitAddAbility(u,'Arav')
        call SetUnitFlyHeight(u,100,0)
        call PauseUnit(u,true)
        set tempDat.u=u
        set tempDat.xV=pow*Cos(dir)*Cos(zTheta)
        set tempDat.yV=pow*Sin(dir)*Cos(zTheta)
        set tempDat.zPrime=pow*Sin(zTheta)
        set dbIndex=dbIndex+1
        set datDB[dbIndex]=tempDat
        if dbIndex==0 then
            call TimerStart(time,.03,true,function p)
        endif
    endfunction
endlibrary

libHExplosion:
JASS:
library HExplosion requires getFlowerID, launchUnit
    private struct dat
        real xvel
        real yvel
        real zvelPrime
        unit u
    endstruct
    
    globals
        private constant real PROJVEL=(1024-128)*.03
        private constant real GRAVITY=4*9.8*.03
        private group g=CreateGroup()
        private player p
        private integer dmg
        private integer dbIndex=-1
        private timer time=CreateTimer()
        private dat array datDB
        private real savedX
        private real savedY
    endglobals
    
    private function per takes nothing returns nothing
        local integer loopIndex=0
        local dat tempDat
        loop
            exitwhen loopIndex>dbIndex
            set tempDat=datDB[loopIndex]
            call SetUnitX(tempDat.u,GetUnitX(tempDat.u)+tempDat.xvel)
            call SetUnitY(tempDat.u,GetUnitY(tempDat.u)+tempDat.yvel)
            call SetUnitFlyHeight(tempDat.u,GetUnitFlyHeight(tempDat.u)+tempDat.zvelPrime,0)
            set tempDat.zvelPrime=tempDat.zvelPrime-GRAVITY
            if GetUnitFlyHeight(tempDat.u)<50 then
                call RemoveUnit(tempDat.u)
                set datDB[loopIndex]=datDB[dbIndex]
                set dbIndex=dbIndex-1
                if dbIndex<0 then
                    call PauseTimer(time)
                endif
            endif
            set loopIndex=loopIndex+1
        endloop
    endfunction
    
    private function throwFlower takes real arc, real x, real y, real planeTheta returns nothing
        local integer id=getFlower()
        local unit u
        local real newArc=arc*GetRandomReal(.95,1.05)
        local real newPlane=planeTheta*GetRandomReal(.95,1.05)
        local dat tempDat=dat.create()
        set tempDat.u=CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),id,x,y,planeTheta)
        call SetUnitVertexColor(tempDat.u,255,255,255,155)
        call UnitAddAbility(tempDat.u,'Arav')
        call UnitAddAbility(tempDat.u,'Aloc')
        call SetUnitFlyHeight(tempDat.u,100,0)
        call SetUnitPathing(tempDat.u,false)
        call SetUnitX(tempDat.u,x)
        call SetUnitY(tempDat.u,y)
        set tempDat.xvel=PROJVEL*Cos(newPlane)*Cos(newArc)
        set tempDat.yvel=PROJVEL*Sin(newPlane)*Cos(newArc)
        set tempDat.zvelPrime=PROJVEL*Sin(newArc)
        set dbIndex=dbIndex+1
        set datDB[dbIndex]=tempDat
        if dbIndex==0 then
            call TimerStart(time,.03,true,function per)
        endif
    endfunction
    
    private function f takes nothing returns boolean
        local real ang
        local real zT
        local real dist
        if IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)==false then
            call UnitDamageTarget(GetFilterUnit(),GetFilterUnit(),dmg,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
            set ang=Atan2(GetUnitY(GetFilterUnit())-savedY,GetUnitX(GetFilterUnit())-savedX)
            set dist=SquareRoot((GetUnitX(GetFilterUnit())-savedX)*(GetUnitX(GetFilterUnit())-savedX)+(GetUnitY(GetFilterUnit())-savedY)*(GetUnitY(GetFilterUnit())-savedY))
            set zT=Atan(100/dist)
            call launch(GetFilterUnit(),ang,zT,PROJVEL)
        endif
        return false
    endfunction
    
    function happyExplosion takes real x, real y, integer hp, player deathPlayer returns nothing
        local integer index=0
        local integer arcIndex=1
        set p=deathPlayer
        set dmg=hp/10
        set savedX=x
        set savedY=y
        call GroupEnumUnitsInRange(g,x,y,100+hp,Filter(function f))
        call throwFlower(bj_PI/2,x,y,0)
        loop
            exitwhen arcIndex>7
            loop
                exitwhen index>15
                call throwFlower(bj_PI/16*arcIndex,x,y,bj_PI/8*index)
                set index=index+1
            endloop
            set index=0
            set arcIndex=arcIndex+1
        endloop
    endfunction
endlibrary

castHappiness:
JASS:
scope castHappiness initializer i
    private struct muiDat
        unit caster
        unit target
        integer steps
    endstruct
    
    private struct projDat
        unit target
        unit projectile
        integer steps
        real xOff
        real yOff
    endstruct
    
    globals
        private constant integer HAPPINESSID='A001'
        private constant real    OFFSET=40.
        private integer stackIndex=-1
        private timer time=CreateTimer()
        private muiDat array muiDB
        private integer moveIndex=-1
        private timer fastTime=CreateTimer()
        private projDat array projDB
        private sound snd=CreateSound("Abilities\\Weapons\\BansheeMissile\\BansheeMissileHit2.wav",false,true,true,0,0,"")
    endglobals
    
    private function fastP takes nothing returns nothing
         local integer tempIndex=0
         local integer circleIndex=0
         local real rads
         local real dist
         local real xDis
         local real yDis
         local real cX
         local real cY
         local effect e
         local projDat tempDat
         loop
            exitwhen tempIndex>moveIndex
            set tempDat=projDB[tempIndex]
            set rads=Atan2(GetUnitY(tempDat.target)+tempDat.yOff-GetUnitY(tempDat.projectile),GetUnitX(tempDat.target)+tempDat.xOff-GetUnitX(tempDat.projectile))
            call SetUnitX(tempDat.projectile,GetUnitX(tempDat.projectile)+OFFSET*Cos(rads))
            call SetUnitY(tempDat.projectile,GetUnitY(tempDat.projectile)+OFFSET*Sin(rads))
            set xDis=GetUnitX(tempDat.target)-GetUnitX(tempDat.projectile)
            set yDis=GetUnitY(tempDat.target)-GetUnitY(tempDat.projectile)
            set dist=SquareRoot(xDis*xDis+yDis*yDis)
            if dist<80 then
                call RemoveUnit(tempDat.projectile)
                call SetSoundPosition(snd,GetUnitX(tempDat.target),GetUnitY(tempDat.target),50)
                call SetSoundVolume(snd,127)
                call StartSound(snd)
                call SetUnitMoveSpeed(tempDat.target,GetUnitMoveSpeed(tempDat.target)-4)
                call SetUnitState(tempDat.target,UNIT_STATE_LIFE,GetUnitState(tempDat.target,UNIT_STATE_LIFE)+1)
                call SetUnitTimeScale(tempDat.target,1-.02*tempDat.steps)
                call SetUnitScale(tempDat.target,1+.025*tempDat.steps,1+.025*tempDat.steps,1+.025*tempDat.steps)
                call SetUnitVertexColor(tempDat.target,255,255-tempDat.steps*5/2,255-tempDat.steps*5/2,255)
                if tempDat.steps>50 and IsUnitType(tempDat.target,UNIT_TYPE_DEAD)==false then
                    set e=AddSpecialEffect("Objects\\Spawnmodels\\Human\\HumanLargeDeathExplode\\HumanLargeDeathExplode.mdl",GetUnitX(tempDat.target),GetUnitY(tempDat.target))
                    call DestroyEffect(e)
                    set e=AddSpecialEffect("Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl",GetUnitX(tempDat.target),GetUnitY(tempDat.target))
                    call DestroyEffect(e)
                    call happyExplosion(GetUnitX(tempDat.target),GetUnitY(tempDat.target),R2I(GetUnitState(tempDat.target,UNIT_STATE_MAX_LIFE)),GetOwningPlayer(tempDat.target))
                    call KillUnit(tempDat.target)
                    call SetUnitScale(tempDat.target,.01,.01,.01)
                    call UnitAddAbility(tempDat.target,'Arav')
                    call SetUnitFlyHeight(tempDat.target,2000,0)
                endif
                set projDB[tempIndex]=projDB[moveIndex]
                set moveIndex=moveIndex-1
            endif
            set tempIndex=tempIndex+1
         endloop
         if moveIndex<0 then
            call PauseTimer(fastTime)
        endif
    endfunction
    
    private function p takes nothing returns nothing
        local integer tempIndex=0
        local integer rand
        local integer createID
        local muiDat tempDat
        local real offs
        local real theta
        loop
            exitwhen tempIndex>stackIndex
            set tempDat=muiDB[tempIndex]
            if IsUnitType(tempDat.caster,UNIT_TYPE_DEAD)==false and IsUnitType(tempDat.target,UNIT_TYPE_DEAD)==false and GetUnitCurrentOrder(tempDat.caster)==OrderId("channel") then
                set createID=getFlower()
                set moveIndex=moveIndex+1
                set tempDat.steps=tempDat.steps+1
                set projDB[moveIndex]=projDat.create()
                set projDB[moveIndex].target=tempDat.target
                set projDB[moveIndex].projectile=CreateUnit(GetOwningPlayer(tempDat.caster),createID,GetUnitX(tempDat.caster),GetUnitY(tempDat.caster),GetUnitFacing(tempDat.caster))
                set projDB[moveIndex].steps=tempDat.steps
                set theta=GetRandomReal(0,2*bj_PI)
                set offs=GetRandomReal(5,75)
                set projDB[moveIndex].xOff=offs*Cos(theta)
                set projDB[moveIndex].yOff=offs*Sin(theta)
                call UnitAddAbility(projDB[moveIndex].projectile,'Arav')
                call SetUnitFlyHeight(projDB[moveIndex].projectile,50,0)
                call SetUnitPathing(projDB[moveIndex].projectile,false)
                call UnitAddAbility(projDB[moveIndex].projectile,'Aloc')
                call SetUnitX(projDB[moveIndex].projectile,GetUnitX(tempDat.caster))
                call SetUnitY(projDB[moveIndex].projectile,GetUnitY(tempDat.caster))
                if moveIndex==0 then
                    call TimerStart(fastTime,.03,true,function fastP)
                endif
            else
                set muiDB[tempIndex]=muiDB[stackIndex]
                set stackIndex=stackIndex-1
                if stackIndex<0 then
                    call PauseTimer(time)
                endif
            endif
            set tempIndex=tempIndex+1
        endloop
    endfunction
    
    private function c takes nothing returns boolean
        local effect fx
        if GetSpellAbilityId()==HAPPINESSID then
            set stackIndex=stackIndex+1
            set muiDB[stackIndex]=muiDat.create()
            set muiDB[stackIndex].caster=GetTriggerUnit()
            set muiDB[stackIndex].target=GetSpellTargetUnit()
            call SetUnitScale(GetSpellTargetUnit(),1,1,1)
            call SetUnitVertexColor(GetSpellTargetUnit(),255,255,255,255)
            set fx=AddSpecialEffect("Abilities\\Spells\\NightElf\\Blink\\BlinkTarget.mdl",GetUnitX(GetSpellTargetUnit()),GetUnitY(GetSpellTargetUnit()))
            call DestroyEffect(fx)
            if stackIndex==0 then
                call TimerStart(time,.1,true,function p)
            endif
        endif
        return false
    endfunction
    
    private function i takes nothing returns nothing
        local trigger t=CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t,Condition(function c))
    endfunction
endscope




edit: Here's the map with lots of very detailed and helpful comments
http://www.hiveworkshop.com/forums/...i-contest-19-a-191874/index6.html#post1878805
 
Last edited:
Level 37
Joined
Mar 6, 2006
Messages
9,240
I think I might not finish the spell... well the spell itself is finished but for some weird reason it lags when I cast it successively, but once the effect wears out, the game gets back to normal... and I don't have anymore time for it coz of lots of exams... ^_^

I can help, let me have a look at it :)

If you have based it on Channel and you're using some art, make sure the Art - Duration isn't at a very low value. Just guessing here.
 
WOW
I've been seeing a loooooooot of vJASS in this thread o.o

You guys make me look like SHIT!
I'm coding my spell in GUI (ntn special)
...
*idea*
I'll write in GUI then convert to JASS, remove BJs, split trigger into functions, add globals, make it a scope and there you have it :) .. a vJASS spell :D
 

Cokemonkey11

Code Reviewer
Level 29
Joined
May 9, 2006
Messages
3,522
WOW
I've been seeing a loooooooot of vJASS in this thread o.o

You guys make me look like SHIT!
I'm coding my spell in GUI (ntn special)
...
*idea*
I'll write in GUI then convert to JASS, remove BJs, split trigger into functions, add globals, make it a scope and there you have it :) .. a vJASS spell :D

If you can do that, you're about 85% done learning vJass :p
 
This would be my entry:

--SUPER FROST JOKE--

JASS:
/*

    Super Frost Joke by Adiktuz
    
    Description:
        The caster cracks a joke which can freeze enemy units around him
    
    Configurables:
        -The jokes
        -The chances of freezing for each joke
        -The duration of the freeze
        -The targets of the freeze
        -The damage of the freeze
        -The AoE of the freeze
    
    How to import:
        -Copy and paste this code into your trigger editor
        -Copy the two abilities and the buff
        -Create a dummy caster if you don't have one or copy the one on this map
        -Change the rawcodes to fit the new rawcodes on your map
        -Edit the configurables to your liking
        -Add your jokes using [function RegisterJokes takes string joke, real chance]
            *examples given on InitJokes trigger
        
        IMPORTANT: On the gameplay constants, set the UNIT MIN MOVESPEED to 0.00
    
    Credits:
        Jesus4Lyf for Timer32
    
*/

library SuperFrostJoke initializer Init requires T32

    globals
    
        //The rawcode of the Frost joke spell
        private constant integer FJ_SPELL_ID = 'A000'
        
        //The rawcode of the frost joke buff placer (the soulburn-based ability)
        private constant integer FJ_BUFFPLACER_ID = 'A001'
        
        //The rawcode of the frost joke buff which the buffplacer uses
        private constant integer FJ_BUFF_ID = 'B000'
        
        //The rawcode of the dummy unit
        private constant integer DUMMY_ID = 'h000'
        
        //Checks if the FJ deals damage, if yes be sure to set the damage amount at the function below the globals
        private constant boolean DEALS_DAMAGE = false
        
        //Checks if the FJ deals damage after the duration, if yes be sure to set the damage amount at the function below the globals
        private constant boolean DEALS_END_DAMAGE = true
        
        /*
            Checks if the duration of the buff will stack if a unit gets hit by SFJ while still
            being affected by a previous one, if false, the new cast will overwrite the older one
        */
        private constant boolean STACK_TIME = false
        
        //The attack type of the primary damage
        private constant attacktype ATPD = ATTACK_TYPE_NORMAL
        
        //The damage type of the primary damage
        private constant damagetype DTPD = DAMAGE_TYPE_NORMAL
        
        //The attack type of the secondary damage
        private constant attacktype ATSD = ATTACK_TYPE_NORMAL
        
        //The damage type of the secondary damage
        private constant damagetype DTSD = DAMAGE_TYPE_NORMAL
        
        //DO NOT EDIT BELOW THIS LINE UP TO THE NEXT COMMENT
        private string array FrostJokes //[8190]
        
        private real array FrostChances //[8190]
        
        private integer JokesTotal = 0
        
        private group FJ_Group = CreateGroup()
        
        private boolean array IsJokeShown
        
        private hashtable SFJ_Hash = InitHashtable()
        
        //END of DO NOT EDIT
    endglobals
    
    //Set the damage formula using this function
    private function GetDamage takes integer level returns real
        return 0.00
    endfunction
    
    //Set the end damage formula using this function
    private function GetEndDamage takes integer level returns real
        return 75.00*level
    endfunction
    
    //Set the buff duration using this function
    private function GetDuration takes integer level returns real
        return 5.00
    endfunction
    
    //Set the chance formula using this function
    private function GetChance takes integer level, integer index returns real
        return FrostChances[index]
    endfunction
    
    //Set The AoE formula using this function
    private function GetAoE takes integer level returns real
        return 250.00*level
    endfunction
    
    //The frost joke struct which handles most of the system's work
    private struct FrostJokeStruct
    
        unit target //the units hit by SFJ
        
        unit caster //the caster of SFJ
        
        integer abillevel //the ability level of SFJ for the caster
        
        real timeleft //the timeleft for the duration of the buff
        
        static thistype data
        
        static unit TempUnit = null
        
        static unit FiltUnit = null
        
        static unit TempCaster = null
        
        static real chance = 0.00
        
        static integer joke
        
        static integer level
        
        static integer playern
        
        static player controller
        
        static integer id
        
        /*
            the periodic method for the buff duration, executed by T32
        */
        private method periodic takes nothing returns nothing
            set this.timeleft = this.timeleft - T32_PERIOD
            if this.timeleft <= 0.00 then
                call this.stopPeriodic()
                call UnitRemoveAbility(this.target, FJ_BUFFPLACER_ID)
                call UnitRemoveAbility(this.target, FJ_BUFF_ID)
                call FlushChildHashtable(SFJ_Hash, GetHandleId(this.target))
                if DEALS_END_DAMAGE then
                    call UnitDamageTarget(this.caster, this.target, GetEndDamage(this.abillevel), false, false, ATPD, DTPD, null)
                endif
                call this.destroy()
            endif
        endmethod
        
        //implements the T32x module
        implement T32x
        
        /*
            the method run when a unit gets hit by the SFJ
        */
        static method create takes unit target, unit caster, integer level returns thistype
            set thistype.id = GetHandleId(target)
            set data = LoadInteger(SFJ_Hash, thistype.id, 0)
            /*
                if the unit is currently unaffected by a SFJ, a new instance is created
                else we override the current one or increase the time depending 
                on the global STACK_TIME
            */
            if data == 0 then 
                set data = thistype.allocate()
                set data.target = target
                set data.caster = caster
                set data.abillevel = level
                set data.timeleft = GetDuration(level)
                set thistype.TempCaster = CreateUnit(GetOwningPlayer(caster), DUMMY_ID,GetUnitX(caster), GetUnitY(caster), 0.00)
                call UnitApplyTimedLife(thistype.TempCaster, 'BTLF', .5)
                call SetUnitExploded(thistype.TempCaster, true)
                call UnitAddAbility(thistype.TempCaster, FJ_BUFFPLACER_ID)
                call IssueTargetOrder(thistype.TempCaster, "soulburn", target)
                call data.startPeriodic()
                call SaveInteger(SFJ_Hash, thistype.id, 0, data)
            else
                set data.target = target
                set data.caster = caster
                set data.abillevel = level
                if STACK_TIME then
                    set data.timeleft = data.timeleft + GetDuration(level)
                else
                    set data.timeleft = GetDuration(level)
                endif
            endif
            if DEALS_DAMAGE then
                call UnitDamageTarget(caster, target, GetDamage(level), false, false, ATPD, DTPD, null) 
            endif
            return data
        endmethod
        
        /*
            this method checks if a unit will get affected by the SFJ or not
        */
        static method FrostJokeGroupLoop takes nothing returns boolean
            set thistype.FiltUnit = GetFilterUnit()
            set thistype.controller = GetOwningPlayer(FiltUnit)
            set thistype.playern = GetPlayerId(thistype.controller)
            if not IsJokeShown[thistype.playern] then
                set IsJokeShown[thistype.playern] = true
                call DisplayTextToPlayer(thistype.controller, 0, 0, FrostJokes[thistype.joke])
            endif
        
            //checks if the unit is alive
            if GetWidgetLife(FiltUnit) > .405 and /*
                checks if the unit is an enemy
            */ IsPlayerEnemy(thistype.controller, GetOwningPlayer(thistype.TempUnit)) and /*
                checks if the unit will be frozen
            */ GetRandomReal(0.00, 100.00) <= thistype.chance then
                call FrostJokeStruct.create(FiltUnit, thistype.TempUnit ,thistype.level)
            endif
            return false
        endmethod
        
        /*
          this method picks every unit around the caster of SFJ and passes them to the method above  
        */
        static method FrostJoke takes nothing returns boolean
            local integer i = 0
            set thistype.TempUnit = GetTriggerUnit()
            set thistype.level = GetUnitAbilityLevel(thistype.TempUnit, FJ_SPELL_ID)
            set thistype.joke = GetRandomInt(0, JokesTotal)
            set thistype.chance = GetChance(thistype.level, thistype.joke)
            if GetSpellAbilityId() == FJ_SPELL_ID then
                call GroupEnumUnitsInRange(FJ_Group, GetUnitX(thistype.TempUnit), GetUnitY(thistype.TempUnit), GetAoE(thistype.level), Condition(function thistype.FrostJokeGroupLoop))
            endif
            loop
                exitwhen i > 15
                set IsJokeShown[i] = false
                set i = i + 1
            endloop
            return false
        endmethod
    
    endstruct
    
    //The init method of this library
    private function Init takes nothing returns nothing
        local integer i = 0
        local trigger t = CreateTrigger()
        loop
            exitwhen i > 15
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            set i = i + 1
        endloop
        call TriggerAddCondition(t, Condition(function FrostJokeStruct.FrostJoke))
        set t = null
    endfunction
    
    //The function used to register jokes
    function RegisterJokes takes string joke, real chance returns nothing
        set FrostJokes[JokesTotal] = joke
        set FrostChances[JokesTotal] = chance
        set JokesTotal = JokesTotal + 1
    endfunction
    
endlibrary
 

Attachments

  • SFJ.w3x
    31.7 KB · Views: 56
My first MUI spell. :D

Miracle Shot

186044-albums3197-picture44720.png


  • Cast Miracle Shot
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Miracle Shot
    • Actions
      • -------- Sets the caster in a variable for later use. --------
      • Set MiracleShot_Caster = (Casting unit)
      • -------- Sets the chance to fail. --------
      • Set MiracleShot_Chance_to_Fail = (Random integer number between 0 and 101)
      • -------- Sets the level of the ability to determine what the level of Miracle Shot for that unit is. --------
      • Set MiracleShot_Level_of_Ability = (Level of Miracle Shot for MiracleShot_Caster)
      • -------- Sets the target of Miracle Shot. --------
      • Set MiracleShot_Target = (Target unit of ability being cast)
      • -------- These are the actions for Level 1 of Miracle Shot. --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • MiracleShot_Level_of_Ability Equal to 1
        • Then - Actions
          • -------- This deals the damage to the target of the spell. --------
          • Unit - Cause MiracleShot_Caster to damage MiracleShot_Target, dealing 50.00 damage of attack type Spells and damage type Normal
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • MiracleShot_Chance_to_Fail Less than or equal to 50
            • Then - Actions
              • -------- This creates a dummy that'll immobilize the caster; if the MiracleShot_Chance_to_Fail variable's value is at most 50. --------
              • Unit - Create 1 Dummy [Miracle Shot] for (Owner of MiracleShot_Caster) at (Position of MiracleShot_Caster) facing Default building facing degrees
              • -------- This adds an expiration timer that will kill the unit after a few seconds; to reduce the amount of units in the map. --------
              • Unit - Add a 2.00 second Generic expiration timer to MiracleShot_Dummy
              • -------- This recognizes the dummy unit for the next action. --------
              • Set MiracleShot_Dummy = (Last created unit)
              • -------- This casts the immobilization part of the spell. --------
              • Unit - Order MiracleShot_Dummy to Human Mountain King - Storm Bolt MiracleShot_Caster
              • -------- This deals damage to the caster. --------
              • Unit - Cause MiracleShot_Caster to damage MiracleShot_Caster, dealing 70.00 damage of attack type Spells and damage type Normal
              • -------- This is the animation for the immobilization. --------
              • Animation - Play MiracleShot_Caster's death animation
              • -------- This creates a floating text that makes you look bad. :D --------
              • Floating Text - Create floating text that reads |cffff0000FAIL|r above MiracleShot_Caster with Z offset 0.00, using font size 15.00, color (100.00%, 0.00%, 0.00%), and 0.00% transparency
              • -------- This recognizes the floating text for the next actions. --------
              • Set MiracleShot_Floating_Text = (Last created floating text)
              • -------- This disables the permanence of the floating text. --------
              • Floating Text - Change MiracleShot_Floating_Text: Disable permanence
              • -------- This sets the amount of time of which the text disappears. --------
              • Floating Text - Change the lifespan of MiracleShot_Floating_Text to 5.00 seconds
              • -------- This sets the fade time of the text. --------
              • Floating Text - Change the fading age of MiracleShot_Floating_Text to 3.50 seconds
            • Else - Actions
        • Else - Actions
          • -------- These are the actions for Level 2 of Miracle Shot. --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • MiracleShot_Level_of_Ability Equal to 2
            • Then - Actions
              • -------- This deals the damage to the target of the spell. --------
              • Unit - Cause MiracleShot_Caster to damage MiracleShot_Target, dealing 70.00 damage of attack type Spells and damage type Normal
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • MiracleShot_Chance_to_Fail Less than or equal to 75
                • Then - Actions
                  • -------- This creates a dummy that'll immobilize the caster; if the MiracleShot_Chance_to_Fail variable's value is at most 75. --------
                  • Unit - Create 1 Dummy [Miracle Shot] for (Owner of MiracleShot_Caster) at (Position of MiracleShot_Caster) facing Default building facing degrees
                  • -------- This adds an expiration timer that will kill the unit after a few seconds; to reduce the amount of units in the map. --------
                  • Unit - Add a 2.00 second Generic expiration timer to MiracleShot_Dummy
                  • -------- This recognizes the dummy unit for the next action. --------
                  • Set MiracleShot_Dummy = (Last created unit)
                  • -------- This casts the immobilization part of the spell. --------
                  • Unit - Order MiracleShot_Dummy to Human Mountain King - Storm Bolt MiracleShot_Caster
                  • -------- This deals damage to the caster. --------
                  • Unit - Cause MiracleShot_Caster to damage MiracleShot_Caster, dealing 90.00 damage of attack type Spells and damage type Normal
                  • -------- This is the animation for the immobilization. --------
                  • Animation - Play MiracleShot_Caster's death animation
                  • -------- This creates a floating text that makes you look bad. :D --------
                  • Floating Text - Create floating text that reads |cffff0000FAIL|r above MiracleShot_Caster with Z offset 0.00, using font size 15.00, color (100.00%, 0.00%, 0.00%), and 0.00% transparency
                  • -------- This recognizes the floating text for the next actions. --------
                  • Set MiracleShot_Floating_Text = (Last created floating text)
                  • -------- This disables the permanence of the floating text. --------
                  • Floating Text - Change MiracleShot_Floating_Text: Disable permanence
                  • -------- This sets the amount of time of which the text disappears. --------
                  • Floating Text - Change the lifespan of MiracleShot_Floating_Text to 5.00 seconds
                  • -------- This sets the fade time of the text. --------
                  • Floating Text - Change the fading age of MiracleShot_Floating_Text to 3.50 seconds
                • Else - Actions
            • Else - Actions
              • -------- These are the actions for Level 3 of Miracle Shot. --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • MiracleShot_Level_of_Ability Equal to 3
                • Then - Actions
                  • -------- This deals the damage to the target of the spell. --------
                  • Unit - Cause MiracleShot_Caster to damage MiracleShot_Target, dealing 90.00 damage of attack type Spells and damage type Normal
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • MiracleShot_Chance_to_Fail Less than or equal to 100
                    • Then - Actions
                      • -------- This creates a dummy that'll immobilize the caster. --------
                      • Unit - Create 1 Dummy [Miracle Shot] for (Owner of MiracleShot_Caster) at (Position of MiracleShot_Caster) facing Default building facing degrees
                      • -------- This adds an expiration timer that will kill the unit after a few seconds; to reduce the amount of units in the map. --------
                      • Unit - Add a 2.00 second Generic expiration timer to MiracleShot_Dummy
                      • -------- This recognizes the dummy unit for the next action. --------
                      • Set MiracleShot_Dummy = (Last created unit)
                      • -------- This casts the immobilization part of the spell. --------
                      • Unit - Order MiracleShot_Dummy to Human Mountain King - Storm Bolt MiracleShot_Caster
                      • -------- This deals damage to the caster. --------
                      • Unit - Cause MiracleShot_Caster to damage MiracleShot_Caster, dealing 110.00 damage of attack type Spells and damage type Normal
                      • -------- This is the animation for the immobilization. --------
                      • Animation - Play MiracleShot_Caster's death animation
                      • -------- This creates a floating text that makes you look bad. :D --------
                      • Floating Text - Create floating text that reads |cffff0000FAIL|r above MiracleShot_Caster with Z offset 0.00, using font size 15.00, color (100.00%, 0.00%, 0.00%), and 0.00% transparency
                      • -------- This recognizes the floating text for the next actions. --------
                      • Set MiracleShot_Floating_Text = (Last created floating text)
                      • -------- This disables the permanence of the floating text. --------
                      • Floating Text - Change MiracleShot_Floating_Text: Disable permanence
                      • -------- This sets the amount of time of which the text disappears. --------
                      • Floating Text - Change the lifespan of MiracleShot_Floating_Text to 5.00 seconds
                      • -------- This sets the fade time of the text. --------
                      • Floating Text - Change the fading age of MiracleShot_Floating_Text to 3.50 seconds
                    • Else - Actions
                • Else - Actions
Enjoy. Will probably suck... :\
 

Attachments

  • SSM#18.w3x
    87.8 KB · Views: 49
Level 9
Joined
Jan 23, 2008
Messages
384
Ok ! spell is done ...
Goblins + Dynamite + Ass ... that's all you need to know about this spell :goblin_boom: !

Plunges a stick of dynamite up the target's ass and lights it up. After 3 seconds pass the dynamite explodes dealing damage to the target and its surroundings sending the target flying.
Level 1 - 100 Damage.
Level 2 - 200 Damage.
Level 3 - 300 Damage.


~MA
 

Attachments

  • PS1.JPG
    PS1.JPG
    396.3 KB · Views: 79
  • PS2.JPG
    PS2.JPG
    403.4 KB · Views: 83
  • S&SMiniContest#19Entry~MA.w3x
    32.2 KB · Views: 38
Status
Not open for further replies.
Top