- Joined
- Jan 30, 2020
- Messages
- 775
So, New Bonus [vJASS][LUA] exists and is pretty good.
It is a simple interface to add bonuses with a few utils to give bonuses to items, or timed bonuses etc.
The problem with it is that if you want to add something, you must modify the system, add another "if" to set and get the values.
I have talked a bit with @chopinski and posted this to his "New Bonus System" in a comment, but was interested to see comments on my code.
The reason for having this is to make it easier to add custom bonuses that might only be relevant to your specific map.
For example: My map has "Spell Power" that is an artificial stat that adds some damage/power to abilities (similar to League of Legends).
It doesn't do anything by itself, but (triggered) abilities can read the value of it and add a % of it to damage/healing/power.
Other non-common bonuses are: Life on hit, armor penetration % and flat, execute damage (damage added to attacks based on target missing hp), etc.
I've been thinking of doing a "camouflaged" (League of Legends mechanic) system, and bonuses to detection range could be a bonus you might want to have...
This, in my opinion, makes it easy to give bonuses to anything in a simple and unified API.
Anyways, to the code:
The "basic bonuses"
Tweak to NewBonusUtils so it uses my library instead, basically replaceing 1 dependency and removed " extends NewBonus". 2 tiny changes!
Used by doing:
The "flow" of the code is:
The core registers bonus types in an array and get them based on vjass "typeid", basically.
I was thinking of how to handle the "bonus_type" integers of the NewBonus system and think it works decently.
The API to add a new type is fairly minimal and has mostly the same API and power of NewBonus.
It is possible to add an optional function to the interface for "onSetEvent" or "onAnyBonusEvent" easily.
I don't know how to make it fully compatible with current constants though... Maybe let the constants be variables and set them onInit?
Note: Testmap has most of NewBonus ported, but not 100% of extensions. Saved with version 1.31.
Testmap has added a few effects to a Warden to show off some basics of how this can be used.
Edit 2021-11-07:
Plugins now has optional function for "IsIntegerBonus" that returns false by default.
If true using "add" will R2I the added values, solving issues with adding 0.5 causing it to sometimes leave +1/-1 when it shouldn't.
"Basic Plugin" now feature complete and 100% compatible with NewBonus (I think).
Added new "optional" plugin for: lifesteal, evasion, critical hit using basic critical hit ability and magic resist using ability-based Magic Resist.
I wouldn't use the "optional" plugin because I would've used triggered versions of such things.
It is a simple interface to add bonuses with a few utils to give bonuses to items, or timed bonuses etc.
The problem with it is that if you want to add something, you must modify the system, add another "if" to set and get the values.
I have talked a bit with @chopinski and posted this to his "New Bonus System" in a comment, but was interested to see comments on my code.
The reason for having this is to make it easier to add custom bonuses that might only be relevant to your specific map.
For example: My map has "Spell Power" that is an artificial stat that adds some damage/power to abilities (similar to League of Legends).
It doesn't do anything by itself, but (triggered) abilities can read the value of it and add a % of it to damage/healing/power.
Other non-common bonuses are: Life on hit, armor penetration % and flat, execute damage (damage added to attacks based on target missing hp), etc.
I've been thinking of doing a "camouflaged" (League of Legends mechanic) system, and bonuses to detection range could be a bonus you might want to have...
This, in my opinion, makes it easy to give bonuses to anything in a simple and unified API.
Anyways, to the code:
JASS:
library ExtendableBonusSystem
/* ----------------------- ExtendableBonusSystem v0.1 by ThompZon ----------------------- */
//! novjass
Inspired by chopinski New Bonus system, I wanted a system that you can add your own bonuses
using a simple interface. Hopefully the interface will be simple so it is easy to implement
but also this means that the core can upgrade without impacting the extensions!
Inspired by: chopinski New Bonus system
https://www.hiveworkshop.com/threads/new-bonus-vjass-lua.324058/
jassApi
//! endnovjass
/* -------------------------------------------------------------------------- */
/* System */
/* --------------------------------------------------------------------------
*/
private interface ExtendableBonusPlugin
method IsIntegerBonus takes nothing returns boolean defaults false
method Get takes unit u returns real
method Set takes unit u, real value returns real
endinterface
struct RealAbilityBonus extends ExtendableBonusPlugin
stub method AbilityCode takes nothing returns integer
call BJDebugMsg("RealAbilityBonus missing AbilityCode!")
return -1
endmethod
stub method Field takes nothing returns abilityreallevelfield
call BJDebugMsg("RealAbilityBonus missing Field!")
return null
endmethod
method Set takes unit u, real value returns real
local integer abilCode = AbilityCode()
if GetUnitAbilityLevel(u, abilCode) == 0 then
call UnitAddAbility(u, abilCode)
call UnitMakeAbilityPermanent(u, true, abilCode)
endif
call BlzSetAbilityRealLevelField(BlzGetUnitAbility(u, abilCode), Field(), 0, value)
call IncUnitAbilityLevel(u, abilCode)
call DecUnitAbilityLevel(u, abilCode)
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, abilCode), Field(), 0)
endmethod
method Get takes unit u returns real
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, AbilityCode()), Field(), 0)
endmethod
endstruct
struct IntegerAbilityBonus extends ExtendableBonusPlugin
stub method AbilityCode takes nothing returns integer
call BJDebugMsg("IntegerAbilityBonus missing AbilityCode!")
return -1
endmethod
stub method Field takes nothing returns abilityintegerlevelfield
call BJDebugMsg("IntegerAbilityBonus missing Field!")
return null
endmethod
method Set takes unit u, real value returns real
local integer abilCode = AbilityCode()
if GetUnitAbilityLevel(u, abilCode) == 0 then
call UnitAddAbility(u, abilCode)
call UnitMakeAbilityPermanent(u, true, abilCode)
endif
call BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(u, abilCode), Field(), 0, R2I(value))
call IncUnitAbilityLevel(u, abilCode)
call DecUnitAbilityLevel(u, abilCode)
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, abilCode), Field(), 0))
endmethod
method Get takes unit u returns real
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, AbilityCode()), Field(), 0))
endmethod
method IsIntegerBonus takes nothing returns boolean
return true
endmethod
endstruct
struct ExtendableBonus
private static ExtendableBonusPlugin array registeredBonuses
//private static integer maxTypeId = -1
static method Register takes ExtendableBonusPlugin bonus returns integer
set registeredBonuses[bonus.getType()] = bonus
//set maxTypeId = IMaxBJ(maxTypeId, bonus.getType())
//call BJDebugMsg("maxTypeId=" + I2S(maxTypeId) + ", registedTypeId=" + I2S(bonus.getType()) + ", bonus=" + I2S(bonus))
return bonus.getType()
endmethod
static method GetBonus takes integer typeId returns ExtendableBonusPlugin
return registeredBonuses[typeId]
endmethod
static method Get takes unit u, integer typeId returns real
if (registeredBonuses[typeId] == 0) then
call BJDebugMsg("type is not registered! id=" + I2S(typeId))
return -1.0
else
return registeredBonuses[typeId].Get(u)
endif
endmethod
static method Set takes unit u, integer typeId, real value returns real
if (registeredBonuses[typeId] == 0) then
call BJDebugMsg("type is not registered! id=" + I2S(typeId))
return -1.0
else
//call BJDebugMsg("Setting type=" + I2S(typeId) + " to " + R2S(value))
return registeredBonuses[typeId].Set(u, value)
endif
endmethod
static method Add takes unit u, integer typeId, real value returns real
local ExtendableBonusPlugin currentBonus = GetBonus(typeId)
local real addedValue
if currentBonus.IsIntegerBonus() then
set addedValue = R2I(value)
else
set addedValue = value
endif
call Set(u, typeId, currentBonus.Get(u) + addedValue)
return addedValue
endmethod
endstruct
function GetUnitBonus takes unit u, integer typeId returns real
return ExtendableBonus.Get(u, typeId)
endfunction
function SetUnitBonus takes unit u, integer typeId, real value returns real
return ExtendableBonus.Set(u, typeId, value)
endfunction
function AddUnitBonus takes unit u, integer typeId, real value returns real
return ExtendableBonus.Add(u, typeId, value)
endfunction
function RemoveUnitBonus takes unit u, integer typeId returns nothing
call ExtendableBonus.Set(u, typeId, 0)
endfunction
endlibrary
The "basic bonuses"
JASS:
library ExtendableBonusesBasicBonuses requires ExtendableBonusSystem
/* ----------------------- ExtendableBonusSystemBasics v0.1 by ThompZon ----------------------- */
//! novjass
Inspired by chopinski New Bonus system, I wanted a system that you can add your own bonuses
using a simple interface. Hopefully the interface will be simple so it is easy to implement
but also this means that the core can upgrade without impacting the extensions!
Inspired by: chopinski New Bonus system
https://www.hiveworkshop.com/threads/new-bonus-vjass-lua.324058/
jassApi
//! endnovjass
/* -------------------------------------------------------------------------- */
/* System */
/* --------------------------------------------------------------------------
*/
globals
//The abilities codes for each bonus
//When pasting the abilities over to your map
//their raw code should match the bonus here
private constant integer DAMAGE_ABILITY = 'Z001'
private constant integer ARMOR_ABILITY = 'Z002'
private constant integer STATS_ABILITY = 'Z003'
private constant integer HEALTH_ABILITY = 'Z004'
private constant integer MANA_ABILITY = 'Z005'
private constant integer HEALTHREGEN_ABILITY = 'Z006'
private constant integer MANAREGEN_ABILITY = 'Z007'
private constant integer ATTACKSPEED_ABILITY = 'Z008'
private constant integer MOVEMENTSPEED_ABILITY = 'Z009'
private constant integer SIGHT_RANGE_ABILITY = 'Z00A'
//The abilities fields that are modified. For the sake of readability
private constant abilityintegerlevelfield DAMAGE_FIELD = ABILITY_ILF_ATTACK_BONUS
private constant abilityintegerlevelfield ARMOR_FIELD = ABILITY_ILF_DEFENSE_BONUS_IDEF
private constant abilityintegerlevelfield AGILITY_FIELD = ABILITY_ILF_AGILITY_BONUS
private constant abilityintegerlevelfield STRENGTH_FIELD = ABILITY_ILF_STRENGTH_BONUS_ISTR
private constant abilityintegerlevelfield INTELLIGENCE_FIELD = ABILITY_ILF_INTELLIGENCE_BONUS
private constant abilityintegerlevelfield HEALTH_FIELD = ABILITY_ILF_MAX_LIFE_GAINED
private constant abilityintegerlevelfield MANA_FIELD = ABILITY_ILF_MAX_MANA_GAINED
private constant abilityintegerlevelfield MOVEMENTSPEED_FIELD = ABILITY_ILF_MOVEMENT_SPEED_BONUS
private constant abilityintegerlevelfield SIGHT_RANGE_FIELD = ABILITY_ILF_SIGHT_RANGE_BONUS
private constant abilityreallevelfield HEALTHREGEN_FIELD = ABILITY_RLF_AMOUNT_OF_HIT_POINTS_REGENERATED
private constant abilityreallevelfield MANAREGEN_FIELD = ABILITY_RLF_AMOUNT_REGENERATED
private constant abilityreallevelfield ATTACKSPEED_FIELD = ABILITY_RLF_ATTACK_SPEED_INCREASE_ISX1
//These are not required by the system, but they were the way to interact with NewBonus by chopinski
//One could use these or use "BonusDamage.typeid"
integer BONUS_DAMAGE
integer BONUS_ARMOR
integer BONUS_AGILITY
integer BONUS_STRENGTH
integer BONUS_INTELLIGENCE
integer BONUS_HEALTH
integer BONUS_MANA
integer BONUS_MOVEMENT_SPEED
integer BONUS_SIGHT_RANGE
integer BONUS_HEALTH_REGEN
integer BONUS_MANA_REGEN
integer BONUS_ATTACK_SPEED
endglobals
//===== Integer Ability Based =====
struct BonusDamage extends IntegerAbilityBonus
method AbilityCode takes nothing returns integer
return DAMAGE_ABILITY
endmethod
method Field takes nothing returns abilityintegerlevelfield
return DAMAGE_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_DAMAGE = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
struct BonusArmor extends IntegerAbilityBonus
method AbilityCode takes nothing returns integer
return ARMOR_ABILITY
endmethod
method Field takes nothing returns abilityintegerlevelfield
return ARMOR_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_ARMOR = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
struct BonusHealth extends IntegerAbilityBonus
method AbilityCode takes nothing returns integer
return HEALTH_ABILITY
endmethod
method Field takes nothing returns abilityintegerlevelfield
return HEALTH_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_HEALTH = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
struct BonusMana extends IntegerAbilityBonus
method AbilityCode takes nothing returns integer
return MANA_ABILITY
endmethod
method Field takes nothing returns abilityintegerlevelfield
return MANA_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_MANA = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
struct BonusMovementSpeed extends IntegerAbilityBonus
method AbilityCode takes nothing returns integer
return MOVEMENTSPEED_ABILITY
endmethod
method Field takes nothing returns abilityintegerlevelfield
return MOVEMENTSPEED_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_MOVEMENT_SPEED = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
struct BonusSightRange extends IntegerAbilityBonus
method AbilityCode takes nothing returns integer
return SIGHT_RANGE_ABILITY
endmethod
method Field takes nothing returns abilityintegerlevelfield
return SIGHT_RANGE_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_SIGHT_RANGE = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
//Hero stats
struct BonusAgility extends IntegerAbilityBonus
method AbilityCode takes nothing returns integer
return STATS_ABILITY
endmethod
method Field takes nothing returns abilityintegerlevelfield
return AGILITY_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_AGILITY = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
struct BonusStrength extends IntegerAbilityBonus
method AbilityCode takes nothing returns integer
return STATS_ABILITY
endmethod
method Field takes nothing returns abilityintegerlevelfield
return STRENGTH_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_STRENGTH = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
struct BonusIntelligence extends IntegerAbilityBonus
method AbilityCode takes nothing returns integer
return STATS_ABILITY
endmethod
method Field takes nothing returns abilityintegerlevelfield
return INTELLIGENCE_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_INTELLIGENCE = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
//===== Real Ability Based =====
struct BonusAttackSpeed extends RealAbilityBonus
method AbilityCode takes nothing returns integer
return ATTACKSPEED_ABILITY
endmethod
method Field takes nothing returns abilityreallevelfield
return ATTACKSPEED_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_ATTACK_SPEED = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
struct BonusHealthRegen extends RealAbilityBonus
method AbilityCode takes nothing returns integer
return HEALTHREGEN_ABILITY
endmethod
method Field takes nothing returns abilityreallevelfield
return HEALTHREGEN_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_HEALTH_REGEN = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
struct BonusManaRegen extends RealAbilityBonus
method AbilityCode takes nothing returns integer
return MANAREGEN_ABILITY
endmethod
method Field takes nothing returns abilityreallevelfield
return MANAREGEN_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_MANA_REGEN = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
endlibrary
JASS:
library ExtendableBonusesBasicAdditionalBonuses requires ExtendableBonusSystem
/*
These are the non-basic stuff that also are included in NewBonus that I'd prefer to use a triggered approach instead of ability-based approach.
Import this if you don't want to use triggered: crit, life-steal, magic resist and evasion.
*/
globals
//The abilities codes for each bonus
//When pasting the abilities over to your map
//their raw code should match the bonus here
private constant integer MAGIC_RESISTANCE_ABILITY = 'Z00B'
private constant integer CRITICAL_STRIKE_ABILITY = 'Z00C'
private constant integer EVASION_ABILITY = 'Z00D'
private constant integer LIFE_STEAL_ABILITY = 'Z00E'
//The abilities fields that are modified. For the sake of readability
private constant abilityreallevelfield MAGIC_RESISTANCE_FIELD = ABILITY_RLF_DAMAGE_REDUCTION_ISR2
private constant abilityreallevelfield CRITICAL_CHANCE_FIELD = ABILITY_RLF_CHANCE_TO_CRITICAL_STRIKE
private constant abilityreallevelfield CRITICAL_DAMAGE_FIELD = ABILITY_RLF_DAMAGE_MULTIPLIER_OCR2
private constant abilityreallevelfield EVASION_FIELD = ABILITY_RLF_CHANCE_TO_EVADE_EEV1
private constant abilityreallevelfield LIFE_STEAL_FIELD = ABILITY_RLF_LIFE_STOLEN_PER_ATTACK
integer BONUS_MAGIC_RESISTANCE
integer BONUS_EVASION_CHANCE
integer BONUS_CRITICAL_DAMAGE
integer BONUS_CRITICAL_CHANCE
integer BONUS_LIFE_STEAL
integer BONUS_MISS_CHANCE
/*
Stuff from NewBonus that have not been migrated:
integer BONUS_SPELL_POWER_FLAT
integer BONUS_SPELL_POWER_PERCENT
integer BONUS_SPELL_VAMP
integer BONUS_COOLDOWN_REDUCTION
integer BONUS_COOLDOWN_REDUCTION_FLAT
integer BONUS_COOLDOWN_OFFSET
*/
endglobals
//===== Real Ability Based =====
struct BonusMagicResistance extends RealAbilityBonus
method AbilityCode takes nothing returns integer
return MAGIC_RESISTANCE_ABILITY
endmethod
method Field takes nothing returns abilityreallevelfield
return MAGIC_RESISTANCE_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_MAGIC_RESISTANCE = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
struct BonusCritChance extends RealAbilityBonus
method AbilityCode takes nothing returns integer
return CRITICAL_STRIKE_ABILITY
endmethod
method Field takes nothing returns abilityreallevelfield
return CRITICAL_CHANCE_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_CRITICAL_CHANCE = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
struct BonusCritDamage extends RealAbilityBonus
method AbilityCode takes nothing returns integer
return CRITICAL_STRIKE_ABILITY
endmethod
method Field takes nothing returns abilityreallevelfield
return CRITICAL_DAMAGE_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_CRITICAL_DAMAGE = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
struct BonusEvasion extends RealAbilityBonus
method AbilityCode takes nothing returns integer
return EVASION_ABILITY
endmethod
method Field takes nothing returns abilityreallevelfield
return EVASION_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_EVASION_CHANCE = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
struct BonusLifeSteal extends RealAbilityBonus
method AbilityCode takes nothing returns integer
return LIFE_STEAL_ABILITY
endmethod
method Field takes nothing returns abilityreallevelfield
return LIFE_STEAL_FIELD
endmethod
static method onInit takes nothing returns nothing
set BONUS_LIFE_STEAL = ExtendableBonus.Register(thistype.allocate())
endmethod
endstruct
endlibrary
Tweak to NewBonusUtils so it uses my library instead, basically replaceing 1 dependency and removed " extends NewBonus". 2 tiny changes!
JASS:
library NewBonusUtils requires ExtendableBonusSystem, RegisterPlayerUnitEvent
/* ----------------------- NewBonusUtils v2.2 by Chopinski ----------------------- */
//! novjass
Required Library: RegisterPlayerUnitEvent -> www.hiveworkshop.com/threads/snippet-registerplayerunitevent.203338/
API:
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())
//! endnovjass
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* System */
/* --------------------------------------------------------------------------
*/
private struct NewBonusUtils
static timer timer = CreateTimer()
static integer key = -1
static thistype array array
static integer k = -1
static thistype array items
unit unit
item item
real ticks
integer type
integer buff
real amount
boolean link
method remove takes integer i, boolean isItem returns integer
call AddUnitBonus(unit, type, -amount)
if isItem then
set items[i] = items[k]
set k = k - 1
else
set array[i] = array[key]
set key = key - 1
if key == -1 then
call PauseTimer(timer)
endif
endif
set unit = null
set item = null
call deallocate()
return i - 1
endmethod
static method removeBonusTypeForItem takes item itm, integer bonusToRemove returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > k
set this = items[i]
if item == itm and type == bonusToRemove then
set i = remove(i, true)
endif
set i = i + 1
endloop
endmethod
static method onDrop takes nothing returns nothing
local item itm = GetManipulatedItem()
local integer i = 0
local thistype this
loop
exitwhen i > k
set this = items[i]
if item == itm then
set i = remove(i, true)
endif
set i = i + 1
endloop
endmethod
static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > key
set this = array[i]
if link then
set ticks = ticks - 1
if ticks <= 0 then
set i = remove(i, false)
endif
else
if GetUnitAbilityLevel(unit, buff) == 0 then
set i = remove(i, false)
endif
endif
set i = i + 1
endloop
endmethod
static method linkTimed takes unit u, integer bonus_type, real amount, real duration, boolean link returns nothing
local thistype this = thistype.allocate()
set this.unit = u
set this.type = bonus_type
set this.ticks = duration/0.03125000
set this.link = link
set this.amount = AddUnitBonus(u, bonus_type, amount)
set key = key + 1
set array[key] = this
if key == 0 then
call TimerStart(timer, 0.03125000, true, function thistype.onPeriod)
endif
endmethod
static method linkBuff takes unit u, integer bonus_type, real amount, integer buffId, boolean link returns nothing
local thistype this = thistype.allocate()
set this.unit = u
set this.type = bonus_type
set this.buff = buffId
set this.link = link
set this.amount = AddUnitBonus(u, bonus_type, amount)
set key = key + 1
set array[key] = this
if key == 0 then
call TimerStart(timer, 0.03125000, true, function thistype.onPeriod)
endif
endmethod
static method linkItem takes unit u, integer bonus_type, real amount, item i returns nothing
local thistype this = thistype.allocate()
set this.unit = u
set this.item = i
set this.type = bonus_type
set this.amount = AddUnitBonus(u, bonus_type, amount)
set k = k + 1
set items[k] = this
endmethod
static method copy takes unit source, unit target returns nothing
local integer i = 1
loop
exitwhen i > 17
if GetUnitBonus(source, i) != 0 then
call AddUnitBonus(target, i, GetUnitBonus(source, i))
endif
set i = i + 1
endloop
endmethod
static method mirror takes unit source, unit target returns nothing
local integer i = 1
loop
exitwhen i > 17
call SetUnitBonus(target, i, GetUnitBonus(source, i))
set i = i + 1
endloop
endmethod
static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DROP_ITEM, function thistype.onDrop)
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* --------------------------------------------------------------------------
*/
function AddUnitBonusTimed takes unit u, integer bonus_type, real amount, real duration returns nothing
call NewBonusUtils.linkTimed(u, bonus_type, amount, duration, true)
endfunction
function LinkBonusToBuff takes unit u, integer bonus_type, real amount, integer buffId returns nothing
call NewBonusUtils.linkBuff(u, bonus_type, amount, buffId, false)
endfunction
function LinkBonusToItem takes unit u, integer bonus_type, real amount, item i returns nothing
call NewBonusUtils.linkItem(u, bonus_type, amount, i)
endfunction
function RemoveSpecificBonusFromItem takes item i, integer bonus_type returns nothing
call NewBonusUtils.removeBonusTypeForItem(i, bonus_type)
endfunction
function UnitCopyBonuses takes unit source, unit target returns nothing
call NewBonusUtils.copy(source, target)
endfunction
function UnitMirrorBonuses takes unit source, unit target returns nothing
call NewBonusUtils.mirror(source, target)
endfunction
endlibrary
Used by doing:
JASS:
//Note: BonusDamage is a struct in ExtendableBonusesBasicBonuses
call AddUnitBonus(GetTriggerUnit(), BonusDamage.typeid, 3.0) // +3 damage
call AddUnitBonus(GetTriggerUnit(), BonusAttackSpeed.typeid, 0.25) //+25% attack speed
The "flow" of the code is:
The core registers bonus types in an array and get them based on vjass "typeid", basically.
I was thinking of how to handle the "bonus_type" integers of the NewBonus system and think it works decently.
The API to add a new type is fairly minimal and has mostly the same API and power of NewBonus.
It is possible to add an optional function to the interface for "onSetEvent" or "onAnyBonusEvent" easily.
I don't know how to make it fully compatible with current constants though... Maybe let the constants be variables and set them onInit?
Note: Testmap has most of NewBonus ported, but not 100% of extensions. Saved with version 1.31.
Testmap has added a few effects to a Warden to show off some basics of how this can be used.
Edit 2021-11-07:
Plugins now has optional function for "IsIntegerBonus" that returns false by default.
If true using "add" will R2I the added values, solving issues with adding 0.5 causing it to sometimes leave +1/-1 when it shouldn't.
"Basic Plugin" now feature complete and 100% compatible with NewBonus (I think).
Added new "optional" plugin for: lifesteal, evasion, critical hit using basic critical hit ability and magic resist using ability-based Magic Resist.
I wouldn't use the "optional" plugin because I would've used triggered versions of such things.
Attachments
Last edited: