• Check out the results of the Techtree Contest #19!
  • 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.
  • Create a void inspired texture for Warcraft 3 and enter Hive's 34th Texturing Contest: Void! Click here to enter!
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!

Item abilities that stack

Status
Not open for further replies.
Level 15
Joined
Aug 7, 2013
Messages
1,342
Hi,

Does anyone have a list of all the item abilities which stack, so for example I read that for health, if you have an ability that adds 100 health, then:

JASS:
call UnitAddAbility(u, 'healthAbil')
call UnitAddAbility(u, 'healthAbil')
call UnitAddAbility(u, 'healthAbil')

would increase the unit's health by 300, rather than having to do the binary count off for something like damage.

What about attack speed? Mana? Spell resistance? etc.
 

I've been pointed to that resource many times, but the code is too general and high level for me to understand.

So I guess we are stuck with a binary count off system as it's called. Now what is the algorithm to calculate this? Here is my idea in JASS/pseudocode, again I don't have any maths or smarts so it's going to be linear time at best.

I suppose also I can just call log_2(amount), but not sure if that function exists (assuming this log only returns integer values, so log_2(70) = 6, but log_2(5) = 2).

JASS:
integer array binaryCounts = [1, 2, 4, 6, 8, 16, 32, 64] //len of 8
integer array attackSpeedAbil [as1, as2, as3, as4, as5, as6, as7, as8]

//returns the highest power of 2 which is less than
//or equal to the amount
function binaryIndex takes integer amount returns integer
  for i in range 0, 8:
    if 2^i > amount:
       return i - 1
endfunction

//sets the corresponding sequences of attack speed
function setAttackSpeed takes integer amount returns nothing
  set integer index = 0 //storing the binary index
  //we need to remove them all, otherwise there's no way to go from attack speed 15 to 16 to 17
  //as powers would be [1, 6, 8] --> [1, 2, 6, 8] --> [1, 16]
  //so we would need to calculate which abilities not to remove and which to add, not going to do that!
  for i in range 0,8: call UnitRemoveAbility(unit, attackSpeedAbil[i])
  loop
    exitwhen amount == 0
    set index =  binaryIndex(amount)
    call UnitAddAbility(unit, attackSpeedAbil[index])
    set amount = amount - (2 ^ index)
  endloop
endfunction

So it's not the most efficient algorithm and it's a bit ugly/brute force, but it will work right? Does anyone have a better way to do this, that doesn't require any additional overhead/smarts?
 
I've been pointed to that resource many times, but the code is too general and high level for me to understand.

You can't just use it? It's a library.

So I guess we are stuck with a binary count off system as it's called. Now what is the algorithm to calculate this? Here is my idea in JASS/pseudocode, again I don't have any maths or smarts so it's going to be linear time at best.

Binary methods like this should in theory be O(lgn) for attack speed of n. Anyway, algorithms rarely have any significance in jass due to the extremely slow nature of the interpreter. Setting, getting, and calling etc are vastly more expensive than you might think.

JASS:
integer array binaryCounts = [1, 2, 4, 6, 8, 16, 32, 64] //len of 8
integer array attackSpeedAbil [as1, as2, as3, as4, as5, as6, as7, as8]

//returns the highest power of 2 which is less than
//or equal to the amount
function binaryIndex takes integer amount returns integer
  for i in range 0, 8:
    if 2^i > amount:
       return i - 1
endfunction

//sets the corresponding sequences of attack speed
function setAttackSpeed takes integer amount returns nothing
  set integer index = 0 //storing the binary index
  //we need to remove them all, otherwise there's no way to go from attack speed 15 to 16 to 17
  //as powers would be [1, 6, 8] --> [1, 2, 6, 8] --> [1, 16]
  //so we would need to calculate which abilities not to remove and which to add, not going to do that!
  for i in range 0,8: call UnitRemoveAbility(unit, attackSpeedAbil[i])
  loop
    exitwhen amount == 0
    set index =  binaryIndex(amount)
    call UnitAddAbility(unit, attackSpeedAbil[index])
    set amount = amount - (2 ^ index)
  endloop
endfunction

Where did you get 6 as a power of 2? :) 2^(8-1) = 128, that should have been your first hint.

So it's not the most efficient algorithm and it's a bit ugly/brute force, but it will work right? Does anyone have a better way to do this, that doesn't require any additional overhead/smarts?

http://en.wikipedia.org/wiki/Dynamic_programming will help you with your binaryIndex function since Pow is expensive.

Try this.

JASS:
function binaryIndex takes integer amt returns integer
    local integer i = 1
    if amt<1 then
        return 0
    endif
    loop
        set i = i * 2
        if i > amt then
            return i/2
        endif
        debug if i < -1 then //Overflow
            debug //message
            debug return -1
       debug endif
    endloop
endfunction
 
You can't just use it? It's a library.



Binary methods like this should in theory be O(lgn) for attack speed of n. Anyway, algorithms rarely have any significance in jass due to the extremely slow nature of the interpreter. Setting, getting, and calling etc are vastly more expensive than you might think.

JASS:
function binaryIndex takes integer amt returns integer
    local integer i = 1
    if amt<1 then
        return 0
    endif
    loop
        set i = i * 2
        if i > amt then
            return i/2
        endif
        debug if i < -1 then //Overflow
            debug //message
            debug return -1
       debug endif
    endloop
endfunction

I'm still learning JASS, and would rather not copy paste libraries to solve my problems (an exception would be save/load system, since that's mostly smarts/maths), since then I won't learn much. Also the generality of that library comes at a cost, so it would be more overhead/power than I actually need. If the author proved that their library was the fastest way to set arbitrary values of these stats, then in a future project I would of course use it.

Well I actually just made my own power function (linear time). I read that the native Pow is slow because it's a generalized power function. The logarithmic time algorithm for power requires me to represent the input as bits, but since I will not be going higher than a power of say 6-7, then I don't need that generality.

So it is better to implement power into the binaryIndex function rather than make it a separate one (e.g. myPower), as this additional function call will be slow?
 
I'm still learning JASS, and would rather not copy paste libraries to solve my problems (an exception would be save/load system, since that's mostly smarts/maths), since then I won't learn much. Also the generality of that library comes at a cost, so it would be more overhead/power than I actually need. If the author proved that their library was the fastest way to set arbitrary values of these stats, then in a future project I would of course use it.

Well I actually just made my own power function (linear time). I read that the native Pow is slow because it's a generalized power function. The logarithmic time algorithm for power requires me to represent the input as bits, but since I will not be going higher than a power of say 6-7, then I don't need that generality.

So it is better to implement power into the binaryIndex function rather than make it a separate one (e.g. myPower), as this additional function call will be slow?

In the dynamic programming case (my example) you don't have to do either one. The result is calculated in ideal (lgn) time without without calling external functions or calling Pow either.

In the case of your custom pow function vs Pow beyond just this example, I suggest doing the test yourself and finding out if it's faster. My guess is your implementation will be slower due to the nature of native calling.
 
It seems that Bonus Mod is actually lacking in stats, because there is no BONUS_SPELL_RESISTANCE.

I tried using the spell resist based on rune bracers, but it does not stack.

I then went to Elune's grace--this stacks, but it takes up a spot on the command card, so it's a bit of an annoyance and I'd almost be willing to go back to 100 levels of resist magic rather than sacrifice a spot on the command card.

Are there any other options before going the naive way? This method worked for mana and attack speed, but not for spell resistance since I'd be forced to give up command card realty.

On second thoughts though, there really is no point to having an arbitrary high spell resistance--anything passed 100% is useless. So I am leaning back towards 100 levels, even if it just means I get to keep an extra command card slot open.
 
A few things:

You can hide command card abilities using a trick with spell books ( http://www.wc3c.net/showthread.php?t=81742 )

Ususally magic resist (for example in LoL) is handled similar to armor, so that scaling increases "relative hit points" instead of a direct reduction percentage.

Here's how you can do MR with a damage detection system. Sort of sloppy, sorry, I don't have the editor open:

JASS:
// Using StructuredDD, DamageType
scope applyBonusResistance initializer i
    globals
        private constant real MAGIC_RESIST=68.3 //arbitrary MR value for unit x
    endglobals
    
    private function h takes nothing returns boolean
        local real mult
        local unit tU
        if DamageType.get()==DamageType.SPELLS then
            set tU=GetTriggerUnit()
            set mult = 100. / (100. + MAGIC_RESIST)
            set mult = 1. - mult
            call SetUnitState(tU,UNIT_STATE_LIFE,GetUnitState(tU,UNIT_STATE_LIFE)+GetEventDamage()*mult)
        endif
        return false
    endfunction
    
    private function i takes nothing returns nothing
        call StructredDD.addHandler(function h)
    endfunction
endscope
 
Ususally magic resist (for example in LoL) is handled similar to armor, so that scaling increases "relative hit points" instead of a direct reduction percentage.

Hm i dont know about lol, but in Wc3 im pretty sure its always just percental reduction (that -33% dmg item, the abilitiy of archers, etc.) of the spells damage.

One important difference between the two is, that with percental reduction you can reach 100% magic resistance, with what Cokemonkey suggested you need an infinity amount of "magic armor" to completely block the spelldamage.
Just use whatever fits your map best :)
 
Status
Not open for further replies.
Back
Top