• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

New Bonus [vJASS][LUA]

Intro
Hello, this is my first submission in the spell section, so apologies in advance for any mistake. I present to you the New Bonus System. Since Object Merger stopped working and we still have no ways to edit the bonus values of a unit natively, I decided to create this light weight system to manage that and give everyone a simpler way to work with bonus values than the Bonus Mod.
How it works?
By using the new Object API introduced to Warcraft, we can now modify an unit ability field value, so when giving an unit a bonus, we add a specific ability to that unit that gives such bonus, if it do not have it already, and change that ability field bonus value to the desired value. Retrieving the amount is also trivial, by just reading that field value.

How to Import?
Importing New Bonus is really simple. Just copy the 9 abilities with the prefix "NewBonus" from the Object Editor into your map [Raw Codes Z001 to Z009 in demo map] and match their new raw code to the bonus types in the global block of the library. You can also define their raw code when pasting to be Z001 to Z009, that's why I created them with this raw codes. Then create a trigger called NewBonus, convert it to custom text, delete all text in it and paste the Library code there. That's it, you are done!
Requirements
NewBonus requires patch 1.31+ and RegisterPlayerUnitEvent Library. NewBonus Extended also Requires DamageInterface, CooldownReduction and Tenacity libraries.

vJASS:
function GetUnitBonus takes unit u, integer bonus_type returns real
    -> Returns the specified bonus amount for the unit
    -> Example: set amount = GetUnitBonus(GetTriggerUnit(), BONUS_AGILITY)

function SetUnitBonus takes unit u, integer bonus_type, real amount returns real
    -> Set the specified bonus type to amount for the unit
    -> Example: call SetUnitBonus(GetTriggerUnit(), BONUS_DAMAGE, 100)

function RemoveUnitBonus takes unit u, integer bonus_type returns nothing
    -> Removes the Specified bonus type from unit
    -> Example: call RemoveUnitBonus(GetTriggerUnit(), BONUS_AGILITY)

function AddUnitBonus takes unit u, integer bonus_type, real amount returns real
    -> Add the specified amount for the specified bonus tyte for unit
    -> Example: call AddUnitBonus(GetTriggerUnit(), BONUS_DAMAGE, 100)

function AddUnitBonusTimed takes unit u, integer bonus_type, real amount, real duration returns nothing
    -> Add the specified amount for the specified bonus type for unit for a duration
    -> Example: call AddUnitBonusTimed(GetTriggerUnit(), BONUS_ARMOR, 13, 10.5)

function LinkBonusToBuff takes unit u, integer bonus_type, real amount, integer buffId returns nothing
    -> Links the bonus amount specified to a buff or ability. As long as the unit has the buff or
    -> the ability represented by the parameter buffId the bonus is not removed.
    -> Example: call LinkBonusToBuff(GetTriggerUnit(), BONUS_ARMOR, 10, 'B000')

function LinkBonusToItem takes unit u, integer bonus_type, real amount, item i returns nothing
    -> Links the bonus amount specified to an item. As long as the unit has that item the bonus is not removed.
    -> Note that it will work for items with the same id, because it takes as parameter the item object.
    -> Example: call LinkBonusToItem(GetManipulatingUnit(), BONUS_ARMOR, 10, GetManipulatedItem())

function UnitCopyBonuses takes unit source, unit target returns nothing
    -> Copy the source unit bonuses using the Add functionality to the target unit
    -> Example: call UnitCopyBonuses(GetTriggerUnit(), GetSummonedUnit())

function UnitMirrorBonuses takes unit source, unit target returns nothing
    -> Copy the source unit bonuses using the Set functionality to the target unit
    -> Example: call UnitMirrorBonuses(GetTriggerUnit(), GetSummonedUnit())

function RegisterBonusEvent takes code c returns nothing
    -> Register code to run when any unit bonus is modified
    -> Example: RegisterBonusEvent(function YourFunction)

function RegisterBonusTypeEvent takes integer bonus, code c returns nothing
    -> Register code to run when a specific unit bonus is modified
    -> Example: RegisterBonusTypeEvent(BONUS_DAMAGE, function YourFunction)

function GetBonusUnit takes nothing returns unit
    -> Call this function to get the bonus event unit

function GetBonusType takes nothing returns integer
    -> Call this function to get the bonus event type

function SetBonusType takes integer bonus returns nothing
    -> Call this function to set the bonus event type

function GetBonusAmount takes nothing returns real
    -> Call this function to get the bonus event amount

function SetBonusAmount takes real amount returns nothing
    -> Call this function to set the bonus event amount
Lua:
function GetUnitBonus(unit, type)
    -> Returns the specified bonus amount for the unit
    -> Example: set amount = GetUnitBonus(GetTriggerUnit(), BONUS_AGILITY)

function SetUnitBonus(unit, type, value)
    -> Set the specified bonus type to amount for the unit
    -> Example: call SetUnitBonus(GetTriggerUnit(), BONUS_DAMAGE, 100)

function RemoveUnitBonus(unit, type)
    -> Removes the Specified bonus type from unit
    -> Example: call RemoveUnitBonus(GetTriggerUnit(), BONUS_AGILITY)

function AddUnitBonus(unit, type, value)
    -> Add the specified amount for the specified bonus tyte for unit
    -> Example: call AddUnitBonus(GetTriggerUnit(), BONUS_DAMAGE, 100)

function AddUnitBonusTimed(unit, type, amount, duration)
    -> Add the specified amount for the specified bonus type for unit for a duration
    -> Example: call AddUnitBonusTimed(GetTriggerUnit(), BONUS_ARMOR, 13, 10.5)

function LinkBonusToBuff(unit, type, amount, buff)
    -> Links the bonus amount specified to a buff or ability. As long as the unit has the buff or
    -> the ability represented by the parameter buffId the bonus is not removed.
    -> Example: call LinkBonusToBuff(GetTriggerUnit(), BONUS_ARMOR, 10, 'B000')

function LinkBonusToItem(unit, type, amount, item)
    -> Links the bonus amount specified to an item. As long as the unit has that item the bonus is not removed.
    -> Note that it will work for items with the same id, because it takes as parameter the item object.
    -> Example: call LinkBonusToItem(GetManipulatingUnit(), BONUS_ARMOR, 10, GetManipulatedItem())

function UnitCopyBonuses(source, target)
    -> Copy the source unit bonuses using the Add functionality to the target unit
    -> Example: call UnitCopyBonuses(GetTriggerUnit(), GetSummonedUnit())

function UnitMirrorBonuses(source, target)
    -> Copy the source unit bonuses using the Set functionality to the target unit
    -> Example: call UnitMirrorBonuses(GetTriggerUnit(), GetSummonedUnit())

function RegisterBonusEvent(code)
    -> Register code to run when any unit bonus is modified
    -> Example: RegisterBonusEvent(function() YourFunctionc end)

function RegisterBonusTypeEvent(type, code)
    -> Register code to run when a specific unit bonus is modified
    -> Example: RegisterBonusTypeEvent(BONUS_DAMAGE, function() YourFunction end)

function GetBonusUnit()
    -> Call this function to get the bonus event unit

function GetBonusType()
    -> Call this function to get the bonus event type

function SetBonusType(type)
    -> Call this function to set the bonus event type

function GetBonusAmount()
    -> Call this function to get the bonus event amount

function SetBonusAmount(real)
    -> Call this function to set the bonus event amount
  • BONUS_DAMAGE
  • BONUS_ARMOR
  • BONUS_AGILITY
  • BONUS_STRENGTH
  • BONUS_INTELLIGENCE
  • BONUS_HEALTH
  • BONUS_MANA
  • BONUS_MOVEMENT_SPEED
  • BONUS_SIGHT_RANGE
  • Real Value Bonusses
  • BONUS_HEALTH_REGEN
  • BONUS_MANA_REGEN
  • BONUS_ATTACK_SPEED
  • BONUS_MAGIC_RESISTANCE
  • BONUS_EVASION_CHANCE
  • BONUS_CRITICAL_CHANCE
  • BONUS_CRITICAL_DAMAGE
  • BONUS_LIFE_STEAL
  • BONUS_DAMAGE
  • BONUS_ARMOR
  • BONUS_AGILITY
  • BONUS_STRENGTH
  • BONUS_INTELLIGENCE
  • BONUS_HEALTH
  • BONUS_MANA
  • BONUS_MOVEMENT_SPEED
  • BONUS_SIGHT_RANGE
  • Real Value Bonusses
  • BONUS_HEALTH_REGEN
  • BONUS_MANA_REGEN
  • BONUS_ATTACK_SPEED
  • BONUS_MAGIC_RESISTANCE
  • BONUS_EVASION_CHANCE
  • BONUS_MISS_CHANCE
  • BONUS_CRITICAL_CHANCE
  • BONUS_CRITICAL_DAMAGE
  • BONUS_SPELL_POWER_FLAT
  • BONUS_SPELL_POWER_PERCENT
  • BONUS_LIFE_STEAL
  • BONUS_SPELL_VAMP
  • BONUS_COOLDOWN_REDUCTION
  • BONUS_COOLDOWN_REDUCTION_FLAT
  • BONUS_COOLDOWN_OFFSET
  • BONUS_TENACITY
  • BONUS_TENACITY_FLAT
  • BONUS_TENACITY_OFFSET

(v1.0)
  • Submission
(v1.1)
  • Updated the code to use BlzSetUnitMaxHP() and BlzSetUnitMaxMana() in order to make Bonus_Health and Bonus_Mana work properly.
(v1.2)
  • Implemented the ability to link a bonus amount to a buff or ability as per requested by @The_Silent . Refactored the code and added a new example of this new functionality in the test map.
(v1.3)
  • FIxed a bug on AddUnitBonusExTimed()
(v1.4)
  • Normalized the AMOUNT input parameter to Integer instead of real to fix a type conversion problem when converting real to integer for abilities which field value is a integer value.
(v1.5)
  • Updated the system to respect integer fields bounds when adding to existing bonus (max 2147483647 and min -2147483648).
  • It's still the users job to pass the correct amount, the system will only handle addtions and subtractions that overflow/underflow.
(v1.6)
  • Split NewBonus into 2 libraries
    • NewBonus contains the core system to set / remove / add bonus types
    • NewBonusUtils contains extra functionalities such as timed and linked bonuses
  • Redesigned timed and linked bonuses to improve performance.
  • New utility functions AddUnitBonusTimed(), LinkBonusToBuff(), LinkBonusToItem()
  • Renamed Constans to upper case to be more visible.
  • Updated test map: included examples for the 3 new utility functions.
(v1.7)
  • Fixed a bug when Adding Health/Mana bonus not keeping the unit Health/Mana Percentage
  • Added the funcitons: They manipuilate real bonuses values correctly.
    • GetUnitBonusReal()
    • SetUnitBonusReal()
    • RemoveUnitBonusReal()
    • AddUnitBonusReal()
  • Refactored the LinkBonusToItem() to use the On Drop event instead of a periodic timer to check the link
  • Included an Expanded version of NewBonus and NewBonusUtils that take advangtage of the Damage Inteface System and Cooldown Reduction System
  • Renamed 4 bonus types for better readability.
  • Removed the "Ex" from the end of the API functions
(v1.8)
  • 2 new bonus types:
    • Sight Range
    • Magic Resistence (real)
  • 2 new functionalities in the NewBonusUtils (See API for usage): Thx to SinisterLuffy for the idea
    • function UnitCopyBonuses takes unit source, unit target returns nothing
    • function UnitMirrorBonuses takes unit source, unit target returns nothing
(v1.9)
  • Correction of a minor spelling error.
(v2.0)
  • Fixed a minor syntax error for the non extended Utils library
(v2.1)
  • System ported to LUA
  • 4 new bonus types for the non-Extended version of the system
    • Evasion Chance
    • Critical Strike Chance
    • Critical Strike Damage
    • Life Steal
(v2.2)
  • Removed the functions GetUnitBonusReal, SetUnitBonusReal, AddUnitBonusReal and RemoveUnitBonusReal
  • Now the functions GetUnitBonus, SetUnitBonus, AddUnitBonus and RemoveUnitBonus handles both real and integer bonus types correctly
  • Fix a minor bug in the NewBonusUtils Library
(v2.3)
  • Support for Bonus Events!!
  • Merged the normal and extended version into one library. (You can control which version is enabled by setting the new EXTENDED constant in the global section)
  • Code Cleaning and formatting.
(v2.4)
  • Fixed a bug in bonus event evaluation
  • 3 new bonus types included from the new Tenacity system
    • BONUS_TENACITY,
    • BONUS_TENACITY_FLAT
    • BONUS_TENACITY_OFFSET


For a quick import of the abilities use the editor Object Data.
For those with problems to open the map because of Reforged 1.32 patch, please see this
Contents

NewBonus (Map)

New Bonus (Map)

Reviews
MyPad
Considering the test map alone, I would approve this system. However, certain things addressed in the Code section of the review would need to be resolved before approval. Hence, this has been moved to Awaiting Update.

Wrda

Spell Reviewer
Level 28
Joined
Nov 18, 2012
Messages
2,011
Well I do, in the screenshot above, the Damage Interface is present.
Looks like Jasshelper is pointing to the wrong line. I checked the script and I can't find s_Damage_get_source function anywhere in this resource. Disable Bribe's damage engine and every trigger that uses it and tell me if you still have the same error.
 
Level 11
Joined
Dec 16, 2017
Messages
418
What a strange bug, lol
Encountered a bug : When dropping and picking up an item with 3 strength (with 12.50 hp per STR gain - in game constants) - the hero will get permanent additional health.


Also, does this has a tutorial to use in more situations?
Or how to use the cooldown reduction / crowd control ?
 
Last edited:
Or how to use the cooldown reduction / crowd control ?
you set the values for cooldown reduction and the system updates the cooldown of casted abilities automatic on a SPELL_EFFECT events.
Crowd control mods only works for crowd control applied over this system's functions for this feature.
 
Level 11
Joined
Dec 16, 2017
Messages
418
Yeah, i want to change my crowd control into these triggers, so i am in fully control of the actions, but how do i call the functions ?
This interferes with bribe's knockback system so i removed bribe's one and kept crowd control.
 
Copy the 14 buffs and 15 abilities with the CC prefix and match their raw code below.
you need to copy/create the skills and buffs of crowd control and make sure they have the rawCode expected by the crowd System. or change the constants ids to match the rawCodes in your map:
JASS:
]
 // The raw code of the silence ability
private constant integer SILENCE    = 'U000'
// The raw code of the stun ability
private constant integer STUN       = 'U001'
// The raw code of the attack slow ability
private constant integer ATTACK_SLOW= 'U002'
// The raw code of the movement slow ability
private constant integer MOVEMENT_SLOW      = 'U003'
// The raw code of the banish ability
private constant integer BANISH     = 'U004'
// The raw code of the ensnare ability
private constant integer ENSNARE    = 'U005'
// The raw code of the purge ability
private constant integer PURGE      = 'U006'
// The raw code of the hex ability
private constant integer HEX= 'U007'
// The raw code of the sleep ability
private constant integer SLEEP      = 'U008'
// The raw code of the cyclone ability
private constant integer CYCLONE    = 'U009'
// The raw code of the entangle ability
private constant integer ENTANGLE   = 'U010'
// The raw code of the disarm ability
private constant integer DISARM     = 'U011'
// The raw code of the fear ability
private constant integer FEAR       = 'U012'
// The raw code of the taunt ability
private constant integer TAUNT      = 'U013'
// The raw code of the true sight ability
private constant integer TRUE_SIGHT = 'U014'
// The raw code of the silence buff
private constant integer SILENCE_BUFF       = 'BU00'
// The raw code of the stun buff
private constant integer STUN_BUFF  = 'BU01'
// The raw code of the attack slow buff
private constant integer ATTACK_SLOW_BUFF   = 'BU02'
// The raw code of the movement slow buff
private constant integer MOVEMENT_SLOW_BUFF = 'BU03'
// The raw code of the banish buff
private constant integer BANISH_BUFF= 'BU04'
// The raw code of the ensnare buff
private constant integer ENSNARE_BUFF       = 'BU05'
// The raw code of the purge buff
private constant integer PURGE_BUFF = 'BU06'
// The raw code of the hex buff
private constant integer HEX_BUFF   = 'BU07'
// The raw code of the sleep buff
private constant integer SLEEP_BUFF = 'BU08'
// The raw code of the cyclone buff
private constant integer CYCLONE_BUFF       = 'BU09'
// The raw code of the entangle buff
private constant integer ENTANGLE_BUFF      = 'BU10'
// The raw code of the disarm buff
private constant integer DISARM_BUFF= 'BU11'
// The raw code of the fear buff
private constant integer FEAR_BUFF  = 'BU12'
// The raw code of the taunt buff
private constant integer TAUNT_BUFF = 'BU13'
seems like this are the orders which tell the base abilities. so you can just create them in your map and dont need to swap around.
JASS:
]
set order[CROWD_CONTROL_SILENCE] = "drunkenhaze"
set order[CROWD_CONTROL_STUN] = "thunderbolt"
set order[CROWD_CONTROL_SLOW] = "cripple"
set order[CROWD_CONTROL_SLOW_ATTACK] = "cripple"
set order[CROWD_CONTROL_BANISH] = "banish"
set order[CROWD_CONTROL_ENSNARE] = "ensnare"
set order[CROWD_CONTROL_PURGE] = "purge"
set order[CROWD_CONTROL_HEX] = "hex"
set order[CROWD_CONTROL_SLEEP] = "sleep"
set order[CROWD_CONTROL_CYCLONE] = "cyclone"
set order[CROWD_CONTROL_ENTANGLE] = "entanglingroots"
set order[CROWD_CONTROL_DISARM] = "drunkenhaze"
When you have the abilities
you can in trigger editor use the api functions to apply an cc.
call DisarmUnit(unit target, real duration, string model, string point, boolean stack)
call SilenceUnit(unit target, real duration, string model, string point, boolean stack)

example
call DisarmUnit(udg_Unit, 5, "", "", false)

no idea, why disarm would stack?
 
Last edited:
Level 11
Joined
Dec 16, 2017
Messages
418
Thanks mate, this is very helpful.
Yeah, i've already imported and everything is good, i just wanted to know how can i make use of them, since it has more options like life steals/spell vamp/spell power etc and tenacity which works only with crowd control spells from the system.
 
Level 11
Joined
Dec 16, 2017
Messages
418
I notice a strange behaviour, the stats work fine for all players except neutral hostile, if i give them items using the bonus, it will double the bonus that the item has, for ex, if the item has 50 str, the unit will receive 100 str, anyone encountered this?
 
Could be nice to have a chance to miss bonus (not a chance to evade)
Omg it is there?
  • BONUS_MISS_CHANCE


  • if amount > 0 and not (neverMiss[Damage.source.id] > 0) then
    set evade = GetRandomReal(0, 100) <= evasion[Damage.target.id] or GetRandomReal(0, 100) <= miss[Damage.source.id]
    if evade then
    set source = Damage.source
    set target = Damage.target
    set damage = amount
    call TriggerEvaluate(trigger)
    call BlzSetEventDamage(0)
    call BlzSetEventWeaponType(WEAPON_TYPE_WHOKNOWS)
    call text(source.unit, "miss", 1.5, 255, 0, 0, 255)
    set damage = 0
    set source = 0
    set target = 0
    endif
    endif

    it just sets damage to 0 if i understand correctly
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,877
Can you add miss chance via curse?...
This is not a real miss chance here...
That would require that a Dummy unit casts Curse on the target which involves a Buff that can be dispelled/transferred. I don't think that's in the same spirit of the system which is meant to add passive stats, but maybe I'm wrong.

Anyway, if you need this effect in your map then you can just trigger it yourself:
  • Unit - Create 1 Dummy...
  • Set Variable MyDummy = (Last created unit)
  • Set Variable MyTarget = (Some unit to curse)
  • Set Variable MyAmount = (Some value between 0.00 and 1.00) // You could get this from NewBonus's stat value
  • Unit - Add Curse (Dummy) to MyDummy
  • Ability - Set Miss Chance for Curse (Dummy) at Level: 0 to value MyAmount
  • Unit - Order MyDummy to Undead - Curse MyTarget
Now you're also hoping that the target isn't spell immune or that it doesn't have spell block.
 
Level 28
Joined
Feb 2, 2006
Messages
1,633
It would be nice to have more ability specific bonuses. For example, increase the number of summoned units for certain abilities only like:

JASS:
call AddUnitBonusAbilityIntegerLevelField(whichUnit, ABILITY_ILF_SUMMONED_UNIT_COUNT_HWE2, 'A000', 5)

This would allow some kind of enchanting/inscription systems which improve the effect of abilities without changing the ability level.
However, it would only work for certain fields due to limitations for certain fields by Blizzard.
 
  • unit.gif
    Unit - Create 1 Dummy...
  • set.gif
    Set Variable MyDummy = (Last created unit)
  • set.gif
    Set Variable MyTarget = (Some unit to curse)
  • set.gif
    Set Variable MyAmount = (Some value between 0.00 and 1.00) // You could get this from NewBonus's stat value
  • unit.gif
    Unit - Add Curse (Dummy) to MyDummy
  • if.gif
    Ability - Set Miss Chance for Curse (Dummy) at Level: 0 to value MyAmount
  • unit.gif
    Unit - Order MyDummy to Undead - Curse MyTarget
Can i transkate it into jass somehow? From your notation?
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,877
Can i transkate it into jass somehow? From your notation?
You can convert GUI triggers into code form (Edit -> Convert to Custom Text).

But why are you using Jass if you don't know how to write any yourself?

Maybe you're not using the proper tools, it's very easy with the correct setup:
 
You can convert GUI triggers into code form (Edit -> Convert to Custom Text).

But why are you using Jass if you don't know how to write any yourself?

Maybe you're not using the proper tools, it's very easy with the correct setup:
I just wanted to copypaste your code without writing myself )
 
Level 3
Joined
Nov 4, 2008
Messages
22
The system in the test map works so smoothly and perfectly, as if it's part of the game engine. 👏

I downloaded this for my own educational purposes, and I am still working on understanding what every single line does and how it works together, but this is just awesome.

EDIT:
While reviewing the Lua code (I am a beginner in Lua language), I noticed a few things and I wonder if anyone encountered issues because of it.
  1. In the file "RegisterPlayerUnitEvent", inside the function RegisterPlayerUnitEvent:
    Lua:
    function RegisterPlayerUnitEvent(playerunitevent, code)
            if type(code) == "function" then
                local i = GetHandleId(playerunitevent)
            
                if not trigger[i] then
                    trigger[i] = CreateTrigger()
                
                    for j = 0, bj_MAX_PLAYERS do
                        TriggerRegisterPlayerUnitEvent(trigger[i], Player(j), playerunitevent, null)
                    end
                end
            
                if not n[i] then n[i] = 1 end
                if not f[i] then f[i] = {} end
                table.insert(f[i], code)
            
                TriggerAddCondition(trigger[i], Filter(function()
                    f[i][n[i]]()
                    n[i] = n[i] + 1
                    if n[i] > #f[i] then n[i] = 1 end
                end))
            end
        end
    null here throws a warning of "undefined global null". Was this forgotten to be changed to nil during the conversion from Jass to Lua? I saw this in about 20 places in the entire Lua version of this. Should I simply replace any null to nil in the entire system?
  2. The same function above is using GetHandleId in the line "local i = GetHandleId(playerunitevent)"; Based on the Lua guide I read, it mentions that the function GetHandleId causes desyncs, and in Lua is not required anyway. Should I adjust the code to simply work with the playerunitevent directly and delete the GetHandleId native?
    E.g
    Lua:
    local i = GetHandleId(playerunitevent) -- Remove this line
    local i = playerunitevent -- Add this line instead (or simply use "playerunitevent" variable instead)
    I saw the usage of GetHandleId in multiple places. If the solution is what I wrote above, I will do that for the rest of the code.
  3. Under Utilities file (inside Utilities folder), inside the function "UnitDamageGroup":
    Lua:
    function UnitDamageGroup(unit, group, damage, attacktype, damagetype, effect, attach, destroy)
            for i = 0, BlzGroupGetSize(group) - 1 do
                local u = BlzGroupUnitAt(group, i)
                UnitDamageTarget(unit, u, damage, true, false, attacktype, damagetype, nil)
    
                if effect and attach then
                    DestroyEffect(AddSpecialEffectTarget(effect, u, attach))
                end
            end
    
            if destroy then
                DestroyGroup(group)
            end
    
            return group
        end
    nil throws the warning: "Cannot assign nil to parameter weapontype. Type nil cannot match `weapontype` Lua Diagnostics.(param-type-mismatch)"
    Should the nil be replaced to "WEAPON_TYPE_WHOKNOWS"? I checked how the native "UnitDamageTargetBJ" is using "UnitDamageTarget".
  4. Under Utilities file, inside the function "CreateChainLightning":
    Lua:
    function CreateChainLightning(source, target, damage, aoe, duration, interval, bounces, attacktype, damagetype, lightning, effect, attach, rebounce)
            local player = GetOwningPlayer(source)
            local group = GetEnemyUnitsInRange(player, GetUnitX(target), GetUnitY(target), aoe, false, false)
    
            if BlzGroupGetSize(group) == 1 then
                DestroyLightningTimed(AddLightningEx(lightning, true, GetUnitX(source), GetUnitY(source), GetUnitZ(source) + 60.0, GetUnitX(target), GetUnitY(target), GetUnitZ(target) + 60.0), duration)
                DestroyEffect(AddSpecialEffectTarget(effect, target, attach))
                UnitDamageTarget(source, target, damage, false, false, attacktype, damagetype, nil)
                DestroyGroup(group)
            else
                local timer = CreateTimer()
                local damaged = CreateGroup()
                local prev = nil
                local this = target
                local next = nil
    
                GroupRemoveUnit(group, this)
                GroupAddUnit(damaged, this)
                UnitDamageTarget(source, this, damage, false, false, attacktype, damagetype, nil)
                DestroyEffect(AddSpecialEffectTarget(effect, this, attach))
                TimerStart(timer, interval, true, function()
                    DestroyGroup(group)
                    if bounces > 0 then
                        group = GetEnemyUnitsInRange(player, GetUnitX(this), GetUnitY(this), aoe, false, false)
                        GroupRemoveUnit(group, this)
    
                        if not rebounce then
                            BlzGroupRemoveGroupFast(damaged, group)
                        end
    
                        if BlzGroupGetSize(group) == 0 then
                            PauseTimer(timer)
                            DestroyTimer(timer)
                            DestroyGroup(group)
                            DestroyGroup(damaged)
                        else
                            next = GetClosestUnitGroup(GetUnitX(this), GetUnitY(this), group)
    
                            if next == prev and BlzGroupGetSize(group) > 1 then
                                GroupRemoveUnit(group, prev)
                                next = GetClosestUnitGroup(GetUnitX(this), GetUnitY(this), group)
                            end
    
                            if next then
                                DestroyLightningTimed(AddLightningEx(lightning, true, GetUnitX(this), GetUnitY(this), GetUnitZ(this) + 60.0, GetUnitX(next), GetUnitY(next), GetUnitZ(next) + 60.0), duration)
                                DestroyEffect(AddSpecialEffectTarget(effect, next, attach))
                                GroupAddUnit(damaged, next)
                                UnitDamageTarget(source, next, damage, false, false, attacktype, damagetype, nil)
                                DestroyGroup(group)
                                prev = this
                                this = next
                                next = nil
                            else
                                PauseTimer(timer)
                                DestroyTimer(timer)
                                DestroyGroup(group)
                                DestroyGroup(damaged)
                            end
                        end
                    else
                        PauseTimer(timer)
                        DestroyTimer(timer)
                        DestroyGroup(group)
                        DestroyGroup(damaged)
                    end
                    bounces = bounces - 1
                end)
            end
            DestroyGroup(group)
        end
    The variable prev is set to nil, and the line "GroupRemoveUnit(group, prev)" throws a warning saying: "Cannot assign nil to parameter unit. Type nil cannot match `unit`Lua Diagnostics.(param-type-mismatch)"
    If I understand this correctly, this if statement will not fire when prev is nil, so I assume no ingame error will rise, so this should be ignored?
  5. The guide recommends to avoid using "location" and instead use x,y coords. I saw a few places where the code uses location. Should I change it to use x,y coords and adjust the code where ever needed to work with the change?
 
Last edited:
Top