Zephyr Contest #15 - The Dark Plague

This bundle is marked as awaiting update. A staff member has requested changes to it before it can be approved.
Zephyr Contest #15 - The Dark Plague

This is my entry for the above Contest.

Icon Credits: CrazyRussian
Model Credits: -Grendel

vJASS:
//-------------------------------------------------------------------------------------------------------
//|
//|  Spell: The Dark Plague
//|  Author: Anachron
//|
//|  Description:
//|    Releases a deadly cloud of bacteria to the target area, making units infected with the "dark plague".
//|
//|    Units suffering from the "dark plague" have a limited sight area, attack and movespeed.
//|    Caused by their low energy every fwe seconds they have a chance for a confusion (2s).
//|
//|    Confused units can't attack and/or cast spells. Every time an unit gets confused, the chance of a sudden death increases drastically.
//|
//|    Units dying from a sudden death will release the sickness to nearby units.
//|
//|  Credits:
//|    Magtheridon96 for RegisterPlayerUnitEvent
//|    Bribe for SpellEffectEvent & Table
//|    Rising_Dusk for GroupUtils
//|
//-------------------------------------------------------------------------------------------------------
library TheDarkPlague initializer onInit requires RegisterPlayerUnitEvent, StructUtils, GroupUtils, Table
 
    globals
        // Main spell ability for hero, inclusive buffID and casting order
        private constant integer HERO_SPELL_CODE='Adkp'
        private constant integer MAIN_SPELL_CODE='Adpb'
        private constant integer MAIN_BUFF_CODE='Btdp'
        private constant string MAIN_SPELL_ORDER="slow"
    
        // Secondary spell ability for confusion casting, including buffID and casting order
        private constant integer CONF_SPELL_CODE='Acnf'
        private constant integer CONF_BUFF_CODE='Bcnf'
        private constant string CONF_SPELL_ORDER="silence"
    endglobals

    // Formula to calculate spell area
    private function GetSpellArea takes integer lvl returns real
        return 150. + lvl * 50.
    endfunction
 
    // Formula to calculate spell duration
    private function GetSpellDuration takes integer lvl returns real
        return 15. + lvl * 5.
    endfunction
 
    // Formula to calculate confusion chance
    private function GetSpellConfusionChance takes integer lvl returns real
        return (15. + lvl * 5.) / 100.
    endfunction
 
    // Formula to calculate sudden death chance
    private function GetSpellSuddenDeathChance takes integer lvl, integer times returns real
        return (times * (8. + lvl * 3.)) / 100.
    endfunction
 
    struct dummySpell
        public      static      real            period          = 2.5
    
        implement PeriodicStruct
    endstruct
 
    struct spell extends dummySpell
        private                 group           unitHitGroup    = null
        private     static      group           tempHitGroup    = null
    
                                real            duration        = 0.
                                unit            caster          = null
                                integer         level           = 0
    
        private     static      Table           shocks          = 0
        private     static      unit            dummy           = null
    
        // Cast spell on unit (For normal buff)
        public method cast takes integer theAbility, unit theUnit, string theOrder returns nothing
            call SetUnitOwner(thistype.dummy, GetOwningPlayer(.caster), false)
            call UnitAddAbility(thistype.dummy, theAbility)
            call SetUnitAbilityLevel(thistype.dummy, theAbility, .level)
            call SetUnitX(thistype.dummy, GetUnitX(theUnit))
            call SetUnitY(thistype.dummy, GetUnitY(theUnit))
            call IssueTargetOrder(thistype.dummy, theOrder, theUnit)
            call UnitRemoveAbility(thistype.dummy, theAbility)
        endmethod
    
        // Cast spell on location (For confusion buff)
        public method castXY takes integer theAbility, real x, real y, string theOrder returns nothing
            call SetUnitOwner(thistype.dummy, GetOwningPlayer(.caster), false)
            call UnitAddAbility(thistype.dummy, theAbility)
            call SetUnitAbilityLevel(thistype.dummy, theAbility, .level)
            call SetUnitX(thistype.dummy, x)
            call SetUnitY(thistype.dummy, y)
            call IssuePointOrder(thistype.dummy, theOrder, x, y)
            call UnitRemoveAbility(thistype.dummy, theAbility)
        endmethod
    
        public method isUnitHit takes unit theUnit returns boolean
            return IsUnitInGroup(theUnit, .unitHitGroup)
        endmethod
    
        stub method unitHitCond takes unit theUnit returns boolean
            local   boolean     triggerHit  = true
        
            set triggerHit = triggerHit and IsPlayerEnemy(GetOwningPlayer(.caster), GetOwningPlayer(theUnit))
            set triggerHit = triggerHit and GetUnitState(theUnit, UNIT_STATE_LIFE) > 0.405
            set triggerHit = triggerHit and not .isUnitHit(theUnit) and GetUnitAbilityLevel(theUnit, MAIN_BUFF_CODE) == 0
        
            return triggerHit
        endmethod
    
        private method onUnitHit takes unit theUnit returns boolean
            call .cast(MAIN_SPELL_CODE, theUnit, MAIN_SPELL_ORDER)
            return true
        endmethod
    
        private static method delegateUnitHitCheck takes nothing returns boolean
            local thistype this = thistype.SELF
            local unit theUnit = GetFilterUnit()
            local boolean hasHit = .unitHitCond(theUnit)
        
            if hasHit then
                call GroupAddUnit(.unitHitGroup, theUnit)
                call .onUnitHit(theUnit)
            endif
        
            set theUnit = null
            return false
        endmethod
    
        private method onSuddenDeath takes unit theUnit returns nothing
            call UnitDamageTarget(.caster, theUnit, GetWidgetLife(theUnit), false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
            call GroupRemoveUnit(.unitHitGroup, theUnit)
        endmethod
    
        private method checkSuddenDeath takes unit theUnit returns nothing
            if GetHeroLevel(theUnit) > 0 then
                return
            endif
        
            if GetRandomReal(0., 1.) <= GetSpellSuddenDeathChance(.level, .shocks[GetHandleId(theUnit)])then
                call .onSuddenDeath(theUnit)
            endif
        endmethod
    
        private method onConfusion takes unit theUnit returns nothing
            call .castXY(CONF_SPELL_CODE, GetUnitX(theUnit), GetUnitY(theUnit), CONF_SPELL_ORDER)
            set .shocks[GetHandleId(theUnit)] = .shocks[GetHandleId(theUnit)] +1
            call .checkSuddenDeath(theUnit)
        endmethod
    
        private static method checkConfusion takes nothing returns nothing
            local thistype this = thistype.SELF
            local unit u = GetEnumUnit()
        
            if GetUnitAbilityLevel(u, MAIN_BUFF_CODE) == 0 then
                call GroupRemoveUnit(.unitHitGroup, u)
                set u = null
                return
            endif
        
            if GetUnitAbilityLevel(u, CONF_BUFF_CODE) > 0 then
                set u = null
                return
            endif
        
            if GetRandomReal(0., 1.) <= GetSpellConfusionChance(.level) then
                call .onConfusion(u)
            endif
        
            set u = null
        endmethod
    
        public method onPeriod takes nothing returns boolean
            if .duration > 0. then
                set .duration = .duration - thistype.period
                call ForGroup(.unitHitGroup, function thistype.checkConfusion)
                return true
            endif
        
            return false
        endmethod
    
        private method onDestroy takes nothing returns nothing
            if .unitHitGroup != null then
                call ReleaseGroup(.unitHitGroup)
                set .unitHitGroup = null
            endif
        
            if .shocks != 0 then
                call .shocks.destroy()
            endif
        
            call .unregister()
        endmethod
    
        private static method onInit takes nothing returns nothing
            set thistype.tempHitGroup = NewGroup()
            set thistype.dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'dumy', 0, 0, 0.)
            call UnitAddAbility(thistype.dummy, 'Aloc')
        endmethod
    
        public static method create takes nothing returns thistype
            local thistype this = thistype.allocate()
        
            set .caster = GetTriggerUnit()
            set .level = GetUnitAbilityLevel(.caster, GetSpellAbilityId())
        
            set .shocks = Table.create()
            set .unitHitGroup = NewGroup()
            set thistype.SELF = this
            call GroupEnumUnitsInRange(thistype.tempHitGroup, GetSpellTargetX(), GetSpellTargetY(), GetSpellArea(.level), function thistype.delegateUnitHitCheck)
        
            set .duration = GetSpellDuration(.level)
        
            set .isAlive = true
            set .isActive = true
            call .register()
        
            return this
        endmethod
    endstruct

    private function onInit takes nothing returns nothing
        call RegisterSpellEffectEvent(HERO_SPELL_CODE, function spell.create)
        call FogEnable(false)
        call FogMaskEnable(false)
    endfunction
 
endlibrary
Contents

The Dark Plague (Map)

Reviews
KILLCIDE
Needs Fixed Please add import instructions to the description (or code) Get rid of the test map actions from the spell code Data member caster should be nulled in the destroy function Double deallocation problem (possibly because of the graveyarded...

KILLCIDE

Spell Moderator
Level 36
Joined
Jul 22, 2015
Messages
3,488

Needs Fixed

  • Please add import instructions to the description (or code)
  • Get rid of the test map actions from the spell code
  • Data member caster should be nulled in the destroy function
  • Double deallocation problem (possibly because of the graveyarded library you are using)

Suggestions

  • Fix any of the remaining suggestions made by IcemanBo in his judge review

Status

Awaiting Update
 
Top