1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. Hey guys, we've posted the Results for the 30th Modeling Contest. Check them out!
    Dismiss Notice
  4. The 15th Mini-Mapping Contest came to an end. The Secrets of Warcraft 3 are soon to be revealed! Come and vote in the public poll for your favorite maps.
    Dismiss Notice
  5. The 12th incarnation of the Music Contest is LIVE! The theme is Synthwave. Knight Rider needs a song to listen to on his journey. You should definitely have some fun with this theme!
    Dismiss Notice
  6. Join other hivers in a friendly concept-art contest. The contestants have to create a genie coming out of its container. We wish you the best of luck!
    Dismiss Notice
  7. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

RPG Threat System v3.2c

Submitted by Quilnez
This bundle is marked as approved. It works and satisfies the submission rules.
The system provides various behaviors to creeps, like:
- Sleeping
- Wandering
- Ambushing
- Helping
- Retreating
- etc.

Code (vJASS):

library RPGTS initializer onInit uses GetClosestWidget, Table, UnitIndexer, optional TimerUtils

    /************************************************************************************
    *                                                                                   *
    *                           RPG Threat System v3.2c                                 *
    *                                         *****                                     *
    *                                       by: Quilnez                                 *
    *                                                                                   *
    *  This system generates special behavior to creep units. Gives some brains to        *
    *  those shrimp-head creeps. They can flee, they have artificial sight area            *
    *  (you can sneak behind them), they are able to help each other, they become        *
    *  aggressive or not aggressive as well. And many more!                             *
    *                                                                                   *
    *  External dependencies:                                                           *
    *   (required)                                                                      *
    *     - Table                                                                       *
    *     - UnitIndexer                                                                 *
    *     - GetClosestWidget                                                            *
    *     - Any DDS                                                                     *
    *   (optional)                                                                      *
    *     - TimerUtils                                                                  *
    *                                                                                   *
    *  Implementation:                                                                  *
    *     - Copy paste RPG Threat System folder into your map                            *
    *     - Give two player slots for passive and aggresive player, better just         *
    *       leave'em as empty player slot                                               *
    *     - Configure the system & start defining your creep behavior                    *
    *     - Done.                                                                       *
    *                                                                                   *
    *  Credits:                                                                         *
    *     - GDD by Weep                                                                 *
    *     - GetClosestWidget by Bannar                                                  *
    *     - UnitIndexer by Nestharus                                                    *
    *     - TimerUtils by Vexorian                                                      *
    *     - Table by Bribe                                                              *
    *                                                                                   *
    *   (You can read more info at READ ME trigger)                                     *
    *                                                                                   *
    *************************************************************************************
    *                                                                                   *
    *                                CONFIGURATION                                      */

    globals
        // Owner of passive creeps
        private constant    player      PASSIVE             = Player(10)
     
        // Owner of active creeps
        private constant    player      AGGRESSIVE          = Player(11)
     
        // If true, creeps will use PASSIVE's player color
        private constant    boolean     COLOR               = true
     
        // Behavior generation area (distance from generator units)
        private constant    real        DISTANCE            = 2400.0
     
        // Created sfx when creeps are sleeping
        private constant    string      SLEEP_SFX           = "Abilities\\Spells\\Undead\\Sleep\\SleepTarget.mdl"
        private constant    string      SLEEP_SFX_PT        = "overhead"
     
        // Order Ids
        private constant    integer     ATTACK_ORDER_ID     = 851983
        private constant    integer     MOVE_ORDER_ID       = 851986
        private constant    integer     STOP_ORDER_ID       = 851972
     
        // Total seconds in a day (can be found in gameplay constants)
        private constant    real        SECONDS_IN_A_DAY    = 480
     
        // If true, all units owned by PASSIVE and AGGRESSIVE will be
        // registered automatically on unit indexing event
        private constant    boolean     AUTO_REGISTER       = true
     
        // Just leave it alone
        private constant    real        INTERVAL            = 0.03125
     
        // Don't touch this
        private group CreepGroup = CreateGroup()
    endglobals
 
    // Damage event of your DDS
    private function addEvent takes trigger t returns nothing
        call TriggerRegisterVariableEvent(t, "udg_GDD_Event", EQUAL, 0.0)
    endfunction
 
    // Damage source of your DDS
    private constant function getSource takes nothing returns unit
        return udg_GDD_DamageSource
    endfunction
 
    // Damage target of your DDS
    private constant function getTarget takes nothing returns unit
        return udg_GDD_DamagedUnit
    endfunction
 
    // Set classifications of affected creeps
    private function creepFilter takes unit u returns boolean
 
        // For safety, just keep this format
        if IsUnitType(u, UNIT_TYPE_HERO) or IsUnitType(u, UNIT_TYPE_STRUCTURE) then
            return false
        endif
     
    /*                                END OF CONFIGURATION                              *
    *                                                                                   *
    ************************************************************************************/

 
        if IsUnitInGroup(u, CreepGroup) then
            return false
        endif
        call GroupAddUnit(CreepGroup, u)
     
        return true
    endfunction
 
    struct SCDataLib
        private static thistype Dex
        private static Table LibIndex
     
        //! textmacro CREEP_DATA_TYPE takes VAR_NAME,VAL_TYPE
        readonly $VAL_TYPE$ $VAR_NAME$Var
        static method operator $VAR_NAME$= takes $VAL_TYPE$ value returns nothing
            set Dex.$VAR_NAME$Var = value
        endmethod
     
        //! endtextmacro
        //! runtextmacro CREEP_DATA_TYPE( "maxHelp",         "integer" )
        //! runtextmacro CREEP_DATA_TYPE( "helpType",        "integer" )
        //! runtextmacro CREEP_DATA_TYPE( "resetTimer",      "boolean" )
        //! runtextmacro CREEP_DATA_TYPE( "canFlee",         "boolean" )
        //! runtextmacro CREEP_DATA_TYPE( "isTamed",         "boolean" )
        //! runtextmacro CREEP_DATA_TYPE( "seekHelp",        "boolean" )
        //! runtextmacro CREEP_DATA_TYPE( "callHelp",        "boolean" )
        //! runtextmacro CREEP_DATA_TYPE( "seekRadius",      "real"    )
        //! runtextmacro CREEP_DATA_TYPE( "callRadius",      "real"    )
        //! runtextmacro CREEP_DATA_TYPE( "sightRadius",     "real"    )
        //! runtextmacro CREEP_DATA_TYPE( "sleepTime",       "real"    )
        //! runtextmacro CREEP_DATA_TYPE( "sleepDur",        "real"    )
        //! runtextmacro CREEP_DATA_TYPE( "lowHealth",       "real"    )
        //! runtextmacro CREEP_DATA_TYPE( "acquisitionRange","real"    )
        //! runtextmacro CREEP_DATA_TYPE( "ambushDelay",     "real"    )
        //! runtextmacro CREEP_DATA_TYPE( "combatDuration",  "real"    )
        //! runtextmacro CREEP_DATA_TYPE( "wanderDelay",     "real"    )
        //! runtextmacro CREEP_DATA_TYPE( "wanderVariant",   "real"    )
        //! runtextmacro CREEP_DATA_TYPE( "wanderDist",      "real"    )
        //! runtextmacro CREEP_DATA_TYPE( "fleeDist",        "real"    )
        //! runtextmacro CREEP_DATA_TYPE( "nestArea",        "real"    )
     
        static method getIndex takes integer unitId returns integer
            return LibIndex.integer[unitId]
        endmethod
     
        static method add takes integer unitId returns nothing
            if LibIndex.integer[unitId] == 0 then
                set Dex = allocate()
                set LibIndex.integer[unitId] = Dex
            endif
        endmethod
     
        static method end takes nothing returns nothing
            set Dex = 0
        endmethod
     
        static method onInit takes nothing returns nothing
            set LibIndex = Table.create()
        endmethod
    endstruct
 
    // Container for creep data
    private struct CreepData
 
        boolean isSleep
        integer helpCount
        effect  sleepSfx
     
        unit    target
        timer   sleepTimer
        real    wanderDelay
     
        real    nestX
        real    nestY
        real    combatDur
     
        real    combatDly
        real    unitX
        real    unitY
     
    endstruct
 
    globals
        private boolean Move          = false
        private group PickGroup       = CreateGroup()
        private group TempGroup       = CreateGroup()
        private integer DummyType
        private integer Total         = -1
        private integer GenTotal      = 0
        private integer array GenDex
        private real array Real
        private timer Timer           = CreateTimer()
        private trigger array Handler
        private unit TempUnit
        private unit EventUnit        = null
        private unit EventThreat      = null
        private unit array GenUnit
        private CreepData array Data
     
        // Real array indexes
        private constant integer R_X             = 0
        private constant integer R_Y             = 1
        private constant integer R_TOD           = 2
        private constant integer R_WAKE          = 3
        private constant integer R_DISTANCE      = 4
        private constant integer R_FACING        = 5
        private constant integer R_DURATION      = 6
     
        // Event constants
        constant integer EVENT_CREEP_SLEEP       = 0
        constant integer EVENT_CREEP_AWAKE       = 1
        constant integer EVENT_CREEP_WANDER      = 2
        constant integer EVENT_CREEP_FLEE        = 3
        constant integer EVENT_CREEP_THREAT      = 4
        constant integer EVENT_CREEP_UNTHREAT    = 5
        constant integer EVENT_CREEP_ATTACK      = 6
        constant integer EVENT_CREEP_CALL_HELP   = 7
        constant integer EVENT_CREEP_SEEK_HELP   = 8
        constant integer EVENT_CREEP_GIVE_HELP   = 9
        constant integer EVENT_CREEP_LOW_HEALTH  = 10
        constant integer EVENT_CREEP_DEAL_DAMAGE = 11
        constant integer EVENT_CREEP_TAKE_DAMAGE = 12
        constant integer EVENT_CREEP_UNATTACK    = 13
    endglobals
 
    native UnitAlive takes unit id returns boolean
 
    // API functions
    function SetGenUnit takes unit u, boolean b returns nothing
 
        local integer uDex = GetUnitUserData(u)
 
        if b then
            if GenDex[uDex] == 0 then
                set GenTotal = GenTotal + 1
                set GenUnit[GenTotal] = u
                set GenDex[uDex] = GenTotal
            endif
        elseif GenDex[uDex] > 0 then
            set GenDex[GetUnitUserData(GenUnit[GenTotal])] = GenDex[uDex]
            set GenUnit[GenDex[uDex]] = GenUnit[GenTotal]
            set GenUnit[GenTotal] = null
            set GenTotal = GenTotal - 1
            set GenDex[uDex] = 0
        endif
     
    endfunction
 
    function AddCreepEventHandler takes integer whichEvent, boolexpr func returns nothing
        call TriggerAddCondition(Handler[whichEvent], func)
    endfunction
 
    function GetTriggerCreep takes nothing returns unit
        return EventUnit
    endfunction
 
    function GetTriggerThreat takes nothing returns unit
        return EventThreat
    endfunction
 
    function GetCreepNestX takes unit u returns real
        return Data[GetUnitUserData(u)].nestX
    endfunction
 
    function GetCreepNestY takes unit u returns real
        return Data[GetUnitUserData(u)].nestY
    endfunction
 
    function IsCreepSleeping takes unit u returns boolean
        return Data[GetUnitUserData(u)].isSleep
    endfunction
 
    function IsCreepMoving takes unit u returns boolean
        local integer uDex = GetUnitUserData(u)
        return GetUnitCurrentOrder(u) == MOVE_ORDER_ID or GetUnitX(u) != Data[uDex].unitX or GetUnitY(u) != Data[uDex].unitY
    endfunction
 
    // Get distance between points
    private function getDistance takes real x, real y, real xt, real yt returns real
        return SquareRoot((xt-x)*(xt-x)+(yt-y)*(yt-y))
    endfunction
 
    // Get angle between points
    private function getAngle takes real x, real y, real xt, real yt returns real
        return Atan2(yt-y, xt-x) * bj_RADTODEG
    endfunction
 
    // Get circular difference between two angles
    private function circularDifference takes real a, real b returns real
 
        local real r = RAbsBJ(a-b)
     
        if r <= 180 then
            return r
        else
            return 180 - r
        endif
     
    endfunction
 
    // Filter enemy units around creep
    private function targetFilter takes nothing returns boolean
 
        local unit u       = GetFilterUnit()
        local player p     = GetOwningPlayer(u)
        local SCDataLib lDex = SCDataLib.getIndex(GetUnitTypeId(TempUnit))
        local real a       = getAngle(GetUnitX(TempUnit), GetUnitY(TempUnit), GetUnitX(u), GetUnitY(u))
        local boolean b    = circularDifference(GetUnitFacing(TempUnit), a) < lDex.sightRadiusVar/4
     
        set b = b and (p != PASSIVE and p != AGGRESSIVE and UnitAlive(u))
        set b = b and (IsUnitVisible(u, PASSIVE) or IsUnitVisible(u, AGGRESSIVE))
        set u = null
     
        return b
    endfunction
 
    // Filter possible helper for creep
    private function helperFilter takes nothing returns boolean
 
        local unit    u    = GetFilterUnit()
        local integer id   = GetUnitTypeId(u)
        local integer uDex = GetUnitUserData(u)
        local SCDataLib lDex = SCDataLib.getIndex(id)
        local boolean b    = (lDex.helpTypeVar != 1 or id == DummyType) and lDex.helpTypeVar >= 1
     
        set b = b and (GetOwningPlayer(u) == PASSIVE and not lDex.isTamedVar)
        set b = b and not IsCreepSleeping(u)
        set u = null
     
        return b
    endfunction
 
    private function fireEvent takes integer whichEvent, unit u, unit t returns nothing
     
        local unit tu   = EventUnit
        local unit tt   = EventThreat
     
        set EventUnit   = u
        set EventThreat = t
     
        call TriggerEvaluate(Handler[whichEvent])
     
        set EventUnit   = tu
        set EventThreat = tt
     
        set tu = null
        set tt = null
     
    endfunction
 
    // Seek for nearby helpers
    private function pickHelper takes unit u, unit t, integer uDex, SCDataLib lDex returns nothing
     
        local integer i = 0
        local SCDataLib lDex2
        local integer uDex2
        local unit h
     
        loop
            exitwhen Data[uDex].helpCount == lDex.maxHelpVar
            set h = GetClosestUnitInRange(Data[uDex].unitX, Data[uDex].unitY, lDex.callRadiusVar, Filter(function helperFilter))
            exitwhen h == null
         
            call SetUnitOwner(h, AGGRESSIVE, not COLOR)
            set uDex2 = GetUnitUserData(h)
            set lDex2 = SCDataLib.getIndex(GetUnitTypeId(h))
         
            set Data[uDex2].combatDur = lDex2.combatDurationVar
            set Data[uDex2].target    = t
         
            call IssueTargetOrderById(h, ATTACK_ORDER_ID, t)
            call fireEvent(EVENT_CREEP_GIVE_HELP, h, null)
            set Data[uDex].helpCount = Data[uDex].helpCount + 1
        endloop
        set h = null
     
    endfunction
 
    // Filter creeps around generators
    private function pickFilter takes nothing returns boolean
     
        local unit u = GetFilterUnit()
     
        if not IsUnitInGroup(u, PickGroup) and IsUnitInGroup(u, CreepGroup) then
            call GroupAddUnit(PickGroup, u)
        endif
        set u = null
     
        return false
    endfunction
 
    private function onLoop takes nothing returns nothing
 
        local unit u
        local unit t
        local SCDataLib lDex
        local integer uDex
        local integer i = 1
     
        // Collect creeps around generator units' positions
        loop
            exitwhen i > GenTotal
            call GroupEnumUnitsInRange(TempGroup, GetUnitX(GenUnit[i]), GetUnitY(GenUnit[i]), DISTANCE, function pickFilter)
            set i = i + 1
        endloop
     
        loop
            set u = FirstOfGroup(PickGroup)
            exitwhen u == null
            call GroupRemoveUnit(PickGroup, u)
         
            set uDex = GetUnitUserData(u)
            if GetUnitTypeId(u) != 0 then
                if UnitAlive(u) then
                    set lDex = SCDataLib.getIndex(GetUnitTypeId(u))
                    // Determine whether the creep is moving atm or not
                    set Move = IsCreepMoving(u)
                    if Move then
                        set Data[uDex].unitX = GetUnitX(u)
                        set Data[uDex].unitY = GetUnitY(u)
                    endif
                 
                    if GetOwningPlayer(u) == PASSIVE then
                        if Data[uDex].combatDly < 0 then
                            // If the creep is able to sleep
                            if lDex.sleepDurVar > 0 then
                                // Gather sleep time datas
                                set Real[R_TOD]  = GetFloatGameState(GAME_STATE_TIME_OF_DAY)
                                set Real[R_WAKE] = lDex.sleepTimeVar + lDex.sleepDurVar
                                if  Real[R_TOD] <= Real[R_WAKE] - 24 then
                                    set Real[R_TOD] = Real[R_TOD] + 24
                                endif
                             
                                // Check sleep time
                                if Real[R_TOD] >= lDex.sleepTimeVar and Real[R_TOD] < Real[R_WAKE] and not Data[uDex].isSleep then
                                    if not Move and not(IsUnitType(u, UNIT_TYPE_STUNNED) or IsUnitPaused(u)) then
                                        set Data[uDex].isSleep  = true
                                        set Data[uDex].sleepSfx = AddSpecialEffectTarget(SLEEP_SFX, u, SLEEP_SFX_PT)
                                        if Data[uDex].sleepTimer == null then
                                            static if LIBRARY_TimerUtils then
                                                set Data[uDex].sleepTimer = NewTimer()
                                            else
                                                set Data[uDex].sleepTimer = CreateTimer()
                                            endif
                                            // Calculate sleep duration
                                            set Real[R_DURATION] = (SECONDS_IN_A_DAY/86400)*((lDex.sleepDurVar-(Real[R_TOD]-lDex.sleepTimeVar))*3600)/GetTimeOfDayScale()
                                            call TimerStart(Data[uDex].sleepTimer, Real[R_DURATION], false, null)
                                        endif
                                        call fireEvent(EVENT_CREEP_SLEEP, u, null)
                                    endif
                                endif
                            endif
                         
                            if Data[uDex].isSleep then
                                // Wake up time
                                if TimerGetRemaining(Data[uDex].sleepTimer) <= 0 then
                                    call DestroyEffect(Data[uDex].sleepSfx)
                                    static if LIBRARY_TimerUtils then
                                        call ReleaseTimer(Data[uDex].sleepTimer)
                                    else
                                        call DestroyTimer(Data[uDex].sleepTimer)
                                    endif
                                 
                                    set Data[uDex].isSleep    = false
                                    set Data[uDex].sleepTimer = null
                                    set Data[uDex].sleepSfx   = null
                                 
                                    call fireEvent(EVENT_CREEP_AWAKE, u, null)
                                endif
                            else
                                // Check if wandering or not
                                if lDex.wanderDelayVar > 0 then
                                    if Data[uDex].wanderDelay > INTERVAL then
                                        set Data[uDex].wanderDelay = Data[uDex].wanderDelay - INTERVAL
                                    else
                                        set Real[R_DISTANCE] = GetRandomReal(lDex.wanderDistVar, lDex.nestAreaVar)
                                        set Real[R_FACING]   = GetRandomReal(0,bj_PI*2)
                                     
                                        // Reset wander delay
                                        set Data[uDex].wanderDelay = lDex.wanderDelayVar + GetRandomReal(-lDex.wanderVariantVar, lDex.wanderVariantVar)/2
                                     
                                        set Real[R_X] = Data[uDex].nestX + Real[R_DISTANCE] * Cos(Real[R_FACING])
                                        set Real[R_Y] = Data[uDex].nestY + Real[R_DISTANCE] * Sin(Real[R_FACING])
                                     
                                        call IssuePointOrderById(u, MOVE_ORDER_ID, Real[R_X], Real[R_Y])
                                        call fireEvent(EVENT_CREEP_WANDER, u, null)
                                    endif
                                endif
                             
                                // If the creep is aggressive
                                if lDex.acquisitionRangeVar > 0 then
                                    // If is around it's nest area
                                    if getDistance(Data[uDex].unitX, Data[uDex].unitY, Data[uDex].nestX, Data[uDex].nestY) <= lDex.nestAreaVar then
                                        set TempUnit = u
                                        set t = GetClosestUnitInRange(Data[uDex].unitX, Data[uDex].unitY, lDex.acquisitionRangeVar, Filter(function targetFilter))
                                        if t != null then
                                            set Data[uDex].target    = t
                                            set Data[uDex].combatDly = lDex.ambushDelayVar
                                            call IssueImmediateOrderById(u, STOP_ORDER_ID)
                                            call fireEvent(EVENT_CREEP_THREAT, u, t)
                                            set t = null
                                        endif
                                    endif
                                endif
                            endif
                        else
                            set Real[R_X] = GetUnitX(Data[uDex].target)
                            set Real[R_Y] = GetUnitY(Data[uDex].target)
                            call SetUnitFacing(u, getAngle(Data[uDex].unitX, Data[uDex].unitY, Real[R_X], Real[R_Y]))
                         
                            // If target has fleed
                            if getDistance(Data[uDex].unitX, Data[uDex].unitY, Real[R_X], Real[R_Y]) > lDex.acquisitionRangeVar then
                                set Data[uDex].combatDly = -1
                                set Data[uDex].target    = null
                                call fireEvent(EVENT_CREEP_UNTHREAT, u, Data[uDex].target)
                            else
                                if Data[uDex].combatDly > INTERVAL then
                                    set Data[uDex].combatDly = Data[uDex].combatDly - INTERVAL
                                else
                                    set Data[uDex].combatDur = lDex.combatDurationVar
                                    call SetUnitOwner(u, AGGRESSIVE, not COLOR)
                                    call IssueTargetOrderById(u, ATTACK_ORDER_ID, Data[uDex].target)
                                    call fireEvent(EVENT_CREEP_ATTACK, u, Data[uDex].target)
                                endif
                            endif
                        endif
                    else
                        // Calm down if the combat timer is up or if the target has died
                        if Data[uDex].combatDur > INTERVAL and UnitAlive(Data[uDex].target) then
                            set Data[uDex].combatDur = Data[uDex].combatDur - INTERVAL
                        else
                            call SetUnitOwner(u, PASSIVE, not COLOR)
                            set Data[uDex].helpCount = 0
                         
                            // Order to move away
                            set Real[R_DISTANCE] = GetRandomReal(0, lDex.nestAreaVar)
                            set Real[R_FACING]   = GetRandomReal(0, bj_PI*2)
                         
                            set Real[R_X] = Data[uDex].nestX + Real[R_DISTANCE] * Cos(Real[R_FACING])
                            set Real[R_Y] = Data[uDex].nestY + Real[R_DISTANCE] * Sin(Real[R_FACING])
                         
                            call IssuePointOrderById(u, MOVE_ORDER_ID, Real[R_X], Real[R_Y])
                            call fireEvent(EVENT_CREEP_UNATTACK, u, Data[uDex].target)
                            set Data[uDex].target = null
                        endif
                    endif
                endif
            else
                call Data[uDex].destroy()
                set  Data[uDex].sleepTimer = null
                set  Data[uDex].sleepSfx   = null
                set  Data[uDex].target     = null
     
                set Total = Total - 1
                if Total < 0 then
                    call PauseTimer(Timer)
                endif
            endif
        endloop
     
    endfunction

    private function onHit takes nothing returns boolean
 
        local SCDataLib lDex
        local integer uDex
        local integer i
        local integer ix
        local unit t = getTarget()
        local unit s = getSource()
        local unit h
     
        if GetOwningPlayer(s) == AGGRESSIVE and IsUnitInGroup(s, CreepGroup) then
            set DummyType = GetUnitTypeId(s)
            set uDex = GetUnitUserData(s)
            set lDex = SCDataLib.getIndex(DummyType)
            call fireEvent(EVENT_CREEP_DEAL_DAMAGE, s, t)
         
            if lDex.resetTimerVar then
                if getDistance(Data[uDex].unitX, Data[uDex].unitY, Data[uDex].nestX, Data[uDex].nestY) <= lDex.nestAreaVar then
                    set Data[uDex].combatDur = lDex.combatDurationVar
                endif
            endif
         
            // If call for help when attacking
            if lDex.maxHelpVar > 0 and lDex.callHelpVar then
                call pickHelper(s, t, uDex, lDex)
                call fireEvent(EVENT_CREEP_CALL_HELP, s, null)
            endif
         
        elseif IsUnitInGroup(t, CreepGroup) then
            set DummyType = GetUnitTypeId(t)
            set uDex = GetUnitUserData(t)
            set lDex = SCDataLib.getIndex(DummyType)
            set Data[uDex].combatDur = lDex.combatDurationVar
            call fireEvent(EVENT_CREEP_TAKE_DAMAGE, t, s)
         
            // If the creep is currently sleeping
            if Data[uDex].isSleep then
                call DestroyEffect(Data[uDex].sleepSfx)
                set Data[uDex].sleepSfx = null
                set Data[uDex].isSleep  = false
                call fireEvent(EVENT_CREEP_AWAKE, t, null)
            endif
         
            if lDex.canFleeVar and lDex.fleeDistVar > 0 then
                // If still around it's nest area
                if getDistance(Data[uDex].unitX, Data[uDex].unitY, Data[uDex].nestX, Data[uDex].nestY) < lDex.nestAreaVar then
                    set Real[R_FACING] = getAngle(GetUnitX(s), GetUnitY(s), Data[uDex].unitX, Data[uDex].unitY) * bj_DEGTORAD
                    set Real[R_X] = Data[uDex].unitX + lDex.fleeDistVar * Cos(Real[R_FACING])
                    set Real[R_Y] = Data[uDex].unitY + lDex.fleeDistVar * Sin(Real[R_FACING])
                else
                    set Real[R_FACING] = GetRandomReal(0, bj_PI*2)
                    set Real[R_X] = Data[uDex].nestX + lDex.fleeDistVar * Cos(Real[R_FACING])
                    set Real[R_Y] = Data[uDex].nestY + lDex.fleeDistVar * Sin(Real[R_FACING])
                endif
                call IssuePointOrderById(t, MOVE_ORDER_ID, Real[R_X], Real[R_Y])
                call fireEvent(EVENT_CREEP_FLEE, t, null)
            endif
         
            if GetOwningPlayer(t) == PASSIVE then
                set Data[uDex].target = s
                // If not tamed
                if not lDex.isTamedVar then
                    call SetUnitOwner(t, AGGRESSIVE, not COLOR)
                    call IssueTargetOrderById(t, ATTACK_ORDER_ID, s)
                endif
             
                if lDex.maxHelpVar > 0 then
                    call pickHelper(t, s, uDex, lDex)
                    call fireEvent(EVENT_CREEP_CALL_HELP, t, s)
                endif
            endif
         
            if GetWidgetLife(t) <= lDex.lowHealthVar then
                call fireEvent(EVENT_CREEP_LOW_HEALTH, t, null)
                // If able to seek help
                if lDex.seekHelpVar and lDex.maxHelpVar > 0 then
                    set h = GetClosestUnitInRange(Data[uDex].unitX,Data[uDex].unitY,lDex.seekRadiusVar,Filter(function helperFilter))
                    // Order to move to helper's position
                    if h != null then
                        call IssuePointOrderById(t, MOVE_ORDER_ID, GetUnitX(h), GetUnitY(h))
                        set h = null
                    endif
                    call fireEvent(EVENT_CREEP_SEEK_HELP, t, null)
                endif
            endif
        endif
        set t = null
        set s = null
     
        return false
    endfunction
 
    private function onDeath takes nothing returns boolean
     
        local integer uDex
        local SCDataLib lDex
        local player  p = GetTriggerPlayer()
        local unit u
     
        if p == PASSIVE or p == AGGRESSIVE then
            set u    = GetTriggerUnit()
            set uDex = GetUnitUserData(u)
            set lDex = SCDataLib.getIndex(GetUnitTypeId(u))
         
            call SetUnitOwner(u, PASSIVE, not COLOR)
            set Data[uDex].wanderDelay = lDex.wanderDelayVar + GetRandomReal(-lDex.wanderVariantVar, lDex.wanderVariantVar)/2
            set Data[uDex].combatDur   = -1
         
            set Data[uDex].combatDly   = -1
            set Data[uDex].helpCount   = 0
            set Data[uDex].isSleep     = false
         
            set u = null
        endif
     
        return false
    endfunction

    function EnableCreepBehavior takes unit u, boolean b returns nothing
 
        local SCDataLib lDex
        local integer uDex
        local player p = GetOwningPlayer(u)
     
        if b then
            if p == PASSIVE or p == AGGRESSIVE then
                if p == AGGRESSIVE then
                    call SetUnitOwner(u, PASSIVE, false)
                    static if COLOR then
                        call SetUnitColor(u, GetPlayerColor(PASSIVE))
                    endif
                else
                    static if not COLOR then
                        call SetUnitColor(u, GetPlayerColor(AGGRESSIVE))
                    endif
                endif
             
                if creepFilter(u) then
                    set Total = Total + 1
                    set uDex  = GetUnitUserData(u)
                    set lDex  = SCDataLib.getIndex(GetUnitTypeId(u))
                 
                    set Data[uDex] = CreepData.create()
                    set Data[uDex].helpCount = 0
                    set Data[uDex].isSleep   = false
                 
                    set Data[uDex].wanderDelay = GetRandomReal(0, lDex.wanderDelayVar)
                    set Data[uDex].nestX = GetUnitX(u)
                    set Data[uDex].nestY = GetUnitY(u)
                 
                    set Data[uDex].combatDly = -1
                    set Data[uDex].unitX = 0
                    set Data[uDex].unitY = 0
                 
                    if Total == 0 then
                        call TimerStart(Timer, INTERVAL, true, function onLoop)
                    endif
                endif
            endif
        elseif IsUnitInGroup(u, CreepGroup) then
            call GroupRemoveUnit(CreepGroup, u)
        endif
     
    endfunction

    private function onIndex takes nothing returns boolean
        call EnableCreepBehavior(GetIndexedUnit(), true)
        return false
    endfunction

    private function setAlliance takes nothing returns nothing
 
        local player p = GetEnumPlayer()
     
        if p != PASSIVE and p != AGGRESSIVE then
            // Aggressive player threats others as enemies
            call SetPlayerAlliance(AGGRESSIVE, p, ALLIANCE_PASSIVE, false)
            // Passive player threats other players as allies
            call SetPlayerAlliance(PASSIVE, p, ALLIANCE_PASSIVE, true)
        endif
     
    endfunction

    private function onInit takes nothing returns nothing
 
        local player  p  = GetLocalPlayer()
        local trigger t1 = CreateTrigger()
        local trigger t2 = CreateTrigger()
     
        static if AUTO_REGISTER then
            call RegisterUnitIndexEvent(Condition(function onIndex), UnitIndexer.INDEX)
        endif
     
        call addEvent(t1)
        call TriggerAddCondition(t1, Condition(function onHit))
     
        call TriggerRegisterAnyUnitEventBJ(t2, EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddCondition(t2, Condition(function onDeath))
     
        // Alliance setting
        call SetPlayerAlliance(PASSIVE, AGGRESSIVE, ALLIANCE_PASSIVE, true)
        call SetPlayerAlliance(AGGRESSIVE, PASSIVE, ALLIANCE_PASSIVE, true)
        call ForForce(bj_FORCE_ALL_PLAYERS, function setAlliance)
     
        // Give global sight for both player
        if p == AGGRESSIVE or p == PASSIVE then
            call FogEnable(false)
            call FogMaskEnable(false)
        endif
     
        set t1 = null
        set t2 = null
     
    endfunction
 
endlibrary
 


Credits
  • TimerUtils by Vexorian
  • GetClosestWidget by Spinnaker
  • UnitIndexer by Nestharus
  • GDD by Weep
  • Table by Bribe

Keywords:
rpg, creep, monster, behavior
Contents

RPG Threat System (Map)

Reviews
Moderator
IcemanBo: - date: 3th March 2015 - submission: Special Creep Engine v3.2b The system allows to define unique unit-type behaviours for creeps to improve the enemy's AI creep controle. All in all the code is efficient, leakless and works fine....
  1. IcemanBo:
    - date: 3th March 2015
    - submission: Special Creep Engine v3.2b

    The system allows to define unique unit-type behaviours
    for creeps to improve the enemy's AI creep controle.

    All in all the code is efficient, leakless and works fine.
    I have not found nor bugs nor major flaws in the system.

    • 2*r <= 360
      ->
      r <= 180
      .
    • It might be a bit confusing for user that the creep sleeping is not the same as the normal wc3 unit sleeping.
      It might be helpful if it was clarified.
    • Arithmetic like "SECONDS_IN_A_DAY/86400" could be calculated once onInit.
    • The term "generator unit" that is used is not really explained. (?)

    Good job. Approved.

    Older

    IcemanBo: https://www.hiveworkshop.com/posts/2640438/

    • Purgeandfire :: 29 October 2014

      Criteria (Systems):
      • Coding (20): efficiency and potential improvement.
      • Concept (10): originality and features.
      • Design (20): modularity, importability, ease of use, and method of attack.
      • Misc (10): test map, image, hive submission, misc.
      • Docs (10): documentation

      Score:
      • Coding: 10 / 20
      • Concept: 7 / 10
      • Design: 14 / 20
      • Misc: 8 / 10
      • Docs: 5 / 10
      • Total Score: 44 / 70

      Needs Fix :: see Required Changes for approval.

      Current Rating
      3 / 5


      Score Distribution
      • 65 - 70 becomes 5 / 5
      • 55 - 65 becomes 4 / 5
      • 40 - 55 becomes 3 / 5
      • 30 - 40 becomes 2 / 5
      • 0 - 30 becmes 1 / 5





      1. GetWorldBounds()
        leaks. You need to store it in a variable and then
        remove it manually (2 occurrences). [-3]
      2. Just a note, adding [13] does not do anything for the following line:
        private trigger array Handler[13]

        It does not change anything unless you use a size > 8192.
      3. filter2 should have a better name. [-1]
      4. In pickHelper, if I'm not mistaken, it seems like you are trying to
        choose the closest units and order them to help. In this case, it may
        be better to take advantage of Spinnaker's system and use:
        GetClosestNUnitsInRange

        It is designed to do what you need to do, and it will result in a
        significantly lighter computation. Note: You will have to change your
        entire loop to adapt to this change. [-2]
      5. This:
        set Real[R_TEMP_FACE] = GetRandomReal(0, 359.9) * bj_DEGTORAD

        Is equivalent to:
        sett Real[R_TEMP_FACE] = GetRandomReal(0, 2*bj_PI)

        Or you can use 6.28319 instead of 2*bj_PI.
      6. In onHit, you can move the assignment of 'dex' outside the blocks.
        (saves 1 line)
      7. In onDeath, you need to set u to null. [-1]
      8. If you really wanted to be extreme, you could redo this entire
        system using structs instead of hashtables. >:) [-2]
      9. Why use a trigger action for initUnit? (use a condition) [-1]

      Score: 10 / 20


      1. Cool concept! I love the diverse features! It really shows effort.
      2. Creep engines are quite common though.
      3. It could be cool to have creep-specific modularity, e.g. creep
        specific sleep durations, so forth.
      Score: 8 / 10

      1. The module design is not very good. Generally, the best design is where
        a user does not have to touch the system at all, and only needs to know
        its functions. Generally, it is better to separate example code from the
        library itself (usually in a different trigger).
      2. A second design flaw is that the data is all expected upon initialization.
      3. The setup functions have too generic names, e.g. ResetTimer or LowBound
      4. To fix issues 1-3, I recommend translating your setup over to a struct
        and adding a .register() method so the user can invoke registering a creep.
        Code (vJASS):

                struct SpecialCreep extends array
                    private static group   cg  = CreateGroup()
                    private static integer uid = 0

                    method operator tamed= takes boolean tame returns nothing
                        call SaveBoolean(Hashtable, P_TAMED_BOOL, this, tame)
                    endmethod

                    method operator sleepDuration= takes real duration returns nothing
                        call SaveReal(Hashtable, P_SLEEP_DUR, this, duration)
                    endmethod

                    // etc...

                    private static method registerCreeps takes nothing returns boolean
                        local unit f = GetFilterUnit()
                        if GetUnitTypeId(f) == thistype.uid then
                            // ... actions to register creeps ...

                            // uid -> rawcode of creep being registered
                            // f -> creep being registered
                        endif  
                        set f = null
                        return false
                    endmethod

                    method update takes nothing returns nothing
                        local rect r = GetWorldBounds()
                        set uid = this
                        call GroupEnumUnitsInRect(cg, r, Filter(function thistype.registerCreeps))
                        call RemoveRect(r)
                        set r = null
                    endmethod

                    static method get takes integer raw returns thistype
                        return raw
                    endmethod
                endstruct
               

        This may be a little advanced. In this situation, we are treating
        the raw ID as the struct itself. With this, we do not even need to
        map the rawcodes to integers 1, 2, 3... etc. We can just use the
        rawcode for everything! In case this was confusing, maybe this will
        help:
        Code (vJASS):

                    local SpecialCreep murloc = SpecialCreep.get('nmrl')
                    set murloc.tamed = false
                    set murloc.sleepDuration = 7.25
                    set murloc.sleepTime = 21.0
                    // etc.
                    call murloc.update()
               

        Note: my code above would change a lot of the system. I recommend
        making these changes only if you understand the code 100%. But the
        advantage is it would allow you to update unit stats at any time by
        using .update()! That is awesome modularity.
      5. When you order a unit to patrol (via the MOVE order), won't it ignore
        enemy targets?
      Score: 14 / 20


      1. The test map should have instructions on what to do, or some
        form of debriefing. It can either be in a message, a quest, etc. [-2]
      Score: 8 / 10

      1. Needs documentation. It is preferrable to have it at the top of
        the code, and have a list of the functions that should be used.
        Ideally, a user should not have to look through your system at all
        in order to use your system.

        Add some descriptions to functions and such. See the JASS section
        for examples. It will make your code a lot more user-friendly. [-5]
      Score: 5 / 10


      • Coding: #1, #4 (or explain if I read your code wrong), #7, #9
      • Design: #5 (need a response)
      • Misc: #1
     
  2. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,235
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    forgot to mention
    this system is not friendly for GUI user because you need a little basic JASS knowledge about filtering unit.
     
    Last edited: Mar 17, 2014
  3. Daffa the Mage

    Daffa the Mage

    Map Moderator

    Joined:
    Jan 30, 2013
    Messages:
    7,573
    Resources:
    27
    Packs:
    1
    Maps:
    8
    Spells:
    16
    Tutorials:
    2
    Resources:
    27
    Bug Patching Help :
    - check if unit is alive, if it's not, removed it from list.
    - I recommend create several versions that suits all renown DDS (LFH and Bribe GUI DDS' are top priority since they're used a lot).
     
  4. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,235
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    I will just use lfh's.. :p bcose it's super lovely and easy to use!
     
  5. Daffa the Mage

    Daffa the Mage

    Map Moderator

    Joined:
    Jan 30, 2013
    Messages:
    7,573
    Resources:
    27
    Packs:
    1
    Maps:
    8
    Spells:
    16
    Tutorials:
    2
    Resources:
    27
    It's recommended that CBS_Loop Value shouldn't go below
     integer 0.3125
    or so, that's the base value of Jass spells loop.
     
  6. TheGoldenGoblin

    TheGoldenGoblin

    Joined:
    Dec 6, 2009
    Messages:
    168
    Resources:
    0
    Resources:
    0
    You should give examples on how to use dds. Also if you use spells on the units they won't attack you.
     
  7. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    The big con is the tremendous ForGroup loop, which runs every 0.03125 seconds.

    I would appreciate it, if you would outline your code with comments.
    Makes it much easier for me and others to read.
     
  8. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,235
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    you are right.. :) but there are many choices of DDS, that's why I got a feeling to left it optional (using basic unit is attacked event)

    yeah, actualy using high accuracy doesn't really affects the performance lol, event using 0.5 is not noticeable..

    300th post!!!

    EDIT:

    Updated to v1.2 with the following:
    - Accuracy changed to a reasonable value
    - Added some outlines
    - Added with DDS version

    credit's going to looking_for_help
     
    Last edited: Mar 2, 2014
  9. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,633
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    The documentation should be included in the code, so when people copy it to their maps or to another website, it's there.

    Also, inside CBS_InitLibrary I think there should be a wrapper for
    SaveInteger
    to improve readability and not require people to specify a parent key (custom allocation).
    This will also prevent users from using a different hashtable.

    By default this system should probably require a DDS, because of how inaccurate the attack event is.
     
  10. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,336
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Code (vJASS):
    function DistanceBetweenCoords takes real x,real y,real xt,real yt returns real
            local real dx = xt - x
            local real dy = yt - y
           
            return SquareRoot(dx * dx + dy * dy)
        endfunction

    ->
    Code (vJASS):
    function DistanceBetweenCoords takes real x,real y,real xt,real yt returns real
            return SquareRoot((xt-x)*(xt-x) + (yt-y)*(yt-y))
        endfunction


    Code (vJASS):
    if angle > 360 then
                loop
                    set angle = angle - 360
                    exitwhen (angle <= 360)
                endloop
            elseif angle < 0 then
                loop
                    set angle = angle + 360
                    exitwhen angle >= 0
                endloop
            endif

    ->
    Code (vJASS):
    if angle > 360. then
                set angle = ModuloReal(angle, 360)
            elseif angle < 0. then
                set angle = ModuloReal(-angle, 360)
            endif

    :p

    Code (vJASS):
    function CBS_Filter2 takes nothing returns boolean
            local unit u = GetFilterUnit()
            local unit c = LoadUnitHandle(udg_CBS_Hash, 0, 0)
            local real a1
            local real a2
            local real rad
            local integer dex
            local player pa = Player(CBS_PassivePlayer())
            local player ag = Player(CBS_AggressivePlayer())
            local player p = GetOwningPlayer(u)
           
            set dex = LoadInteger(udg_CBS_Hash, 1911, GetUnitTypeId(c))
            set a1 = GetUnitFacing(c) + 360.0
            set a2 = AngleBetweenCoords(GetUnitX(c),GetUnitY(c),GetUnitX(u),GetUnitY(u)) + 360.0
            // Load sight radius
            set rad = LoadReal(udg_CBS_Hash, 5511, dex) * 0.5
            // Filter out target not in sight radius
            if (a2 <= a1 - rad or a2 >= a1 + rad) and (a2 <= a1 - rad - 360.0 or a2 >= a1 + rad - 360.0) then
                return false
            endif
            if p == pa or p == ag then
                return false
            endif
            return IsUnitVisible(u, pa) and IsUnitVisible(u, ag) and not IsUnitType(u, UNIT_TYPE_DEAD)
        endfunction

    This function leak ^^'
    I suggest storing the result into a boolean, null every local handle and at least return the boolean.

    Code (vJASS):
    function CBS_HelpFilter takes nothing returns boolean
            local unit u = GetFilterUnit()
            local integer ut = GetUnitTypeId(u)
            local integer dex = LoadInteger(udg_CBS_Hash, 1911, ut)
            local integer ht = LoadInteger(udg_CBS_Hash, 7550, dex)
           
            if ht == 1 then
                if ut != udg_CBS_DuTy then
                    return false
                endif
            else
                if ht < 1 then
                    return false
                endif
            endif
            return GetOwningPlayer(u) == Player(CBS_PassivePlayer()) and not LoadBoolean(udg_CBS_Hash, 2343, dex)
        endfunction

    Same there.

    if GetWidgetLife(u) > .405 then
    isn't enough to check if a unit is dead :
    if GetWidgetLife(u) > .405 and not IsUnitType(u, UNIT_TYPE_DEAD)



    Code (vJASS):
    local player pa = Player(CBS_PassivePlayer())
           
            if GetOwningPlayer(a) == Player(CBS_AggressivePlayer()) then

    ->
    Code (vJASS):
    local player pa = Player(CBS_PassivePlayer())
           
            if GetOwningPlayer(a) == pa then



    Code (vJASS):
    else
                    if not CBS_ColorBool() then
                        call SetUnitColor(u, GetPlayerColor(ag))
                    endif

    ->
    Code (vJASS):
    elseif not CBS_ColorBool() then
        ....
    endif



    Code (vJASS):
    call SetPlayerAllianceStateBJ(ag, p, bj_ALLIANCE_UNALLIED)
                    // Passive player threats other players as allies
                    call SetPlayerAllianceStateBJ(pa, p, bj_ALLIANCE_ALLIED)

    Bjs needed ?


    call TriggerRegisterEnterRectSimple(t, GetWorldBounds())

    This one can be avoid and it leaks :/
     
  11. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,110
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    Code (vJASS):
    private function AngleBetweenCoords takes real x, real y, real xt, real yt returns real
            local real angle = Atan2((yt - y), (xt - x)) * bj_RADTODEG
           
            if angle > 360 then
                loop
                    set angle = angle - 360
                    exitwhen (angle <= 360)
                endloop
            elseif angle < 0 then
                loop
                    set angle = angle + 360
                    exitwhen angle >= 0
                endloop
            endif
            return angle
        endfunction

    This is ok, but I would just do:
    Code (vJASS):
    private function AngleBetweenCoords takes real x, real y, real xt, real yt returns real
        return Atan2((yt - y), (xt - x)) * bj_RADTODEG
    endfunction

    If you keep yours (not wrong) change the first check "if angle > 360 then" to if equal or bigger. (because if you have 360 you want to get it 0)
    Code (vJASS):
    private function filter2 takes nothing returns boolean
            local unit u = GetFilterUnit()
            local unit c = LoadUnitHandle(HASH, 0, 0)
            local real a1
            local real a2
            local real rad
            local integer dex
            local player pa = Player(PASSIVE)
            local player ag = Player(AGGRESSIVE)
            local player p = GetOwningPlayer(u)
            local boolean b = true
           
            set dex = LoadInteger(HASH, 1911, GetUnitTypeId(c))
            set a1 = GetUnitFacing(c) + 360.0
            set a2 = AngleBetweenCoords(GetUnitX(c),GetUnitY(c),GetUnitX(u),GetUnitY(u)) + 360.0
            set rad = LoadReal(HASH, 5511, dex) * 0.5
            if (a2 <= a1 - rad or a2 >= a1 + rad) and (a2 <= a1 - rad - 360.0 or a2 >= a1 + rad - 360.0) then
                set b = false
            endif
            if (p == pa or p == ag) or IsUnitType(u, UNIT_TYPE_DEAD) then
                set b = false
            endif
            if not IsUnitVisible(u, pa) and not IsUnitVisible(u, ag) then
                set b = false
            endif
            set u = null
            set c = null
            return b
        endfunction

    Use locols for UnitX/Y since you make 2 function calls.
    Atm you do 3 checks, even b would be FALSE already after first one. You could put further checks in 'else' of first 'if' to prevent useless checks. ;)

    Same with move further 'if's' in 'else' of first 'if' to prevent needless checks for
    Code (vJASS):
     private function helpfilter

    Then soon stopped reading code carefully because Im too lazy to read this all :d

    But in "private function ini takes nothing returns nothing" you forgot to null local region.

    And does your system work if I want to have more than 1 AGGRESIVE and 1 PASSIVE player?

    And for me idc, but you have to change variable names. Only capital letters --> only constants. Start normal variables with lowcase and each new word with capital letter.
     
  12. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,235
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    you want it for what? C:

    I use it only once

    okay, thnks!

    can you give me example? I don't understand that part :)
    thnks for the review..
     
  13. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,110
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    I dont need it, just wanted to know :p

    Oh yo, one time 'c' and other one is 'u'. You're right

    private constant string NAME : good
    private constant string name : not good

    private string MAPNAME : not good
    private string mapName : good
     
  14. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,110
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    In my system BPower told me not to use _
    So if it's constant then maybe NAMENAME else nameName.
    http://www.hiveworkshop.com/forums/2494473-post3.html

    Edit:
    MAP_NAME was correct for constant ^^
     
    Last edited: Mar 7, 2014
  15. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,336
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Remember that if you use only one time the value in the function there is no need to use a local :) I didn't check the code on this criteria but seemed good.

    Code (vJASS):
    set dex = LoadInteger(HASH, 1911, GetUnitTypeId(c))
            set a1 = GetUnitFacing(c) + 360.0
            set a2 = AngleBetweenCoords(GetUnitX(c),GetUnitY(c),GetUnitX(u),GetUnitY(u)) + 360.0
            set rad = LoadReal(HASH, 5511, dex) * 0.5

    Could be done on local declaration :D

    Code (vJASS):
    local unit u = gettarget()
            local unit a = getsource()

    Set the values of those local inside the if block and put the nulling of those local in the if block too :)

    Code (vJASS):
    local player pa = Player(PASSIVE)
           
            if GetOwningPlayer(a) == Player(AGGRESSIVE) then

    ->
    Code (vJASS):
    local player pa = Player(PASSIVE)
           
            if GetOwningPlayer(a) == pa then


    You forgot to use
    call RemoveRect(r)
    in the init function :p


    Code (vJASS):
    if GetUnitCurrentOrder(u) != OrderId("move") and GetUnitX(u) == LoadReal(HASH, hand, 9) and GetUnitY(u) == LoadReal(HASH, hand, 10) then
                return false
            endif
            return true

    ->
    return not(GetUnitCurrentOrder(u) != OrderId("move") and GetUnitX(u) == LoadReal(HASH, hand, 9) and GetUnitY(u) == LoadReal(HASH, hand, 10))
     
  16. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,235
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    Roger that!

    there is PASSIVE and AGGRESIVE, they are not the same :p

    Code (vJASS):
            local unit u = gettarget()
            local unit a = getsource()

    I think that part just stay at local declaration is okay
     
  17. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,336
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Holy xD !
    My eagle eye didn't see this ^^
     
  18. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,235
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    call RemoveRect(r)
    result in complie error? :/ or maybe you meant
    call RemoveRegion(r)
    ? because r is region
     
  19. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,336
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Oh yes you're right ^^