• 🏆 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!

Small Code Snippets

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
xor is not deprecated in other programming languages. For WarCraft III booleans you have "true (1)" and "false (0)". For other programming languages, you sometimes deal with more complex things than just 0 and 1, for example remember the IsUnitType bug which used to exist with UNIT_TYPE_TOWNHALL? It was returning a boolean which didn't correspond with "1" (I think it was 64 or 32). So if you compare 1 != 64 you will get "true" even though you are supposed to compare "false != false".

Provided everything is handed to you and you know for sure that you are only dealing with 0 and 1, yes you can use the comparison operator "!=".
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
The fact that they were returning a value of 64 is bad code on their part. A boolean value in C is an integer, and in C++ I believe it just works like an enum. When you declare something as an enum the entries attain values of 0, 1, etc...

In order for them to have a value of 64 for a boolean, they would have to not be using a boolean, in which case they're not returning what they should be.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
JASS:
//Requires
//  KnuthChecksum   hiveworkshop.com/forums/1846246-post343.html
//  NumberStack     hiveworkshop.com/forums/1993458-post521.html
library ApplyChecksum uses KnuthChecksum, NumberStack
    /***********************************************************************
    *
    *   Security Details
    *
    *       -   1 in checksum codes will work
    *       -   Version unique checksums
    *       -   Code overflow/underflow checking
    *
    ***********************************************************************
    *
    *   function ApplyCRC takes NumberStack stack, integer crc returns nothing
    *       -   Applies a CRC, which is a checksum that is added to an empty stack.
    *       -   If doing non versoined save/load, pass in a 1.
    *       -   If doing versioned save/load, pass in the current version.
    *       -   Always use a CRC as it validates the code's size! Without a CRC, players can load up invalid codes!
    *       -   May only apply 1 CRC
    *       -   CRC Max: 999999999
    *
    *   function ValidateCRC takes NumberStack stack, integer crc returns boolean
    *       -   Validates the CRC (can only be validated after loading all of the values out of the stack).
    *       -   Pass in the expected value. If the expected value is 1, pass in 1. If the expected value
    *       -   is the version, pass in the version.
    *
    *   function ApplyChecksum takes NumberStack stack, BigInt security returns nothing
    *       -   Applies checksum to code. The larger the security, the bigger the code will be. 1 in security codes
    *       -   will be valid. Without a checksum, all codes will be valid! A security value between
    *       -   100,000 and 500,000 is recommended.
    *       -   Be sure to use a CRC value of 1
    *       -   May apply multiple checksums. If applying a versioned checksum, use the ver as the CRC instead.
    *
    *   function ApplyVersionChecksum takes NumberStack stack, BigInt security, integer ver, integer maxVer returns nothing
    *       -   Applies a versioned checksum. The version is the version the code is being saved for.
    *       -   The max version is the maximum amount of versions your map will support. You can't change the max version
    *       -   value or you will break your save/load codes!
    *       -   Be sure to use a CRC value of ver
    *       -   May apply 1 versioned checksum. Versioned checksums are version unique.
    *       -   Version max will not increase the code size as long as it is smaller than the checksum max, thus a version
    *       -   max of 50,000 or so is recommended.
    *
    *   function ValidateChecksum takes NumberStack stack, BigInt security returns boolean
    *       -   Validates a checksum (go in backwards order of how they were applied)
    *   function ValidateChecksumVersion takes NumberStack stack, BigInt security, integer maxVer returns integer
    *       -   Validates versoined checksum (go in backwards order of how they were applied)
    *       -   The returned value is the version. If the returned value is 0, the checksum was invalid.
    *       -   Keep in mind that versioned checksums bleed across different versions, so while the checksum
    *       -   may be valid, the code itself may be invalid. A CRC storing the version is required to completely
    *       -   validate a versioned checksum.
    *
    ***********************************************************************/
    function ApplyCRC takes BigInt number, integer crc returns nothing
        debug if (number.size != 0) then
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 10, "CAN ONLY APPLY CRC TO EMPTY BIG INT")
            debug return
        debug endif
        call number.add(crc)
    endfunction
    function ValidateCRC takes BigInt number, integer crc returns boolean
        return number.size < 10 and number.size > 0 and number.toInt() == crc
    endfunction
    private function GetChecksumMax takes BigInt security returns BigInt
        return security
    endfunction
    private function GetVersionChecksumMax takes BigInt security, integer maxVersion returns BigInt
        local BigInt maximum
        
        set maximum = security.copy()
        call maximum.add(maxVersion)
        
        return maximum
    endfunction
    private function GetChecksum takes NumberStack number, BigInt security returns BigInt
        return GetKnuthChecksum(number, security)
    endfunction
    private function GetVersionChecksum takes NumberStack stack, BigInt security, integer ver returns BigInt
        local BigInt checksum
        
        set checksum = GetChecksum(stack, security)
        call checksum.add(ver)
        
        return checksum
    endfunction
    function ApplyChecksum takes BigInt number, BigInt security returns nothing
        local BigInt checksum = GetChecksum(number, security)
        call number.multiplyBig(security)
        call number.addBig(checksum)
        call checksum.destroy()
    endfunction
    function ApplyVersionChecksum takes BigInt number, BigInt security, integer ver, integer maxVer returns nothing
        local BigInt maxChecksum = GetVersionChecksumMax(security, maxVer)
        local BigInt checksum = GetVersionChecksum(number, security, ver)
        call number.multiplyBig(maxChecksum)
        call number.addBig(checksum)
        call maxChecksum.destroy()
        call checksum.destroy()
    endfunction
    function ValidateChecksum takes BigInt number, BigInt security returns boolean
        local BigInt checksum = number.divideBig(security)
        local BigInt actualChecksum = GetKnuthChecksum(number, security)
        local boolean valid = checksum.eq(actualChecksum)
        
        call checksum.destroy()
        call actualChecksum.destroy()
        
        return valid
    endfunction
    function ValidateChecksumVersion takes BigInt number, BigInt security, integer maxVer returns integer
        local BigInt checksum
        local BigInt actualChecksum
        local integer ver
        
        local BigInt checksumMax = security.copy()
        call checksumMax.add(maxVer)
        
        set checksum = number.divideBig(checksumMax)
        set actualChecksum = GetKnuthChecksum(number, security)
        call checksum.subtractBig(actualChecksum)
        set ver = checksum.toInt()
        
        call checksum.destroy()
        call actualChecksum.destroy()
        call checksumMax.destroy()
        
        if (1 > ver or maxVer < ver) then
            return 0
        endif
        
        return ver
    endfunction
endlibrary
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
JASS:
library FloatingText /* v1.0.1.1
*************************************************************************************
*
*   Fast creation of floating text
*
*   Useful for things like displaying damage in ORPGs or displaying bounty from killing creeps
*
*************************************************************************************
*
*   */uses/*
*
*       */ TextTag /*         hiveworkshop.com/forums/submissions-414/snippet-texttag-213488/
*
*************************************************************************************/
    globals
        private constant real LIFE_SPAN = 1
        private constant real HEIGHT = 128
        private constant real VELOCITY_X = 0
        private constant real VELOCITY_Y = 128
        private constant real FADEPOINT = .5
        private constant real SIZE = 10
        private constant real MAX_DISTANCE = 2000
    endglobals

    function CreateFloatingText takes string text, real x, real y, boolean createForPlayer returns TextTag
        local TextTag tag
        
        local real playerX = GetCameraTargetPositionX() - x
        local real playerY = GetCameraTargetPositionY() - y
        local real distance = playerX*playerX + playerY*playerY
        
        set tag = TextTag.createLocal(createForPlayer and distance <= MAX_DISTANCE*MAX_DISTANCE)
        
        call tag.setText(text, SIZE)
        call tag.setPosition(x, y, HEIGHT)
        set tag.lifespan = LIFE_SPAN
        call tag.setVelocityXY(VELOCITY_X, VELOCITY_Y)
        set tag.fadepoint = FADEPOINT
        
        return tag
    endfunction
    
    function CreateFloatingTextAtWidget takes string text, widget position, boolean createForPlayer returns TextTag
        return CreateFloatingText(text, GetWidgetX(position), GetWidgetY(position), createForPlayer)
    endfunction
endlibrary
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
JASS:
/*
*   uses
*
*       Advanced Damage Event       hiveworkshop.com/forums/submissions-414/extension-advanced-damage-event-213572/
*       DamageQueue                 hiveworkshop.com/forums/submissions-414/system-damage-queue-213752/
*       DamageType                  hiveworkshop.com/forums/submissions-414/snippet-damagetype-213751/
*       Floating Text               hiveworkshop.com/forums/2119387-post755.html
*/
struct DamageText extends array
    private static method display takes nothing returns boolean
        return GetLocalPlayer() == GetOwningPlayer(source) or GetLocalPlayer() == GetOwningPlayer(target)
    endmethod

    private static constant method PRIORITY takes nothing returns integer
        return DAMAGE_PRIORITY_DISPLAY
    endmethod
    
    private static method onDamage takes nothing returns nothing
        local DamageQueue node = DamageQueue.first
        local string str = ""
        local real damage
        if (1 == depth) then
            loop
                exitwhen node.head
                set damage = node.damage
                if (0 < damage - .5) then
                    set str = str + "|cff"+node.type.color+("-"+I2S(R2I(damage + .5)))+"|r "
                elseif (0 > damage + .5) then
                    set str = str + "|cff"+node.type.color+("+"+I2S(R2I(-damage - .5)))+"|r "
                endif
                set node = node.next
            endloop
            if (str != "") then
                call CreateFloatingText(str, GetUnitX(target), GetUnitY(target), display())
            endif
        endif
    endmethod
    
    implement DamageEvent
endstruct
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
JASS:
/*
*   uses
*
*       UnitIndex                       hiveworkshop.com/forums/jass-functions-413/unit-indexer-172090/
*       AdvDamageEvent                  hiveworkshop.com/forums/submissions-414/extension-advanced-damage-event-213572/
*       DamagePriority                  hiveworkshop.com/forums/submissions-414/repo-damage-priority-213750/
*       DamageModificationEffect        hiveworkshop.com/forums/submissions-414/system-damage-modification-effect-213608/
*/
struct DamageModifierCancelNegative extends array
    private static constant method PRIORITY takes nothing returns integer
        return DAMAGE_PRIORITY_MODIFIER_CANCEL_NEGATIVE
    endmethod
    
    private static method onDamageIncoming takes nothing returns nothing
        if (0 > modifiedAmount) then
            set modifiedAmount = 0
        endif
    endmethod
    
    private method index takes nothing returns nothing
        call thistype(GetIndexedUnitId()).apply(true)
    endmethod

    implement DamageModificationEffect
    implement UnitIndexStruct
endstruct

This place thread seems inactive again.
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
Found that it could make sense to have a hierarchy of buffs.

For example, if using the general buff "Ignition", which makes the unit lose 2% life per second, there could be a magical "Dark Burn" version of it, additionally causing silence or a physical version that in contrast to Dark Burn cannot be dispelled. A cure for Ignition (stepping in water e.g.) would cure all variants of it.

JASS:
class Buff
    thistype array parents
    thistype array variants

    method onLose takes nothing returns nothing
        for parent in this.parents do
            triggerUnit.subtractBuff(parent)  //since multiple variants may be active at the same time, references have to be counted on the parent buff
        next

        for variant in this.variants do
            triggerUnit.removeBuff(variant)
        next
    endmethod

    method onGain takes nothing returns nothing
        for parent in this.parents do
            triggerUnit.addBuff(parent)
        next
    endmethod

    method SetVariant takes Buff parent returns nothing
        set parent.variants += this
        set this.parents += parent
    endmethod
endstruct

Buffs may derive multiple parents.
 
Level 5
Joined
Dec 12, 2011
Messages
116
Want to display a player's name with the proper color?
JASS:
function GetPlayerColoredName takes player p returns string
    local string prefix = ""
    if (GetPlayerId(p) == 0) then
        set prefix = "|cffff0303"
    elseif (GetPlayerId(p) == 1) then
        set prefix = "|cff0042ff"
    elseif (GetPlayerId(p) == 2) then
        set prefix = "|cff1ce6b9"
    elseif (GetPlayerId(p) == 3) then
        set prefix = "|cff540081"
    elseif (GetPlayerId(p) == 4) then
        set prefix = "|cfffffc01"
    elseif (GetPlayerId(p) == 5) then
        set prefix = "|cfffeba0e"
    elseif (GetPlayerId(p) == 6) then
        set prefix = "|cff20c000"
    elseif (GetPlayerId(p) == 7) then
        set prefix = "|cffe55bb0"
    elseif (GetPlayerId(p) == 8) then
        set prefix = "|cff959697"
    elseif (GetPlayerId(p) == 9) then
        set prefix = "|cff7ebff1"
    elseif (GetPlayerId(p) == 10) then
        set prefix = "|cff106246"
    elseif (GetPlayerId(p) == 11) then
        set prefix = "|cff4e2a04"
    endif
    return prefix + GetPlayerName(p) + "|r"
endfunction

Notice this will be white for Neutral Passive, Neutral Hostile, etc.

EDIT: credits to Anitarf for the player colors...

hamsterpellet
 
:V

Or:

JASS:
library GetPlayerColoredName
    globals
        private string array colors
    endglobals

    private module Init
        private static method onInit takes nothing returns nothing
            set colors[0] = "|cffff0303"
            set colors[1] = "|cff0042ff"
            set colors[2] = "|cff1ce6b9"
            set colors[3] = "|cff540081"
            set colors[4] = "|cfffffc01"
            set colors[5] = "|cfffeba0e"
            set colors[6] = "|cff20c000"
            set colors[7] = "|cffe55bb0"
            set colors[8] = "|cff959697"
            set colors[9] = "|cff7ebff1"
            set colors[10] = "|cff106246"
            set colors[11] = "|cff4e2a04"
        endmethod
    endmodule

    private struct InitS extends array
        implement Init
    endstruct

    function GetPlayerColoredName takes player p returns string
        return colors[GetPlayerId(p)] + GetPlayerName(p) + "|r"
    endfunction
endlibrary
 
Oh I see, if your intention was to make a JASS-only script, then what you can do is have a string array created in the variable editor and configured on map init so that colors[0] is equal to the player color string of Player(0), etc...

Then, your code would be this:

JASS:
function GetPlayerColoredName takes player p returns string
    return udg_PlayerColors[GetPlayerId(p)] + GetPlayerName(p) + "|r"
endfunction
 
Level 16
Joined
Aug 7, 2009
Messages
1,403
Pretty self-explanatory; I needed this function recently, but since I didn't know about a library that contains it, I wrote it myself.

JASS:
/*
Usage:
˘˘˘˘˘˘
Mod(4,2): 0
Mod(5,2): 1
Mod(5,3): 2
Mod(5,6): 5

Note: divider should not be zero.
*/
function Mod takes integer dividend,integer divider returns integer
    return dividend-(dividend/divider)*divider
endfunction
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
There is the infamous library spelled "blizzard.j" :

JASS:
function ModuloInteger takes integer dividend, integer divisor returns integer
    local integer modulus = dividend - (dividend / divisor) * divisor

    // If the dividend was negative, the above modulus calculation will
    // be negative, but within (-divisor..0).  We can add (divisor) to
    // shift this result into the desired range of (0..divisor).
    if (modulus < 0) then
        set modulus = modulus + divisor
    endif

    return modulus
endfunction
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
You know what, the if for the GUI function seems to be bullshit, unless i'm missing something the only way where modulus could be < 0 is when dividend and divisor are both < 0.
And in this case the result makes absolutely no sense.

I know that the definition of modulo is not clear with negative numbers, but at least without the if it makes some sense, it's not just "random" like the one provided by the BJ.
 
Level 5
Joined
Dec 12, 2011
Messages
116
Oh I see, if your intention was to make a JASS-only script, then what you can do is have a string array created in the variable editor and configured on map init so that colors[0] is equal to the player color string of Player(0), etc...

Then, your code would be this:

JASS:
function GetPlayerColoredName takes player p returns string
    return udg_PlayerColors[GetPlayerId(p)] + GetPlayerName(p) + "|r"
endfunction

Yep, yep, I see
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
Code:
LockPlayerCameraToRect takes player p, rect r returns nothing

"locks" a player's camera to a target region by forcing it to the closest point inside the region if it is detected to be outside.

You can still drag the camera around on the minimap, which results in the camera switching between the two locations at a high frequency.

This is useful because it doesn't kill your minimap.

JASS:
library LockCameraToRect initializer Init
    globals
        private trigger CameraLockLoop
        private real array BoundMaxX
        private real array BoundMinX
        private real array BoundMaxY
        private real array BoundMinY
    endglobals
    
    function LockPlayerCameraToRect takes player p, rect r returns nothing
        local integer i = GetPlayerId(p)
        set BoundMaxX[i] = GetRectMaxX(r)
        set BoundMinX[i] = GetRectMinX(r)
        set BoundMaxY[i] = GetRectMaxY(r)
        set BoundMinY[i] = GetRectMinY(r)
    endfunction
    
    private function LockLoop takes nothing returns nothing
        local player p
        local integer i = 0
        local real x
        local real y
        loop
            exitwhen i == 11
            set p = Player(i)
            if GetLocalPlayer() == p then
                set x = GetCameraTargetPositionX()
                set y = GetCameraTargetPositionY()
                if (not ( (BoundMinX[i] <= x) and (x <= BoundMaxX[i]) and (BoundMinY[i] <= y) and (y <= BoundMaxY[i]) )) then
                    if ( x > BoundMaxX[i] ) then
                        set x = BoundMaxX[i] - 1
                    endif
                    if ( x < BoundMinX[i] ) then
                        set x = BoundMinX[i] + 1
                    endif
                    if ( y > BoundMaxY[i] ) then
                        set y = BoundMaxY[i] - 1
                    endif
                    if ( y < BoundMinY[i] ) then
                        set y = BoundMinY[i] + 1
                    endif
                    call SetCameraPosition(x, y)
                endif
            endif
            set i = i + 1
        endloop
    endfunction

    private function Init takes nothing returns nothing
        local integer i = 0
        loop
            exitwhen i == 11
            call LockPlayerCameraToRect(Player(i), bj_mapInitialCameraBounds)
            set i = i + 1
        endloop
        set CameraLockLoop = CreateTrigger(  )
        call TriggerRegisterTimerEvent(CameraLockLoop, 0.03, true)
        call TriggerAddAction(CameraLockLoop, function LockLoop)
    endfunction
endlibrary
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Code:
LockPlayerCameraToRect takes player p, rect r returns nothing

"locks" a player's camera to a target region by forcing it to the closest point inside the region if it is detected to be outside.

You can still drag the camera around on the minimap, which results in the camera switching between the two locations at a high frequency.

This is useful because it doesn't kill your minimap.

JASS:
library LockCameraToRect initializer Init
    globals
        private trigger CameraLockLoop
        private real array BoundMaxX
        private real array BoundMinX
        private real array BoundMaxY
        private real array BoundMinY
    endglobals
    
    function LockPlayerCameraToRect takes player p, rect r returns nothing
        local integer i = GetPlayerId(p)
        set BoundMaxX[i] = GetRectMaxX(r)
        set BoundMinX[i] = GetRectMinX(r)
        set BoundMaxY[i] = GetRectMaxY(r)
        set BoundMinY[i] = GetRectMinY(r)
    endfunction
    
    private function LockLoop takes nothing returns nothing
        local player p
        local integer i = 0
        local real x
        local real y
        loop
            exitwhen i == 11
            set p = Player(i)
            if GetLocalPlayer() == p then
                set x = GetCameraTargetPositionX()
                set y = GetCameraTargetPositionY()
                if (not ( (BoundMinX[i] <= x) and (x <= BoundMaxX[i]) and (BoundMinY[i] <= y) and (y <= BoundMaxY[i]) )) then
                    if ( x > BoundMaxX[i] ) then
                        set x = BoundMaxX[i] - 1
                    endif
                    if ( x < BoundMinX[i] ) then
                        set x = BoundMinX[i] + 1
                    endif
                    if ( y > BoundMaxY[i] ) then
                        set y = BoundMaxY[i] - 1
                    endif
                    if ( y < BoundMinY[i] ) then
                        set y = BoundMinY[i] + 1
                    endif
                    call SetCameraPosition(x, y)
                endif
            endif
            set i = i + 1
        endloop
    endfunction

    private function Init takes nothing returns nothing
        local integer i = 0
        loop
            exitwhen i == 11
            call LockPlayerCameraToRect(Player(i), bj_mapInitialCameraBounds)
            set i = i + 1
        endloop
        set CameraLockLoop = CreateTrigger(  )
        call TriggerRegisterTimerEvent(CameraLockLoop, 0.03, true)
        call TriggerAddAction(CameraLockLoop, function LockLoop)
    endfunction
endlibrary
Could be better if you set it to the closest outside bound rather than the center
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
Check if unit is invulnerable.

JASS:
library InvulnerabilityCheck initializer Init
    globals
        private unit InvulnerabilityChecker //unit we'll use to test targets
    endglobals
    
    private function Init takes nothing returns nothing //create our checking unit
        set InvulnerabilityChecker = CreateUnit(Player(12), 'hpea', 0, 0, 0)
        call ShowUnit(InvulnerabilityChecker, false)
    endfunction
    
    function IsUnitInvulnerable takes unit u returns boolean
        call IssueTargetOrder(InvulnerabilityChecker, "smart", u)
        if (GetUnitCurrentOrder(InvulnerabilityChecker) == 851971) then
            call IssueImmediateOrder(InvulnerabilityChecker, "stop" )
            return false
        else
            call IssueImmediateOrder(InvulnerabilityChecker, "stop" )
            return true
        endif
    endfunction
endlibrary

Use IsUnitInvulnerable(unit) in a condition.

Note: Neutral Hostile must be hostile towards the owner of the unit.

If you need to check for neutral hostile, replace it in the system with neutral extra or victim, but you have to set their alliances to all players to hostile.

Version to also check neutral passive:

JASS:
library InvulnerabilityCheck initializer Init
    globals
        private unit InvulnerabilityChecker //unit we'll use to test targets
    endglobals
    
    private function Init takes nothing returns nothing //create our checking unit
        set InvulnerabilityChecker = CreateUnit(Player(12), 'hpea', 0, 0, 0)
        call ShowUnit(InvulnerabilityChecker, false)
    endfunction
    
    function IsUnitInvulnerable takes unit u returns boolean
        if (GetOwningPlayer(u) == Player(15)) then //for neutral passive compatibility
            call SetPlayerAlliance( Player(12), Player(15), ALLIANCE_PASSIVE, false)
        endif
        call IssueTargetOrder(InvulnerabilityChecker, "smart", u)
        if (GetUnitCurrentOrder(InvulnerabilityChecker) == 851971) then
            call IssueImmediateOrder(InvulnerabilityChecker, "stop" )
            if (GetOwningPlayer(u) == Player(15)) then
                call SetPlayerAlliance( Player(12), Player(15), ALLIANCE_PASSIVE, true)
            endif
            return false
        else
            call IssueImmediateOrder(InvulnerabilityChecker, "stop" )
            if (GetOwningPlayer(u) == Player(15)) then
                call SetPlayerAlliance( Player(12), Player(15), ALLIANCE_PASSIVE, true)
            endif
            return true
        endif
    endfunction
endlibrary


JASS:
library InvulnerabilityCheck initializer Init
    globals
        private unit InvulnerabilityCheckerPhysical //unit we'll use to test targets
        private unit InvulnerabilityCheckerEthereal // our failsafe priest
        private constant integer CHECKER_TYPE_PHYSICAL = 'hrif' //for physical damage. hrif = rifleman
        private constant integer CHECKER_TYPE_ETHEREAL = 'hmpr' //unit type to do checking. hmpr = priest
    endglobals
    
    private function Init takes nothing returns nothing //create our checking unit
        local integer i = 0
        set InvulnerabilityCheckerPhysical = CreateUnit(Player(12), CHECKER_TYPE_PHYSICAL, 0, 0, 0)
        set InvulnerabilityCheckerEthereal = CreateUnit(Player(12), CHECKER_TYPE_ETHEREAL, 0, 0, 0)
        call ShowUnit(InvulnerabilityCheckerPhysical, false)
        call ShowUnit(InvulnerabilityCheckerEthereal, false)
        call SetPlayerAlliance( Player(12), Player(15), ALLIANCE_PASSIVE, false)
    endfunction
    
    function IsUnitInvulnerable takes unit u returns boolean
        call IssueTargetOrder(InvulnerabilityCheckerPhysical, "smart", u)
        if (GetUnitCurrentOrder(InvulnerabilityCheckerPhysical) == 851971) then
            call IssueImmediateOrder(InvulnerabilityCheckerPhysical, "stop" )
            call IssueTargetOrder(InvulnerabilityCheckerEthereal, "smart", u)
            if (GetUnitCurrentOrder(InvulnerabilityCheckerEthereal) == 851971) then
                call IssueImmediateOrder(InvulnerabilityCheckerEthereal, "stop" )
                return false
            else
                call IssueImmediateOrder(InvulnerabilityCheckerEthereal, "stop" )
                return true
            endif
        else
            call IssueImmediateOrder(InvulnerabilityCheckerPhysical, "stop" )
            return true
        endif
    endfunction
endlibrary
 
Last edited:
Level 25
Joined
Jul 10, 2006
Messages
3,315
i think it exists on wc3c.net

Found it: http://www.wc3c.net/showthread.php?t=103889

Reading through the thread I realised that my code might not work for ethereal units. Time to test.

I really wouldn't like to have to make a custom dummy with spell damage type.

EDIT: It was actually as simple as using a different unit. Using Priest (hmpr).

EDIT2: I've actually overlooked some more things:
- Magic damage type used to check ethereal units returns invul on resistant units.
- The peasant checker cannot target flying units, using a ranged unit instead.

EDIT3: My solution was to make two dummy units: a rifleman and a priest. If the one fails, the other is checked.

My only problem right now is that I'm using neutral hostile, and any attempts to use neutral extra/victim have failed.

PS: The thread on wc3c had two methods:
1. Uses a custom Finger of Death spell, which is bad because you need to import a custom ability
2. Deals damage, which interrupts Sleep, can conflict with damage detection, and can apparently fire events twice.
 
Last edited:
Level 25
Joined
Jul 10, 2006
Messages
3,315
Snippet to reset the cooldown of a specific ability for a unit.

JASS:
function ResetUnitAbilityCooldown takes unit u, integer abil returns nothing
    local integer l = GetUnitAbilityLevel( u, abil )
    if UnitRemoveAbility( u, abil ) then
        call UnitAddAbility( u, abil )
        call SetUnitAbilityLevel( u, abil, l )
    endif
endfunction

EDIT: Fixed. Thanks Troll-Brain.
 
Last edited:
Level 17
Joined
Apr 27, 2008
Messages
2,455
If the unit has not the ability :

JASS:
function ResetUnitAbilityCooldown takes unit u, integer abil returns nothing
    local integer l = GetUnitAbilityLevel( u, abil )
    if UnitRemoveAbility( u, abil ) then
        call UnitAddAbility( u, abil )
        call SetUnitAbilityLevel( u, abil, l )
    endif
endfunction
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
UnitCreateIllusion(unit)
Creates an illusion of the unit and fires an event, setting the created illusion to LastCreatedIllusion and firing an event.

Notes:
  • Speed is fast but not instant. You cannot use LastCreatedIllusion directly after calling UnitCreateIllusion. It can create multiple illusions simultaneously.
  • Requires a custom ability (edit Item Illusion to type unit, targets allowed air,ground)
  • Re-use speed is dependant on the dummy caster's cast animation point.

JASS:
library CreateIllusion initializer Init
    globals
        private unit IllusionCaster
        private constant integer IllusionAbility =   'A000'  //item illusion
        private constant integer IllusionUnit    =   'nalb'  //dummy caster
        private boolean IsIllusion          //used for checking if the illusion was made by system
        unit LastCreatedIllusion            //as at any time to reference the last illusion made by system
        real IllusionCreatedEvent           //use to detect when an illusion is created
    endglobals
    
    function UnitCreateIllusion takes unit u returns nothing
        call SetUnitX(IllusionCaster, GetUnitX(u))
        call SetUnitY(IllusionCaster, GetUnitY(u))
        call SetUnitOwner(IllusionCaster, GetOwningPlayer(u), false)
        call IssueTargetOrderById(IllusionCaster, 852274, u)
        call SetUnitOwner(IllusionCaster, Player(15), false)
        set IsIllusion = true
    endfunction
    
    private function GetIllusion takes nothing returns nothing
        if IsIllusion then
            set LastCreatedIllusion = GetTriggerUnit()
            set IllusionCreatedEvent = 0
            set IllusionCreatedEvent = 1
        endif
    endfunction
    
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        local region r = CreateRegion()
        call RegionAddRect(r, GetPlayableMapRect())
        set IllusionCaster = CreateUnit(Player(15), IllusionUnit, 0, 0, 0)
        call UnitAddAbility(IllusionCaster, IllusionAbility)
        call ShowUnit(IllusionCaster, false)
        call TriggerAddAction(t, function GetIllusion)
        call TriggerRegisterEnterRegion( t, r, null )
    endfunction
endlibrary

Usage:
JASS:
call UnitCreateIllusion(GetTriggerUnit())

As event:
JASS:
call TriggerRegisterVariableEvent( t, "IllusionCreatedEvent", EQUAL, 1.00 )

EDIT: There is a problem with the event, I'm busy fixing it, for now you should only use the create function.
 
Last edited:
Top