Spell Energy Empower

Dinowc

don't expect anything, prepare for everything
Reaction score
223
Energy Empower
v1.6
manaflare.gif

Type: Instant, Point Target
Targets: Enemy
Description:
Activates a magic shell charging energy every time hero loses mana. He can then blast an area with energy dealing part of the lost mana in damage and slowing enemies by 50% for 4 seconds.
Can store up to 25 x hero's intelligence mana.

Level 1 - 30% of lost mana, 300 AOE.
Duration 25 seconds.
Level 2 - 40% of lost mana, 350 AOE.
Duration 30 seconds.
Level 3 - 50% of lost mana, 400 AOE.
Duration 35 seconds.
Level 4 - 60% of lost mana, 450 AOE.
Duration 40 seconds.

Requires: TU, PUI, dummy model (you can export the dummy model from the map cause I can't remember the link :p)
Import Difficulty: Not very simple (you need 2 systems, 2 spells and 2 dummies)

JASS:
////////////////////////////////////////////////////////
//
// ENERGY EMPOWER - by Dinowc
//
// Changelog:
//
// v1.6 - fixed the code, used one global dummy for casting purge instead of creating many, increased the duration of slow to 5 seconds
// v1.5 - improved the spell (it deals damage on effect explosion, looks much better)
// v1.4 - improved and optimized the code
// v1.3 - modified spell and code, add a new spell mode, fixed some bugs
// v1.2 - further improved code and the spell, added eye-candy effects
// v1.1 - modified the spell, fixed the code, added a floating text that shows damage done (can be turned off)
// v1.0 - initial release
//
// Pros:
// - MUI, leakless, lagless (might lag if you spam)
// - fully configurable
//
// Cons:
//
// - requires 2 systems
// - huge code
// - first time cast lag (needs preloading)
// - the more/bigger effects you use, the more lag could appear
//
// Requirements: NewGen, TimerUtils, PUI, Vexorian's dummy model (everything included in map)
//
// Installation:
//
// 1. create a new trigger, go to Edit > Convert to Custom text and copy this code into it
// 2. create 2 abilities - 1 hero and 1 unit ability, hero ability must be instant, unit must be point targeted
// 3. write their raw codes in "SPELL_ID" and "CHARGE_ID" fields
// 4. save and test the map
//
// if you got any problems or encounter any bug, pm me!
//

scope energy initializer init

//changeable:

globals
    private constant integer SPELL_ID = 'A000' // ID of the main spell
    private constant integer CHARGE_ID = 'A001' // ID of the charge spell
    private constant integer PURGE_ID = 'A002' // dummy's spell
    private constant integer BUFF_ID = 'B000'
    private constant integer DUMMY_ID = 'h000'
    private constant integer EFFECT_DUMMY = 'h001'
    
    private constant real INTERVAL = 0.25 // every [this value] seconds checks unit's mana, the lower it is the more precise it will be, but also lagier
    private constant real DMG_INTERVAL = 0.50 // wait [this value] seconds before dealing dmg
    private constant real DamageFactor = 0.20 // + (level of ability * 0.1) of stored mana dealt in damage
    private constant real ManaCapacity = 25. // * hero's intelligence -> maximum mana stored
    
    private constant string MANA_EFFECT = "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl"  //mana gain effect, type null to show no effect
    private constant string MANA_EFFECT_ATTACH = "chest"
    private constant string DMG_EFFECT = "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdl" // the effect that appears on damaged units, type null to show no effect
    private constant string DMG_EFFECT_ATTACH = "chest"
    private constant string SPELL_EFFECT1 = "Abilities\\Spells\\Human\\ReviveHuman\\ReviveHuman.mdl" // type null to show no effect
    private constant real SPELL_EFFECT1_FACTOR = 250. // size of SPELL_EFFECT1 (smaller effects require smaller value)
    private constant string SPELL_EFFECT2 = "Abilities\\Spells\\NightElf\\Blink\\BlinkTarget.mdl" // type null to show no effect
    private constant real SPELL_EFFECT2_FACTOR = 125. // size of SPELL_EFFECT2 (smaller effects require smaller value)
    
    private constant boolean SHOW_DMG = true // whether  to show floating text or not
    private constant real AOE = 250. // + (level of ability * 50) - the size of the SPELL_EFFECTS depends on this
    private constant attacktype ATTACK_TYPE = ATTACK_TYPE_MAGIC
    private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_LIGHTNING
    
    private constant unitstate SPELL_MODE = UNIT_STATE_MANA // type UNIT_STATE_LIFE if you want to gain damage every time unit loses hp instead
endglobals

//don't touch this:

private function damage takes integer level returns real
    return (level * 0.1) + DamageFactor
endfunction

private function AoE takes integer level returns real
    return (level * 50) + AOE
endfunction

function SetUnitSize takes unit whichUnit, real a, real b, integer level returns nothing
    call SetUnitScale(whichUnit, a + (b * level), a + (b * level), a + (b * level))
endfunction

private function floatText takes unit u, real dmg returns nothing
    local real x
    local real y
    
    local texttag text = CreateTextTag()
    call SetTextTagText(text, I2S(R2I(dmg)) + "!", 0.023)
    call SetTextTagPos(text, GetUnitX(u), GetUnitY(u), 50.)
    call SetTextTagColor(text, 0, 255, 255, 255)
    call SetTextTagPermanent(text, false)
    call SetTextTagLifespan(text, 2.)
    call SetTextTagFadepoint(text, 1.)
    
    set x = 0.0532 * Cos(90. * bj_DEGTORAD)
    set y = 0.0532 * Sin(90. * bj_DEGTORAD)
    
    call SetTextTagVelocity(text, x, y)
    
    set text = null
endfunction


//////////////////////////////////////////////////////////

private struct data
    //! runtextmacro PUI()
    unit caster
    real storedMana
    real currentMana
    real x
    real y
    player p
    real newMana
    timer t
    
    static method create takes unit whichUnit returns data
        local data d = data.allocate()
        
        set d.caster = whichUnit
        set d.storedMana = 0.
        set d.currentMana = 0.
        set d.t = NewTimer()
        
        return d
    endmethod
    
    private method onDestroy takes nothing returns nothing
        call ReleaseTimer(.t)
    endmethod
    
endstruct

//////////////////////////////////////////////////////////

globals
    private unit DUMMY
    private unit U
    private unit Picked
    private real DAMAGE
    private player P
    private group G = CreateGroup()
endglobals

/////////////////////////////////////////////////////////

private function cond1 takes nothing returns boolean
    return GetSpellAbilityId() == SPELL_ID
endfunction

private function cond2 takes nothing returns boolean
    return GetSpellAbilityId() == CHARGE_ID and GetUnitAbilityLevel(GetTriggerUnit(), SPELL_ID) > 0
endfunction

///////////////////////////////////////////////////////////

private function manaStore takes nothing returns nothing
    local data d = GetTimerData(GetExpiredTimer())
    
    if GetUnitAbilityLevel(d.caster, BUFF_ID) > 0 then
    
        set d.newMana = GetUnitState(d.caster, SPELL_MODE)
    
        if d.newMana < d.currentMana then
            if d.storedMana < ManaCapacity * GetHeroInt(d.caster, true) then
                call DestroyEffect(AddSpecialEffectTarget(MANA_EFFECT, d.caster, MANA_EFFECT_ATTACH))
                set d.storedMana = d.storedMana + (d.currentMana - d.newMana)
            else
                set d.storedMana = ManaCapacity * GetHeroInt(d.caster, true)
            endif
        endif
    
        set d.currentMana = GetUnitState(d.caster, SPELL_MODE)
        
        call TimerStart(d.t, INTERVAL, false, function manaStore)
    else
        call d.destroy()
    endif
    
endfunction

private function filterFunc takes nothing returns boolean
    set Picked = GetFilterUnit()
    
    if IsUnitEnemy(Picked, P) == true and GetWidgetLife(Picked) > 0. then
        call UnitDamageTarget(U, Picked, DAMAGE, true, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE_WHOKNOWS)
        call SetUnitX(DUMMY, GetUnitX(Picked))
        call SetUnitY(DUMMY, GetUnitY(Picked))
        
        call IssueTargetOrder(DUMMY, "purge", Picked)
        call DestroyEffect(AddSpecialEffectTarget(DMG_EFFECT, Picked, DMG_EFFECT_ATTACH))
        
        if SHOW_DMG == true then
            call floatText(Picked, DAMAGE)
        endif
    endif
    
    return false
endfunction

private function blastEffect takes nothing returns nothing
    local data d = GetTimerData(GetExpiredTimer())
    
    set P = GetOwningPlayer(d.caster)
    set U = d.caster
    call SetUnitOwner(DUMMY, P, false)
    
    call GroupEnumUnitsInRange(G, d.x, d.y, AoE(GetUnitAbilityLevel(d.caster, SPELL_ID)), Condition(function filterFunc))
    
    call d.release()
endfunction

//////////////////////////////////////////////////////////

private function actions2 takes nothing returns nothing
    local data d = data[GetTriggerUnit()]
    
    local location target = GetSpellTargetLoc()
    local unit dummy
    set d.x = GetLocationX(target)
    set d.y = GetLocationY(target)
    
    call UnitRemoveAbility(d.caster, BUFF_ID)
    
    set U = d.caster
    set d.p = GetOwningPlayer(U)
    
    set DAMAGE = d.storedMana * damage(GetUnitAbilityLevel(U, SPELL_ID))
    
    set dummy = CreateUnit(d.p, EFFECT_DUMMY, d.x, d.y, 0.)
    call SetUnitSize(dummy, (AOE / SPELL_EFFECT1_FACTOR), AOE / SPELL_EFFECT1_FACTOR, (GetUnitAbilityLevel(U, SPELL_ID)))
    call DestroyEffect(AddSpecialEffectTarget(SPELL_EFFECT1, dummy, "origin"))
    call UnitApplyTimedLife(dummy, 'BTLF', 0.10)
    
    set dummy = CreateUnit(d.p, EFFECT_DUMMY, d.x, d.y, 0.)
    call SetUnitSize(dummy, (AOE / SPELL_EFFECT2_FACTOR), AOE / SPELL_EFFECT2_FACTOR, (GetUnitAbilityLevel(U, SPELL_ID)))
    call DestroyEffect(AddSpecialEffectTarget(SPELL_EFFECT2, dummy, "origin"))
    call UnitApplyTimedLife(dummy, 'BTLF', 0.10)
    
    call UnitRemoveAbility(d.caster, CHARGE_ID)
    
    call SetTimerData(d.t, d)
    call TimerStart(d.t, DMG_INTERVAL, false, function blastEffect)
    
    call RemoveLocation(target)
    set target = null
    set dummy = null
endfunction

//////////////////////////////////////////////////////////

private function actions1 takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local data d = data.create(u)
    
    set data<u> = d

    call UnitAddAbility(d.caster, CHARGE_ID)
    call SetUnitAbilityLevel(d.caster, CHARGE_ID, GetUnitAbilityLevel(d.caster, SPELL_ID))
    
    call SetTimerData(d.t, d)
    call TimerStart(d.t, INTERVAL, false, function manaStore)
    
    set u = null
endfunction
    
//=========================================================

private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function cond1))
    call TriggerAddAction(t, function actions1)
    
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function cond2))
    call TriggerAddAction(t, function actions2)
    
    set t = null
    set DUMMY = CreateUnit(Player(13), DUMMY_ID, 0., 0., 0.)
endfunction

endscope</u>



-mana charge
81461287.jpg

-energy blast
45864078.jpg

71053678.jpg


no point judging from the screenshots, try it out ingame


Changelog:

v1.6 - fixed the code, used one global dummy for casting purge instead of creating many, increased the duration of slow to 5 seconds
v1.5 - improved the spell (it deals damage on effect explosion, looks much better)
v1.4 - improved and optimized the code
v1.3 - modified spell and code, add a new spell mode, fixed some bugs
v1.2 - further improved code and the spell, added eye-candy effects
v1.1 - modified the spell, fixed the code, added a floating text that shows damage done (can be turned off)
v1.0 - initial release

updated daily.
 

Azlier

Old World Ghost
Reaction score
461
...Why are debug messages showing up during the spell? What's the point of that?
 

Dinowc

don't expect anything, prepare for everything
Reaction score
223
they show how much dmg is inflicted...
I just added it for testing

it can be removed by deleting 1 line (where the call BJDebugMsg appears)
 

Romek

Super Moderator
Reaction score
963
Why on earth are you destroying timers you create with NewTimer()?

Oh, and spells with visible Debug Messages won't be approved. It's an easy removal anyway.
 

Dinowc

don't expect anything, prepare for everything
Reaction score
223
so I should use ReleaseTimer() instead?

and I'll remove the debug message when I return from school

I needed it for testing
 

Dinowc

don't expect anything, prepare for everything
Reaction score
223
BUMP

map updated.

please give comments/suggestions :eek:
 

Dinowc

don't expect anything, prepare for everything
Reaction score
223
bump.

aw come on...

is the spell really so bad? why nobody says anything? :(

I've already made v1.3
 

Dinowc

don't expect anything, prepare for everything
Reaction score
223
JASS:
local unit u = GetTriggerUnit()
local integer i = GetUnitIndex(u)
local data d = data.create(u)
set D<i> = d</i>


JASS:
local data d = D[GetUnitIndex(GetTriggerUnit())]


I'm making it, am I?
it needs the timer so it can check hero's mana

I still suck in vJass so not sure am I doing it the correct way :(
 

Dinowc

don't expect anything, prepare for everything
Reaction score
223
lol didn't know about that (first time using PUI)

I'll try it now


EDIT:

I got some problems now

the spell isn't MUI anymore :(

I must have done something wrong...
how do I use that PUI struct system?

is there any tutorial?
 

Viikuna

No Marlo no game.
Reaction score
265
Use one global dummy for casting those purges, instead of creating new one alla time.
 

Dinowc

don't expect anything, prepare for everything
Reaction score
223
one global dummy

uhm I don't get it...

how do you do that with 1 dummy?

EDIT: I did it like you posted here and it doesn't work...
 

Dinowc

don't expect anything, prepare for everything
Reaction score
223
EDIT: yeah it works now
thanks! :)

v1.6 uploaded (read changelog)
 

Dinowc

don't expect anything, prepare for everything
Reaction score
223
but still I got no comments of the spell :(

I just wanna know what ppl think of it and should I continue improving it or not
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top