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

Triggered Incinerate v1.2

Credits:
- Bribe [Damage Engine]

You can use this spell as an alternative to the FireLord's Incinerate spell.
Many of us including myself have encountered problems when editing or making duplicate out of this spell and for this reason I made this.
With this simple system, you can have as many incinerate-like spells in your map as you want, all with different rawcodes and stats.

Read the readme for importing instructions.


Configuration Section
  • Incinerate SpellsList
    • Events
    • Conditions
    • Actions
      • -------- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| --------
      • -------- |||||||||||||||||||||||||||||||||||||||| INCINERATE SPELLS LIST |||||||||||||||||||||||||||||||||||||||| --------
      • -------- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| --------
      • -------- --------
      • -------- If you want to add a slot for an incinerate spell, copy one of these --------
      • -------- spell blocks and paste it next to the last block. Then you can freely --------
      • -------- configure the stats of the spell. --------
      • -------- --------
      • -------- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||| --------
      • -------- ||||| Incinerate Spell 1 ||||| --------
      • -------- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||| --------
      • -------- --------
      • -------- [ Activation spell ] --------
      • Set TI_Spell = Incinerate
      • -------- [ Determines if spells can trigger incinerate ] --------
      • Set TI_AllowSpellAsTrigger = False
      • -------- [ Damage increase per attack ] --------
      • Set TI_DamageStackBase = 8.00
      • Set TI_DamageStackPerLevel = 2.00
      • -------- [ Duration of the stack damage ] --------
      • Set TI_DurBase = 8.00
      • Set TI_DurPerLevel = 0.00
      • -------- [ Limit of the damage stacking (Value of 0 means no stacking limit) ] --------
      • Set TI_DCapBase = 500.00
      • Set TI_DCapPerLevel = 0.00
      • -------- [ Full damage area/radius of the explosion ] --------
      • Set TI_EXAOEBase = 150.00
      • Set TI_EXAOEPerLevel = 0.00
      • -------- [ Small damage area/radius of the explosion ] --------
      • Set TI_EXSmallAOEBase = 250.00
      • Set TI_EXSmallAOEPerLevel = 0.00
      • -------- [ Explosion's small damage factor ] --------
      • Set TI_EXSmallDamageFactorBase = 0.60
      • Set TI_EXSmallDamageFactorPerLevel = 0.00
      • -------- [ Attack type of the spell ] --------
      • Set TI_AttackType = Hero
      • -------- [ Damage type of the spell ] --------
      • Set TI_DamageType = Magic
      • -------- [ Damage stacking SFX model ] --------
      • Set TI_EffectModel1 = Abilities\Spells\Other\Incinerate\IncinerateBuff.mdl
      • -------- [ Explosion SFX model ] --------
      • Set TI_EffectModel2 = Abilities\Spells\Other\Incinerate\FireLordDeathExplode.mdl
      • -------- [ Damage stacking SFX attachment point ] --------
      • Set TI_EffectAttachment = chest
      • -------- [ The following determines the type of units allowed as the spell's target ] --------
      • Set TI_Structures = False
      • Set TI_Mechanicals = False
      • Set TI_MagicImmune = False
      • Set TI_Allies = True
      • Set TI_Illusions = True
      • -------- [ It's possible that this script was compiled first before TI_InitSpellIndex in which case normal function call won't work. ] --------
      • -------- [ Therefore we use ExecuteFunc. ] --------
      • Custom script: call ExecuteFunc( "TI_InitSpellIndex" )
      • -------- --------
      • -------- --------
      • -------- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||| --------
      • -------- ||||| Incinerate Spell 2 ||||| --------
      • -------- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||| --------
      • -------- --------
      • -------- [ Activation spell ] --------
      • Set TI_Spell = Fury Swipe
      • -------- [ Determines if spells can trigger incinerate ] --------
      • Set TI_AllowSpellAsTrigger = False
      • -------- [ Damage increase per attack ] --------
      • Set TI_DamageStackBase = 10.00
      • Set TI_DamageStackPerLevel = 5.00
      • -------- [ Duration of the stack damage ] --------
      • Set TI_DurBase = 8.00
      • Set TI_DurPerLevel = 0.00
      • -------- [ Limit of the damage stacking (Value of 0 means no stacking limit) ] --------
      • Set TI_DCapBase = 0.00
      • Set TI_DCapPerLevel = 0.00
      • -------- [ Full damage area/radius of the explosion ] --------
      • Set TI_EXAOEBase = 0.00
      • Set TI_EXAOEPerLevel = 0.00
      • -------- [ Small damage area/radius of the explosion ] --------
      • Set TI_EXSmallAOEBase = 0.00
      • Set TI_EXSmallAOEPerLevel = 0.00
      • -------- [ Explosion's small damage factor ] --------
      • Set TI_EXSmallDamageFactorBase = 0.00
      • Set TI_EXSmallDamageFactorPerLevel = 0.00
      • -------- [ Attack type of the spell ] --------
      • Set TI_AttackType = Hero
      • -------- [ Damage type of the spell ] --------
      • Set TI_DamageType = Normal
      • -------- [ Damage stacking SFX model ] --------
      • Set TI_EffectModel1 = Abilities\Spells\NightElf\BattleRoar\RoarTarget.mdl
      • -------- [ Explosion SFX model ] --------
      • Set TI_EffectModel2 = Objects\Spawnmodels\Undead\UndeadBlood\UndeadBloodNecromancer.mdl
      • -------- [ Damage stacking SFX attachment point ] --------
      • Set TI_EffectAttachment = overhead
      • -------- [ The following determines the type of units allowed as the spell's target ] --------
      • Set TI_Structures = False
      • Set TI_Mechanicals = False
      • Set TI_MagicImmune = True
      • Set TI_Allies = True
      • Set TI_Illusions = True
      • -------- [ It's possible that this script was compiled first before TI_InitSpellIndex in which case normal function call won't work. ] --------
      • -------- [ Therefore we use ExecuteFunc. ] --------
      • Custom script: call ExecuteFunc( "TI_InitSpellIndex" )
      • -------- --------
      • -------- --------
Main Section
JASS:
///////////////////////////////////////////////////////////////////////////////////////////////////////
//===================================================================================================//
//============================= ***    ****   ***   ****   *   *  **** ==============================//
//============================= *  *   *     *   *  *   *  ** **  *    ==============================//
//============================= ***    ***   *****  *   *  * * *  ***  ==============================//
//============================= *  *   *     *   *  *   *  *   *  *    ==============================//
//============================= *   *  ****  *   *  ****   *   *  **** ==============================//
//===================================================================================================//
///////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                   //
// *****************************                                                                     //
// * Triggered Incinerate v1.2 *                                                                     //
// *          by: AGD          *                                                                     //
// *****************************                                                                     //
//                                                                                                   //
// Credits:                                                                                          //
// - Bribe ( Damage Engine )                                                                         //
//                                                                                                   //
//                                                                                                   //
// How to Import:                                                                                    //
// - Copy the all the custom abilities                                                               //
// - Copy the "Damage Engine by Bribe" trigger category                                              //
// - Copy the "Triggered Incinerate by AGD" trigger category                                         //
//                                                                                                   //
// But first, check "automatically create unknown variables while pasting trigger data" so that the  //
// "TI Variable Creator" will create the necessary variables in your map.                            //
//                                                                                                   //
//                                                                                                   //
// Spell Summary:                                                                                    //
//                                                                                                   //
// The spell's effect is passive. It activates everytime the unit deals damage to its target. This   //
// spell causes the unit to deal increasing damage (additionally) per attack. The damage stacking    //
// has a duration after which if the target takes no damage from a unit with incinerate spell, it    //
// will be reset back to zero. Upon the target unit's death, it will explode and deal damage equal   //
// to the damage stacked to a certain AOE.                                                           //
//                                                                                                   //
//                                                                                                   //
// Spell Info (Please Read):                                                                         //
//                                                                                                   //
// For those who don't know yet, the Incinerate spell of Fire Lord which was made by Blizzard is     //
// actually buggy if you're not using the original spell ( i.e. if you're using a custom ability     //
// based on that spell ). In this case, even if you change the stats of the custom spell, the stats  //
// of the original spell will persist and it's almost impossible or atleast difficult to make        //
// many incinerate spells with different stats and sometimes you will be forced to use triggers to   //
// do this.                                                                                          //
//                                                                                                   //
// For this reason I made this spell hoping that this will help you with your difficulties regarding //
// the buggy Incinerate. In this spell, you can make as many incinerate spells as you like, all with //
// different stats and spellIDs. The spell's effects is also not limited by the unit's weapon type   //
// which, unlike Blizzard's Incinerate, will only work with missile attacks. And lastly, one         //
// POSSIBLE advantage of this sytem is that it works together with other buff placers and orb        //
// effects.                                                                                          //
//                                                                                                   //
// Please share your feedback and suggestions about this spell at Hive Workshop or you can PM AGD    //
// at Hive. Please also report bugs and glitches if you found some.                                  //
//                                                                                                   //
//                                                                                                   //
// Note: If you use this resource in your map, please don't forget to give credits to AGD. And if    //
//       you're having problem regarding how to import or in configuring the spell, you can PM him   //
//       or post your comment at Hive Workshop.                                                      //
//                                                                                                   //
//                                                                                                   //
///////////////////////////////////////////////////////////////////////////////////////////////////////
//===================================================================================================//
//===================================================================================================//
//===================================================================================================//
///////////////////////////////////////////////////////////////////////////////////////////////////////



////////////////////////////////////////////////////
// This function indexes the spell's stats listed //
// in the Incinerate spells list one by one       //
////////////////////////////////////////////////////
function TI_InitSpellIndex takes nothing returns nothing

    local integer i = udg_TI_SpellIndex + 1

    set udg_TI_SpellID[i] = udg_TI_Spell
    set udg_TI_SpellAsTrigger[i] = udg_TI_AllowSpellAsTrigger
    set udg_TI_DPABase[i] = udg_TI_DamageStackBase
    set udg_TI_DPAPerLevel[i] = udg_TI_DamageStackPerLevel
    set udg_TI_DurationBase[i] = udg_TI_DurBase
    set udg_TI_DurationPerLevel[i] = udg_TI_DurPerLevel
    set udg_TI_DamageCapBase[i] = udg_TI_DCapBase
    set udg_TI_DamageCapPerLevel[i] = udg_TI_DCapPerLevel
    set udg_TI_ExplodeAOEBase[i] = udg_TI_EXAOEBase
    set udg_TI_ExplodeAOEPerLevel[i] = udg_TI_EXAOEPerLevel
    set udg_TI_ExplodeSmallDAOEBase[i] = udg_TI_EXSmallAOEBase
    set udg_TI_ExplodeSmallDAOEPerLev[i] = udg_TI_EXSmallAOEPerLevel
    set udg_TI_ExplodeSmallDFactorBase[i] = udg_TI_EXSmallDamageFactorBase
    set udg_TI_ExplodeSmallDFactorPerLev[i] = udg_TI_EXSmallDamageFactorPerLevel
    set udg_TI_AT[i] = udg_TI_AttackType
    set udg_TI_DT[i] = udg_TI_DamageType
    set udg_TI_SFXModel1[i] = udg_TI_EffectModel1
    set udg_TI_SFXModel2[i] = udg_TI_EffectModel2
    set udg_TI_AttachPoint[i] = udg_TI_EffectAttachment
    set udg_TI_IsUnitStructure[i] = udg_TI_Structures
    set udg_TI_IsUnitMechanical[i] = udg_TI_Mechanicals
    set udg_TI_IsUnitMagicImmune[i] = udg_TI_MagicImmune
    set udg_TI_IsUnitAlly[i] = udg_TI_Allies
    set udg_TI_IsUnitIllusion[i] = udg_TI_Illusions

    set udg_TI_SpellIndex = i

endfunction


/////////////////////////////////////////////////////
// This function filters unwanted units from being //
// affected by the spell                           //
/////////////////////////////////////////////////////
function TI_TargetFilter takes unit target, player p, integer i returns boolean
    return ( ( not IsUnitType( target, UNIT_TYPE_STRUCTURE ) ) or udg_TI_IsUnitStructure[i] ) and ( ( not IsUnitType( target, UNIT_TYPE_MECHANICAL ) ) or udg_TI_IsUnitMechanical[i] ) and ( ( not IsUnitType( target, UNIT_TYPE_MAGIC_IMMUNE ) ) or udg_TI_IsUnitMagicImmune[i] ) and ( IsUnitEnemy( target, p ) or udg_TI_IsUnitAlly[i] ) and ( ( not IsUnitIllusion( target ) ) or udg_TI_IsUnitIllusion[i] )
endfunction


/////////////////////////////////////////////////////
// This function debuffs the target unit when not  //
// damaged for a certain duration                  //
/////////////////////////////////////////////////////
function TI_Debuff takes nothing returns nothing

    local timer t           = GetExpiredTimer()
    local integer timerkey  = GetHandleId( t )
    local integer i         = LoadInteger( udg_TI_Hash, timerkey, 0 )
    local unit u            = LoadUnitHandle( udg_TI_Hash, timerkey, 1 )
    local integer key       = GetHandleId( u )
    local string I          = I2S( i )

    call DestroyEffect( LoadEffectHandle( udg_TI_Hash, key, StringHash( "SFX" + I ) ) )
    call DestroyTimer( t )
    call SaveBoolean( udg_TI_Hash, key, i, false )
    call SaveReal( udg_TI_Hash, key, StringHash( "Damage" + I ), 0 )
    call FlushChildHashtable( udg_TI_Hash, timerkey )

    set t = null
    set u = null
    set I = null

endfunction


//////////////////////////////////////////////////////
// This function triggers the dead unit's explosion //
//////////////////////////////////////////////////////
function TI_Incinerate takes nothing returns boolean

    local unit dying        = GetTriggerUnit()
    local integer key       = GetHandleId( dying )
    local real x            = GetUnitX( dying )
    local real y            = GetUnitY( dying )
    local integer i         = 0
    local unit target
    local player p
    local real dx
    local real dy
    local real damage
    local real smalldfactor
    local unit buffplacer
    local string I

    loop

        set i = i + 1
        set I = I2S( i )

        if LoadBoolean( udg_TI_Hash, key, i ) then

            set damage = LoadReal( udg_TI_Hash, key, StringHash( "Damage" + I ) )
            set smalldfactor = LoadReal( udg_TI_Hash, key, StringHash( "SmallDFactor" + I ) )
            set buffplacer = LoadUnitHandle( udg_TI_Hash, key, StringHash( "BuffPlacer" + I ) )
            set p = GetOwningPlayer( buffplacer )
            call SaveReal( udg_TI_Hash, key, StringHash( "Damage" + I ), 0 )
            call DestroyEffect( LoadEffectHandle( udg_TI_Hash, key, StringHash( "SFX" + I ) ) )
            call DestroyEffect( AddSpecialEffect( udg_TI_SFXModel2[i], x, y ) )
            call GroupEnumUnitsInRange( udg_TI_TempGroup, x, y, LoadReal( udg_TI_Hash, key, StringHash( "SmallDAOE" + I ) ), null )

            loop

                set target = FirstOfGroup( udg_TI_TempGroup )
                exitwhen target == null
                call GroupRemoveUnit( udg_TI_TempGroup, target )
                set dx = GetUnitX( target ) - x
                set dy = GetUnitY( target ) - y

                if ( target != buffplacer ) and TI_TargetFilter( target, p, i ) then

                    if SquareRoot( dx*dx + dy*dy ) > LoadReal( udg_TI_Hash, key, StringHash( "AOE" + I ) ) then

                        call UnitDamageTarget( buffplacer, target, damage*smalldfactor, true, false, udg_TI_AT[i], udg_TI_DT[i], null )

                    else

                        call UnitDamageTarget( buffplacer, target, damage, true, false, udg_TI_AT[i], udg_TI_DT[i], null )

                    endif

                endif

            endloop

        endif

        exitwhen i == udg_TI_SpellIndex

    endloop

    call FlushChildHashtable( udg_TI_Hash, key )

    set dying = null
    set buffplacer = null
    set p = null
    set I = null

    return false

endfunction


///////////////////////////////////////////////////////////
// This function checks if the level of incinerate spell //
// for the damage source is greater than zero in order   //
// run the main actions of the spell.                    //
///////////////////////////////////////////////////////////
function TI_MainAction takes nothing returns boolean

    local trigger trig   = GetTriggeringTrigger()
    local integer key    = GetHandleId( udg_DamageEventTarget )
    local integer i      = 0
    local integer level
    local integer timerkey
    local real dcap
    local string I

    loop

        set i = i + 1
        set level = GetUnitAbilityLevel( udg_DamageEventSource, udg_TI_SpellID[i] )

        if level > 0 then

            if not udg_IsDamageSpell or udg_TI_SpellAsTrigger[i] then

                set I = I2S( i )
                set dcap = udg_TI_DamageCapBase[i] + udg_TI_DamageCapPerLevel[i]*level

                if TI_TargetFilter( udg_DamageEventTarget, GetOwningPlayer( udg_DamageEventSource ), i ) then

                    call DestroyEffect( LoadEffectHandle( udg_TI_Hash, key, StringHash( "SFX" + I ) ) )
                    call SaveEffectHandle( udg_TI_Hash, key, StringHash( "SFX" + I ), AddSpecialEffectTarget( udg_TI_SFXModel1[i], udg_DamageEventTarget, udg_TI_AttachPoint[i] ) )
                    call DestroyTimer( LoadTimerHandle( udg_TI_Hash, key, StringHash( "Timer" + I ) ) )
                    call SaveTimerHandle( udg_TI_Hash, key, StringHash( "Timer" + I ), CreateTimer() )
                    set timerkey = GetHandleId( LoadTimerHandle( udg_TI_Hash, key, StringHash( "Timer" + I ) ) )
                    call SaveUnitHandle( udg_TI_Hash, timerkey, 1, udg_DamageEventTarget )
                    call SaveUnitHandle( udg_TI_Hash, key, StringHash( "BuffPlacer" + I ), udg_DamageEventSource )
                    call SaveReal( udg_TI_Hash, key, StringHash( "Damage" + I ), LoadReal( udg_TI_Hash, key, StringHash( "Damage" + I ) ) + udg_TI_DPABase[i] + udg_TI_DPAPerLevel[i]*level )
                    call SaveReal( udg_TI_Hash, key, StringHash( "AOE" + I ), udg_TI_ExplodeAOEBase[i] + udg_TI_ExplodeAOEPerLevel[i]*level )
                    call SaveReal( udg_TI_Hash, key, StringHash( "SmallDAOE" + I ), udg_TI_ExplodeSmallDAOEBase[i] + udg_TI_ExplodeSmallDAOEPerLev[i]*level )
                    call SaveReal( udg_TI_Hash, key, StringHash( "SmallDFactor" + I  ), udg_TI_ExplodeSmallDFactorBase[i] + udg_TI_ExplodeSmallDFactorPerLev[i]*level )
                    call SaveInteger( udg_TI_Hash, timerkey, 0, i )
                    call SaveBoolean( udg_TI_Hash, key, i, true )

                    if dcap != 0 then

                        if LoadReal( udg_TI_Hash, key, StringHash( "Damage" + I ) ) > dcap then

                            call SaveReal( udg_TI_Hash, key, StringHash( "Damage" + I ), dcap )

                        endif

                    endif

                    call DisableTrigger( trig )
                    call UnitDamageTarget( udg_DamageEventSource, udg_DamageEventTarget, udg_DamageEventAmount + LoadReal( udg_TI_Hash, key, StringHash( "Damage" + I ) ), true, false, udg_TI_AT[i], udg_TI_DT[i], null )
                    call EnableTrigger( trig )
                    set udg_DamageEventAmount = 0
                    call TimerStart( LoadTimerHandle( udg_TI_Hash, key, StringHash( "Timer" + I ) ), udg_TI_DurationBase[i] + udg_TI_DurationPerLevel[i]*level, false, function TI_Debuff )

                endif

            endif

        endif

        exitwhen i == udg_TI_SpellIndex

    endloop

    set trig = null
    set I = null

    return false

endfunction


/////////////////////////////
// Initialization function //
/////////////////////////////
function InitTrig_Triggered_Incinerate takes nothing returns nothing

    local trigger t1  = CreateTrigger()
    local trigger t2  = CreateTrigger()
    set udg_TI_Hash   = InitHashtable()

    call TriggerRegisterAnyUnitEventBJ( t1, EVENT_PLAYER_UNIT_DEATH )
    call TriggerAddCondition( t1, Filter( function TI_Incinerate ) )
    call TriggerRegisterVariableEvent( t2, "udg_DamageEvent", EQUAL, 1 )
    call TriggerAddCondition( t2, Filter( function TI_MainAction ) )
    call ExecuteFunc( "Trig_Incinerate_SpellsList_Actions" )

endfunction


//////////////////////
//******************//
//** End of Spell **//
//******************//
//////////////////////



v1.0
- First Upload
v1.1
- Multiple incinerates of different rawcodes now doesn't stack damage with each other on
a single unit but instead, they stack their OWN damage( or incinerates of the same rawcode )
on that same unit.
- Removed the dummy units, the attacker is now the one to damage the targets instead of
the dummy
- Removed the AddEvent function, now uses a damage detection system instead
- Added a debug option
- Combined the triggeractions with triggerconditions
- Removed the TI_AbilLevel function for ability level check but instead, uses a simplier way
- Replaced the global indexes at the configuration with a local integer for neatness
- Fixed some lapses in the previous spell such as:
* Damage stacked not removed from the hero after dying and being revived
* incineration of once affected units when they die even after the incinerate timer expires
- Replaced the local groups with a single global group
- Other changes
v1.1b
- Moved the TI_SpellsList to a different section and also converted is from jass
to a GUI friendly configuration section
- Moved the debug section to a separate trigger
- Renamed a variable with a misleading name. Changed the name from killer => buffplacer
- Other very minor changes
v1.2
- Replaced GDD by Bribe's Damage Engine
- You can now configure whether spells( this extends to all damage of attack type normal) can trigger incinerate or not
- Combined the full damage explosion and small damage explosion group into one loop
- Made a separate function for filtering target units
- Minor changes



Keywords:
Incinerate, Fury Swipe, Damage Stacking, Simple
Contents

Triggered Incinerate v1.2 (Map)

Reviews
KILLCIDE
Ugh yes. The code is much shorter :D Here are a few suggestions: You should maybe switch all the global variables to some type of default incinerate just in case users forget to use one of the variables before they call the function. If they do...
Level 37
Joined
Jul 22, 2015
Messages
3,485
Cool idea, especially for a passive ability like Incinerate that has a lot of hardcoded values. However, I see this functioning way more as a system rather than multiple abilities. I also wonder how many different types of Incinerates people would actually want in their maps. Anyway, here are some issues I would like for you to tackle:
  • It's not necessary to null the local triggers in the InitTrig function
  • The way you index abilities are horrendous. Instead of copy-pasting all the variables inside one function, why not have a function that will do it for you? You set some values to some temp global variables, and then call the function that will index + transfer all the temp global variables to the indexed variables. This will dramatically reduce the size of function TI_Config
  • Instead of making your own "DDS", please just use any of the reliable DDS in the spell section
  • TI_SpellCheck & MainAction can be combined into one function
  • In TI_SpellCheck, replace return true to exitwhen true. Even if the ability is found, the loop will still continue to run with your current setup
  • The dummy unit's ID is currently hardcoded
  • It's not necessary to convert level to a real when you calculate things like duration & damage
  • I would move the filters to a function somewhere near the top of the code so users can easily configure it
  • In MainAction, why is the dummy only removed if unit u passes the filters?
  • In MainAction, you should only declare the locals like level nand duration, and then store things into them if the unit passes the filter
  • Why SaveStringBJ over SavStr?
  • Personally, I think the damage and death event functions should only register events if there is an instance of the debuff
  • You can get rid of the locals fulldamagegroup & smalldamage group by just using a single recycled global group
  • Why is a dummy unit dealing damage to the units instead of the actual caster?

Could you also add an ingame screenshot instead of the spell's code? For now, I will set the spell's status to Awaiting Update.
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
Hey AGD, why are you using
JASS:
StringHash()
instead of integer numbers? For readability?

Yes

  • Why is a dummy unit dealing damage to the units instead of the actual caster?
It is because if the actual caster will be the one to deal damage, it will trigger another incinerate, and thus creating an unending loop. But if it is the dummy, it will not because it has no incinerate ability.
 
Last edited by a moderator:
The 'n000' unit type in code should not be hardcoded, as Killcide mentioned.

The StringHash function is not very compared to usage of constants. It's not required to evaluate it again and again.
It would be more performant to use variables for the usage.

Directly give the user access to define attacktype, damagetype, weapntype, instead of defining the index. No need to convert them each call.

Really follow Killcide's suggestion and use a DDS system. Some systems are made for good reasons, and are not easy to do perfectly from scratch.
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
The
'n000'
unit type in code should not be hardcoded, as Killcide mentioned.

The StringHash function is not very compared to usage of constants. It's not required to evaluate it again and again.
It would be more performant to use variables for the usage.

Directly give the user access to define attacktype, damagetype, weapntype, instead of defining the index. No need to convert them each call.

Really follow Killcide's suggestion and use a DDS system. Some systems are made for good reasons, and are not easy to do perfectly from scratch.

Yes I'll include it in the update.

Could you not add an extra condition to your "DDS" to make sure that the target source is not already affected by Incinerate? Or can other incinerates stack on each other?

The source is not affected by the incinerate but the target unit. And yes, other incinerates can stack damage on each other ( additionally ).
I'm not sure if I understood your first question here correctly.
 
Level 37
Joined
Jul 22, 2015
Messages
3,485
The source is not affected by the incinerate but the target unit. And yes, other incinerates can stack damage on each other ( additionally ).
I'm not sure if I understood your first question here correctly.
I'm aware. However, that was not what I was suggesting. I really dislike the fact that the caster of the spell does not get appropriate credit for the kills. Since the dummy unit is dealing damage, the dummy unit will get credit. If you're afraid of an infinite loop, why not just disable the trigger before the you deal the triggered damage and then turn it back on afterwards?
 
Level 37
Joined
Jul 22, 2015
Messages
3,485
It seems you ignored some of my important suggestions.
  • The brute copy-paste setup you have for TI_SpellsList can be avoided by using temp global variables that a user can setup and then simply calling a function that will index all the variables for them is better than having every single incinerate spell under one function
  • It would be better to keep the unit filters in TI_MainAction in a seperate function near the top of the code so that users can easily configure it to their liking instead of having to look for it in the code
  • Out of curiousity, why does the unit that deals the killing blow not get damaged by the AoE?
  • My same suggestion for the filters in TI_MainAction go for TI_Incinerate
  • I personally think all the debug messages you have in the code are not needed and just make the code look like a mess. Since you are using hashtables, you can have the debug in some seperate code/trigger and easily look up who is dealing what damage with what spell, right?
I would really like for you to do the first suggestion and maybe the one about the debug messages. This will dramatically reduce the length of your code. I will set this resource back to Awaiting Update.
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
The brute copy-paste setup you have for TI_SpellsList can be avoided by using temp global variables that a user can setup and then simply calling a function that will index all the variables for them is better than having every single incinerate spell under one function
If I understood correctly, that would mean that they can only setup one set of stats that is the same for all incinerates.

It would be better to keep the unit filters in TI_MainAction in a seperate function near the top of the code so that users can easily configure it to their liking instead of having to look for it in the code
My same suggestion for the filters in TI_MainAction go for TI_Incinerate

I think these lines in the configurations does it already, no?
JASS:
   //** Determines if the following type of units are allowed as target **//

   // Structures
   set udg_TI_IsUnitStructure[i] = false

   // Mechanical
   set udg_TI_IsUnitMechanical[i] = false

   // Magic Immune
   set udg_TI_IsUnitMagicImmune[i] = false

   // Allies
   set udg_TI_IsUnitAlly[i] = true

   // Illusions
   set udg_TI_IsUnitIllusion[i] = true

I personally think all the debug messages you have in the code are not needed and just make the code look like a mess. Since you are using hashtables, you can have the debug in some seperate code/trigger and easily look up who is dealing what damage with what spell, right?
Okay I will do it

Out of curiousity, why does the unit that deals the killing blow not get damaged by the AoE?
I missed this one, I'll fix it
 
Level 37
Joined
Jul 22, 2015
Messages
3,485
If I understood correctly, that would mean that they can only setup one set of stats that is the same for all incinerates.
No? What makes you think that?

  • Set SaveAbility = Incinerate v1
  • Set SaveBaseDamage = 100
  • Set SaveBaseDamagePerLevel = 50
  • Set SaveSFXExplosion = Abilities\Spells\Other\Incinerate\FireLordDeathExplode.mdl
  • Custom script: call TI_SpellsList()
  • -------- --------
  • Set SaveAbility = Incinerate v2
  • Set SaveBaseDamage = 50
  • Set SaveBaseDamagePerLevel = 100
  • Set SaveSFXExplosion = Objects\Spawnmodels\Undead\UndeadBlood\UndeadBloodNecromancer.mdl
  • Custom script: call TI_SpellsList()
JASS:
function TI_SpellsList takes nothing returns nothing
    set udg_Ability[udg_Index] = udg_SaveAbility
    set udg_BaseDamage[udg_Index] = udg_SaveBaseDamage
    set udg_BaseDamagePerLevel[udg_Index] = udg_SaveBaseDamagePerLevel
    set udg_SFXExplosion[udg_Index] = udg_SaveSFXExplosion
    set udg_Index = udg_Index + 1
endfunction

You can even add a "safety" by having default Incinerate that will switch all the global variables to their default values.

I think these lines in the configurations does it already, no?
Ahh yes :p my mistake. I would still do it for readability though.
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
No? What makes you think that?
  • Set SaveAbility = Incinerate v1
  • Set SaveBaseDamage = 100
  • Set SaveBaseDamagePerLevel = 50
  • Set SaveSFXExplosion = Abilities\Spells\Other\Incinerate\FireLordDeathExplode.mdl
  • Custom script: call TI_SpellsList()
  • -------- --------
  • Set SaveAbility = Incinerate v2
  • Set SaveBaseDamage = 50
  • Set SaveBaseDamagePerLevel = 100
  • Set SaveSFXExplosion = Objects\Spawnmodels\Undead\UndeadBlood\UndeadBloodNecromancer.mdl
  • Custom script: call TI_SpellsList()

But users still need to do the same copy - paste if they want to add more slot for the spell right?
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
Now updated

The brute copy-paste setup you have for TI_SpellsList can be avoided by using temp global variables that a user can setup and then simply calling a function that will index all the variables for them is better than having every single incinerate spell under one function
Done

Out of curiousity, why does the unit that deals the killing blow not get damaged by the AoE?
The unit named killer there is not actually the killing unit but the one that places the incinerate buff on the dying unit so it should not take damage from the explosion it caused.
However I already changed the variable name from killer => buffplacer to make it clear.

I personally think all the debug messages you have in the code are not needed and just make the code look like a mess. Since you are using hashtables, you can have the debug in some seperate code/trigger and easily look up who is dealing what damage with what spell, right?
Done

BTW, I also added the credits which I forgot to put previously.
 
Level 37
Joined
Jul 22, 2015
Messages
3,485
Ugh yes. The code is much shorter :D Here are a few suggestions:
  • You should maybe switch all the global variables to some type of default incinerate just in case users forget to use one of the variables before they call the function. If they do forget, the global variable will be storing the most recent incinerate they made. You could have users configure the default incinerate in some seperate function or a bunch of constant functions
  • I fail to see the purpose of this call ExecuteFunc( "Trig_Incinerate_SpellsList_Actions" )
  • You don't have to post your debug trigger in your description :p
My only gripe with the code is how you keep the actual filters in the code ! It makes the code all wide and ugly. I still stand by my previous suggestion to you before by just calling the function directly like so:
JASS:
function Filters takes unit u, player p returns boolean
    return (not IsUnitType(u, UNIT_TYPE_STRUCTURE) and (not IsUnitType(u,UNIT_TYPE_MECHANICAL) and (IsUnitEnemy(u, p)
endfunction

//=======================================================
function SomeFunction takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local player p = GetTriggerPlayer()

    if Filters(u, p) then
        // do stuff
    endif

Other than that, the code looks fine to me. The submission overall isn't something gamebreaking, nor is it original :p I still question how many versions of Incinerate people will actually have in their map, but someone is bound to find this useful. Approved with a rating of 3/5.
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
You should maybe switch all the global variables to some type of default incinerate just in case users forget to use one of the variables before they call the function. If they do forget, the global variable will be storing the most recent incinerate they made.
This is currently how the indexing works, if they forget to set the value of a temp global, the value that will be passed to the indexed global is the value that the temp global is currently containing which is actually the its value on the latest incinerate they made.
I fail to see the purpose of this
call ExecuteFunc( "Trig_Incinerate_SpellsList_Actions" )
It is because the configuration script could be possibly compiled by WE first before the main script in which case using a normal function call wont work because it is calling a function below it.
Approved with a rating of 3/5.
I'll still be updating this soon, btw I still didn't saw the rating. :D
 
Last edited:
Level 12
Joined
May 16, 2020
Messages
660
Hi AGD, I want to use this system in my map (which already has Damage Engine), but I have some questions:
  • Why is the dummy unit required? I searched for "n000", but didn't find this in any part of the code?
  • Same thing with the 3 custom abilities (A000, A001, A002) - are these needed? Didn't find them referred in the JASS Code...?
  • Can I delete the TI Variable Creator after importing it into my map? So essentially I leave only "Incinerate SpellsList" and "Triggered Incinerate" in my map
Cheers!
 
Top