SPELL CONTEST #2 | Theme: Forbidden Arts | Submissions

Romek

Super Moderator
Reaction score
963
Spell Contest #2
Submission Thread

Post your spell contest submissions here.
Only one post per member here. Do not post anything except your submission.
Feel free to make your posts look nice, with a bit of detail about the spell.

RULES:
- JASS and GUI are both allowed
- Hybrid-code is not allowed (Converted GUI, pseudo locals)
- Custom script in GUI to remove leaks is allowed
- Imports are not allowed, excluding Vexorians caster model
- Attaching systems are allowed
- 1 submission per member, 1 member per submission

Main Contest Thread

 

Draphoelix

It's not the wintercold that's killing me
Reaction score
132
Cauldron of Skulls

First submission!

Cauldron of Skulls

Type: GUI and MUI
Update: Fixed the periodic trigger not to be random. Also increased the map size from 34.9 to 35 so it would be nicer (nah, I'm just kidding. Not sure why it happens).
00271wh5.jpg

00271la7.jpg

00271ub4.jpg
 

Attachments

  • demomap_contest_Draphoelix.w3x
    35 KB · Views: 240

Tom Jones

N/A
Reaction score
437
screenieiconoi9.jpg

Ancient Flames.

Sends forth a ball of ancient flames. The ball explodes when it reaches a targeted point, spreading the ancient flames in an area and dealing damage to units who touches the flames.

Level 1 - 40 initial damage, 10 damage over time.
Level 2 - 50 initial damage, 15 damage over time.
Level 3 - 60 initial damage, 20 damage over time.

Screenie:
screeniesa3.jpg


Map:
View attachment Ancient Flames.w3x
 

scorpion182

New Member
Reaction score
5
bp2iw3.jpg


Black Parade v1.3 by scorpion182

GUI/JASS/vJASS? vJASS
MUI?Yes

Requires :
- vJASS compiler
- TimerUtils by Vexorian
- Function CopyGroup made by Blade.dk;
- PUI by Cohadar

Ability Type: Channeling
Target Type: Point
Effect: Area Damage, Summon, Animate Dead, HP & Mana Recovery
Cooldown:60 seconds
Channeling Duration: 45 seconds
Mana Cost: 100
Description:
Arthas calls his undead minions out to come to the battlefield and fight alongside him. If a minion crash enemy, he will deal amount of damage, and stay in the battlefield to fight. If an enemy unit killed by those stayed minions, it will be reborn as an undead for 45 seconds to aid Arthas, and its soul will be consumed to recover Arthas' hp and mana by 25.

Level 1 - Deals 50 damage per hit, summon weak minions.
Level 2 - Deals 100 damage per hit, summon stronger minions.
Level 3 - Deals 150 damage per hit, summon powerful minions.

Screen:
18992354rx5.jpg


History:
v1.0 First Upload
v1.1 Fixed Code and Remove Useless Variables
v1.2 Remove Useless member struct
v1.3 Make the heal MUI
JASS:
 

Attachments

  • demomap_contest_Black Parade.w3x
    46.7 KB · Views: 238

lindenkron

You can change this now in User CP
Reaction score
102
Dark Magic
So, this is my first submission :p. We'll see how it goes.

4rqe4z.jpg

Language?
GUI / MUI
Leakless?
To my knowledge, yes
Lagless?
If you don't use more then 2 spells at the time. :p
Working?
Yes
Was it fun?
Yup :D

Modified one way
Circle range: 250
Spell time: 3 seconds
2iadf7a.jpg



Modified another way
Circle range: 500
Spell time: 3 seconds
2zo97v5.jpg


Good luck all :thup:,
-Lindenkron

Edit:
1.1
-Fixed leak.
1.2
-Changed target special effect to something more rare and suitable.
-Changed attack type to "Point Target" to avoid the "Cannot target self" message
-Added "Options - Targeting Image"
 

Attachments

  • lindenkron demomap_contest 1.2.w3x
    40.8 KB · Views: 236

Exfyre

hmm...
Reaction score
60
Corrupt​
Corrupt
Corrupts a target unit, forcing it to attack allied units whenever it tries to attack an enemy unit. If a unit is killed by an allied unit under this effect, the killer will die instantly. While the afflicted unit is not attacking, it loses 15 hp/second.

Lasts 10 seconds

MUI?
Yes
Leakless?
Yes
Lagless?
Yes
JASS/GUI?
Both (not pseudo jass)
Multiple Levels?
Sadly, no.
2 Corrupted units attacking each other
eqtc0x.jpg


1 corrupted unit attacking allies that are attacking the hero.
zog7xj.jpg


Tooltip
ncffhs.jpg


Note that the tooltip says "If a unit is killed by an allied unit under this effect, the killer will die instantly." NOT "If a unit is killed by an allied unit as a result of this effect, the killer will die instantly." The killer must be corrupted to die.

Forgot to upload map
 

Attachments

  • demomap_contest_Exfyre_Corrupt.w3x
    25.9 KB · Views: 247

09103094

New Member
Reaction score
3
Forbidden Dagger

Forbidden Dagger
images

by 09103094

This spell is intended for a hero who utilizes invisibility to their advantage. By combining three spells, Shadow Strike, Invisibility, and Blink, an interesting subtlety spell is created.
I came up with this spell to be synergistic with 3 other spells. One would be a spell which would decrease the movement speed and turning speed of a unit; this would allow the hero to get chase down and get behind its target. Another would be a passive ability, granting a chance on hit to turn invisible, in case the hero needed to get behind the target, wait for cool downs, or just simply run away. The ultimate would combine these 3 abilities to make a cunning hero who, when played right, is invisible most of the time, and dealing deadly damage. It would go along these lines: "a chance on hit when behind an enemy, you critical hit for 5x.."

This is merely my synopsis of its intention, but I hope that you can enjoy the spell by itself.


Forbidden Dagger

Spell Detail
forbiddendaggerspelldes.png


1st and 2nd Stage:
Throw poison dagger and go invisible
forbiddendaggerfirstsec.png


Finally, the hero blinks towards the target (remaining invisible)
forbiddendaggerthridsta.png


if there are any problems with it, please post me
 

Attachments

  • 09103094demomap_contest.w3x
    31.4 KB · Views: 266
Reaction score
91
Malevolence
v1.0

(Spell was named "Incinerate" but had to overhaul it).

GUI/JASS/vJASS? vJASS.
MUI? Yes.
Works for 3+ levels? Yes.
Lagless? Even though I preload, it still lags on first cast, but only then.
Requires? Table & PUI v5.1, and of course JNGP v1.5b.
Should follow JESP. Sort of.

Description:
The Hero creates a pact with demons that is known to be forbidden amongst all mortals - he will spawn fearsome shades but will pay with a portion of his life. These summons will randomly move around the caster and attack nearby enemies, corroding their armor on each strike by a stacking value, while constantly transforming into waves of darkness, charging at random locations and blasting foes they acquire. Lasts a fixed amount of time or until the Hero dies. Armor is reduced by 2 each hit.

JASS:

scope Malevolence initializer Init 

// Created by Tyrande_ma3x for the spell contest at <a href="http://thehelper.net/" target="_blank" class="link link--external" rel="nofollow ugc noopener">http://thehelper.net/</a>.
// Theme: Forbidden Arts
// Requires: PUI v5.1 and Table.

//===========================================================================

// DO NOT CHANGE THE TEXTMACROS BELLOW!

// Stack is the counter for the armor stack.
//! runtextmacro PUI_PROPERTY(&quot;private&quot;, &quot;integer&quot;, &quot;STACK&quot;, &quot;1&quot;)
// TIME[] is needed to make really accurate stacks.
// Keep in mind that TIME[] is refreshed every time stack is increased.
//! runtextmacro PUI_PROPERTY(&quot;private&quot;, &quot;integer&quot;, &quot;TIME&quot;, &quot;0&quot;)
// This is used to check whether a spirit has casted the Wave ability.
//! runtextmacro PUI_PROPERTY(&quot;private&quot;, &quot;boolean&quot;, &quot;CASTED&quot;, &quot;false&quot;)

//===========================================================================
// C O N F I G U R A T I O N     M E N U
//===========================================================================

globals
    private constant integer AID_MALEVOLENCE = &#039;A004&#039;
    private constant integer AID_WAVE = &#039;A000&#039;
    private constant integer AID_ARMOR_REDUCE = &#039;A005&#039;
    private constant string OID_WAVE = &quot;carrionswarm&quot;
    private constant string OID_ARMOR_REDUCE = &quot;innerfire&quot;
    private constant integer UID_SPIRIT = &#039;n000&#039;
    
// Special effect created on the unit attacked by a spirit.
    private constant string REDUCE_ARMOR_EFFECT = &quot;Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl&quot;
// Attachment point of the effect REDUCE_ARMOR_EFFECT.
    private constant string AP_ARMOR_EFFECT = &quot;chest&quot;
// Effect attached on spirits.
    private constant string SFX_ATTACHED_ON_SPIRIT = &quot;Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl&quot;
// First attachment point of the effect SFX_ATTACHED_ON_SPIRIT.
    private constant string AP_ONE = &quot;hand left&quot;
// Second attachment point of the effect SFX_ATTACHED_ON_SPIRIT.
    private constant string AP_TWO = &quot;hand right&quot;

// Unfortunately, if you want more effects and attachment points you&#039;d have to edit the code...
    
// Maximum armor stack.
    private constant integer MAX_ARMOR_STACK = 4
// Duration of the armor stack. Refreshes when the stack is increased.
    private constant integer ARMOR_STACK_DURATION = 10
    
    // Please do NOT change this or it will screw up the spell.
    // This interval should be perfectly fine.
    // (If you REALLY want to edit - put in range 0.02 - 0.05)
    private constant real PERIOD = 0.03125
    // Do not change this either if you don&#039;t want to bug your stack counter.
    // I put it here just in case someone wants to experiment with my code.
    private constant real STACK_INTERVAL = 1.
    
// Should the spell be preloaded at map initialization?
// You can always disable this and do the preloading yourself,
// but I made sure not to forget anything so first cast isn&#039;t that performance consuming.
    private constant boolean PRELOAD = true
endglobals
// JESP should be changed so that functions take a UNIT, not an integer
// since some people (like me) like to base values on a unit&#039;s stats.
// I haven&#039;t made the bellow values constants since they&#039;ll be inlined anyway.
    private function WAVE_SPEED takes unit cast returns real
        return 1000.
    endfunction
// Area of effect of the wave, used for damaging.
    private function WAVE_RADIUS takes unit cast returns real
        return 200.
    endfunction
// Damage dealt when a spawn in wave form touches an enemy.
    private function WAVE_DAMAGE takes unit cast returns real
        return (GetUnitAbilityLevel(cast, AID_WAVE) * 25.) + 25
    endfunction
// Special effect created as a &quot;trail&quot; after the spirit when it casts wave and charges forward.
    private function WAVE_EFFECT takes unit cast returns string
        return &quot;Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl&quot;
    endfunction
// Attack type of the damaging.
    private function WAVE_ATTACK_TYPE takes unit cast returns attacktype
        return ATTACK_TYPE_MAGIC
    endfunction
// Damage type of the damaging.
    private function WAVE_DAMAGE_TYPE takes unit cast returns damagetype
        return DAMAGE_TYPE_MAGIC
    endfunction
//===========================================================================
// Number of spirits spawned.
    private function SPIRITS_SPAWNED takes unit cast returns integer
        return GetUnitAbilityLevel(cast, AID_MALEVOLENCE) + 1
    endfunction
// Duration of the ability. 
    private function MALEVOLENCE_DURATION takes unit cast returns real
        return 5. + (5. * GetUnitAbilityLevel(cast, AID_MALEVOLENCE))
    endfunction
// Area of effect in which the spirits move, attack and cast spells.
    private function AREA_OF_EFFECT takes unit cast returns real
        return 600.
    endfunction
// Damage dealt to the caster when he casts Incinerate.
    private function DAMAGE_TO_CASTER takes unit cast returns real
        return GetWidgetLife(cast) * ((0.1 * GetUnitAbilityLevel(cast, AID_MALEVOLENCE)) + 0.1)
    endfunction
// If set to true, the health of the caster will be SUBSTRACTED!
// That means it cannot be reduced by shields or invulnerability.
// If it&#039;s false - damage can be blocked by custom shields and invulnerability.
    private function CUT_THROUGH_SHIELD takes unit cast returns boolean
        return false
    endfunction

//===========================================================================
// E N D     O F     C O N F I G U R A T I O N     M E N U
//===========================================================================
    
globals
    private HandleTable ht 
    private group forStack = CreateGroup() // Handles all units with stacks.
endglobals

//===========================================================================
// Custom timer recycling, I hate using systems like TimerUtils... Just preference.
//===========================================================================
globals  
    private timer array TIMERS 
	private integer TIMERS_N = 0 
endglobals 

private function NT takes nothing returns timer  
	if TIMERS_N == 0 then  
		return CreateTimer()  
	endif  
	set TIMERS_N = TIMERS_N - 1 
	return TIMERS[TIMERS_N] 
endfunction 

function RT takes timer t returns nothing  
	call PauseTimer(t)  
	set TIMERS[TIMERS_N] = t 
	set TIMERS_N = TIMERS_N + 1 
endfunction 

//===========================================================================
// Used in spawns&#039; movement and in the spell casting.
private function RandomLocInCircle takes real x, real y, real d returns location
    local real temp
    set d = d * SquareRoot(GetRandomReal(0, 1))
    set temp = d * Cos(GetRandomReal(0, 2) * bj_PI)
    if GetRandomInt(0, 1) &lt; 1 then
        // If it returned only this it would move the units only on top of the Hero.
        return Location(x + temp, y + SquareRoot(d * d - temp * temp)) 
    endif
    // This adds more randomness.
    return Location(x - temp, y - SquareRoot(d * d - temp * temp))
endfunction

// We don&#039;t want leaking boolexprs, do we?
private function ReturnTrue takes nothing returns boolean
    return true
endfunction

//===========================================================================

private struct Data
    unit cast
    integer ticks
    integer moveTicks
    integer maxSpirit
    unit array spirit[100]
    effect array sfx[100]
    
    static method create takes unit cast returns Data
        local Data d = Data.allocate()
        local integer a = 0
        local integer b = 0
        local location loc
        set d.cast = cast
        set d.ticks = R2I(MALEVOLENCE_DURATION(d.cast) / PERIOD)
        set d.moveTicks = GetRandomInt(R2I(1. / PERIOD), R2I(3. / PERIOD)) // Some random stuff.
        loop
            exitwhen a &gt; SPIRITS_SPAWNED(d.cast) - 1
            set d.spirit[a] = CreateUnit(GetOwningPlayer(cast), UID_SPIRIT, GetUnitX(d.cast), GetUnitY(d.cast), GetRandomReal(0., 359.))
            call UnitAddAbility(d.spirit[a], AID_WAVE)
            call UnitAddAbility(d.spirit[a], AID_ARMOR_REDUCE)
            call UnitAddAbility(d.spirit[a], &#039;Aloc&#039;)
            
            set d.sfx<b> = AddSpecialEffectTarget(SFX_ATTACHED_ON_SPIRIT, d.spirit[a], AP_ONE)
            set b = b + 1
            set d.sfx<b> = AddSpecialEffectTarget(SFX_ATTACHED_ON_SPIRIT, d.spirit[a], AP_TWO)
            set b = b + 1
            // Add more effects?
            
            set loc = RandomLocInCircle(GetUnitX(d.cast), GetUnitY(d.cast), AREA_OF_EFFECT(d.cast))
            call IssuePointOrderLoc(d.spirit[a], &quot;move&quot;, loc)
            call RemoveLocation(loc)
            set a = a + 1
        endloop
        set d.maxSpirit = SPIRITS_SPAWNED(d.cast) - 1
        set loc = null
        return d
    endmethod
    
    method onDestroy takes nothing returns nothing
        local integer a = 0
        loop
            exitwhen .spirit[a] == null
            call KillUnit(.spirit[a])
            set a = a + 1
        endloop
        set a = 0
        loop
            exitwhen .sfx[a] == null
            call DestroyEffect(.sfx[a])
            set a = a + 1
        endloop
    endmethod
endstruct

//===========================================================================

private struct Wave
    unit cast
    integer ticks
    real dx
    real dy
    timer tim 
    trigger trig
    
    static method create takes unit cast, real distance, real angle returns Wave
        local Wave w = Wave.allocate()
        set w.cast = cast
        set w.ticks = R2I(distance / (WAVE_SPEED(w.cast) * PERIOD))
        set w.dx = (WAVE_SPEED(w.cast) * PERIOD) * Cos(angle)
        set w.dy = (WAVE_SPEED(w.cast) * PERIOD) * Sin(angle)
        call PauseUnit(w.cast, true)
        call ShowUnit(w.cast, false)
        call SetUnitPathing(w.cast, false)
        set w.trig = CreateTrigger() // I hate this. A potential game crash. But since nothing can be done...
        set w.tim = NT()
        set CASTED[w.cast] = true
        return w
    endmethod
    
    method onDestroy takes nothing returns nothing
        call ht.flush(.tim)
        call ht.flush(.trig)
        call RT(.tim)
        // I cannot destroy it simply because it will screw handle ids...
        // And since nobody came up with a sollution for dynamic triggers
        // and there is no system that uses one trigger with multiple events
        // I have to just disable it. It isn&#039;t THAT bad but it&#039;s still a leak.
        
        call DisableTrigger(.trig)
        //...
        // Oh, well, I guess I have to. Clean of leak...
        call DestroyTrigger(.trig)
        set CASTED[.cast] = false
    endmethod
endstruct

private function WaveConditions takes nothing returns boolean
    return GetSpellAbilityId() == AID_WAVE
endfunction

private function WaveDamage takes nothing returns boolean
    local trigger trig = GetTriggeringTrigger()
    local Wave w = ht[trig]
    local integer lvl = GetUnitAbilityLevel(w.cast, AID_WAVE)
    local unit pick = GetTriggerUnit()
    // Don&#039;t dare say multiple ifs are ugly - it&#039;s really a lot better to read and configure.
    if IsUnitEnemy(pick, GetOwningPlayer(w.cast)) then
        if GetWidgetLife(pick) &gt; 0.405 then
            if IsUnitType(pick, UNIT_TYPE_STRUCTURE) == false then
                call UnitDamageTarget(w.cast, pick, WAVE_DAMAGE(w.cast), false, false, WAVE_ATTACK_TYPE(w.cast), WAVE_DAMAGE_TYPE(w.cast), null)
            endif
        endif
    endif
    set pick = null
    set trig = null
    return true
endfunction

private function WaveCallback takes nothing returns nothing
    local timer tim = GetExpiredTimer()
    local Wave w = ht[tim]
    local real x = GetUnitX(w.cast)
    local real y = GetUnitY(w.cast)
    local real dx = x + w.dx
    local real dy = y + w.dy
    call SetUnitPosition(w.cast, dx, dy) 
    if GetRandomInt(0, 1) &lt; 1 then // Not so intensive...
        call DestroyEffect(AddSpecialEffect(WAVE_EFFECT(w.cast), x, y))
    endif
    set w.ticks = w.ticks - 1
    // Spirit has reached its destination.
    if w.ticks &lt;= 0 then
        call PauseUnit(w.cast, false)
        call ShowUnit(w.cast, true)
        call SetUnitPathing(w.cast, true)
        call w.destroy()
    endif
    set tim = null
endfunction

private function WaveActions takes nothing returns nothing
    local unit cast = GetTriggerUnit()
    local location targ = GetSpellTargetLoc()
    local real dx = GetLocationX(targ) - GetUnitX(cast)
    local real dy = GetLocationY(targ) - GetUnitY(cast)
    local real distance = SquareRoot(dx * dx + dy * dy)
    local real angle = Atan2(dy, dx)
    local Wave w = Wave.create(cast, distance, angle)
    // Attach data to the timer and trigger.
    set ht[w.tim] = w
    set ht[w.trig] = w
    call TriggerRegisterUnitInRange(w.trig, w.cast, WAVE_RADIUS(w.cast), Condition(function ReturnTrue))
    call TriggerAddCondition(w.trig, Condition(function WaveDamage))
    call TimerStart(w.tim, PERIOD, true, function WaveCallback)
    // Clean memory and handle leak.
    call RemoveLocation(targ)
    set cast = null
    set targ = null
endfunction

//===========================================================================

private function OnAttack takes nothing returns boolean
    local unit cast = GetAttacker()
    local unit targ = GetTriggerUnit()
    if GetUnitTypeId(cast) == UID_SPIRIT then // Is a spirit attacking?
        call DestroyEffect(AddSpecialEffectTarget(REDUCE_ARMOR_EFFECT, targ, AP_ARMOR_EFFECT))
        call SetUnitAbilityLevel(cast, AID_ARMOR_REDUCE, STACK[targ])
        call IssueTargetOrder(cast, OID_ARMOR_REDUCE, targ)
        if STACK[targ] &lt; MAX_ARMOR_STACK then // Increase stack if not over limit.
            set STACK[targ] = STACK[targ] + 1
            if not IsUnitInGroup(targ, forStack) then // Is the attacked unit in the stack group?
                call GroupAddUnit(forStack, targ)
            endif
        endif
        set TIME[targ] = ARMOR_STACK_DURATION // Reset time of the stack.
    endif
    set cast = null
    set targ = null
    return true
endfunction

//===========================================================================

private function ForStackHandleGroup takes nothing returns nothing
    local unit cast = GetEnumUnit() // Don&#039;t freak with the variables... I just prefer &quot;cast&quot;.
    if TIME[cast] &gt; 0 then
        set TIME[cast] = TIME[cast] - 1
    else // Stack isn&#039;t refreshed any more so remove unit.
        set STACK[cast] = 1
        call GroupRemoveUnit(forStack, cast)
    endif
    set cast = null
endfunction

private function StackHandle takes nothing returns nothing
    call ForGroup(forStack, function ForStackHandleGroup)
endfunction

//===========================================================================

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

private function Callback takes nothing returns nothing
    local timer tim = GetExpiredTimer()
    local Data d = ht[tim]
    local integer a = 0
    local location loc
    local real x
    local real y
    
    set d.moveTicks = d.moveTicks - 1
    if d.moveTicks &lt;= 0 then // Is it time for the spawns to move a little?
        set d.moveTicks = GetRandomInt(10, R2I(1. / PERIOD))
        loop
            exitwhen d.spirit[a] == null
            set loc = RandomLocInCircle(GetUnitX(d.cast), GetUnitY(d.cast), AREA_OF_EFFECT(d.cast))
            call IssuePointOrderLoc(d.spirit[a], &quot;move&quot;, loc)
            call RemoveLocation(loc)
            set loc = null
            set x = GetUnitX(d.spirit[a]) - GetUnitX(d.cast)
            set y = GetUnitY(d.spirit[a]) - GetUnitY(d.cast)
            set x = SquareRoot(x * x + y * y)
            if x &gt; AREA_OF_EFFECT(d.cast) and CASTED[d.spirit[a]] == false then // Moved too far away. 
                // Return to caster.
                call SetUnitX(d.spirit[a], GetUnitX(d.cast))
                call SetUnitY(d.spirit[a], GetUnitY(d.cast))
            endif
            set a = a + 1
        endloop
    endif
    set a = GetRandomInt(1, 30) // Some random stuff to look cool.
    if a &lt; 4 then 
        set a = GetRandomInt(0, d.maxSpirit) // Get a random spirit and start blazing.
        if CASTED[d.spirit[a]] == false then
            set loc = RandomLocInCircle(GetUnitX(d.cast), GetUnitY(d.cast), AREA_OF_EFFECT(d.cast))
            call IssuePointOrderLoc(d.spirit[a], OID_WAVE, loc)
            call RemoveLocation(loc)
            set loc = null
        endif
    endif
    set d.ticks = d.ticks - 1
    if d.ticks &lt;= 0 or GetWidgetLife(d.cast) &lt; 0.405 then 
        call ht.flush(tim)
        call RT(tim)
        call d.destroy()
    endif
    set tim = null
    // loc already nulled.
endfunction

private function Actions takes nothing returns nothing
    local unit cast = GetTriggerUnit()
    local timer tim = NT()
    local Data d = Data.create(cast)
    set ht[tim] = d
    call TimerStart(tim, PERIOD, true, function Callback)
    if CUT_THROUGH_SHIELD(d.cast) == true then // The damage can&#039;t be blocked?
        call SetWidgetLife(d.cast, GetWidgetLife(d.cast) - DAMAGE_TO_CASTER(d.cast))
    else // Or it can?
        call UnitDamageTarget(d.cast, d.cast, DAMAGE_TO_CASTER(d.cast), true, true, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null)
    endif
    set tim = null
    set cast = null
endfunction

//===========================================================================

private function PreloadData takes nothing returns nothing
    local unit targ = CreateUnit(Player(PLAYER_NEUTRAL_AGGRESSIVE), &#039;nowl&#039;, 0., 0., 0.) // Some enemy to preload on.
    local unit dum = CreateUnit(Player(0), UID_SPIRIT, 0., 0., 0.)
    call UnitAddAbility(dum, AID_WAVE)
    call UnitAddAbility(dum, AID_ARMOR_REDUCE)
    call IssueTargetOrder(dum, OID_ARMOR_REDUCE, targ)
    call TriggerSleepAction(0)
    call IssuePointOrder(dum, OID_WAVE, 0., 0.)
    call UnitApplyTimedLife(dum, &#039;BTLF&#039;, 0.1)
    call KillUnit(targ)
    call Preload(SFX_ATTACHED_ON_SPIRIT)
    call Preload(REDUCE_ARMOR_EFFECT)
    call Preload(WAVE_EFFECT(dum))
    set targ = null
    set dum = null
endfunction

//===========================================================================
    
private function Init takes nothing returns nothing
    local timer tim = CreateTimer()
    local trigger trig = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(trig, Condition(function Conditions))
    call TriggerAddAction(trig, function Actions)
    
    // I separate the movement of the spirits with a different trigger,
    // so it&#039;s easier to check movement function.
    set trig = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(trig, Condition(function WaveConditions))
    call TriggerAddAction(trig, function WaveActions)
    
    set trig = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_ATTACKED)
    call TriggerAddCondition(trig, Condition(function OnAttack))
    
    call TimerStart(tim, 1., true, function StackHandle)
    
    set ht = HandleTable.create()
    
    if PRELOAD then
        call PreloadData.execute()
    endif
    // No need to null variables because the triggers and the timer will be used until the end of the game.
endfunction
    
endscope
</b></b>


Screenshots:
WIP.
 

Attachments

  • [Forbidden Arts] Malevolence v1[1].0.w3x
    52.6 KB · Views: 286

FFMaster

New Member
Reaction score
1
Shroud of Darkness

-MUI
-vJass
-Leakless
-Works to n levels, where n approaches infinity.
I have tested it running 10 units. Lagless for my computer.

EDIT: Removed some useless code.

Screenshotasdf.jpg
 

Attachments

  • Shroud of Darkness - FFMaster.w3x
    29.9 KB · Views: 236

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Infest

Infest:)

This is my forbidden spell.

This spell is MUI and vJass.

Enemies in 500 AoE will infested by magic, reducing atk/move speed, takes damage according to their current hit point and also amplified damage. Need channeling.

I cun screenshot my spell cauz my graphic problem, so plz download it to try!

Changelog :
Added Rotating Lightning Effect
Added Channneling codes.:banghead:
 

free_killing

TH.net Regular
Reaction score
23
Level 1 info:
Creates a poison nova

Damage:
level x 17.5

Misssile:
Death Tower

Special:
None

Missile Speed:
400 x level

Level 2 info:
Creates a poison nova

Damage:
level x 17.5

Misssile:
Hydra

Special:
Finger of Death

Missile Speed:
400 x level

Level 3 info:
Creates a poison nova

Damage:
level x 17.5

Misssile:
Carrion Swarm

Special:
Feral Spirit

Missile Speed:
400 x level

Level 4 info:
Creates a poison nova

Damage:
level x 17.5

Misssile:
Demon Hunter

Special:
Animate Dead

Missile Speed:
400 x level

Level 1 - screenshot


Level 2 - screenshot


Level 3 - screenshot


Level 4 - screenshot


Edit: Uploaded map
Edit2: Resized images..
 

Attachments

  • A Spell Map [Poison Nova] Forbidden Arts.w3x
    25.1 KB · Views: 226

Larcenist

REP: Respect, Envy, Prosperity?
Reaction score
211
So I'm guessing this would be version 1.0 of by submission... It's nothing special really, and does pretty much what the name suggests.

With this I bring thee, Soul Burn.

Description:

Extracts the soul of a target enemy unit, then incinerates it damaging the target for 100 damage per second the soul is burned. Soul extraction takes 1 second. When the soul is fully extracted the target will freeze, rendering it unable to follow any command for the duration of the spell.

And yes I'm too lazy to take screenshots, upload to photobucket, then copy the URL and paste it here, so you'll have to live without it.

Coded in vJASS, giving it the requirement of NewGen (assuming you have the intention of using or editiing it).

The code if someone for some unfathomable reason would be interested in it...

JASS:
scope SoulBurn initializer Init
    
    private keyword Data
    
    globals
        private constant integer SpellAID = &#039;A000&#039;              //Raw code for the Soul Burn ability.
        private constant integer SoulAlpha = 128                //Alpha value of the &quot;soul&quot; unit (transparency).       \
        private constant integer LightningRed = 165             //Red value of the lightning effect.                    \
        private constant integer LightningGreen = 0             //Green value of the lightning effect.                   |- Ranges from 0 to 255
        private constant integer LightningBlue = 255            //Blue value of the lightning effect.                   /
        private constant integer LightningAlpha = 55            //Alpha value of the lightning effect (transparency).  /
        private constant integer BurnAnimationIndex = 4         //Index of the animation played while pulling out the soul.  \__ Can be found out using a code similar to the disabled trigger named &quot;test&quot;.
        private constant integer ExtractAnimationIndex = 6      //Index of the animation played while burning the soul.      /
        private constant real LightningZModifier = 75.          //Z value above the ground of the lightning effect.
        private constant real TimerInterval = 0.03125           //Interval of the global timer.
        private constant real SoulExtractPull = 100.            //Distance the soul will be pulled over SoulExtractTime before starting the incineration.
        private constant real SoulExtractTime = 1.              //Time taken in seconds for the soul to be pulled out.
        private constant real InitMaxDur = 2.                   //Max duration of the ability in level 1. Note that the extract time is included, so a duration of 2 seconds with 1 second ectract time will deal damage for the remaining second.
        private constant real AddMaxDur = 1.                    //Additional max duration per level of this ability. For a static duration simply enter the value 0. here, and leave the InitMaxDur variable your duration.
        private constant real InitDamagePerSec = 100.           //Damage dealt per second at level 1. (Damage is dealt after SoulExtractTime seconds have passed.)
        private constant real AddDamagePerSec = 0.              //Additional damage per second per level of this ability. For a static damage per second leave this value at 0.
        private constant real ExtractAnimationSpeed = 2.        //Animation speed while extracting the target&#039;s soul (2. = 200% of regular animation speed etc).
        private constant real BurnAnimationSpeed = 1.           //Animation speed while burning the extracted soul (1. = regular animation speed).
        private constant string LightningModel = &quot;LEAS&quot;         //Model path of the lightning used to extract the soul.
        private constant string SpellOrder = &quot;channel&quot;          //OrderID of the ability you based this of. 
        private constant string ExplosionSFX = &quot;Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl&quot;  //Incineration-effect played while burning the soul of the target.
        private constant attacktype AttackType = ATTACK_TYPE_NORMAL     //Attack type of the spell&#039;s damage.
        private constant damagetype DamageType = DAMAGE_TYPE_NORMAL     //Damage type of the spell&#039;s damage.
        
        //Spell required globals, not to be tampered with.
        private Data array D
        
        private timer T = CreateTimer()
        private integer N = 0
    endglobals
    
    private function MaxDurCalc takes integer i returns real
        return InitMaxDur + AddMaxDur * (i - 1)
    endfunction
    
    private function DamageCalc takes integer i returns real
        return InitDamagePerSec + AddDamagePerSec * (i - 1)
    endfunction
    
    private struct Data
        unit caster
        unit target
        unit soul
        lightning light
        real counter
        real cx
        real cy
        real tx
        real ty
        real z1
        real z2
        real angle
        real maxdur
        real curdist
        real pullspeed
        real damage
        boolean extract
        static method create takes unit c, unit t returns Data
            local Data d = Data.allocate()
            local location l
            local integer i = GetUnitAbilityLevel(c, SpellAID)
            //Just some safety to prevent a division with 0 if someone would enter 0. as SoulExtractTime.
            local real temp = SoulExtractTime
            if (temp &lt;= 0) then
                set temp = 0.0001
            endif
            
            set d.caster = c
            set d.target = t
            set d.tx = GetUnitX(t)
            set d.ty = GetUnitY(t)
            //Unit is created for the owner of the target then changed to neutral passive for the sake of preventing it from attacking anything, while keeping the original unit&#039;s color.
            set d.soul = CreateUnit(GetOwningPlayer(t), GetUnitTypeId(t), d.tx, d.ty, GetUnitFacing(t))
            set d.counter = 0.
            set d.cx = GetUnitX(c)
            set d.cy = GetUnitY(c)
            set l = Location(d.cx, d.cy)
            set d.z1 = GetLocationZ(l)
            call RemoveLocation(l)
            set l = Location(d.tx, d.ty)
            set d.z2 = GetLocationZ(l)
            call RemoveLocation(l)
            set d.angle = Atan2(d.cy - d.ty, d.cx - d.tx)
            set d.light = AddLightningEx(LightningModel, true, d.cx, d.cy, d.z1 + LightningZModifier, d.tx, d.ty, d.z2 + LightningZModifier)
            set d.maxdur = MaxDurCalc(i)
            set d.curdist = 0.
            set d.pullspeed = (SoulExtractPull * TimerInterval) / temp
            set d.damage = DamageCalc(i)
            set d.extract = true
            
            call UnitAddAbility(d.soul, &#039;Aloc&#039;)
            call SetUnitVertexColor(d.soul, 255, 255, 255, SoulAlpha)
            call SetUnitPosition(d.soul, d.tx, d.ty)
            call SetUnitOwner(d.soul, Player(13), false)
            call SetLightningColor(d.light, LightningRed, LightningGreen, LightningBlue, LightningAlpha)
            call SetUnitAnimationByIndex(c, ExtractAnimationIndex)
            call SetUnitTimeScale(c, ExtractAnimationSpeed)
            
            set l = null
            
            return d
        endmethod
        
        method onDestroy takes nothing returns nothing
            call DestroyLightning(.light)
            call RemoveUnit(.soul)
            call SetUnitVertexColor(.target, 255, 255, 255, 255)
            call PauseUnit(.target, false)
            call SetUnitTimeScale(.caster, 1.)
        endmethod
    endstruct
    
    private function TimerCallback takes nothing returns nothing
        local integer i = N
        local Data d
        local real x
        local real y
        loop
            exitwhen i &lt;= 0
            set d = i<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite8" alt=":D" title="Big Grin    :D" loading="lazy" data-shortname=":D" />
            set d.counter = d.counter + TimerInterval
            if (d.counter &gt;= d.maxdur) or (GetUnitCurrentOrder(d.caster) != OrderId(SpellOrder)) or (GetWidgetLife(d.target) &lt; .405) then
                call d.destroy()
                
                set i<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite8" alt=":D" title="Big Grin    :D" loading="lazy" data-shortname=":D" /> = N<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite8" alt=":D" title="Big Grin    :D" loading="lazy" data-shortname=":D" />
                set N = N - 1
                if (N == 0) then
                    call PauseTimer(T)
                endif
            elseif (d.extract == true) then
                set d.curdist = d.curdist + d.pullspeed
                if (d.curdist &gt; SoulExtractPull) then
                    set d.curdist = SoulExtractPull
                endif
                
                set x = d.tx + d.curdist * Cos(d.angle)
                set y = d.ty + d.curdist * Sin(d.angle)
                
                call SetUnitPosition(d.soul, x, y)
                call MoveLightningEx(d.light, true, d.cx, d.cy, d.z1 + LightningZModifier, x, y, d.z2 + LightningZModifier)
                call SetUnitVertexColor(d.target, R2I(255 - 255 * d.counter), R2I(255 - 255 * d.counter), 255, 255)
                if (d.curdist &gt;= SoulExtractPull) then
                    call PauseUnit(d.target, true)
                    call SetUnitAnimationByIndex(d.caster, BurnAnimationIndex)
                    call SetUnitTimeScale(d.caster, BurnAnimationSpeed)
                    
                    set d.tx = x
                    set d.ty = y
                    set d.extract = false
                endif
            else
                call UnitDamageTarget(d.caster, d.target, d.damage * TimerInterval, false, false, AttackType, DamageType, WEAPON_TYPE_WHOKNOWS)
                call DestroyEffect(AddSpecialEffect(ExplosionSFX, d.tx, d.ty))
            endif
            
            set i = i - 1
        endloop
    endfunction
    
    private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == SpellAID
    endfunction
    
    private function Actions takes nothing returns nothing
        local Data d = Data.create(GetTriggerUnit(), GetSpellTargetUnit())
        
        set N = N + 1
        set N<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite8" alt=":D" title="Big Grin    :D" loading="lazy" data-shortname=":D" /> = d
        if (N == 1) then
            call TimerStart(T, TimerInterval, true, function TimerCallback)
        endif
    endfunction
    
    private function Init takes nothing returns nothing
        local trigger trig = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(trig, Condition(function Conditions))
        call TriggerAddAction(trig, function Actions)
    endfunction
endscope
 

Attachments

  • Soul Burn by Larcenist.w3x
    32.4 KB · Views: 205

Redeamed

New Member
Reaction score
2
Forbidden Summon

Ability name: Forbidden Summon

Description: Transform a target host (friend or foe) into an Ak-nite spider queen. The Ak-nite spider is a unique creature of dark magic, it's unstable existance makes it hard to maintain in a physical form. It feeds off pain making it so that the more it's victims fight back the stronger the brood becomes. attack the queen spawn a spiderling, kill a spiderling spawn two. when the queen dies the spiderlings die. This power comes at a high cost to the caster, the entire brood is linked to the casters health, when a spider gets hurt the caster gets hurt so the more spiders the more damage they can do but the more damage the caster takes. Also the spiders minds are chaos and uncontrolable so they will not hesitate to attack the caster or his allies.
Level 1: last 5 seconds
Level 2: last 7 seconds
Level 3 last 10 seconds

I dont know how to post screen shots but the file is attached. This is my first real spell so advice and comment much appreciated.


Thanks to free_killing and Carl-Fredrik for pointing me in the right direction for my leaking problems.
 

Attachments

  • Forbbidden spell.w3x
    29 KB · Views: 204

CuteCumber

Member
Reaction score
4
Ancestral Energy

Ancestral Energy

Morgan releases the ancestral energies within his hammer, granting him and his allies movement speed bonus. When Morgan charges in max speed towards its enemies, he'll deal extra damage in the targeted area with movement speed penalty.



This is my first time submitting spell for spell contest. The Spell is very SIMPLE. Please enjoy it. Thank You.
 

Attachments

  • demomap_contest_Cutecumber.w3x
    26.4 KB · Views: 203

Dirac

22710180
Reaction score
147
Blood Pact
GUI/Jass/vJass: GUI
MUI/MPI/None: MUI
Works for N levels?: Yes
Leakless?

Description:
Hidan shots a sharp glaive to a target location that wounds units it encounters on the way, when the glaive returns, he creates a pact between him and the unit's wounded by the glaive and deals an amount of damage to itslef. As long Hidan stays in the pact circle the damage done to him also affects units in the pact.
Level 1 - 30% of total damage received, 50 damage to itslef.
Level 2 - 60% of total damage received, 100 damage to itslef.
Level 3 - 90% of total damage received, 150 damage to itslef.
Level 4 - 120% of total damage received, 200 damage to itslef.

Screenshots
http://img514.imageshack.us/img514/4329/pic1.jpg
http://img262.imageshack.us/img262/683/pic2.jpg
http://img22.imageshack.us/img22/8147/pic3u.jpg

The Code
Trigger:
  • BloodPact
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Blood Pact
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • MUI Less than or equal to 999
        • Then - Actions
          • Set MUI = (MUI + 1)
        • Else - Actions
          • Set MUI = 1
      • Set MUICaster[MUI] = (Casting unit)
      • Set MUIPoint[MUI] = (Target point of ability being cast)
      • Set TempPointArray[1] = (Position of MUICaster[MUI])
      • Set TempPoint = (TempPointArray[1] offset by 50.00 towards (Angle from TempPointArray[1] to MUIPoint[MUI]) degrees)
      • Unit - Create 1 Missile for (Owner of MUICaster[MUI]) at TempPoint facing (Angle from TempPoint to (Target point of ability being cast)) degrees
      • Unit - Set the custom value of (Last created unit) to MUI
      • Unit Group - Add (Last created unit) to BloodPactGroup
      • Set MUISlide[MUI] = 32.00
      • Custom script: call RemoveLocation (udg_TempPoint)
      • Custom script: call RemoveLocation (udg_TempPointArray[1])
Trigger:
  • BloodPact Slide
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
      • (BloodPactGroup is empty) Equal to False
    • Actions
      • Unit Group - Pick every unit in BloodPactGroup and do (Actions)
        • Loop - Actions
          • Set TempInteger = (Custom value of (Picked unit))
          • Set MUISlide[(Custom value of (Picked unit))] = (MUISlide[(Custom value of (Picked unit))] - 0.50)
          • Set TempPointArray[1] = (Position of (Picked unit))
          • Set TempPointArray[2] = (Position of MUICaster[TempInteger])
          • Set TempPoint = (TempPointArray[1] offset by MUISlide[(Custom value of (Picked unit))] towards (Angle from TempPointArray[2] to TempPointArray[1]) degrees)
          • Unit - Move (Picked unit) instantly to TempPoint, facing (Angle from TempPointArray[2] to MUIPoint[(Custom value of (Picked unit))]) degrees
          • Set TempGroup = (Units within 120.00 of TempPointArray[1])
          • Custom script: call RemoveLocation (udg_TempPointArray[1])
          • Custom script: call RemoveLocation (udg_TempPoint)
          • Custom script: call RemoveLocation (udg_TempPointArray[2])
          • Unit Group - Pick every unit in TempGroup and do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ((Picked unit) is in MUITargets[TempInteger]) Equal to False
                  • ((Picked unit) is A structure) Equal to False
                  • ((Picked unit) belongs to an enemy of (Owner of MUICaster[TempInteger])) Equal to True
                  • ((Picked unit) is alive) Equal to True
                  • (Custom value of (Picked unit)) Equal to 0
                • Then - Actions
                  • Unit Group - Add (Picked unit) to MUITargets[TempInteger]
                  • Unit - Set the custom value of (Picked unit) to TempInteger
                  • Set TempPoint = (Position of (Picked unit))
                  • Special Effect - Create a special effect at TempPoint using Abilities\Spells\Other\Stampede\StampedeMissileDeath.mdl
                  • Special Effect - Destroy (Last created special effect)
                  • Custom script: call RemoveLocation (udg_TempPoint)
                • Else - Actions
          • Custom script: call DestroyGroup (udg_TempGroup)
          • Set TempPointArray[5] = (Position of MUICaster[TempInteger])
          • Set TempPointArray[6] = (Position of (Picked unit))
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • MUISlide[(Custom value of (Picked unit))] Less than or equal to 0.00
              • (Distance between TempPointArray[5] and TempPointArray[6]) Less than 50.00
            • Then - Actions
              • Unit - Remove (Picked unit) from the game
              • Unit - Cause MUICaster[TempInteger] to damage MUICaster[TempInteger], dealing ((Real((Level of Blood Pact for MUICaster[TempInteger]))) x 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
                  • (MUITargets[TempInteger] is empty) Equal to False
                • Then - Actions
                  • Set TempPoint = (Position of MUICaster[TempInteger])
                  • Unit - Create 1 Circle for (Owner of MUICaster[TempInteger]) at TempPoint facing 0.00 degrees
                  • Set Circle[TempInteger] = (Last created unit)
                  • Unit - Set the custom value of (Last created unit) to TempInteger
                  • Unit - Add a 15.00 second Generic expiration timer to (Last created unit)
                  • Unit - Create 1 Circle for (Owner of MUICaster[TempInteger]) at TempPoint facing 45.00 degrees
                  • Unit - Add a 15.00 second Generic expiration timer to (Last created unit)
                  • Special Effect - Create a special effect at TempPoint using Abilities\Spells\Undead\AnimateDead\AnimateDeadTarget.mdl
                  • Custom script: call RemoveLocation (udg_TempPoint)
                  • Unit Group - Pick every unit in MUITargets[TempInteger] and do (Actions)
                    • Loop - Actions
                      • Set TempPoint = (Position of (Picked unit))
                      • Unit - Create 1 Dummy for (Owner of MUICaster[TempInteger]) at TempPoint facing Default building facing degrees
                      • Unit - Add Blood Pact Buff to (Last created unit)
                      • Unit - Order (Last created unit) to Undead Necromancer - Cripple (Picked unit)
                      • Unit - Add a 1.00 second Generic expiration timer to (Last created unit)
                      • Unit - Cause MUICaster[TempInteger] to damage (Picked unit), dealing ((Real((Level of Blood Pact for MUICaster[TempInteger]))) x 50.00) damage of attack type Spells and damage type Normal
                      • Custom script: call RemoveLocation (udg_TempPoint)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (MUICaster[TempInteger] is in BloodPactCasters) Equal to False
                    • Then - Actions
                      • Trigger - Add to BloodPact DMG &lt;gen&gt; the event (Unit - MUICaster[TempInteger] Takes damage)
                      • Unit Group - Add MUICaster[TempInteger] to BloodPactCasters
                    • Else - Actions
                • Else - Actions
              • Set MUISlide[(Custom value of (Picked unit))] = 0.00
              • Custom script: call RemoveLocation (udg_MUIPoint[udg_TempInteger])
            • Else - Actions
          • Custom script: call RemoveLocation (udg_TempPointArray[5])
          • Custom script: call RemoveLocation (udg_TempPointArray[6])
Trigger:
  • Removal
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Unit-type of (Dying unit)) Equal to Circle
    • Actions
      • Set TempPoint = (Position of (Dying unit))
      • Special Effect - Create a special effect at TempPoint using Objects\Spawnmodels\Undead\UCancelDeath\UCancelDeath.mdl
      • Custom script: call RemoveLocation (udg_TempPoint)
      • Set TempInteger = (Custom value of (Dying unit))
      • Set TempGroup = (Units in (Playable map area))
      • Unit Group - Pick every unit in TempGroup and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) is in MUITargets[TempInteger]) Equal to True
            • Then - Actions
              • Unit Group - Remove (Picked unit) from MUITargets[TempInteger]
              • Unit - Set the custom value of (Picked unit) to 0
            • Else - Actions
      • Custom script: call DestroyGroup (udg_TempGroup)
      • Unit - Remove (Dying unit) from the game
Trigger:
  • BloodPact DMG
    • Events
    • Conditions
    • Actions
      • For each (Integer A) from 1 to MUI, do (Actions)
        • Loop - Actions
          • Unit Group - Pick every unit in MUITargets[(Integer A)] and do (Actions)
            • Loop - Actions
              • Set TempInteger = (Custom value of (Picked unit))
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • MUICaster[TempInteger] Equal to (Triggering unit)
                  • ((Picked unit) has buff Blood Pact ) Equal to True
                  • (Custom value of (Picked unit)) Not equal to 0
                • Then - Actions
                  • Set TempPointArray[1] = (Position of MUICaster[TempInteger])
                  • Set TempPointArray[2] = (Position of Circle[TempInteger])
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Distance between TempPointArray[1] and TempPointArray[2]) Less than or equal to 300.00
                    • Then - Actions
                      • Unit - Set life of (Picked unit) to ((Life of (Picked unit)) - ((Damage taken) x (0.30 x (Real((Level of Blood Pact for MUICaster[TempInteger]))))))
                      • Set TempPoint = (Position of (Picked unit))
                      • Special Effect - Create a special effect at TempPoint using Abilities\Spells\Other\Stampede\StampedeMissileDeath.mdl
                      • Custom script: call RemoveLocation (udg_TempPoint)
                    • Else - Actions
                • Else - Actions
 

Attachments

  • Dirac_demomap_contest.w3x
    31.5 KB · Views: 174

Dinowc

don't expect anything, prepare for everything
Reaction score
223
good:
-MUI (if you don't use it over 99 times at once... increasing array size of variables would enable this too :p), GUI, Leakless, Lagless (although it lags when you cast it first time)

bad:
-ugly code, a little bugged, too big description, ugly terrain? xd

UPDATE - includes a new feature (read bolded description)

The spirit of death
Summons a deathly spirit that will haunt a random nearby enemy hero. If there are no heroes nearby it will attack any other unit.
While reaching it's victim, the spirit will also damage nearby enemies with aura of death and shoot bolts upon them. If the target dies by the spirit (it wont work if the spirit kills the target with bolts or aura) it will explode and damage nearby enemies by 25% of it's max hit points and will release another death spirit (like a chain reaction).
The spirit is invulnerable and it will last until it hits the target or the channel stops.

this is my final submission and I hope there aren't any bugs I've missed :banghead:
______________
screenies (old ones though)

-spirits
View attachment 29706
-the spirit has marked it's target and it flies towards him
View attachment 29707
-the target is struck
View attachment 29708
______________

View attachment 29717
 

~GaLs~

† Ғσſ ŧħə ѕαĸε Φƒ ~Ğ䣚~ †
Reaction score
180
Blood Curse

Description
Channels 4 seconds, sacrifice his own blood and deal damage to units around.

Blood sacrifice - ( 25% x Level ) of the current hitpoints.
Damages - Blood sacrificed x ( 100 + (5% x Level) / 100 )

Unit only being damaged once.
Stackable


In words
It channel for 4 second. (Massive eye candy)
Deal damage to the surrounding.
Push enemy away.
Slow down enemies' move/attack speed.


Coded in
Jass + vJass?

Additional coded in feature
Multiple Unit Instanceable!

Code
JASS:
scope BloodCurse

globals
    private constant integer SPELL_ID = &#039;A000&#039;
    private constant string SPELL_ORDERID = &quot;channel&quot;
    private constant integer DUMMY_ID = &#039;e000&#039;
    private constant integer BLOODSPLIT_ID = &#039;A004&#039;
endglobals

private constant function BloodSacrificed takes integer Lvl, real Hp returns real
    return (25.*Lvl)/100*Hp
endfunction

private constant function GetDamage takes integer Lvl, real BSacrificed returns real
    return BSacrificed*((100+5*Lvl)/100)
endfunction

//=========================================================================
//Internal Function
//=========================================================================

struct BCConstant //Things that is always constant but not healthy for editing
string GroundEff = &quot;Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeTarget.mdl&quot;
string BloodMod = &quot;Objects\\Spawnmodels\\Orc\\Orcblood\\BattrollBlood.mdl&quot;
string BloodMod2 = &quot;Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl&quot;
string BlodSplitOrderStrg = &quot;thunderclap&quot;
real ChannelDura = 4.
real OneTick = .5
integer PentagonInternalAng = 72
integer PentagonSides = 360/.PentagonInternalAng
real BloodSpreadInterval = .08
real BlodIntervalDist = 18.
real MaxAOE = 400.
endstruct

struct BCS extends BCConstant
unit caster
unit array dummyBlod [5]
group filtered = CreateGroup()
effect array BlodEff [5]
player p
real cx
real cy
real array ang [5]
real TickCounter = 0
real TotalHpShouldLoss
real HpLoss = 0
real Damage
timer InChan = CreateTimer()
timer BloodSpreadt = CreateTimer()

private static BCS bcGlo
private static real dxGlo
private static real dyGlo

    private static method enemyFil takes nothing returns boolean
    local unit fil = GetFilterUnit()
    local BCS bc = BCS.bcGlo
        if IsUnitInGroup(fil,bc.filtered) == false and IsUnitAlly(fil,bc.p) == false and GetWidgetLife(fil)&gt;0 and IsUnitType(fil, UNIT_TYPE_MAGIC_IMMUNE) == false then
            call UnitDamageTarget(bc.caster,fil,bc.Damage,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_MAGIC,null) 
        endif
        if IsUnitAlly(fil,bc.p) == false and fil != bc.caster and GetWidgetLife(fil)&gt;.405then
            call SetUnitX(fil,BCS.dxGlo)
            call SetUnitY(fil,BCS.dyGlo)
        endif
        call GroupAddUnit(bc.filtered,fil)
        
    return false
    endmethod

    private static method BloodSpreadAct takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local BCS bc = GetTimerStructA(t)
    local integer i = 1
    local real dx
    local real dy
    local real nx
    local real ny
    local unit fil
    local group enemy = CreateGroup()
    
    loop
    exitwhen i &gt; bc.PentagonSides
        set dx = GetWidgetX(bc.dummyBlod<i>)
        set dy = GetWidgetY(bc.dummyBlod<i>)
        set nx = dx+bc.BlodIntervalDist*Cos(bc.ang<i>*bj_DEGTORAD)
        set ny = dy+bc.BlodIntervalDist*Sin(bc.ang<i>*bj_DEGTORAD)
        if SquareRoot((nx - bc.cx) * (nx - bc.cx) + (ny - bc.cy) * (ny - bc.cy)) &lt;= bc.MaxAOE then
            set bc.dummyBlod<i> = CreateUnit(bc.p,DUMMY_ID,nx,ny,bc.ang<i>) 
            call DestroyEffect(AddSpecialEffectTarget(&quot;Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl&quot;,bc.dummyBlod<i>,&quot;origin&quot;))
            call SetUnitScale(bc.dummyBlod<i>, 150 * 0.01, 150 * 0.01, 150 * 0.01)
            call DestroyEffect(bc.BlodEff<i>)
            set bc.BlodEff<i> = AddSpecialEffectTarget(bc.BloodMod,bc.dummyBlod<i>,&quot;origin&quot;)
            call UnitApplyTimedLife(bc.dummyBlod<i>,&#039;BTLF&#039;,1.)
            
            set BCS.bcGlo = bc //--&gt; Instant usage of global, not affecting MUI
            set BCS.dxGlo = dx
            set BCS.dyGlo = dy
            call GroupEnumUnitsInRange(enemy,nx,ny,100.,Condition(function BCS.enemyFil))
            set BCS.bcGlo = 0  //--&gt; Immediate null it for safety measure          
        elseif SquareRoot((nx - bc.cx) * (nx - bc.cx) + (ny - bc.cy) * (ny - bc.cy)) &gt; bc.MaxAOE then
            call PauseTimer(t)
            call ClearTimerStructA(t)
            call DestroyTimer(t)
            call bc.destroy()
            set i = bc.PentagonSides+1 // stop the loop
        endif
    set i = i +1
    endloop
    
    call DestroyGroup(enemy)
    set enemy = null
    set t = null
    set fil = null
    endmethod

    private method SetAng takes nothing returns nothing
    local integer swap = 1
    local integer i = 90
    local real nx
    local real ny
    
    loop
    exitwhen i &gt; 378
        set .ang[swap] = I2R(i) 
        set nx = .cx+100*Cos(.ang[swap]*bj_DEGTORAD)
        set ny = .cy+100*Sin(.ang[swap]*bj_DEGTORAD)
        set .dummyBlod[swap] = CreateUnit(.p,DUMMY_ID,nx,ny,.ang[swap])
        call SetUnitScale(.dummyBlod[swap], 150 * 0.01, 150 * 0.01, 150 * 0.01)
        set .BlodEff[swap] = AddSpecialEffectTarget(.BloodMod,.dummyBlod[swap],&quot;origin&quot;)
        call UnitApplyTimedLife(.dummyBlod[swap],&#039;BTLF&#039;,1.)
        set swap = swap +1
    set i = i + .PentagonInternalAng
    endloop
    
    endmethod

    private static method InChanAct takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local BCS bc = GetTimerStructA(t)
    local unit dum
    local real Dmg2Self
    
    if bc.TickCounter &lt;bc.ChannelDura then
    if GetUnitCurrentOrder(bc.caster) != 852600 then
        set bc.TickCounter = bc.ChannelDura + 10000. //Make the channel stop, thus advance to damaging phase
    endif
    endif
    
    if bc.TickCounter &gt;=bc.ChannelDura then 
        //Finished channeling
        call bc.SetAng()
        
        set dum = CreateUnit(bc.p,DUMMY_ID,bc.cx,bc.cy,0) //Clap Phase
        call SetUnitScale(dum, 300 * 0.01, 300 * 0.01, 300 * 0.01)
        call UnitAddAbility(dum,BLOODSPLIT_ID)
        call IssueImmediateOrder(dum,bc.BlodSplitOrderStrg)
        call UnitApplyTimedLife(dum,&#039;BTLF&#039;,1)
        
        set bc.Damage = GetDamage(GetUnitAbilityLevel(bc.caster,SPELL_ID),bc.HpLoss)
        call SetTimerStructA(bc.BloodSpreadt,bc)
        call TimerStart(bc.BloodSpreadt,bc.BloodSpreadInterval,true,function BCS.BloodSpreadAct)
        call PauseTimer(t)
        call ClearTimerStructA(t)
        call DestroyTimer(t)
    elseif bc.TickCounter &lt;bc.ChannelDura then
        set bc.TickCounter = bc.TickCounter + bc.OneTick
        call DestroyEffect(AddSpecialEffect(bc.GroundEff,bc.cx,bc.cy))
        //-- Damage self (Hp sacrficed)
        set Dmg2Self = bc.TotalHpShouldLoss/(bc.ChannelDura/bc.OneTick)
        set bc.HpLoss = bc.HpLoss + Dmg2Self
        call UnitDamageTarget(bc.caster,bc.caster,Dmg2Self,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_MAGIC,null)
        call DestroyEffect(AddSpecialEffectTarget(&quot;Objects\\Spawnmodels\\Other\\HumanBloodCinematicEffect\\HumanBloodCinematicEffect.mdl&quot;,bc.caster,&quot;origin&quot;))
    endif
    set dum = null
    endmethod

    static method create takes unit cas returns BCS
    local BCS bc = BCS.allocate()
    local integer i = GetUnitAbilityLevel(cas,SPELL_ID)
    set bc.caster = cas
    set bc.cx = GetWidgetX(cas)
    set bc.cy = GetWidgetY(cas)
    set bc.p = GetOwningPlayer(cas)
    set bc.TotalHpShouldLoss = BloodSacrificed(i,GetWidgetLife(cas))
    

    call SetTimerStructA(bc.InChan,bc)
    call TimerStart(bc.InChan,bc.OneTick,true,function BCS.InChanAct)

    return bc
    endmethod
endstruct


private function Act takes nothing returns nothing
local BCS bc
    if GetSpellAbilityId() != SPELL_ID then
        return
    endif
set bc = BCS.create(GetTriggerUnit())
call WispWheel_Unit(GetTriggerUnit(),&quot;Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl&quot;,5,150.,bc.ChannelDura)// dura = 2
endfunction

//===========================================================================
function InitTrig_Blood_Curse takes nothing returns nothing
    set gg_trg_Blood_Curse = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Blood_Curse, function Act )
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Blood_Curse,EVENT_PLAYER_UNIT_SPELL_EFFECT)
endfunction
endscope
//===========================================================================
library WispWheel uses ABC //A library created just for this spell
globals
    private constant integer MAXWISP = 6
    private constant integer DUMMY_ID = &#039;e000&#039;
endglobals

struct WWS 
unit target
string model
integer number
real distance
real angle
real tx
real ty
real dura
real array dAng[MAXWISP]
timer t = CreateTimer()
timer End = CreateTimer()

    private static method EndAct takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local WWS ww = GetTimerStructA(t)
        call ww.destroy()
    endmethod

    private static method tAct takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local WWS ww = GetTimerStructA(t)
    local real nx
    local real ny
    local integer i = 1
    
    if GetUnitCurrentOrder(ww.target) == 852600 then //852600 is the channeling&#039;s order id
    loop
    exitwhen i &gt; ww.number
        set ww.dAng<i> = ww.dAng<i> + 5.
        set nx = ww.tx + ww.distance * Cos(ww.dAng<i> * bj_DEGTORAD)
        set ny = ww.ty + ww.distance * Sin(ww.dAng<i> * bj_DEGTORAD)
        call DestroyEffect(AddSpecialEffect(ww.model,nx,ny))
    set i = i + 1
    endloop
    elseif GetUnitCurrentOrder(ww.target) != 852600 then
        call ww.destroy()
    endif
    
    set t = null
    endmethod

    static method create takes unit tar, string mod, integer num, real dist, real period returns WWS
    local WWS ww = WWS.allocate()
    local integer i = 1
    local real nx
    local real ny
    set ww.target = tar
    set ww.model = mod
    set ww.number = num
    set ww.tx = GetWidgetX(tar)
    set ww.ty = GetWidgetY(tar)
    set ww.distance = dist
    set ww.angle = 360./num
    set ww.dura = period

    loop
    exitwhen i &gt; num
        set nx = ww.tx + ww.distance * Cos((ww.angle*i) * bj_DEGTORAD)
        set ny = ww.ty + ww.distance * Sin((ww.angle*i) * bj_DEGTORAD)
        set ww.dAng<i> = ww.angle * i
        call DestroyEffect(AddSpecialEffect(mod,nx,ny))
    set i = i +1
    endloop

    call SetTimerStructA(ww.t,ww)
    call TimerStart(ww.t,.03,true,function WWS.tAct)
    
    call SetTimerStructA(ww.End,ww)
    call TimerStart(ww.End,period,false,function WWS.EndAct)
    
    return ww
    endmethod
    
    private method onDestroy takes nothing returns nothing
    call PauseTimer(.t)
    call ClearTimerStructA(.t)
    call DestroyTimer(.t)
    call PauseTimer(.End)
    call ClearTimerStructA(.End)
    call DestroyTimer(.End)
    endmethod
endstruct

public function Unit takes unit target, string model, integer number, real dist, real period returns WWS
local WWS ww

if number &lt;= MAXWISP then
    set ww = WWS.create(target, model, number, dist, period)
elseif number &gt; MAXWISP then
    call BJDebugMsg(&quot;Creating too much wisp around unit!&quot;)
endif

return ww
endfunction

endlibrary</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>


Screenshot

21961650.png

ss2n.png


Where is da map?
Version v1
View attachment 29637

Edit: 27/2
Version Update v2
View attachment 29700

Edit: 28/2
Version Update v3
View attachment Contest - Blood Curse v3.w3x

Changelog
Version 1
-Initial Release

Version 2
-Fixed issue pointed out by Viikuna

Version 3
-Script Optimization
 

Stratovarius

New Member
Reaction score
7
Dark Eruption

By Stratovarius

This is my first time entering a contest :). Everything about the spell is pretty much explained below except for how I made it,
but it was pretty basic nothing special and I thinks it looks cool. Hope you enjoy and GL everyone too!


What it does?






What it looks like!



This is when the Assassin goes immune for a quick second afterward. (Banished)




A unit effected with the DoT from the Dark Eruption.

 

Attachments

  • demomap_contest_Stratovarius.w3x
    25.2 KB · Views: 189

Kenny

Back for now.
Reaction score
202
Soul Transferral

BTNLament2.jpg

Tech Stuff:

VJASS: Yes.
MUI/MPI: Yes.
Leakless: Yes.
Lagless: Yes.
Works for N levels: Yes.
Requires: Vexorians dummy model.
Configurable: Very.
Importing: Easy.
Theme: The forbidden theme is shown through the use of souls (a taboo and ritualistic subject).

Simple(ish) Description:

So this is like your basic heal/damage ability. Cast it on an area, undead (dead) bodies will "explode" and deal small damage to enemies around them(*). Allied (dead) bodies will be turned into purified souls, that heal the caster, and give him +1 to all stats. Enemy (dead) bodies have a percent chance to do the same as allied bodies, but if they don't they do the same as undead bodies.

Souls are stored within the hero for X seconds. Then they disappear, along with the bonus stats.

If the hero dies while souls are stored, they will all be released, flying around to random locations until they hit an enemy unit, or until their time runs out.

(*) - This goes for all undead units, allied or enemy, as the nature of undead units overpowers the heroes ability to purify their soul.

It may seem complicated, but it is actually quite simple. Bad guys = damage (not all the times) and good guys = heal.

Learn Tooltip:

LearnTooltip.jpg


Active Tooltip:

ActiveTooltip.jpg


Screenshots:

Projectile on impact with AoE indictor:

http://i279.photobucket.com/albums/kk138/kennskies/ProjectileLandedPlusAreaofEffectInd.jpg

Tainted and Purified Souls:

http://i279.photobucket.com/albums/kk138/kennskies/TaintedandPurifiedSouls.jpg

The Script:

JASS:
//------------------------------------------------------------------------------------\\
//                             Soul Transferral [v1]                                  \\
//                                   by kenny!                                        \\
//                            Constructed using vJASS                                 \\
//                               Requires NewGen WE                                   \\
//------------------------------------------------------------------------------------\\

scope SoulTransferral initializer Init

globals
// Configurables:

// Raw Codes:
    private constant integer Abil_id = &#039;A003&#039;  // Raw code of the Hero ability (Soul Transferral).
    private constant integer Stats_id = &#039;A001&#039; // Raw code of the hidden bonus stats ability.
    private constant integer Crow_id = &#039;Amrf&#039;  // Raw code of the Crow Form ability used for changing fly heights. Does not change for most maps.
    private constant integer Dummy_id = &#039;u001&#039; // Raw code of the dummy unit needed for the spell. Note: You need the dummy.mdx model.
    
// Constant Values:
    private constant real Max_curve = 2.50   // Maximum curve of the parabola for the projectile. Oddly enough, the high the number the lower the curve.
    private constant real Min_curve = 1.50   // Minimum curve of the parabola for the projectile.
    private constant real Max_dist = 200.00  // Maximum distance the souls (from when you die) will travel before changing paths.
    private constant real Min_dist = 100.00  // Minimum distance the souls (from when you die) will travel before changing paths.
    private constant real Proj_scale = 1.75  // Scale size of the ability projectile.
    private constant real Soul_scale = 1.00  // Scale size of the purified souls.
    private constant real Height = 30.00     // Fly height of the dummy model (the &quot;souls&quot;).
    private constant real Interval = 0.04    // Interval used for the periodic timer. It is recommended not to use a lower interval than 0.04.
    private constant real Collision = 100.00  // How close to units the souls have to be to either damage or heal.
    private constant integer Ring_count = 20 // How many effects are used to make the ring when the missile lands.
    
// Attack/Damage/Weapon types of damage dealt:
    private constant attacktype A_type = ATTACK_TYPE_CHAOS
    private constant damagetype D_type = DAMAGE_TYPE_UNIVERSAL
    private constant weapontype W_type = WEAPON_TYPE_WHOKNOWS
    
// Below is the special effect attached to create the projectile of the spell.
    private constant string Dummy_sfx = &quot;Abilities\\Spells\\Undead\\AbsorbMana\\AbsorbManaBirthMissile.mdl&quot;
    private constant string Dummy_point = &quot;chest&quot;
    
// Below is the special effect attached to unit when they are damaged by a tainted soul.
    private constant string Damage_sfx = &quot;Abilities\\Spells\\Undead\\DeathandDecay\\DeathandDecayTarget.mdl&quot;
    private constant string Damage_point = &quot;head&quot;
    
// Below is the special effect used to create the &quot;tainted souls&quot;.
    private constant string Tainted_sfx = &quot;Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl&quot;
    
// Below is the special effect used with the above effect. This one makes it look like the body explodes. This effect will only work if the dead units are removed (Dont_remove_bodies = false).
    private constant string Explode_sfx = &quot;Objects\\Spawnmodels\\Undead\\UndeadLargeDeathExplode\\UndeadLargeDeathExplode.mdl&quot;
    
// Below is the effect used as &quot;eye candy&quot; for when the projectile lands. Makes a ring around the target area using this effect.
    private constant string AoE_sfx = &quot;Abilities\\Spells\\Undead\\AbsorbMana\\AbsorbManaBirthMissile.mdl&quot;
    
// Below is the effect used to create the &quot;purified souls&quot;, this includes the ones that heal the caster and the ones that fly around when he dies.
    private constant string Purified_sfx = &quot;Abilities\\Spells\\Undead\\AbsorbMana\\AbsorbManaBirthMissile.mdl&quot;
    private constant string Purified_point = &quot;chest&quot;
    
// Below is the special effect created when the &quot;purified souls&quot; heal the caster.
    private constant string Complete_sfx = &quot;Abilities\\Spells\\Undead\\ReplenishMana\\SpiritTouchTarget.mdl&quot;
    private constant string Complete_point = &quot;overhead&quot;
    
// Below is the error message that is shown when there are no bodies.
    private constant string Error_msg = &quot;There are no usable bodies near the target area.&quot;
    
// Boolean variables:
    private constant boolean Allow_preload = true       // Whether or not to allow preloading.
    private constant boolean Dont_remove_bodies = false // If the bodies that souls come from should be removed or not. This should be false in an actual game.
endglobals

//=======================================================================
private function Projectile_duration takes integer lvl returns real
    return 1.50 + (0.00 * lvl) // Duration of the projectile of the spell.
endfunction

private function Body_radius takes integer lvl returns real
    return 175.00 + (25.00 * lvl) // Radius in which bodies are checked, to create souls.
endfunction

private function Damage_radius takes integer lvl returns real
    return 125.00 + (0.00 * lvl) // Radius in which enemies are checked, to deal damage.
endfunction

private function Damage_percent takes integer lvl returns real
    return 0.10 + (0.10 * lvl) // Percentage of the dead units maximum hitpoints that will be dealt in damage.
endfunction

private function Max_damage takes integer lvl returns real
    return 25.00 + (25.00 * lvl) // The maximum damage allowed by the above function (damage cap).
endfunction

private function Heal_percent takes integer lvl returns real
    return 0.10 + (0.05 * lvl) // Percentage of the dead units maximum hitpoints that will be used to heal the caster.
endfunction

private function Max_heal takes integer lvl returns real
    return 15.00 + (15.00 * lvl) // The maximum amount of health allowed to heal by the above function (heal cap).
endfunction

private function Soul_movespeed takes integer lvl returns real
    return 700.00 + (0.00 * lvl) // The movement speed of the purified souls as the move towards the caster.
endfunction

private function End_soul_movespeed takes integer lvl returns real
    return 500.00 + (0.00 * lvl) // The movement speed of the purified souls as they scatter when the caster dies.
endfunction

private function Enemy_soul_chance takes integer lvl returns integer
    return 20 + (10 * lvl) // Percent chance for an enemy (non-undead) unit to be purified and made into a soul.
endfunction

private function Max_souls takes integer lvl returns integer
    return 4 + (2 * lvl) // Maximum amount of souls that can be stored. Make sure you bonus stats ability has at least as many levels as this.
endfunction

private function Soul_duration takes integer lvl returns real
    return 5.00 + (5.00 * lvl) // How long the souls will be stored, and how long the will scatter for when the caster dies.
endfunction

private function Soul_hit_damage takes integer lvl returns real
    return 50.00 + (50.00 * lvl) // Damage dealt to a unit when they come in contact with a scattering soul.
endfunction

private function Max_bodies_allowed takes integer lvl returns integer
    return 100 // How many dead bodies within the area of effect will be used to create souls or damage enemies.
endfunction

// Below is the function used to detect bodies:
private function BodyFilt takes nothing returns boolean
    return GetWidgetLife(GetFilterUnit()) &lt;= 0.405 and IsUnitType(GetFilterUnit(),UNIT_TYPE_MECHANICAL) == false and IsUnitType(GetFilterUnit(),UNIT_TYPE_HERO) == false
endfunction

// Below if the function used to detect enemies (note: checking if the unit is an enemy is done internally):
private function EnemyFilt takes nothing returns boolean
    return GetWidgetLife(GetFilterUnit()) &gt; 0.405 and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) == false
endfunction

//=======================================================================\\
//                                                                       \\
//     DO NOT TOUCH PAST HERE UNLESS YOU KNOW WHAT YOU ARE DOING!!!      \\
//                                                                       \\
//=======================================================================\\

// Keywords needed to pass data.
private keyword Data
private keyword Move
private keyword Stat
private keyword Soul

globals
    private Data array A // Struct array.
    private Move array B // Struct array.
    private Stat array C // Struct array.
    private Soul array D // Struct array.
    private integer AT = 0 // Total amount of structs.
    private integer BT = 0 // Total amount of structs.
    private integer CT = 0 // Total amount of structs.
    private integer DT = 0 // Total amount of structs.
    private group Group = null // Global group used to group enemies.
    private timer Timer = null // Timer needed for the spell to run.
    private sound Error = null // Error sound used for error message.
    private real Game_MaxX = 0.00 // Used to detect map bounds.
    private real Game_MinX = 0.00 // Used to detect map bounds.
    private real Game_MaxY = 0.00 // Used to detect map bounds.
    private real Game_MinY = 0.00 // Used to detect map bounds.
    private boolexpr Truefilt = null // Used to stop this so called leak within trigger events.
    private boolexpr Bodyfilt = null // Used to refer to the BodyFilt function. More efficient then calling it numerous times.
    private boolexpr Enemyfilt = null // Used to refer to the EnemyFilt function. More efficient then calling it numerous times.
    private constant integer Order_stop = 851972 // Order Id for the &quot;stop&quot; order.
    private constant integer Order_move = 851986 // Order Id for the &quot;move&quot; order.
    private constant real Partial_angle = 360.00 / Ring_count // Used to find the angle difference for the ring effect.
endglobals

//=======================================================================
private function Parabola takes real dist, real maxdist, real curve returns real
    local real t = (dist * 2) / maxdist - 1
    return (-t * t + 1) * (maxdist / curve) // Parabolic function needed for projectile.
endfunction

private function DistanceXY takes real x1, real y1, real x2, real y2 returns real
    return SquareRoot((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) // Finds distance between points. Used this to make the code easier to read.
endfunction

private function AngleXY takes real x1, real y1, real x2, real y2 returns real
    return Atan2((y2 - y1),(x2 - x1)) // Finds the angle between points. Used this to make the code easier to read.
endfunction

//=======================================================================
private function SimError takes player Whichplayer, string Message returns nothing
    set Message = &quot;\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n|cffffcc00&quot;+Message+&quot;|r&quot;
    if (GetLocalPlayer() == Whichplayer) then
        call ClearTextMessages()
        call DisplayTimedTextToPlayer(Whichplayer,0.5125,0.97120,2.00,Message)
        call StartSound(Error) // Replicates a sim error. Used this to make the spell seem more &quot;professional&quot;.
    endif
endfunction

//=======================================================================
private function SafeX takes real x returns real
    if x &lt; Game_MinX then
        return Game_MinX
    elseif x &gt; Game_MaxX then // Finds a safe x location within map bounds.
        return Game_MaxX
    endif
    return x
endfunction

private function SafeY takes real y returns real
    if y &lt; Game_MinY then
        return Game_MinY
    elseif y &gt; Game_MaxY then // Finds a safe y location within map bounds.
        return Game_MaxY
    endif
    return y
endfunction

//=======================================================================
private struct Data
    unit cast = null
    unit dum = null
    real targx = 0.00     // Initialising struct members isn&#039;t necessary, but it is a habit of mine.
    real targy = 0.00     // This does not impede on performace or script readability.
    real cos = 0.00
    real sin = 0.00
    real curve = 0.00
    real maxdist = 0.00
    real movedist = 0.00
    real counter = 0.00
    integer lvl = 0
    effect sfx = null
    group g = CreateGroup() // Needed so that groups arent overridden.
    
    static method create takes nothing returns Data
        local Data a = Data.allocate()
        local location targ = GetSpellTargetLoc()// I wish there was a GetSpellTargetLocX/Y
        local real castx = 0.00
        local real casty = 0.00
        local real angle = 0.00
    
        // Assigning struct members:
        set a.cast = GetTriggerUnit()
        set castx = GetUnitX(a.cast)
        set casty = GetUnitY(a.cast)
        set a.targx = GetLocationX(targ)
        set a.targy = GetLocationY(targ)
        set a.lvl = GetUnitAbilityLevel(a.cast,Abil_id)
        set angle = AngleXY(castx,casty,a.targx,a.targy)
        set a.maxdist = DistanceXY(castx,casty,a.targx,a.targy)
        set a.movedist = (2.00 * a.maxdist) / (Projectile_duration(a.lvl) / Interval)
        set a.curve = GetRandomReal(Min_curve,Max_curve)
        set a.cos = Cos(angle)
        set a.sin = Sin(angle)
        set a.counter = 0.00
        
        // Creating the dummy unit and adding effect.
        set a.dum = CreateUnit(GetOwningPlayer(a.cast),Dummy_id,castx,casty,(angle * bj_RADTODEG))
        set a.sfx = AddSpecialEffectTarget(Dummy_sfx,a.dum,Dummy_point)
        call SetUnitScale(a.dum,Proj_scale,Proj_scale,Proj_scale)
        call SetUnitPathing(a.dum,false)
        call UnitAddAbility(a.dum,Crow_id)
        call UnitRemoveAbility(a.dum,Crow_id)
        
        set AT = AT + 1
        set A[AT] = a // Adding this struct instance to the array.
    
        call RemoveLocation(targ) // Removing the gay location.
        set targ = null
        
        return a
    endmethod
    
    // Below is clearing the struct instance and gets rid of the dummy unit:
    private method onDestroy takes nothing returns nothing
        call DestroyEffect(.sfx)
        set .sfx = null
        
        call RemoveUnit(.dum)    // Again, nulling struct members isn&#039;t necessary,
        set .dum = null          // as they will just be overridden, but it doesn&#039;t hurt.
        
        call GroupClear(.g)
        call DestroyGroup(.g)
        set .g = null
        
        set .cast = null
    endmethod
endstruct

//=======================================================================
private struct Move
    unit cast = null
    unit dum = null
    real angle = 0.00
    real maxdist = 0.00  // Same as last struct, not necessary.
    real speed = 0.00
    real heal = 0.00
    integer lvl = 0
    effect sfx = null
    
    // Below creates a purified soul as sets the struct members.
    static method create takes unit caster, unit body, real bx, real by, integer level returns Move
        local Move b = Move.allocate()
        local real x = GetUnitX(caster)
        local real y = GetUnitY(caster)

        set b.cast = caster
        set b.dum = CreateUnit(GetOwningPlayer(b.cast),Dummy_id,bx,by,0.00)
        set b.angle = AngleXY(bx,by,x,y)
        set b.lvl = level
        set b.maxdist = DistanceXY(x,y,bx,by)
        set b.speed = Soul_movespeed(b.lvl) * Interval
        set b.sfx = AddSpecialEffectTarget(Purified_sfx,b.dum,Purified_point)
        set b.heal = GetUnitState(body,UNIT_STATE_MAX_LIFE) * Heal_percent(b.lvl)

        if b.heal &gt; Max_heal(b.lvl) then
            set b.heal = Max_heal(b.lvl)
        endif
    
        call SetUnitPathing(b.dum,false)
        call UnitAddAbility(b.dum,Crow_id)
        call UnitRemoveAbility(b.dum,Crow_id)
        call SetUnitScale(b.dum,Soul_scale,Soul_scale,Soul_scale)
        call SetUnitFlyHeight(b.dum,Height,0.00)
        
        set BT = BT + 1
        set B[BT] = b  // Adding this struct instance to the array.
        
        return b
    endmethod
    
    // Below clear the struct instance and ets rid of the soul:
    private method onDestroy takes nothing returns nothing    
        call DestroyEffect(.sfx)
        set .sfx = null
        
        call RemoveUnit(.dum)
        set .dum = null       // Same as last struct, not needed, but doesn&#039;t hurt.
        
        // Below heals the caster when the soul reaches it, and plays the effect.
        call SetWidgetLife(.cast,GetWidgetLife(.cast) + .heal)
        call DestroyEffect(AddSpecialEffectTarget(Complete_sfx,.cast,Complete_point))
        
        set .cast = null
    endmethod
endstruct

//=======================================================================
private struct Stat
    unit cast = null
    real time = 0.00  // I made a new struct for the bonus stats, to make it &quot;modular&quot;, if thats what you could call it.
    integer lvl = 0   // It makes it far easier to read, and if you want to remove it, it is also easier.
    
    // Below adds a bonus stat if necessary.
    static method create takes unit caster, integer level returns Stat
        local Stat c = Stat.allocate()
        local integer lvl = GetUnitAbilityLevel(caster,Stats_id)
        
        set c.cast = caster
        set c.lvl = level
                    
        if lvl == 0 then
            call UnitAddAbility(c.cast,Stats_id)
        elseif lvl &gt;= Max_souls(c.lvl) then
            call SetUnitAbilityLevel(c.cast,Stats_id,Max_souls(c.lvl))
        else
            call IncUnitAbilityLevel(c.cast,Stats_id)
        endif
        
        set CT = CT + 1
        set C[CT] = c  // Adding this struct instance to the array.
        
        return c
    endmethod
    
    // Below decreases the bonus stats or removes the ability.
    private method onDestroy takes nothing returns nothing
        if GetUnitAbilityLevel(.cast,Stats_id) == 1 then
            call UnitRemoveAbility(.cast,Stats_id)
        else
            call DecUnitAbilityLevel(.cast,Stats_id)
        endif
        
        set .cast = null
    endmethod
endstruct

//=======================================================================
private struct Soul
    unit cast = null
    unit dum = null
    real targx = 0.00
    real targy = 0.00
    real angle = 0.00
    real dist = 0.00
    real speed = 0.00
    real counter = 0.00
    real time = 0.00
    integer lvl = 0
    integer hit = 0
    effect sfx = null
    group g = CreateGroup() // I know its bad, but i used it to ensure no group-overriding occurs. Better safe then sorry <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite8" alt=":D" title="Big Grin    :D" loading="lazy" data-shortname=":D" />.
    
    // Below will create a &quot;scattering soul&quot; when the hero dies with stats still remaining.
    static method create takes unit caster, integer level returns Soul
        local Soul d = Soul.allocate()
        local real dumx = 0.00
        local real dumy = 0.00
        
        set d.cast = caster
        set d.dum = CreateUnit(GetOwningPlayer(d.cast),Dummy_id,GetUnitX(d.cast),GetUnitY(d.cast),GetRandomReal(0.00,360.00))
        set dumx = GetUnitX(d.dum)
        set dumy = GetUnitY(d.dum)
        set d.lvl = level
        set d.sfx = AddSpecialEffectTarget(Purified_sfx,d.dum,Purified_point)
        set d.targx = dumx + GetRandomReal(Min_dist,Max_dist) * Cos(GetUnitFacing(d.dum) * bj_DEGTORAD)
        set d.targy = dumy + GetRandomReal(Min_dist,Max_dist) * Sin(GetUnitFacing(d.dum) * bj_DEGTORAD)
        set d.dist = DistanceXY(dumx,dumy,d.targx,d.targy)
        set d.angle = AngleXY(dumx,dumy,d.targy,d.targy)
        set d.speed = End_soul_movespeed(d.lvl) * Interval
        
        call SetUnitPathing(d.dum,false)
        call UnitAddAbility(d.dum,Crow_id)
        call UnitRemoveAbility(d.dum,Crow_id)
        call SetUnitFlyHeight(d.dum,Height,0.00)
        call SetUnitScale(d.dum,Soul_scale,Soul_scale,Soul_scale)
        
        set DT = DT + 1
        set D[DT] = d  // Adding this struct instance to the array.
        
        return d
    endmethod
    
    // Below destroys the dummy unit and effects and the dynamic group used.
    private method onDestroy takes nothing returns nothing
        call DestroyEffect(.sfx)
        set .sfx = null
        
        call RemoveUnit(.dum)
        set .dum = null
        
        call GroupClear(.g)
        call DestroyGroup(.g)
        set .g = null
        
        set .cast = null
    endmethod
endstruct

//=======================================================================
private function DamageArea takes unit cast, real x, real y, real damage, integer lvl returns nothing
    local unit u = null
    
    call DestroyEffect(AddSpecialEffect(Tainted_sfx,x,y)) // Plays the tainted effect.
    if Dont_remove_bodies == false then
        call DestroyEffect(AddSpecialEffect(Explode_sfx,x,y)) // If bodies are being removed, then make it explode.
    endif
                    
    call GroupEnumUnitsInRange(Group,x,y,Damage_radius(lvl),Enemyfilt) // Damages an area if the dead body is undead or an enemy that cant be purified.
    
    loop
        set u = FirstOfGroup(Group)
        exitwhen u == null
        call GroupRemoveUnit(Group,u)
        if IsUnitEnemy(u,GetOwningPlayer(cast)) then
            call UnitDamageTarget(cast,u,damage,false,false,A_type,D_type,W_type) // damage any enemy unit within the area of effect.
            call DestroyEffect(AddSpecialEffectTarget(Damage_sfx,u,Damage_point)) // Add a special effect to that unit.
        endif
    endloop
    
    set u = null // Not really needed, but it seemed to help the handle count :S.
endfunction

//=======================================================================
private function Update takes nothing returns nothing
    local Move b = 0
    local Stat c = 0
    local integer i = 1
    local integer j = 0
    local integer lvl = 0
    local real damage = 0.00
    local real height = 0.00
    local real tmpang = 0.00
    local real x = 0.00
    local real y = 0.00
    local unit u = null
    
    // Looping through the struct array for the Data struct (main struct of the ability).
    loop
        exitwhen i &gt; AT
        
        set x = GetUnitX(A<i>.dum)
        set y = GetUnitY(A<i>.dum)
        
        if A<i>.counter &gt;= A<i>.maxdist then // If we have reached the max distance, finish.
            set tmpang = 0.00
            loop
                exitwhen tmpang == 360.00
                set x = A<i>.targx + (Body_radius(A<i>.lvl) * 0.90) * Cos(tmpang * bj_DEGTORAD) // The effects make the area of effect look bigger, so we reduce it a bit, to fit better.
                set y = A<i>.targy + (Body_radius(A<i>.lvl) * 0.90) * Sin(tmpang * bj_DEGTORAD)
                call DestroyEffect(AddSpecialEffect(AoE_sfx,SafeX(x),SafeY(y))) // Make the circle effects to show the area of effect.
                set tmpang = tmpang + Partial_angle
            endloop
            call GroupEnumUnitsInRange(A<i>.g,A<i>.targx,A<i>.targy,Body_radius(A<i>.lvl),Bodyfilt)
            loop
                set u = FirstOfGroup(A<i>.g)
                exitwhen u == null or j == Max_bodies_allowed(A<i>.lvl)            // Loops the the dead bodies.
                call GroupRemoveUnit(A<i>.g,u)
                set x = SafeX(GetUnitX(u))
                set y = SafeY(GetUnitY(u))
                set damage = GetUnitState(u,UNIT_STATE_MAX_LIFE) * Damage_percent(A<i>.lvl)
                if damage &gt; Max_damage(A<i>.lvl) then
                    set damage = Max_damage(A<i>.lvl) // Keeps the damage under the max allowed.
                endif
                // Below checks if the unit is either undead or a demon.
                if IsUnitRace(u,RACE_UNDEAD) or IsUnitRace(u,RACE_DEMON) or IsUnitType(u,UNIT_TYPE_UNDEAD) == true then
                    call DamageArea(A<i>.cast,x,y,damage,A<i>.lvl)
                else
                    if IsUnitEnemy(u,GetOwningPlayer(A<i>.cast)) then
                        if GetRandomInt(0,100) &lt;= Enemy_soul_chance(A<i>.lvl) then // Percent chance to purify the unit.
                            set b = Move.create(A<i>.cast,u,x,y,A<i>.lvl) // Add everything to the create method for better readability.
                        else
                            call DamageArea(A<i>.cast,x,y,damage,A<i>.lvl)
                        endif
                    else
                        set b = Move.create(A<i>.cast,u,x,y,A<i>.lvl) // Add everything to the create method for better readability.
                    endif
                endif
                
                if Dont_remove_bodies == false then
                    call RemoveUnit(u) // Used mostly for testing purposes.
                endif
                
                set j = j + 1
            endloop
            call A<i>.destroy()
            set A<i> = A[AT]    // Destroys the struct instance, and fixes array slots.
            set AT = AT - 1
            set i = i - 1
            set j = 0
        else
            set x = x + A<i>.movedist * A<i>.cos
            set y = y + A<i>.movedist * A<i>.sin
            set height = Parabola(A<i>.counter,A<i>.maxdist,A<i>.curve)
            
            call SetUnitX(A<i>.dum,SafeX(x)) // Moves the unit and sets the fly height (parabola)
            call SetUnitY(A<i>.dum,SafeY(y))
            call SetUnitFlyHeight(A<i>.dum,height,0.00)
            
            set A<i>.counter = A<i>.counter + A<i>.movedist
        endif
        
        set i = i + 1
    endloop
    
    set i = 1
    
    // Looping through the struct array for the Move struct (used for the purified souls):
    loop
        exitwhen i &gt; BT
        
        set x = GetUnitX(B<i>.dum)
        set y = GetUnitY(B<i>.dum)
        
        // Constantly checks for the distance between the caster and the dummy.
        // A necessary evil <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite3" alt=":(" title="Frown    :(" loading="lazy" data-shortname=":(" />.
        set B<i>.maxdist = DistanceXY(x,y,GetUnitX(B<i>.cast),GetUnitY(B<i>.cast))
        
        if B<i>.maxdist &lt;= Collision then // If the soul is close enough to the unit, finish.
            if GetUnitAbilityLevel(B<i>.cast,Stats_id) &lt; Max_souls(B<i>.lvl) then
                set c = Stat.create(B<i>.cast,B<i>.lvl) // If the max souls threshold hasnt been reached, add another stat.
            endif
            call B<i>.destroy()
            set B<i> = B[BT]    // Destroys the struct instance, and fixes array slots.
            set BT = BT - 1
            set i = i - 1
        else    
            set B<i>.angle = AngleXY(x,y,GetUnitX(B<i>.cast),GetUnitY(B<i>.cast)) // Another necessary evil.
            
            set x = x + B<i>.speed * Cos(B<i>.angle)
            set y = y + B<i>.speed * Sin(B<i>.angle)
            
            call SetUnitX(B<i>.dum,SafeX(x)) // Moves the dummy unit.
            call SetUnitY(B<i>.dum,SafeY(y))
        endif
        
        set i = i + 1
    endloop
    
    set i = 1
    
    // Looping through the struct array for the Stat struct (very simple but needed).
    loop
        exitwhen i &gt; CT
        
        if C<i>.time &gt;= Soul_duration(C<i>.lvl) then // If the duration is up, finish.
            call C<i>.destroy()
            set C<i> = C[CT]   // Destroys the struct instance, and fixes array slots.
            set CT = CT - 1
            set i = i - 1
        else
            set C<i>.time = C<i>.time + Interval // Increases the time by &quot;Interval&quot;.
        endif
        
        set i = i + 1
    endloop
    
    set i = 1
    
    // Looping through the struct array for the Soul struct (moves the &quot;scattering souls&quot;):
    loop
        exitwhen i &gt; DT
        
        set x = GetUnitX(D<i>.dum)
        set y = GetUnitY(D<i>.dum)
        
        if D<i>.time == Soul_duration(D<i>.lvl) or D<i>.hit == 1 then // If the duration is up, or a unit has been hit, finish.
            call D<i>.destroy()
            set D<i> = D[DT]   // Destroys the struct instance, and fixes array slots.
            set DT = DT - 1
            set i = i - 1
        else
            // If the unit has reached the random point, assign a new random point to go to.
            if D<i>.counter &gt;= D<i>.dist then
                set D<i>.targx = x + GetRandomReal(Min_dist,Max_dist) * Cos(GetRandomReal(0.00,360.00) * bj_DEGTORAD)
                set D<i>.targy = y + GetRandomReal(Min_dist,Max_dist) * Sin(GetRandomReal(0.00,360.00) * bj_DEGTORAD) 
                set D<i>.dist = DistanceXY(x,y,D<i>.targx,D<i>.targy) // More necessary evils.
                set D<i>.angle = AngleXY(x,y,D<i>.targx,D<i>.targy)
                set D<i>.counter = 0.00
            endif
            
            set x = x + D<i>.speed * Cos(D<i>.angle)
            set y = y + D<i>.speed * Sin(D<i>.angle)
            
            call SetUnitX(D<i>.dum,SafeX(x)) // Moves the dummy unit.
            call SetUnitY(D<i>.dum,SafeY(y))
                
            call GroupEnumUnitsInRange(D<i>.g,x,y,Collision,Enemyfilt)
            
            loop
                set u = FirstOfGroup(D<i>.g)
                exitwhen u == null or D<i>.hit == 1  // Finds a unit to damage and damages it, otherwise keep moving.
                call GroupRemoveUnit(D<i>.g,u)
                if IsUnitEnemy(u,GetOwningPlayer(D<i>.cast)) then
                    call UnitDamageTarget(D<i>.cast,u,Soul_hit_damage(D<i>.lvl),false,false,A_type,D_type,W_type)
                    set D<i>.hit = 1
                endif
            endloop
            
            set D<i>.counter = D<i>.counter + D<i>.speed
            set D<i>.time = D<i>.time + Interval // Increases the time by &quot;Interval&quot;.
        endif
        
        set i = i + 1
    endloop
    
    if AT &lt;= 0 and BT &lt;= 0 and CT &lt;= 0 and DT &lt;= 0 then
        call PauseTimer(Timer)
        set AT = 0
        set BT = 0  // If there are no more struct instances running we can pause the timer.
        set CT = 0
        set DT = 0
    endif
    
    set u = null // probably not needed, but just to be safe.
endfunction
        
//=======================================================================
private function Actions takes nothing returns nothing
    local Data a = Data.create()

    if AT == 1 and BT == 0 and CT == 0 and DT == 0 then
        call TimerStart(Timer,Interval,true,function Update) // If this is the only instance running we need to start the timer.
    endif
endfunction

//=======================================================================
private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == Abil_id // Conditions for the spell.
endfunction

//=======================================================================
private function CastConds takes nothing returns boolean
    local unit cast = GetTriggerUnit()
    local location targ = GetSpellTargetLoc()
    
    call GroupEnumUnitsInRange(Group,GetLocationX(targ),GetLocationY(targ),Body_radius(GetUnitAbilityLevel(cast,Abil_id)),Bodyfilt)
    
    if FirstOfGroup(Group) == null then
        call PauseUnit(cast,true)
        call IssueImmediateOrderById(cast,Order_stop)   // If there are no dead units within the target error,
        call PauseUnit(cast,false)                      // then lets stop the unit, and show an error message.
        call SimError(GetOwningPlayer(cast),Error_msg)
    endif
    
    set cast = null
    call RemoveLocation(targ) // Removal of gay location again.
    set targ = null // Nulling.
    
    return false
endfunction

//=======================================================================
private function DeathConds takes nothing returns boolean
    local Soul d = 0
    local unit dead = GetDyingUnit()
    local integer stat = GetUnitAbilityLevel(dead,Stats_id) // How many souls are inside this hero?
    local integer lvl = GetUnitAbilityLevel(dead,Abil_id)
    local integer i = 1
    
    if stat &gt; 0 then
        loop
            exitwhen i &gt; stat
            set d = Soul.create(dead,lvl) // Create a new &quot;scattering soul&quot; for every level of the stat ability.
            set i = i + 1
        endloop
        
        call UnitRemoveAbility(dead,Stats_id) // Remove the stat ability from the unit.
    endif
    
    set dead = null // Nulling.
    
    return false
endfunction

//=======================================================================
private function TrueFilt takes nothing returns boolean
    return true // The true filter needed for the so called leak.
endfunction

//=======================================================================
private function Init takes nothing returns nothing
    local trigger trig = CreateTrigger()
    local integer i = 0
    local unit dum = null
    
    set Group = CreateGroup() // Creating the global group.
    set Timer = CreateTimer() // Creating the timer needed for the spell.
    set Truefilt = Filter(function TrueFilt)   // Setting the true filter, so we only call it once.
    set Bodyfilt = Filter(function BodyFilt)   // Setting the body filter, so we only call it once.
    set Enemyfilt = Filter(function EnemyFilt) // Setting the enemy filter, so we only call it once.
    set Error = CreateSoundFromLabel(&quot;InterfaceError&quot;,false,false,false,10,10) // Setting the sound variable.
    
    set Game_MaxX = GetRectMaxX(bj_mapInitialPlayableArea) - 64.00 // Setting up the map bounds.
    set Game_MinX = GetRectMinX(bj_mapInitialPlayableArea) + 64.00 // Setting up the map bounds.
    set Game_MaxY = GetRectMaxY(bj_mapInitialPlayableArea) - 64.00 // Setting up the map bounds.
    set Game_MinY = GetRectMinY(bj_mapInitialPlayableArea) + 64.00 // Setting up the map bounds.
    
    loop
        call TriggerRegisterPlayerUnitEvent(trig,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,Truefilt)
        set i = i + 1 // This loop is for the actual trigger of the ability.
        exitwhen i == bj_MAX_PLAYER_SLOTS
    endloop
    
    call TriggerAddCondition(trig,Condition(function Conditions))
    call TriggerAddAction(trig,function Actions)
    
    set i = 0
    set trig = CreateTrigger()
    
    loop
        call TriggerRegisterPlayerUnitEvent(trig,Player(i),EVENT_PLAYER_UNIT_SPELL_CAST,Truefilt)
        set i = i + 1 // This loop is for the pre-cast checking of dead units.
        exitwhen i == bj_MAX_PLAYER_SLOTS
    endloop
    
    call TriggerAddCondition(trig,Condition(function CastConds))
    
    set i = 0
    set trig = CreateTrigger()
    
    loop
        call TriggerRegisterPlayerUnitEvent(trig,Player(i),EVENT_PLAYER_UNIT_DEATH,Truefilt)
        set i = i + 1 // This loop is for when a hero does and has the stat ability.
        exitwhen i == bj_MAX_PLAYER_SLOTS
    endloop
    
    call TriggerAddCondition(trig,Condition(function DeathConds))
    
    // If Allow_preload is true, then this will preload some effects to reduce first cast lag and all that.
    if Allow_preload then
        set dum = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),Dummy_id,0.00,0.00,0.00)
        call UnitAddAbility(dum,Stats_id)
        call RemoveUnit(dum)
        call DestroyEffect(AddSpecialEffect(Dummy_sfx,0.00,0.00))
        call DestroyEffect(AddSpecialEffect(Damage_sfx,0.00,0.00))
        call DestroyEffect(AddSpecialEffect(Tainted_sfx,0.00,0.00))
        call DestroyEffect(AddSpecialEffect(Explode_sfx,0.00,0.00))
        call DestroyEffect(AddSpecialEffect(AoE_sfx,0.00,0.00))
        call DestroyEffect(AddSpecialEffect(Purified_sfx,0.00,0.00))
        call DestroyEffect(AddSpecialEffect(Complete_sfx,0.00,0.00))
    endif
    
    set trig = null // Not needed as the trigger will run all game, but why not?
    set dum = null  // More nulling.
endfunction

// The end of the spell <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite8" alt=":D" title="Big Grin    :D" loading="lazy" data-shortname=":D" />.
endscope

</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>
 

Attachments

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

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top