• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Math Kills v1.7

  • Like
Reactions: deepstrasz
JASS:
scope MathKills initializer ini/* v1.7

    Made based on my over-hatred of mathematics
    
        Throws away an over-heading mathematics onto the targeted point. The larger calculation done
    within the throwing sequence, the larger damage will be dealt. Just like the fact, harder calculation
    deals more damage to our brain (and often causes dizziness) Nuclear explosion shows how destructive
    is that mathematics
    
    
    This spell is just for fun, Im not really sure this spell is practical in any map. And sorry
    that you cant configure the slow via trigger, you need to configure via Object Editor. Anyway
    
        Enjoy..
        
    
       Requires:
           WorldBounds #github.com/nestharus/JASS/blob/master/jass/Systems/WorldBounds/script.j
        
        
    How to import:
        - Copy MathKills folder into your map
        - Copy MathKills dummy unit, all dummy spells, and dummy buff
        - Export dummy.mdx into your map
        
        
    Credits
        - NuclearExplosion.mdx by WILLTHEALMIGHTY
        - WorldBounds by Nestharus
                
*/
    
    globals
    
        // Rawcode of main spell
        private     constant        integer             SPELL_ID                = 'A000'
        // Alpha channel of missile, max is 255
        private     constant        integer             MISSILE_ALPHA           = 255
        // Missile arcing
        private     constant        real                MISSILE_ARC             = .75
        // Additional chars before minor missiles integer
        private     constant        string              MISSILE_PREFIX          = "+"
        // Missile size
        private     constant        real                MISSILE_SIZE            = .023
        // Missile speed
        private     constant        real                MISSILE_SPEED           = 10.
        // How fast is the droppings
        private     constant        real                DROP_SPEED              = 20.
        // Low bound of dropped integer
        private     constant        integer             RANDOMINT_LOWBOUND      = 5
        // Upper bound of dropped integer
        private     constant        integer             RANDOMINT_UPPERBOUND    = 30
        // True if you want to make the distance constant
        private     constant        boolean             CONSTANT_DISTANCE       = false
        // Give random color to missile
        private     constant        boolean             COLOR_ENABLED           = true
        // Generate rainbow color on missile
        private     constant        boolean             COLOR_RAINBOW           = true
        // How fast is the color change
        private     constant        integer             RAINBOW_COLOR_RATE      = 10
        // Sfx created on main missile impact
        private     constant        string              EXPLODE_SFX_MAJOR       = "war3mapImported\\NuclearExplosion.mdx"
        // Sfx created on little missile impact
        private     constant        string              EXPLODE_SFX_MINOR       = "Abilities\\Weapons\\FragDriller\\FragDriller.mdl"
        // True will make the spell causes dizziness
        private     constant        boolean             DIZZINESS_ENABLED       = true
        // Dummy unit rawcode
        private     constant        integer             DIZZINESS_DUMMY_ID      = 'h000'
        // Dummy slow spell rawcode
        private     constant        integer             DIZZINESS_SPELL_ID      = 'A001'
        // Slow buff rawcode
        private     constant        integer             DIZZINESS_BUFF_ID       = 'B000'
        // Slow spell order string
        private     constant        string              DIZZINESS_ORDER_ID      = "slow"
        // Sfx for dizziness buff
        private     constant        string              DIZZINESS_SFX_PATH      = "Abilities\\Spells\\Orc\\StasisTrap\\StasisTotemTarget.mdl"
        // Dizziness sfx attach point
        private     constant        string              DIZZINESS_SFX_POINT     = "overhead"
        // Accuracy of loop triggers
        private     constant        real                ACCURACY                = .03
        // Initial amount damage for main missile
        private     constant        real                BASE_DAMAGE             = 0.
        // Attack type of dealt damage
        private     constant        attacktype          ATTACK_TYPE             = ATTACK_TYPE_HERO
        // Damage type of dealt damage
        private     constant        damagetype          DAMAGE_TYPE             = DAMAGE_TYPE_NORMAL
        // Weapon type of dealt damage
        private     constant        weapontype          WEAPON_TYPE             = WEAPON_TYPE_WHOKNOWS
        
    endglobals
    
    // This is for constant max distance
    private constant function MK_MaxDistance takes integer level returns real
        return 1200.
    endfunction
    
    // Little missile drop rate
    private constant function MK_DropRate takes integer level returns real
        return .5 - .2 * (level - 1)
    endfunction
    
    // AoE of minor missile
    private constant function MK_MinorAoE takes integer level returns real
        return 100.
    endfunction
    
    // AoE of major missile
    private constant function MK_MajorAoE takes integer level returns real
        return 350.
    endfunction
    
    // Duration of dizziness. 0 for permanent
    private constant function MK_Dizziness_Duration takes integer level returns real
        return 5.
    endfunction
    
    // Custom filtration of target for this spell
    private function extraFiltration takes unit u returns boolean
        return not(IsUnitType(u, UNIT_TYPE_MECHANICAL) or IsUnitType(u, UNIT_TYPE_STRUCTURE) or IsUnitType(u, UNIT_TYPE_RESISTANT))
    endfunction
    
/*  'END OF CONFIGURATION'          */
    
    globals
        private effect array Dizziness_Sfx
        private group DamageGroup = CreateGroup()
        private integer Dizziness_Total = -1
        private integer Major_Total = -1
        private integer Minor_Total = -1
        private integer array Major_Level
        private integer array Minor_Level
        private integer array Major_Red
        private integer array Major_Green
        private integer array Major_Blue
        private integer array Major_RedR
        private integer array Major_GreenR
        private integer array Major_BlueR
        private player array Major_Player
        private player array Minor_Player
        private real array Dizziness_Duration
        private real array Major_Angle
        private real array Major_Damage
        private real array Major_DC
        private real array Major_DX
        private real array Major_Z
        private real array Major_Delay
        private real array Major_X
        private real array Major_Y
        private real array Minor_Damage
        private real array Minor_X
        private real array Minor_Y
        private real array Minor_H
        private texttag array Major_Missile
        private texttag array Minor_Missile
        private timer Dizziness_Timer = CreateTimer()
        private timer Major_Timer = CreateTimer()
        private timer Minor_Timer = CreateTimer()
        private unit Dizziness_Dummy
        private unit array Dizziness_Target
        private unit array Major_Caster
        private unit array Minor_Caster
    endglobals
    
    native UnitAlive takes unit id returns boolean
    
    private function dizzinessLoop takes nothing returns nothing
    
        local integer i = 0
        
        loop
            exitwhen i > Dizziness_Total
            if Dizziness_Duration[i] > 0 then
                set Dizziness_Duration[i] = Dizziness_Duration[i] - ACCURACY
                if Dizziness_Duration[i] <= 0 or IsUnitType(Dizziness_Target[i], UNIT_TYPE_DEAD) then
                    call UnitRemoveAbility(Dizziness_Target[i], DIZZINESS_BUFF_ID)
                    call DestroyEffect(Dizziness_Sfx[i])
                    if i != Dizziness_Total then
                        set Dizziness_Duration[i] = Dizziness_Duration[Dizziness_Total]
                        set Dizziness_Sfx[i] = Dizziness_Sfx[Dizziness_Total]
                        set Dizziness_Target[i] = Dizziness_Target[Dizziness_Total]
                    endif
                    set Dizziness_Target[Dizziness_Total] = null
                    set Dizziness_Total = Dizziness_Total - 1
                    if Dizziness_Total < 0 then
                        call PauseTimer(Dizziness_Timer)
                    else
                        set i = i - 1
                    endif
                endif
            endif
            set i = i + 1
        endloop
        
    endfunction
    
    private function dealDamage takes unit c, player p, real d, integer l returns nothing
    
        local unit u
        
        loop
            set u = FirstOfGroup(DamageGroup)
            exitwhen u == null
            if extraFiltration(u) then
                if UnitAlive(u) and IsPlayerEnemy(GetOwningPlayer(u), p) then
                    call UnitDamageTarget(c, u, d, false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
                    static if DIZZINESS_ENABLED then
                        if GetUnitAbilityLevel(u, DIZZINESS_BUFF_ID) < 1 then
                            set Dizziness_Total = Dizziness_Total + 1
                            set Dizziness_Duration[Dizziness_Total] = MK_Dizziness_Duration(l)
                            set Dizziness_Target[Dizziness_Total] = u
                            set Dizziness_Sfx[Dizziness_Total] = AddSpecialEffectTarget(DIZZINESS_SFX_PATH, u, DIZZINESS_SFX_POINT)
                            call IssueTargetOrder(Dizziness_Dummy, DIZZINESS_ORDER_ID, u)
                            if Dizziness_Total == 0 then
                                call TimerStart(Dizziness_Timer, ACCURACY, true, function dizzinessLoop)
                            endif
                        endif
                    endif
                endif
            endif
            call GroupRemoveUnit(DamageGroup, u)
        endloop
        
    endfunction
    
    private function minorLoop takes nothing returns nothing
    
        local integer i = 0
        local integer i2
        
        loop
            exitwhen i > Minor_Total
            set Minor_H[i] = Minor_H[i] - DROP_SPEED
            call SetTextTagPos(Minor_Missile[i], Minor_X[i], Minor_Y[i], Minor_H[i])
            set i2 = 0
            loop
                exitwhen i2 > 11
                if GetLocalPlayer() == Player(i2) then
                    if IsVisibleToPlayer(Minor_X[i], Minor_Y[i], Player(i2)) then
                        call SetTextTagVisibility(Minor_Missile[i], true)
                    else
                        call SetTextTagVisibility(Minor_Missile[i], false)
                    endif
                endif
                set i2 = i2 + 1
            endloop
            if Minor_H[i] <= 0 then
                call GroupEnumUnitsInRange(DamageGroup, Minor_X[i], Minor_Y[i], MK_MinorAoE(Minor_Level[i]), null)
                call dealDamage(Minor_Caster[i], Minor_Player[i], Minor_Damage[i], Minor_Level[i])
                call DestroyTextTag(Minor_Missile[i])
                call DestroyEffect(AddSpecialEffect(EXPLODE_SFX_MINOR, Minor_X[i], Minor_Y[i]))
                if i != Minor_Total then
                    set Minor_Missile[i] = Minor_Missile[Minor_Total]
                    set Minor_Damage[i] = Minor_Damage[Minor_Total]
                    set Minor_Caster[i] = Minor_Caster[Minor_Total]
                    set Minor_Player[i] = Minor_Player[Minor_Total]
                    set Minor_H[i] = Minor_H[Minor_Total]
                    set Minor_X[i] = Minor_X[Minor_Total]
                    set Minor_Y[i] = Minor_Y[Minor_Total]
                endif
                set Minor_Caster[Minor_Total] = null
                set Minor_Missile[Minor_Total] = null
                set Minor_Total = Minor_Total - 1
                if Minor_Total < 0 then
                    call PauseTimer(Minor_Timer)
                else
                    set i = i - 1
                endif
            endif
            set i = i + 1
        endloop
        
    endfunction
    
    private function majorLoop takes nothing returns nothing
    
        local integer i = 0
        local integer i2
        local integer d
        local real h
        local real xt
        local real yt
        
        loop
            exitwhen i > Major_Total
            if Major_DC[i] >= Major_DX[i] then
                call GroupEnumUnitsInRange(DamageGroup, Major_X[i], Major_Y[i], MK_MajorAoE(Major_Level[i]), null)
                call dealDamage(Major_Caster[i], Major_Player[i], Major_Damage[i], Major_Level[i])
                call DestroyTextTag(Major_Missile[i])
                call DestroyEffect(AddSpecialEffect(EXPLODE_SFX_MAJOR, Major_X[i], Major_Y[i]))
                if i != Major_Total then
                    set Major_Angle[i] = Major_Angle[Major_Total]
                    set Major_Caster[i] = Major_Caster[Major_Total]
                    set Major_Damage[i] = Major_Damage[Major_Total]
                    set Major_DC[i] = Major_DC[Major_Total]
                    set Major_DX[i] = Major_DX[Major_Total]
                    set Major_Delay[i] = Major_Delay[Major_Total]
                    set Major_Z[i] = Major_Z[Major_Total]
                    set Major_Level[i] = Major_Level[Major_Total]
                    set Major_Missile[i] = Major_Missile[Major_Total]
                    set Major_Player[i] = Major_Player[Major_Total]
                    set Major_Red[i] = Major_Red[Major_Total]
                    set Major_RedR[i] = Major_RedR[Major_Total]
                    set Major_Green[i] = Major_Green[Major_Total]
                    set Major_GreenR[i] = Major_GreenR[Major_Total]
                    set Major_Blue[i] = Major_Blue[Major_Total]
                    set Major_BlueR[i] = Major_BlueR[Major_Total]
                    set Major_X[i] = Major_X[Major_Total]
                    set Major_Y[i] = Major_Y[Major_Total]
                endif
                set Major_Caster[Major_Total] = null
                set Major_Missile[Major_Total] = null
                set Major_Total = Major_Total - 1
                if Major_Total < 0 then
                    call PauseTimer(Major_Timer)
                else
                    set i = i - 1
                endif
            else
                set Major_DC[i] = Major_DC[i] + MISSILE_SPEED
                set h = ((4. * Major_Z[i]) / Major_DX[i]) * (Major_DX[i] - Major_DC[i]) * (Major_DC[i] / Major_DX[i])
                set xt = Major_X[i] + MISSILE_SPEED * Cos(Major_Angle[i])
                set yt = Major_Y[i] + MISSILE_SPEED * Sin(Major_Angle[i])
                if xt <= WorldBounds.maxX and xt >= WorldBounds.minX and yt <= WorldBounds.maxY and yt >= WorldBounds.minY then
                    set Major_X[i] = xt
                    set Major_Y[i] = yt
                    call SetTextTagPos(Major_Missile[i], xt, yt, h)
                else
                    call SetTextTagPos(Major_Missile[i], Major_X[i], Major_Y[i], h)
                endif
                set i2 = 0
                loop
                    exitwhen i2 > 11
                    if GetLocalPlayer() == Player(i2) then
                        if IsVisibleToPlayer(Major_X[i], Major_Y[i], Player(i2)) then
                            call SetTextTagVisibility(Major_Missile[i], true)
                        else
                            call SetTextTagVisibility(Major_Missile[i], false)
                        endif
                    endif
                    set i2 = i2 + 1
                endloop
                static if COLOR_RAINBOW then
                    if Major_Red[i] + Major_RedR[i] > 255 or Major_Red[i] + Major_RedR[i] < 0 then
                        set Major_RedR[i] = Major_RedR[i] * -1
                    endif
                    if Major_Green[i] + Major_GreenR[i] > 255 or Major_Green[i] + Major_GreenR[i] < 0 then
                        set Major_GreenR[i] = Major_GreenR[i] * -1
                    endif
                    if Major_Blue[i] + Major_BlueR[i] > 255 or Major_Blue[i] + Major_BlueR[i] < 0 then
                        set Major_BlueR[i] = Major_BlueR[i] * -1
                    endif
                    set Major_Red[i] = Major_Red[i] + Major_RedR[i]
                    set Major_Green[i] = Major_Green[i] + Major_GreenR[i]
                    set Major_Blue[i] = Major_Blue[i] + Major_BlueR[i]
                    call SetTextTagColor(Major_Missile[i], Major_Red[i], Major_Green[i], Major_Blue[i], MISSILE_ALPHA)
                endif
                if Major_Delay[i] > 0 then
                    set Major_Delay[i] = Major_Delay[i] - ACCURACY
                    if Major_Delay[i] <= 0 then
                        set Major_Delay[i] = MK_DropRate(Major_Level[i])
                        set d = GetRandomInt(RANDOMINT_LOWBOUND, RANDOMINT_UPPERBOUND)
                        set Major_Damage[i] = Major_Damage[i] + I2R(d)
                        call SetTextTagText(Major_Missile[i], I2S(R2I(Major_Damage[i])), MISSILE_SIZE)
                        set Minor_Total = Minor_Total + 1
                        set Minor_Player[Minor_Total] = Major_Player[i]
                        set Minor_Caster[Minor_Total] = Major_Caster[i]
                        set Minor_Level[Minor_Total] = Major_Level[i]
                        set Minor_Damage[Minor_Total] = I2R(d)
                        set Minor_X[Minor_Total] = Major_X[i]
                        set Minor_Y[Minor_Total] = Major_Y[i]
                        set Minor_H[Minor_Total] = h
                        set Minor_Missile[Minor_Total] = CreateTextTag()
                        call SetTextTagText(Minor_Missile[Minor_Total], MISSILE_PREFIX + I2S(R2I(Minor_Damage[Minor_Total])), MISSILE_SIZE)
                        call SetTextTagPos(Minor_Missile[Minor_Total], Minor_X[Minor_Total], Minor_Y[Minor_Total], h)
                        call SetTextTagColor(Minor_Missile[Minor_Total], Major_Red[i], Major_Green[i], Major_Blue[i], MISSILE_ALPHA)
                        if Minor_Total == 0 then
                            call TimerStart(Minor_Timer, ACCURACY, true, function minorLoop)
                        endif
                    endif
                endif
            endif
            set i = i + 1
        endloop
        
    endfunction
    
    private function onCast takes nothing returns boolean
    
        local real xt
        local real yt
        
        if GetSpellAbilityId() == SPELL_ID then
            set Major_Total = Major_Total + 1 
            set Major_Caster[Major_Total] = GetTriggerUnit()
            set Major_X[Major_Total] = GetUnitX(Major_Caster[Major_Total])
            set Major_Y[Major_Total] = GetUnitY(Major_Caster[Major_Total])
            set xt = GetSpellTargetX()
            set yt = GetSpellTargetY()
            set Major_Damage[Major_Total] = BASE_DAMAGE
            set Major_Angle[Major_Total] = Atan2(yt - Major_Y[Major_Total], xt - Major_X[Major_Total])
            set Major_Player[Major_Total] = GetTriggerPlayer()
            set Major_Level[Major_Total] = GetUnitAbilityLevel(Major_Caster[Major_Total], SPELL_ID)
            set Major_Delay[Major_Total] = MK_DropRate(Major_Level[Major_Total])
            set Major_DC[Major_Total] = 0
            static if CONSTANT_DISTANCE then
                set Major_DX[Major_Total] = MK_MaxDistance(Major_Level[Major_Total])
            else
                set Major_DX[Major_Total] = SquareRoot((xt - Major_X[Major_Total]) * (xt - Major_X[Major_Total]) + (yt - Major_Y[Major_Total]) * (yt - Major_Y[Major_Total]))
            endif
            set Major_Z[Major_Total] = MISSILE_ARC * Major_DX[Major_Total]
            set Major_Missile[Major_Total] = CreateTextTag()
            call SetTextTagText(Major_Missile[Major_Total], I2S(R2I(Major_Damage[Major_Total])), MISSILE_SIZE)
            call SetTextTagPos(Major_Missile[Major_Total], Major_X[Major_Total], Major_Y[Major_Total], 0)
            static if COLOR_ENABLED then
                set Major_Red[Major_Total] = GetRandomInt(0, 255)
                set Major_Green[Major_Total] = GetRandomInt(0, 255)
                set Major_Blue[Major_Total] = GetRandomInt(0, 255)
                call SetTextTagColor(Major_Missile[Major_Total], Major_Red[Major_Total], Major_Green[Major_Total], Major_Blue[Major_Total], MISSILE_ALPHA)
                static if COLOR_RAINBOW then
                    set Major_RedR[Major_Total] = GetRandomInt(RAINBOW_COLOR_RATE * -1, RAINBOW_COLOR_RATE)
                    set Major_GreenR[Major_Total] = GetRandomInt(RAINBOW_COLOR_RATE * -1, RAINBOW_COLOR_RATE)
                    set Major_BlueR[Major_Total] = GetRandomInt(RAINBOW_COLOR_RATE * -1, RAINBOW_COLOR_RATE)
                endif
            else
                set Major_Red[Major_Total] = 255
                set Major_Green[Major_Total] = 255
                set Major_Blue[Major_Total] = 255
                call SetTextTagColor(Major_Missile[Major_Total], 255, 255, 255, MISSILE_ALPHA)
            endif
            if Major_Total == 0 then
                call TimerStart(Major_Timer, ACCURACY, true, function majorLoop)
            endif
        endif
        
        return false
    endfunction
    
    private function ini takes nothing returns nothing
    
        local trigger t = CreateTrigger()
        
        static if DIZZINESS_ENABLED then
            set Dizziness_Dummy = CreateUnit(Player(PLAYER_NEUTRAL_AGGRESSIVE), DIZZINESS_DUMMY_ID, WorldBounds.maxX, WorldBounds.maxY, 270.)
            call UnitAddAbility(Dizziness_Dummy, DIZZINESS_SPELL_ID)
        endif
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CAST)
        call TriggerAddCondition(t, Condition(function onCast))
        
    endfunction
    
endscope

Keywords:
math, kills
Contents

Math Kills (Map)

Reviews
15:23, 6th Aug 2014 BPower: Code and object editor data looks fine to me. The spell is fun to cast. Approved 19:38, 1st Aug 2014 BPower: Awaiting an update, because of the constant boolean DIZZINESS_ENABLED. Check out my last comment.

Moderator

M

Moderator

15:23, 6th Aug 2014
BPower:
Code and object editor data looks fine to me. The spell is fun to cast.
Approved

19:38, 1st Aug 2014
BPower:
Awaiting an update, because of the constant boolean DIZZINESS_ENABLED. Check out my last comment.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
In general I recommend the usage of structs, because they are much easier to read for me :). However your way is also ok.
I'm affraid I'm too lazy to reconstruct it into structs. But I promise I will use struct for my next submissions :)

Make it a scope and not a library.
what is scope?

In general you should null all handles, even though they are globals.
okay

and thanks
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
Scopes are another way of organizing a piece of code, the difference is that they get placed after the libraries so conflicts (syntax errors due to unknown functions, variables and the like) wouldn't arise.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
In general I recommend the usage of structs, because they are much easier to read for me :). However your way is also ok.

In general you should null all handles, even though they are globals.

I on the other hand am against abusing struct syntax, if you dont need it.

You should null all agents, not necessarily handles(they dont give a shit about ref counting)
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
If DIZZINESS_ENABLED is set to false dizzinessloop will still be called, however the dizziness_dummy is null and nothing would happen.
Solution: put the whole dizziness block into a static if condition.

I would prefer if you null all handles in the end of the spell instance.

Basically spells should be scopes and not libraries. Of course this depends on if the spell works autonomous or must be created via function from another library.

Funny spell I must say.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
COLOR_ENABLED and COLOR_RAINBOW are constant booleans and therefore should be treated with static ifs in your code.

We always appreciate when all handles are nulled once not needed anymore, not only local ones.


----------------------------------------

IsUnitType(Dizziness_Target[i], UNIT_TYPE_DEAD) then
In order to perfectly cover unit death/existing status you have to add (GetUnitTypeId(unit) != 0) or use the very powerful native UnitAlive from the common.ai
native UnitAlive takes unit id returns boolean

It doesn't really matter how the initializing function is called, however the name init is much more convenient than ini is.

The JPAG is always very welcome, but your code is very read-able. You don't have to change variable names etc. :)
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
JASS:
                if COLOR_RAINBOW then
                    set Major_RedR[Major_Total] = GetRandomInt(RAINBOW_COLOR_RATE * -1, RAINBOW_COLOR_RATE)
                    set Major_GreenR[Major_Total] = GetRandomInt(RAINBOW_COLOR_RATE * -1, RAINBOW_COLOR_RATE)
                    set Major_BlueR[Major_Total] = GetRandomInt(RAINBOW_COLOR_RATE * -1, RAINBOW_COLOR_RATE)
                endif
just that right? wait a sec

I can't change that, I take care of them when I have the time.
well, it's okay then
 
Top