HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

[vJASS] what causes this?

01-07-2011, 12:38 PM#1
Idontneedaname
I've made my first approach to vJass.
General idea of the spell: All units around the target lose their armor, the target gets all of it.
Collapse JASS:
function Trig_Disbalance_Harmony_Actions takes nothing returns nothing
    local unit caster = GetSpellAbilityUnit()
    local unit target = GetSpellTargetUnit()
    local unit first
    local location loc = GetUnitLoc(target)
    local group g = CreateGroup()
    local real r = 0.
    local real arm
    local timer t = CreateTimer()
    local trigger trig
    local integer i = 0
    
    call GroupEnumUnitsInRangeOfLoc(g, loc, 400., null)
    call GroupRemoveUnit(g, target)
    // call DisplayTextToPlayer(Player(0), 0.00, 0.00, R2S(GetUnitBaseArmor(target)))
    loop
        set first = FirstOfGroup(g)
        exitwhen first == null
        if IsUnitAlly(first, GetOwningPlayer(caster)) == false and IsUnitType(first, UNIT_TYPE_STRUCTURE) != true then // and not ancient
            set arm = GetUnitBaseArmor(first)
            if arm < 90000. then //invul
                set first:Armor = first:Armor - arm
                // call DisplayTextToPlayer(Player(0), 0.00, 0.00, "Transferring "+R2S(arm)+" from "+GetUnitName(first)+" to the "+GetUnitName(target)+".")
                set r = r + arm
                set i = i + 1
                set DB_unit[i] = first
                set DB_unit_stolen[i] = arm
            endif
        endif
        call GroupRemoveUnit(g, first)
        set first = null
    endloop
    call DestroyGroup(g)
    // call DisplayTextToPlayer(Player(0), 0.00, 0.00, R2S(target:Armor)+" + "+R2S(r)+" = "+R2S(target:Armor + r))
    set target:Armor = target:Armor + r
    // call DisplayTextToPlayer(Player(0), 0.00, 0.00, R2S(GetUnitBaseArmor(target)))
    set DB_target = target
    set DB_target_given = r
    set DB_caster = caster
    set DB_caster_dmg = 100.*DB_GetTime(GetUnitAbilityLevel(caster, 'A002'))
endfunction

I'm using UnitProperties. I've recoded it a bit to work with AutoIndex and it _might_ have gotten broken in the process. I've made several test triggers to check that, but it turned out fine. It seems that it's this trigger.
The problem is that this spell works only on the first unit around (it loses it's 10 armor), the second one loses 14 while it has only 5 before the spell. The target doesn't gain anything.
I've commented the lines which should only tell me what the spell is doing at the moment. However, if I cast the spell with those lines uncommented, it TELLS me the correct values, while it doesn't apply correct ones. For those who want it, here's the new UnitProperties (I've marked my changes):
UnitProperties

The only thing I did was replacing the u:Id with GetUnitId(u) from AutoIndex. AutoIndex remained unchanged.
Collapse JASS:
//*******************************************************************************
//*                              Unit Properties                                *
//*                                    v.D                                      *
//*                                                                             *
//*                                By: Cassiel                                  *
//*******************************************************************************

//*******************************************************************************
// The ObjectMerger command will automatically generate all the necessary
// abilities for you using the external Lua script, which should be placed in the
// same directory as the map you're installing to. It only needs to be run once.
//
////! external ObjectMerger UnitPropertiesGenerator.lua

library UnitProperties initializer Init requires AutoIndex
    globals

    //*******************************************************************************
    // Max:     Specifies the highest power of 2 the property ability sets use. A Max
    //          of 8 means the system supports values of +/- 511. To change values
    //          simply reset the Max variable in the Lua script.
    //
    // Offset:  Specifies the difference between the + and - abilities for any
    //          property.
    //
        private constant integer MAX    = 8
        private constant integer OFFSET = 512

    //*******************************************************************************
    // These globals reference the starting abilities for properties that use binary
    // counting. Changing them means changing the rawcodes of all the abilities the
    // system uses for that property. This list includes all properties that stack
    // linearly and are binary countable.
    //
        private constant integer AGI                = 'AG+a'
        private constant integer INT                = 'IN+a'
        private constant integer STR                = 'ST+a'
        private constant integer ATTACK_SPEED       = 'AT+a'
        private constant integer ARMOR              = 'AR+a'
        private constant integer DAMAGE             = 'DA+a'
        private constant integer LIFE_REGEN         = 'LI+a'
        private constant integer MANA_REGEN_PERCENT = 'MR+a'
        
    //*******************************************************************************
    // These globals reference the starting abilities for properties that use the
    // life/mana bug.
    //
        private constant integer MAX_LIFE = 'Lif+'
        private constant integer MAX_MANA = 'Man+'

    // ******************************************************************************
    // Timer:           Used for any periodic properties that you want/need to
    //                  trigger. Static mana gain (as opposed to percentage mana gain)
    //                  is included as an example.
    //
    // pow2:            Powers of 2 up to 30 are calculated and stored in this array at
    //                  Init.
    //
    // UnitProperties:  This array stores the properties struct for each unit that has
    //                  it. It and the properties struct are public so that advanced
    //                  users have the option of manipulating properties directly
    //                  instead of relying on the UnitGet/Set functions.
    //
        private timer         Timer          = CreateTimer()
        private integer array Pow2
        properties array      UnitProperties
    endglobals

    struct properties
    // ******************************************************************************
    // These are the standard properties you would want to manipulate on a given unit
    //
        real Agi              = 0
        real Int              = 0
        real Str              = 0
        real LifeRegen        = 0
        real ManaRegen        = 0
        real ManaRegenPercent = 0
        real Armor            = 0
        real Damage           = 0
        real AttackSpeed      = 0
        real MoveSpeed
        
    // ******************************************************************************
    // These properties are used by the Evasion module, which gives fully dynamic
    // control over a unit's chance to evade incoming or miss on outgoing attacks.
    //
        unit unit
        real AttackEvasion = 0
        real AttackMiss    = 0
        
    // ******************************************************************************
    // These are examples of additional properties which would require other systems
    // to take advantage of.
    //
        //real AttackCritical = 0
        //real SpellEvasion   = 0
        //real SpellMiss      = 0
        //real SpellCritical  = 0

    // ******************************************************************************
    // JASS doesn't handle decimal values very well. 1. + .05 = 1.049999952, and
    // 1. + .05 - .05 != 1. Thus it is necessary to store the values without decimals
    // and then convert them when they they are retrieved.
    //
        //real ExpRate    = 100
        //real BountyRate = 100

        static method create takes unit u returns properties
            local properties this = properties.allocate()
            set .unit = u
            // You may want to use GetUnitDefaultMoveSpeed here, but I have seen
            // some bugs with it.
            set .MoveSpeed = GetUnitMoveSpeed(u)
            return this
        endmethod
        
        method onDestroy takes nothing returns nothing
            set UnitProperties[GetUnitId(.unit)] = 0
            set .unit = null
        endmethod
    endstruct

    // ******************************************************************************
    // These functions allow you to retrieve the handle index of a unit. Other
    // methods of indexing units, like UnitUserData and HAIL, would also work. This
    // method is only viable if you correctly dispose of used handles, so if your
    // map suffers from inflated handle indices you should either change
    // the "UnitProperties" array above to "UnitProperties[verybignumber]", or use a
    // different system. A UnitUserData system is recommended as a replacement
    // regardless.
    //
    // The Id wrapper allows you to retrieve a unit's Id as with:
    //
    // unit:Id
    
    // deleted. ~Idontneedaname@

    // ******************************************************************************
    // Create or manipulate a set of properties for a given unit.
    //
    function CreateUnitProperties takes unit u returns nothing
        local integer id = GetUnitId(u)
        if UnitProperties[id] == 0 then
            set UnitProperties[id] = properties.create(u)
        endif
    endfunction

    function GetUnitProperties takes unit u returns properties
        return UnitProperties[GetUnitId(u)]
    endfunction
    
    function DestroyUnitProperties takes unit u returns nothing
        local integer id = GetUnitId(u)
        if UnitProperties[id] != 0 then
            call properties.destroy(UnitProperties[id])
        endif
    endfunction

    //*******************************************************************************
    // These are the custom functions that allow you to manipulate specific
    // properties. For each property, the macros generate a UnitSet, UnitModify and
    // UnitGet function.
    //
    // UnitSetAgi(u, 10):      This would set a unit's bonus Agility to 10.
    //
    // UnitModifyAgi(u, 10):   This would add 10 to a unit's bonus Agility. A
    //                         negative number could be used to subtract.
    //
    // UnitGetAgi(u):          This would return a unit's current Agi bonus.
    //
    // The OperatorWrappers library offers a different interface for those who are
    // comfortable with vJASS. More details are available at the top of the library.
    //
    function UnitModifyMoveSpeed takes unit u, real amount returns nothing
        local properties p = UnitProperties[GetUnitId(u)]
        set p.MoveSpeed = p.MoveSpeed + R2I(amount)
        call SetUnitMoveSpeed(u, p.MoveSpeed)
    endfunction

    function UnitSetMoveSpeed takes unit u, real amount returns nothing
        local properties p = UnitProperties[GetUnitId(u)]
        set p.MoveSpeed = R2I(amount)
        call SetUnitMoveSpeed(u, p.MoveSpeed)
    endfunction

    //There's already a native for this, but for the sake of completeness:
    function UnitGetMoveSpeed takes unit u returns real
        return UnitProperties[GetUnitId(u)].MoveSpeed
    endfunction

    // ******************************************************************************
    // Periodic properties, like static mana regeneration.
    //
    //! textmacro UnitSetPeriodic takes member
    globals
        private group $member$Group = CreateGroup()
    endglobals
    function UnitModify$member$ takes unit u, real amount returns nothing
        local properties p = UnitProperties[GetUnitId(u)]
        set p.$member$ = p.$member$ + amount
        if p.$member$ != 0 then
            call GroupAddUnit($member$Group, u)
        else
            call GroupRemoveUnit($member$Group, u)
        endif
    endfunction

    function UnitSet$member$ takes unit u, real amount returns nothing
        local properties p = UnitProperties[GetUnitId(u)]
        set p.$member$ = amount
        if amount != 0 then
            call GroupAddUnit($member$Group, u)
        else
            call GroupRemoveUnit($member$Group, u)
        endif
    endfunction

    function UnitGet$member$ takes unit u returns real
        return UnitProperties[GetUnitId(u)].$member$
    endfunction
    //! endtextmacro
    //! runtextmacro UnitSetPeriodic("ManaRegen")

    // ******************************************************************************
    // Triggered properties like Spell Crits and Spell Evasion use these macros.
    //
    //! textmacro UnitSetProperty takes member
    function UnitModify$member$ takes unit u, real amount returns nothing
        local properties p = UnitProperties[GetUnitId(u)]
        set p.$member$ = p.$member$ + R2I(amount)
    endfunction

    function UnitSet$member$ takes unit u, real amount returns nothing
        set UnitProperties[GetUnitId(u)].$member$ = R2I(amount)
    endfunction

    function UnitGet$member$ takes unit u returns real
        return UnitProperties[GetUnitId(u)].$member$
    endfunction
    //! endtextmacro
    //! runtextmacro UnitSetProperty("AttackEvasion")
    //! runtextmacro UnitSetProperty("AttackMiss")
    ////! runtextmacro UnitSetProperty("AttackCritical")
    ////! runtextmacro UnitSetProperty("SpellCritical")
    ////! runtextmacro UnitSetProperty("SpellEvasion")
    ////! runtextmacro UnitSetProperty("SpellMiss")
    ////! runtextmacro UnitSetProperty("SpellResistance")
    ////! runtextmacro UnitSetProperty("SpellReflection")

    //! textmacro UnitSetPercentageProperty takes member
    function UnitModify$member$ takes unit u, real amount returns nothing
        local properties p = UnitProperties[GetUnitId(u)]
        set p.$member$ = p.$member$ + R2I(amount)
    endfunction

    function UnitSet$member$ takes unit u, real amount returns nothing
        set UnitProperties[GetUnitId(u)].$member$ = R2I(amount)
    endfunction

    function UnitGet$member$ takes unit u returns real
        return UnitProperties[GetUnitId(u)].$member$
    endfunction
    //! endtextmacro
    ////! runtextmacro UnitSetPercentageProperty("SpellPower")
    ////! runtextmacro UnitSetPercentageProperty("ExpRate")
    ////! runtextmacro UnitSetPercentageProperty("BountyRate")
    ////! runtextmacro UnitSetPercentageProperty("BloodRate")

    // ******************************************************************************
    // Properties that are modified by using a binary count system. This includes
    // stats, armor, damage etc.
    //
    //! textmacro UnitSetBinary takes member, MEMBER
    function UnitModify$member$ takes unit u, real amount returns nothing 
        local properties p = GetUnitProperties(u)
        local real       r = p.$member$
        local integer    i = 1
        local integer    e
        local integer    a
        set p.$member$ = p.$member$ + R2I(amount)
        set amount = R2I(p.$member$)
        loop
            exitwhen i > 1
            if amount >= 0 and r >= 0. then
                set e = $MEMBER$
                set r = amount
            elseif amount <= 0 and r <= 0. then
                set e = $MEMBER$ + OFFSET
                set r = -amount
            elseif amount <= 0 and r >= 0. then
                set e = $MEMBER$
                set r = 0.
                set i = 0
            elseif amount >= 0 and r <= 0. then
                set e = $MEMBER$ + OFFSET
                set r = 0.
                set i = 0
            endif
            set a = MAX
            loop
                exitwhen a < 0
                if r >= Pow2[a] then
                    call UnitAddAbility(u, e + a)
                    set r = r - Pow2[a]
                else
                    call UnitRemoveAbility(u, e + a)
                endif
                set a = a - 1
            endloop
            set i = i + 1
        endloop
    endfunction

    function UnitSet$member$ takes unit u, real amount returns nothing 
        local properties p = GetUnitProperties(u)
        local real       r = p.$member$
        local integer    i = 1
        local integer    e
        local integer    a
        set p.$member$ = R2I(amount)
        set amount     = R2I(p.$member$)
        loop
            exitwhen i > 1
            if amount >= 0 and r >= 0. then
                set e = $MEMBER$
                set r = amount
            elseif amount <= 0 and r <= 0. then
                set e = $MEMBER$ + OFFSET
                set r = -amount
            elseif amount <= 0 and r >= 0. then
                set e = $MEMBER$
                set r = 0.
                set i = 0
            elseif amount >= 0 and r <= 0. then
                set e = $MEMBER$ + OFFSET
                set r = 0.
                set i = 0
            endif
            set a = MAX
            loop
                exitwhen a < 0
                if r >= Pow2[a] then
                    call UnitAddAbility(u, e + a)
                    set r = r - Pow2[a]
                else
                    call UnitRemoveAbility(u, e + a)
                endif
                set a = a - 1
            endloop
            set i = i + 1
        endloop
    endfunction

    function UnitGet$member$ takes unit u returns real
        return UnitProperties[GetUnitId(u)].$member$
    endfunction

    struct $member$ extends array
        static method operator [] takes unit u returns real
            return UnitProperties[GetUnitId(u)].$member$
        endmethod
        
        static method operator []= takes unit u, real r returns nothing
            call UnitSet$member$(u, r)
        endmethod
    endstruct
    //! endtextmacro
    //! runtextmacro UnitSetBinary("Agi", "AGI")
    //! runtextmacro UnitSetBinary("Int", "INT")
    //! runtextmacro UnitSetBinary("Str", "STR")
    //! runtextmacro UnitSetBinary("Damage", "DAMAGE")
    //! runtextmacro UnitSetBinary("Armor", "ARMOR")
    //! runtextmacro UnitSetBinary("AttackSpeed", "ATTACK_SPEED")
    //! runtextmacro UnitSetBinary("LifeRegen", "LIFE_REGEN")
    //! runtextmacro UnitSetBinary("ManaRegenPercent", "MANA_REGEN_PERCENT")

    // ******************************************************************************
    // Modifying max life and mana are special cases, although they could also be
    // done using binary counting.
    //
    //! textmacro UnitSetMaxState takes member, state
    function UnitModify$member$ takes unit u, real amount returns nothing 
        local integer comp = 100 
        local integer i    = 4
        local integer abil = $state$
        if amount < 0 then
            set abil = abil + 2
            set amount = -amount 
        endif 
        set amount = R2I(amount)
        loop 
            exitwhen i < 2 
             if amount >= comp then 
                loop 
                    exitwhen amount < comp 
                    call UnitAddAbility     (u, abil) 
                    call SetUnitAbilityLevel(u, abil, i) 
                    call UnitRemoveAbility  (u, abil) 
                    set amount = amount - comp 
                endloop 
            endif 
            set comp = comp / 10 
            set i = i - 1 
        endloop 
    endfunction

    function UnitSet$member$ takes unit u, real amount returns nothing 
        local integer comp = 100 
        local integer i    = 4
        local integer abil = $state$
        local real r = GetUnitState(u, UNIT_STATE_$state$)
        if amount > r then
            set amount = R2I(amount - r)
        elseif amount < r then
            set amount = R2I(RAbsBJ(r - amount))
            set abil = abil + 2
        endif
        loop 
            exitwhen i < 2 
             if amount >= comp then 
                loop 
                    exitwhen amount < comp 
                    call UnitAddAbility     (u, abil) 
                    call SetUnitAbilityLevel(u, abil, i) 
                    call UnitRemoveAbility  (u, abil) 
                    set amount = amount - comp 
                endloop 
            endif 
            set comp = comp / 10 
            set i = i - 1 
        endloop 
    endfunction

    function UnitGet$member$ takes unit u returns real
        return GetUnitState(u, UNIT_STATE_$state$)
    endfunction
    //! endtextmacro
    //! runtextmacro UnitSetMaxState("MaxLife", "MAX_LIFE")
    //! runtextmacro UnitSetMaxState("MaxMana", "MAX_MANA")

    // ******************************************************************************
    // Refreshes properties for a unit in case a morph ability or something else
    // causes them to vanish.
    //
    function RefreshUnitProperties takes unit u returns nothing
        call UnitModifyArmor           (u, 0)
        call UnitModifyDamage          (u, 0)
        call UnitModifyAttackSpeed     (u, 0)
        call UnitModifyMoveSpeed       (u, 0)
        call UnitModifyAgi             (u, 0)
        call UnitModifyInt             (u, 0)
        call UnitModifyStr             (u, 0)
        call UnitModifyLifeRegen       (u, 0)
        call UnitModifyManaRegen       (u, 0)
        call UnitModifyManaRegenPercent(u, 0)
    endfunction

    // ******************************************************************************
    // Additional periodic properties would be added to the Periodic function and
    // would require their own ForGroup.
    //
    private function UnitAdjustMana takes nothing returns nothing
        local unit u = GetEnumUnit()
        set u:Mana = u:Mana + u:ManaRegen
        set u = null
    endfunction

    private function Periodic takes nothing returns nothing
        call ForGroup(ManaRegenGroup, function UnitAdjustMana)
    endfunction

    // ******************************************************************************
    // Initialization stores powers of 2 up to 30, starts the periodic timer and
    // preloads all property abilities.
    //
    globals
        private unit u
    endglobals

    private function PreloadBinary takes integer i returns nothing
        local integer done = i + OFFSET + MAX
        local integer exit
        loop
            set exit = i + MAX
            loop
                exitwhen i == exit
                call UnitAddAbility(u, i)
                set i = i + 1
            endloop
            exitwhen i == done
            set i = (i - MAX) + OFFSET
        endloop
    endfunction

    private function Init takes nothing returns nothing
        local integer i = 1
        set Pow2[0] = 1
        call TimerStart(Timer, 1, true, function Periodic)
        loop
            exitwhen i > 30  // Can't go above 2^30, integer will overflow
            set Pow2[i] = Pow2[i - 1] * 2
            set i = i + 1
        endloop
        set u = CreateUnit(Player(14), 'hfoo', 0, 0, 0)
        call PreloadBinary (AGI)
        call PreloadBinary (INT)
        call PreloadBinary (STR)
        call PreloadBinary (ATTACK_SPEED)
        call PreloadBinary (DAMAGE)
        call PreloadBinary (LIFE_REGEN)
        call PreloadBinary (ARMOR)
        call PreloadBinary (MANA_REGEN_PERCENT)
        call UnitAddAbility(u, MAX_LIFE)
        call UnitAddAbility(u, MAX_LIFE+2)
        call UnitAddAbility(u, MAX_MANA)
        call UnitAddAbility(u, MAX_MANA+2)
        call UnitAddAbility(u, 'Evas')
        call KillUnit      (u)
        call RemoveUnit    (u)
        set u = null
    endfunction

    //*******************************************************************************
    // These wrappers use operator overloading to allow a more intuitive syntax than
    // UnitSet/Modify/GetProperty():
    //
    // set Unit:Property = x
    // or
    // set Property[Unit] = x
    //
    // To modify a property rather than set it to a specific value:
    //
    // set Unit:Property = Unit:Property + x
    // or
    // set Property[Unit] = Property[Unit] + x
    //

    //! textmacro UnitPropertyWrapper takes name
    struct $name$ extends array
        static method operator [] takes unit u returns real
            return UnitGet$name$(u)
        endmethod
        static method operator []= takes unit u, real r returns nothing
            call UnitSet$name$(u, r)
        endmethod
    endstruct
    //! endtextmacro
    //! runtextmacro UnitPropertyWrapper("ManaRegen")
    //! runtextmacro UnitPropertyWrapper("MoveSpeed")
    //! runtextmacro UnitPropertyWrapper("AttackEvasion")
    //! runtextmacro UnitPropertyWrapper("AttackMiss")

    //! textmacro UnitStateWrapper takes name, type
    struct $name$ extends array
        static method operator [] takes unit u returns real
            return GetUnitState(u, UNIT_STATE_$type$)
        endmethod
        static method operator []= takes unit u, real r returns nothing
            call SetUnitState(u, UNIT_STATE_$type$, r)
        endmethod
    endstruct
    struct Max$name$ extends array
        static method operator [] takes unit u returns real
            return GetUnitState(u, UNIT_STATE_MAX_$type$)
        endmethod
        static method operator []= takes unit u, real r returns nothing
            call UnitSetMax$name$(u, r)
        endmethod
    endstruct
    //! endtextmacro
    //! runtextmacro UnitStateWrapper("Life", "LIFE")
    //! runtextmacro UnitStateWrapper("Mana", "MANA")
endlibrary

01-07-2011, 05:07 PM#2
Anitarf
If the debug messages display correct values, then the error has to be elsewhere. Try swapping UnitProperties with BonusMod and see how that works.
01-07-2011, 07:46 PM#3
Idontneedaname
yep. better!
although it's much more complicated, i still have no idea which //! to delete in order to get rid of the save-delay.
01-07-2011, 10:15 PM#4
Anitarf
Quote:
Originally Posted by Idontneedaname
yep. better!
although it's much more complicated, i still have no idea which //! to delete in order to get rid of the save-delay.
Try searching for this line: //! runtextmacro BonusMod_BeginBonuses("true") The documentation above the line describes how to use it.
01-08-2011, 08:31 PM#5
Idontneedaname
when i made it ////!, i had an error. i got to set it to false?
01-12-2011, 11:03 AM#6
Bribe
Just delete the exclamation mark. vJass errors are legion.
01-15-2011, 11:25 AM#7
Earth-Fury
Collapse JASS:
//------------------------------------------------------------------------------
// The BonusMod_BeginBonuses macro takes a single boolean type parameter.
// If set to true, bonus abilities will be created (or recreated) on save.
// If set to false, abilities will not be generated.
// 
// If you modify any of the bonus declaration macros, or add new ones, you must
// regenerate abilities.
// 
// Note that if you remove a bonus, the abilities it had created will not be
// automatically removed. This is also true of reducing the number of abilities
// a bonus uses.
// 
// After you generate abilities, you must close your map and reopen it in the
// editor. You can then disable ability generation until the next time you
// modify the bonus types.
//------------------------------------------------------------------------------
//! runtextmacro BonusMod_BeginBonuses("true")

In other words, replace "true" with "false".
01-15-2011, 11:53 AM#8
Idontneedaname
Okay, it worked fine. Thanks!