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

[vJass] Strange Damage Detection Fail

Status
Not open for further replies.
Level 11
Joined
Sep 30, 2009
Messages
697
Well I made my damage totally triggered in my map. But I have a problem: Whenever I use the firebolt spell the first time the damage event doesnt trigger anymore :( I use IDDS as damage detection system and all damage is triggered by another trigger. If someone could help me I will give + rep if possible :D



Firebolt:
JASS:
scope FireBolt initializer init

globals
    private integer AbiId = 'AHtb'
    private integer DummyId = 'hdf1'
endglobals

private struct Spell
    static Spell array Index
    static integer Total = 0
    static timer t = CreateTimer()
    
    integer level    
    
    unit caster
    unit target
    unit dummy
    
    boolean TargetReached = false
    
    real CurrentX 
    real CurrentY
    real damage
    
    static method CastLoop takes nothing returns nothing
        
        local Spell d
        local integer i = 0

        loop 
            exitwhen i >= d.Total 
            set d = d.Index[i]

            if not d.TargetReached then

                set d.CurrentX = PolarProjectionX(d.CurrentX, 20, GetUnitFacing(d.dummy))
                set d.CurrentY = PolarProjectionY(d.CurrentY, 20, GetUnitFacing(d.dummy))
                call SetUnitX(d.dummy, d.CurrentX)
                call SetUnitY(d.dummy, d.CurrentY) 
                
                if GetDistanceBetweenUnits(d.target, d.dummy) < 50 then
                    set d.TargetReached = true
                    call UnitDamageTargetEx(d.caster, d.target, d.damage, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_IGNORED, false)
                endif
            else
                call BJDebugMsg("Stop")
                call RemoveUnit(d.dummy)
                call d.destroy()
                
                // Recycling the indexer system
                set d.Total = d.Total - 1
                set d.Index[i] = d.Index[d.Total]

                set i = i - 1                
            endif

            set i = i + 1
        endloop

        if d.Total == 0 then
            call PauseTimer(d.t)
        endif
    endmethod
    
endstruct

private function CastConditions takes nothing returns boolean
    return GetSpellAbilityId() == AbiId
endfunction

private function CastActions takes nothing returns nothing
    local Spell d = Spell.create()
    
    set d.caster = GetTriggerUnit()
    set d.dummy = CreateUnit(GetOwningPlayer(d.caster), DummyId, GetUnitX(d.caster), GetUnitY(d.caster), GetUnitFacing(d.caster))
    set d.target = GetSpellTargetUnit()
    set d.damage = GetUnitAbilityLevel(d.caster, AbiId) * 100
    set d.CurrentX = GetUnitX(d.dummy)
    set d.CurrentY = GetUnitY(d.dummy)
    call IssueTargetOrder(d.dummy, "smart", d.target)
    
    if d.Total == 0 then
        call TimerStart(d.t, 0.03, true, function Spell.CastLoop)
        call BJDebugMsg("Start")
    endif

        // Adding the struct to the indexer system
        set d.Index[d.Total] = d
        // Setting the total amount of structs in loop to Total + 1
        set d.Total = d.Total + 1    
endfunction


private function init takes nothing returns nothing
    local trigger t = CreateTrigger()    
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CAST)
    call TriggerAddCondition(t, Condition(function CastConditions))
    call TriggerAddAction(t, function CastActions)
endfunction

endscope

IDDS
JASS:
library IntuitiveDamageSystem initializer Init requires Table
//******************************************************************************
//* BY: Rising_Dusk
//*     (Intuitive) Damage Detection System 1.13
//* 
//* This library is the core for what has come to be known as the Intuitive
//* Damage Detection System, or IDDS for short. Simply by copying this library
//* into your map somewhere, you will have access to all of its features and
//* options. Below this documentation are some global variables that can be
//* edited to make the system more useful for your map, whatever it might be.
//* Please note that you should only change those globals listed under 
//* configuration constants and damage type constants.
//* 
//* An important note for the system is that all non-attack damage in your map
//* MUST BE TRIGGERED using the special function call included in this system,
//* UnitDamageTargetEx. This is how the system works to detect attacks, because
//* if the only non-triggered damage in your map originates from attacks, you
//* clearly know which damage packets are attacks. This allows users to use
//* orb abilities in their maps for whatever they want.
//* 
//*     function UnitDamageTargetEx takes unit source, unit target, real damage, ...
//*     ...attacktype attackType, integer damageType, boolean ConsiderArmor returns boolean
//* 
//* This is the function with which you will deal all triggered damage in your
//* map. The damageType argument is one of the predefined integer constants that
//* you can edit or add below. Default values for this with the system are
//* DAMAGE_TYPE_ATTACK, DAMAGE_TYPE_SPELL, and DAMAGE_TYPE_EXTRA. You can
//* trigger the system to treat triggered damage like it is an attack if you
//* want to by using DAMAGE_TYPE_ATTACK. It is very easy to make new damage
//* types in the system, just follow the instructions in the configuration
//* constants area. In addition, be sure that the constants you define do not
//* conflict with the predefined Blizzard constants. (ie. DAMAGE_TYPE_FIRE) If
//* these conflicts do exist, you will encounter multiply defined syntax errors.
//* The AttackType argument is the same as in the regular UnitDamageTarget
//* native. Also, the system allows you to consider armor when dealing damage or
//* not. Set the ConsiderArmor boolean argument to false if you want to ignore
//* armor for that damage, or true if you want to factor it in.
//* 
//*     function TriggerUnregisterDamageEvent takes trigger trg returns boolean
//*     function TriggerRegisterDamageEvent takes trigger trg, integer priority returns boolean
//* 
//* The TriggerRegisterDamageEvent function is used when initializing a damage
//* detection response trigger. By using this, it allows you to use a syntax
//* structure nigh-identical to the standard JASS2. It returns a boolean for
//* your convenience that is false if you pass it a null trigger. The system
//* also allows you to pass a positive, zero-inclusive integer to it as that
//* trigger's priority. The higher the number you pass, the later on in the
//* trigger executions it will fire. This is useful if you want shield
//* abilities, as you will want their priorities low so that they can block the
//* damage before it gets to other things. You are also allowed to unregister
//* a trigger from the system at any time if you want; this will likely never
//* have to be done for most maps.
//* 
//*     function SetDamage takes real dmg returns nothing
//*     function SetDamageType takes integer dmgtype returns boolean 
//* 
//* With this function, you can modify the damage the system interprets for its
//* triggers. This function DOES NOT ACTUALLY CHANGE THE DAMAGE BEING DEALT, it
//* is merely a tool for users to use to change the internal variables. The user
//* will need to modify the damage himself by some other means. Similarly, the
//* SetDamageType function internally changes the damage type of a given packet
//* of damage. This can be useful if you want to convert DAMAGE_TYPE_ATTACK into
//* something else or if you want dynamic damagetypes in-game.
//* 
//*     function SetTriggerPriority takes trigger trg, integer priority returns boolean
//*     function GetTriggerPriority takes trigger trg returns integer
//* 
//* These functions let you set or get a given trigger's priority at will. These
//* functions both require that the trigger being passed to it is registered to
//* the IDDS system. If you pass an unregistered trigger to GetTriggerPriority,
//* it will return -1. If you pass a similar trigger to SetTriggerPriority, it
//* will return false.
//* 
//*     function IgnoreHigherPriority takes nothing returns boolean
//* 
//* This function is one of the most important reasons for priorities to exist.
//* With it, you can tell the system to ignore higher priority triggers. This
//* is useful, for instance, if you have a triggered evasion ability and don't
//* want anything else to be done with that damage because it was dodged. Other,
//* similar damage-preventing routines will also find this function useful.
//* 
//*     function RegisterDamageType takes nothing returns integer
//* 
//* This function is useful for declaring your own DAMAGE_TYPE_ETC constants
//* external to the system. By declaring your global variable and then calling
//* this on it as follows, you can register new damage types on the fly. This
//* is very useful if you want other systems or spells to introduce new damage
//* types that are either ignored or do special things for that application.
//* 
//*     function GetTriggerDamageType takes nothing returns integer
//*     function GetTriggerDamageSource takes nothing returns unit
//*     function GetTriggerDamageTarget takes nothing returns unit
//*     function GetTriggerDamageBase takes nothing returns real
//*     function GetTriggerDamage takes nothing returns real
//* 
//* Like normal WC3 damage detection, the system has event responses for the
//* damage source, the target of the damage, the amount of damage dealt, and
//* other things. It also permits the detection of damage type, which is
//* something standard WC3 does not have. This lets you create on-attack spells
//* very easily whereas without the system it would be very difficult and
//* computationally costly. GetTriggerDamageBase returns the amount of damage
//* the unit was dealt at the beginning of a given trigger series, whereas
//* GetTriggerDamage returns whatever damage the unit has left to receive, if
//* it has been modified in any way with the SetDamage function mentioned
//* earlier.
//* 
//* Once you understand all of the aforementioned aspects of the system, you're
//* ready to put it to use. I know it can be tricky to require all spells be
//* triggered, but this is the way of many great maps anyways, so such a
//* requirement is not so unreasonable. If you have any questions regarding the
//* system, please go to [url]www.wc3c.net[/url] and send a private message to the account
//* Rising_Dusk and I will respond as soon as I can. This system may only be
//* released at [url]www.wc3c.net[/url] and its existence on any other website is against
//* the author's will.
//* 
//* Enjoy!
//* 
globals
    //* Configuration constants
    private          integer       DamageTypeCount     = 4
    
    //* These are the damagetype constant globals for ease of use
            constant integer       DAMAGE_TYPE_ATTACK  = 0
            constant integer       DAMAGE_TYPE_SPELL   = 1
            constant integer       DAMAGE_TYPE_EXTRA   = 2
            constant integer       DAMAGE_TYPE_IGNORED = 3
            
    //* To add new constants, simply follow the naming convention and increment
    //* the number accordingly. You shouldn't change or remove the first of the
    //* damage types, since it is a special case, but you can change the others
    //* however you'd like.
    
    //* These are static constants used by the system and shouldn't be changed
    private          trigger       RunTrigger          = CreateTrigger()
    private          trigger       AddTrigger          = CreateTrigger()
    private          integer       Count               = 0
    private          Table         TrigTable           = 0
    private          Table         RegiTable           = 0
    private          boolean       IgnPrior            = false
    private          integer array NewDamageType
    private          real    array NewDamage
    private          trigger array Trg
    private          integer array Priority
    
    //* Temporary variables used by the system
    private          unit          DamageSource        = null
    private          unit          DamageTarget        = null
    private          integer       DamageType          = 0
    private          integer       DamageId            = 0
    private          real          DamageBase          = 0.
    private          real          Damage              = 0.
endglobals

//******************************************************************************
//******************************************************************************

//* Returns the integer index of a given handle object (Updated for 1.24)
private function H2I takes handle h returns integer
    return GetHandleId(h)
endfunction

//* Use an insertion sort algorithm to sort the trigger stack based on priority
private function TriggerSort takes nothing returns boolean
    local integer i = 1
    local integer j = 0
    local integer p = 0
    local trigger t = null
    
    loop
        exitwhen i >= Count
        set t = Trg[i]
        set p = Priority[i]
        set j = i-1
        loop 
            exitwhen j < 0 or Priority[j] <= p
            set Priority[j+1]          = Priority[j]
            set Trg[j+1]               = Trg[j]
            set TrigTable[H2I(Trg[j])] = j+1
            set j = j - 1
        endloop
        set Priority[j+1]     = p
        set Trg[j+1]          = t
        set TrigTable[H2I(t)] = j+1
        set i = i + 1
    endloop
    
    set t = null
    return true
endfunction

//******************************************************************************
//******************************************************************************

//* The function to call when you want to end a damage's trigger series
function IgnoreHigherPriority takes nothing returns boolean
    if DamageSource != null then
        //Make sure it was called in the right place
        set IgnPrior = true
    endif
    return IgnPrior
endfunction

//* Changes the base damage for a trigger series on the fly
function SetDamage takes real dmg returns boolean
    if DamageSource != null and dmg >= 0 then
        //Make sure it was called in the right place
        set NewDamage[DamageId] = dmg
        set Damage              = dmg
        return true
    endif
    return false
endfunction

//* Changes the base damage type of the series
function SetDamageType takes integer dmgtype returns boolean
    if DamageSource != null and dmgtype >= 0 then
        //Make sure it was called in the right place
        set NewDamageType[DamageId] = dmgtype
        set DamageType              = dmgtype
        return true
    endif
    return false
endfunction

//* Returns the given trigger's priority if it's loaded to the system
function GetTriggerPriority takes trigger trg returns integer
    if RegiTable[H2I(trg)] == 0 then
        return -1
    endif
    return Priority[TrigTable[H2I(trg)]]
endfunction

//* Sets the given trigger's priority if it's loaded to the system
function SetTriggerPriority takes trigger trg, integer priority returns boolean
    if RegiTable[H2I(trg)] == 0 or priority < 0 then
        return false
    endif
    set Priority[TrigTable[H2I(trg)]] = priority
    return TriggerSort()
endfunction

//******************************************************************************
//******************************************************************************

//* The new damage function used by the system
function UnitDamageTargetEx takes unit source, unit target, real damage, attacktype attackType, integer damageType, boolean ConsiderArmor returns boolean
    local boolean b  = false
    set DamageType   = damageType
    set DamageSource = source
    if ConsiderArmor then
        set b = UnitDamageTarget(source, target, damage, false, false, attackType, DAMAGE_TYPE_NORMAL, null)
    else
        set b = UnitDamageTarget(source, target, damage, false, false, attackType, DAMAGE_TYPE_UNIVERSAL, null)
    endif
    if not b then
        set DamageType = 0
        set DamageSource = null
    endif
    return b
endfunction

//* The method by which one registers a trigger with the system
function TriggerRegisterDamageEvent takes trigger trg, integer priority returns boolean
    if trg == null or priority < 0 then
        return false
    endif
    if RegiTable[H2I(trg)] == 0 then
        set RegiTable[H2I(trg)] = 1
    endif
    set Trg[Count]          = trg
    set Priority[Count]     = priority
    set TrigTable[H2I(trg)] = Count
    set Count               = Count + 1
    return TriggerSort()
endfunction

//* The method by which one unregisters a trigger from the system
function TriggerUnregisterDamageEvent takes trigger trg returns boolean
    local integer i = 0
    if trg == null then
        return false
    endif
    set i = TrigTable[H2I(trg)]
    if trg != Trg[i] then
        return false
    endif
    set Trg[i]                 = Trg[Count]
    set Priority[i]            = Priority[Count]
    set TrigTable[H2I(Trg[i])] = i
    set RegiTable[H2I(trg)]    = 0
    set Count                  = Count - 1
    return TriggerSort()
endfunction

//* Initialization shorthand to register a new damage type externally
function RegisterDamageType takes nothing returns integer
    local integer i = DamageTypeCount
    set DamageTypeCount = DamageTypeCount + 1
    return i
endfunction

//******************************************************************************
//******************************************************************************

//* Wrappers for the system that can get inlined anyways
function GetTriggerDamageType takes nothing returns integer
    return DamageType
endfunction
function GetTriggerDamageSource takes nothing returns unit
    return DamageSource
endfunction
function GetTriggerDamageTarget takes nothing returns unit
    return DamageTarget
endfunction
function GetTriggerDamageBase takes nothing returns real
    return DamageBase
endfunction
function GetTriggerDamage takes nothing returns real
    return Damage
endfunction

//******************************************************************************
//******************************************************************************

private function RunConditions takes nothing returns boolean
    //* The conditions for what must be true for damage detection to run
    return GetEventDamage() >= 0.0001 and DamageType != DAMAGE_TYPE_IGNORED
endfunction

private function AddConditions takes nothing returns boolean
    //* The conditions for registering a unit with the damage system
    return true
endfunction

private function PreloadConditions takes unit u returns boolean
    //* The conditions for preloading a unit to the damage system
    return true
endfunction

//******************************************************************************
//******************************************************************************

globals
    private integer array IDStack
    private integer       IDC     = 0
    private integer       IDN     = 0
endglobals

private function Run takes nothing returns nothing
    local unit    u  = GetEventDamageSource()
    local unit    s  = DamageSource
    local unit    t  = GetTriggerUnit()
    local integer i  = 0
    local integer id = 0
    local integer d  = DamageType
    local real    r  = GetEventDamage()
    local real    b  = r
    
    //Allocate an id for this damage packet
    if IDN > 0 then
        set id  = IDStack[IDN]
        set IDN = IDN - 1
    else
        set id  = IDC
        set IDC = IDC + 1
    endif
    
    if DamageSource == null then
        //Damage is of type attack
        set d = DAMAGE_TYPE_ATTACK
        set s = u
    endif
    loop
        exitwhen i > Count or IgnPrior
        //Ensure all variables are correct for nesting
        set Damage            = r
        set DamageBase        = b
        set DamageTarget      = t
        set DamageSource      = s
        set DamageType        = d
        set DamageId          = id
        set NewDamage[id]     = 0.
        set NewDamageType[id] = -1
        if IsTriggerEnabled(Trg[i]) and TriggerEvaluate(Trg[i]) then
            call TriggerExecute(Trg[i])
        endif
        if NewDamage[id] > 0. then
            //Update damage if it was changed
            set r = NewDamage[id]
        endif
        if NewDamageType[id] >= 0 then
            //Update damagetype if it was changed
            set d = NewDamageType[id]
        endif
        set i = i + 1
    endloop
    set Damage        = 0.
    set DamageBase    = 0.
    set DamageTarget  = null
    set DamageSource  = null
    set DamageType    = 0
    set DamageId      = 0
    set IgnPrior      = false
    set NewDamage[id] = 0.
    
    //Return id to the stack
    set IDN          = IDN + 1
    set IDStack[IDN] = id
    
    set u = null
    set s = null
    set t = null
endfunction

private function Load takes nothing returns nothing
    call TriggerRegisterUnitEvent(RunTrigger, GetEnteringUnit(), EVENT_UNIT_DAMAGED)
endfunction

//******************************************************************************
//******************************************************************************

private function PreloadUnits takes nothing returns boolean
    if PreloadConditions(GetFilterUnit()) then
        call TriggerRegisterUnitEvent(RunTrigger, GetFilterUnit(), EVENT_UNIT_DAMAGED)
    endif
    return false
endfunction

private function Init takes nothing returns nothing
    local rect     r  = GetWorldBounds()
    local region   re = CreateRegion()
    local boolexpr b  = Condition(function PreloadUnits)
    local group    g  = CreateGroup()
    
    //* Create the tables for use with the system
    set TrigTable = Table.create()
    set RegiTable = Table.create()
    
    call TriggerAddAction(RunTrigger, function Run)
    call TriggerAddCondition(RunTrigger, Condition(function RunConditions))
    call GroupEnumUnitsInRect(g, r, b)
    
    call RegionAddRect(re, r)
    call TriggerRegisterEnterRegion(AddTrigger, re, null)
    call TriggerAddAction(AddTrigger, function Load)
    call TriggerAddCondition(AddTrigger, Condition(function AddConditions))
    
    call RemoveRect(r)
    call DestroyGroup(g)
    call DestroyBoolExpr(b)
    set re = null
    set g  = null
    set b  = null
    set r  = null
endfunction
endlibrary

My Damage System:
JASS:
scope DealAttackDamage initializer init

globals
    private attacktype ATTACK_TYPE = ATTACK_TYPE_CHAOS
    private integer LEVEL
    private integer UNIT_ID

    private real DAMAGE
    private unit SOURCE
    private unit TARGET
    private real ARMOR
    private real DAMAGE_BONI

    private integer DAMAGE_BASE
    private integer DAMAGE_SIDESPERDIE
    private integer DAMAGE_DICES

    private constant integer HERO_DAMAGE_BASE           = 30
    private constant integer HERO_DAMAGE_SIDESPERDIE    = 4
    private constant integer HERO_DAMAGE_DICES          = 2

    private constant integer ID_BASH                    = 'A002'
    private constant integer ID_CRITICALHIT             = 'A001'
    private constant integer ID_EVASION                 = 'A004'
    private constant integer ID_FEEDBACK                = 'A000'
    private constant integer ID_WAVESTRIKE              = 'A003'
    private constant integer ID_HARDSKIN                = 'A007'
    private constant integer ID_WARPATTACK              = 'A008'
endglobals

//###########################################################################################//

private function CriticalHit takes nothing returns nothing
    local texttag te = CreateTextTag()
    set DAMAGE = DAMAGE + DAMAGE * LEVEL
    call SetTextTagText(te, I2S(R2I(DAMAGE)) + "!", 0.024)
    call SetTextTagPos(te, GetUnitX(SOURCE), GetUnitY(SOURCE) + 20, 0.00)
    call SetTextTagColor(te, 255, 0, 0, 255)
    call SetTextTagVelocity(te, 0, 0.04)
    call SetTextTagVisibility(te, true)
    call SetTextTagFadepoint(te, 2)
    call SetTextTagLifespan(te, 4)
    call SetTextTagPermanent(te, false)
endfunction

//###########################################################################################//

private function Bash takes nothing returns nothing
    set DAMAGE = DAMAGE + GetHeroStr(SOURCE, true) / 2 +  LEVEL * 10.00
    if not IsUnitType(TARGET, UNIT_TYPE_DEAD) then
        call StunUnitTimed(TARGET, 1.5 + LEVEL)
    endif
endfunction

//###########################################################################################//

globals
    private group TEMP = CreateGroup()
endglobals

private struct Spell
    static Spell array Index
    static integer Total = 0
    static timer t = CreateTimer()
    
    group g = CreateGroup()
    integer distance = 0
    integer level
    real x
    real y
    real f
    real dam
    unit caster
    unit target
    unit wave
    
    static method Loop takes nothing returns nothing
        
        local Spell d
        local integer i = 0
        local unit u

        loop 
            exitwhen i >= Spell.Total 
            set d = Spell.Index[i]

            if d.distance < 600 then
            set d.x = PolarProjectionX(d.x, 20, d.f)
            set d.y = PolarProjectionY(d.y, 20, d.f)
            call SetUnitX(d.wave, d.x) 
            call SetUnitY(d.wave, d.y)
            call GroupEnumUnitsInRange(TEMP, d.x, d.y, 125, null)
            loop
                set u = FirstOfGroup(TEMP)
                if not IsUnitInGroup(u, d.g) then
                    call GroupAddUnit(d.g, u)
                    if IsUnitEnemy(u, GetOwningPlayer(d.caster)) then
                        //Damage
                        call UnitDamageTargetEx(d.caster, u, d.dam, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_IGNORED, false)
                    endif
                endif
                call GroupRemoveUnit(TEMP, u)
                exitwhen u == null
            endloop
            call GroupClear(TEMP)
            set d.distance = d.distance + 20    
            else
                call RemoveUnit(d.wave)
                call d.destroy()
                
                // Recycling the indexer system
                set Spell.Total = Spell.Total - 1
                set Spell.Index[i] = Spell.Index[d.Total]

                set i = i - 1                
            endif

            set i = i + 1
        endloop

        if d.Total == 0 then
            call PauseTimer(Spell.t)
        endif
        set u = null
    endmethod
    
endstruct

private function WaveStrike takes nothing returns nothing
    local Spell d = Spell.create()
    set d.caster    = SOURCE
    set d.target    = TARGET
    set d.level     = LEVEL
    set d.f         = GetUnitFacing(d.caster)
    set d.x         = PolarProjectionX(GetUnitX(d.caster), 150, d.f) 
    set d.y         = PolarProjectionY(GetUnitY(d.caster), 150, d.f)
    set d.wave      = CreateUnit(GetOwningPlayer(d.caster), 'h003', d.x, d.y, d.f)
    set d.dam       = GetHeroStr(SOURCE, true) + LEVEL * 20.00
    if Spell.Total == 0 then
        call TimerStart(Spell.t, 0.03, true, function Spell.Loop)
    endif

    // Adding the struct to the indexer system
    set Spell.Index[Spell.Total] = d
    // Setting the total amount of structs in loop to Total + 1
    set Spell.Total = Spell.Total + 1    
endfunction

//###########################################################################################//

private function Feedback takes nothing returns nothing
    if GetUnitState(GetTriggerDamageTarget(), UNIT_STATE_MANA) > (20 + 10.00 * LEVEL) then
        set DAMAGE = DAMAGE + (20 + 10 * LEVEL)
        call SetUnitState(TARGET, UNIT_STATE_MANA, GetUnitState(TARGET, UNIT_STATE_MANA) - (20 + 10 * LEVEL))
    else
        set DAMAGE = DAMAGE + GetUnitState(TARGET, UNIT_STATE_MANA)
        call SetUnitState(TARGET, UNIT_STATE_MANA, 0)
    endif

    if IsUnitType(GetTriggerDamageTarget(), UNIT_TYPE_SUMMONED) then
        set DAMAGE = DAMAGE + 100 + 50 * LEVEL
    endif
endfunction

//###########################################################################################//

private function Evasion takes nothing returns nothing
    local texttag te = CreateTextTag()
    call SetTextTagText(te, "Miss", 0.024)
    call SetTextTagPos(te, GetUnitX(SOURCE), GetUnitY(SOURCE) + 20, 0.00)
    call SetTextTagColor(te, 255, 0, 0, 255)
    call SetTextTagVelocity(te, 0, 0.04)
    call SetTextTagVisibility(te, true)
    call SetTextTagFadepoint(te, 1.5)
    call SetTextTagLifespan(te, 3)
    call SetTextTagPermanent(te, false)
    set DAMAGE = 0
endfunction

private function HardSkin takes nothing returns nothing
    set DAMAGE = DAMAGE - 10 * LEVEL
endfunction

private function WarpAttack takes nothing returns nothing
    local real x = GetUnitX(SOURCE)
    local real y = GetUnitY(SOURCE)
    local real face = GetUnitFacing(SOURCE)
    
    call StunUnitTimed(TARGET, LEVEL)
    
    call SetUnitX(SOURCE, GetUnitX(TARGET) + 100 * Cos((GetUnitFacing(TARGET)-180)))
    call SetUnitY(SOURCE, GetUnitY(TARGET) + 100 * Sin((GetUnitFacing(TARGET)-180)))
    call SetUnitFacing(SOURCE, GetUnitFacing(TARGET))
endfunction

//###########################################################################################//

private function Actions takes nothing returns nothing
    set SOURCE          = GetTriggerDamageSource()
    set TARGET          = GetTriggerDamageTarget()
    set ARMOR           = GetUnitArmor(TARGET)
    set DAMAGE_BONI     = GetUnitBonus(SOURCE, BONUS_DAMAGE)
    set UNIT_ID         = GetUnitTypeId(SOURCE)

    if IsUnitType(SOURCE, UNIT_TYPE_HERO) then
        set DAMAGE = HERO_DAMAGE_BASE + GetRandomInt(1, HERO_DAMAGE_SIDESPERDIE) * HERO_DAMAGE_DICES + DAMAGE_BONI + GetPrimaryAttributeValue(SOURCE)
    else
        set DAMAGE_BASE         = LoadInteger(h, UNIT_ID, HASH_UNIT_DAMAGE_BASE)
        set DAMAGE_SIDESPERDIE  = LoadInteger(h, UNIT_ID, HASH_UNIT_DAMAGE_SIDESPERDIE)
        set DAMAGE_DICES        = LoadInteger(h, UNIT_ID, HASH_UNIT_DAMAGE_DICES)  
        
        set DAMAGE = DAMAGE_BASE + GetRandomInt(1, DAMAGE_SIDESPERDIE) * DAMAGE_DICES + DAMAGE_BONI
    endif


    set DAMAGE = GetReducedDamage(DAMAGE, ARMOR)

//###########################################################################################//

    //ABILITIES ~ Defensive
    //Evasion
    set LEVEL = GetUnitAbilityLevel(TARGET, ID_EVASION)
    if GetRandomInt(1, 10) <= LEVEL and not IsUnitType(TARGET, UNIT_TYPE_STRUCTURE) then
        call Evasion()
        return
    endif

    set LEVEL = GetUnitAbilityLevel(TARGET, ID_HARDSKIN)
    if LEVEL > 0  then
        call HardSkin()
    endif

    if DAMAGE <= 0 then
        return
    endif
//###########################################################################################//

    //ABILITIES ~ Offensive
    //CriticalHit
    set LEVEL = GetUnitAbilityLevel(SOURCE, ID_CRITICALHIT)
    if GetRandomInt(1, 10) <= LEVEL and not IsUnitType(TARGET, UNIT_TYPE_STRUCTURE) then
        call CriticalHit()
    endif

    //Feedback
    set LEVEL = GetUnitAbilityLevel(SOURCE, ID_FEEDBACK)
    if LEVEL > 0 and not IsUnitType(TARGET, UNIT_TYPE_STRUCTURE) then
        call Feedback()
    endif

    //Bash
    set LEVEL = GetUnitAbilityLevel(SOURCE, ID_BASH)
    if GetRandomInt(1, 10) <= LEVEL and not IsUnitType(TARGET, UNIT_TYPE_STRUCTURE) then
        call Bash()
    endif

//###########################################################################################//

    call UnitDamageTargetEx(SOURCE, TARGET, DAMAGE, ATTACK_TYPE, DAMAGE_TYPE_IGNORED, false)
    
//###########################################################################################//   
    
    //Abilities ~ AfterDamage
    //Warp Attack
    set LEVEL = GetUnitAbilityLevel(SOURCE, ID_WARPATTACK)
    if GetRandomInt(1, 10) <= LEVEL and not IsUnitType(TARGET, UNIT_TYPE_STRUCTURE) and not IsUnitIllusion(SOURCE) and not IsUnitType(TARGET, UNIT_TYPE_DEAD) then
        call WarpAttack()
    endif
    
    //WaveStrike
    set LEVEL = GetUnitAbilityLevel(SOURCE, ID_WAVESTRIKE)
    if GetRandomInt(1, 10) <= LEVEL and not IsUnitType(TARGET, UNIT_TYPE_STRUCTURE) then
        call WaveStrike()
    endif

//###########################################################################################//
    
    set SOURCE              = null
    set TARGET              = null
    set DAMAGE              = 0
    set ARMOR               = 0
    set LEVEL               = 0
    set DAMAGE_BONI         = 0
    set DAMAGE_BASE         = 0
    set DAMAGE_SIDESPERDIE  = 0
    set DAMAGE_DICES        = 0
    
endfunction

//###########################################################################################//

private function condition takes nothing returns boolean
    return GetTriggerDamageType() == DAMAGE_TYPE_ATTACK
endfunction

//###########################################################################################//

private function init takes nothing returns nothing 
    local trigger t = CreateTrigger()
    call TriggerRegisterDamageEvent(t, 0)
    call TriggerAddCondition(t, Condition(function condition))
    call TriggerAddAction(t, function Actions)
endfunction

endscope
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Okay, first of all, why not just have this:

JASS:
            if not d.TargetReached then

                set d.CurrentX = PolarProjectionX(d.CurrentX, 20, GetUnitFacing(d.dummy))
                set d.CurrentY = PolarProjectionY(d.CurrentY, 20, GetUnitFacing(d.dummy))
                call SetUnitX(d.dummy, d.CurrentX)
                call SetUnitY(d.dummy, d.CurrentY) 
                
                if GetDistanceBetweenUnits(d.target, d.dummy) < 50 then
                    set d.TargetReached = true
                    call UnitDamageTargetEx(d.caster, d.target, d.damage, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_IGNORED, false)
                    
                    call BJDebugMsg("Stop")
                    call RemoveUnit(d.dummy)
                    call d.destroy()
                    
                    // Recycling the indexer system
                    set d.Total = d.Total - 1
                    set d.Index[i] = d.Index[d.Total]

                    set i = i - 1  
                endif
              
            endif

            set i = i + 1
        endloop

Also, to optimize:

JASS:
                set d.CurrentX = PolarProjectionX(d.CurrentX, 20, GetUnitFacing(d.dummy))
                set d.CurrentY = PolarProjectionY(d.CurrentY, 20, GetUnitFacing(d.dummy))

Just do the math behind it:

JASS:
    // You should also use a variable to store the value of 'GetUnitFacing(d.dummy)' to optimize the speed of the code.
    set d.CurrentX = d.CurrentX + 20*Cos(GetUnitFacing(d.dummy)*bj_DEGTORAD)
    set d.CurrentY = d.CurrentY + 20*Sin(GetUnitFacing(d.dummy)*bj_DEGTORAD)

This code doesn't compile properly when I paste the code into a blank map (along with the required libraries) so you're going to have to post a map file. It would be a waste of time and effort to read through your library and IDDS trying to find where you've used the system improperly.

JASS:
                call d.destroy()
                
                // Recycling the indexer system
                set d.Total = d.Total - 1
                set d.Index[i] = d.Index[d.Total]

                set i = i - 1

You're destroying d and then you're trying to reference it afterward. Try doing it like this:

JASS:
                // Recycling the indexer system
                set d.Total = d.Total - 1
                set d.Index[i] = d.Index[d.Total]

                call d.destroy()
                set i = i - 1
 
Last edited:
Level 11
Joined
Sep 30, 2009
Messages
697
First: Thank you for you fast help, even if it was just for efficiency :)

I solved the problem just by changing the
JASS:
call UnitDamageTargetEx(d.caster, d.target, d.damage, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_IGNORED, false)
to:
JASS:
call UnitDamageTargetEx(d.caster, d.target, d.damage, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_SPELL, false)

I dunno why this bugged but:

Problem solved :)
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Justify said:
Then, he doesn't reference d after destroying it but the static variables, that's allowed (why not...). It looks better if he'd use "thistype" instead of "d", but k :)p

This is true, but its kind of logically incorrect is all.

Justify said:
PolarProjectionX and Y get inlined anyways, it looks better imo with the function.

I didn't know that PolarProjectionX gets inlined, so it would be okay to simply leave it.

Axarion said:
I dunno why this bugged but:

That is very strange. You should post this problem on the IDDS thread (on wc3c.net) and see what Dusk has to say.
 
Status
Not open for further replies.
Top