1. Find your way through the deepest dungeon in the 18th Mini Mapping Contest Poll.
    Dismiss Notice
  2. A brave new world lies beyond the seven seas. Join the 34th Modeling Contest today!
    Dismiss Notice
  3. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
Hive 3 Remoosed BETA - NOW LIVE. Go check it out at BETA Hive Workshop! Post your feedback in this new forum BETA Feedback.
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Increase Max HP on Kill

Discussion in 'World Editor Help Zone' started by DaneTheBeast, Jan 22, 2018.

  1. DaneTheBeast

    DaneTheBeast

    Joined:
    Dec 11, 2014
    Messages:
    608
    Resources:
    1
    Maps:
    1
    Resources:
    1
    Goal: I need to increase the hero's max hp by a set amount every time he kills an enemy unit, preferably with a basic attack.

    What I tried:
    Giving the hero a manual of health

    • Set UNITTemp = (Killing unit)
    • Hero - Create Health +5 and give it to UNITTemp


    This worked (except it also gave HP from ability kills) but it always showed that "dust" when you pick up a tome.

    Then I tried using the BonusMod along with UnitMaxState

    • Custom script: call AddUnitMaxState(udg_UNITTemp, UNIT_STATE_MAX_LIFE, 1.0)


    This works, but again, it gives HP even on ability kills. I think a solution to this would be to trigger every other skill, so that dummy units are getting the kills, this way he would get the XP but not the extra HP.
    Another problem: whenever I save the map, errors come up, but JASSHelper then pops up and makes the map playable, but this is really annoying and there must be a way to import it correctly.

    This is what I put in my map header:
    Code (vJASS):

    library BonusMod initializer OnInit requires optional AbilityPreload, optional xepreload
    private keyword AbilityBonus
    ////////////////////////////////////////////////////////////////////////////////
    //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    //@ BonusMod - v3.3.1
    //@=============================================================================
    //@ Credits:
    //@-----------------------------------------------------------------------------
    //@    Written by:
    //@        Earth-Fury
    //@    Based on the work of:
    //@        weaaddar
    //@-----------------------------------------------------------------------------
    //@ If you use this system, please at least credit weaaddar. Without him, this
    //@ system would not exist. I would be happy if you credited me as well.
    //@=============================================================================
    //@ Requirements:
    //@-----------------------------------------------------------------------------
    //@ This library is written in vJass and thus requires JASS Helper in order to
    //@ function correctly. This library also uses the ObjectMerger created by
    //@ PitzerMike. The ObjectMerger must be configured as an external tool for
    //@ JASS Helper.
    //@
    //@ All of these things are present in the NewGen world editor.
    //@
    //@=============================================================================
    //@ Introduction:
    //@-----------------------------------------------------------------------------
    //@ BonusMod is a system for applying reversible bonuses to certain stats, such
    //@ as attack speed or mana regen, for specific units. Most of the bonuses
    //@ provided by BonusMod show green or red numbers in the command card, exactly
    //@ like the bonuses provided by items.
    //@
    //@ BonusMod has two kinds of bonuses:
    //@   1. Ability based bonuses
    //@   2. Code based bonuses
    //@
    //@ All of the bonuses in the configuration section for the basic BonusMod
    //@ library are ability-based bonuses. Code-based bonuses are provided by
    //@ additional libraries.
    //@
    //@ Ability based bonuses have a limit to how much of a bonus they can apply.
    //@ The actual limit depends on the number of abilities that type of bonus uses.
    //@ See the "Default bonuses" section of this readme for the default limits
    //@ of the bonuses that come with BonusMod. For changing the limits of the
    //@ default bonuses, or for adding new types of bonuses, see the below
    //@ configuration section.
    //@
    //@ Code based bonuses may or may not have a limit to how much of a bonus they
    //@ can apply. The limits for code based bonuses depend entirely on how the
    //@ bonus is implemented. See their documentation for more information.
    //@
    //@=============================================================================
    //@ Adding BonusMod to your map:
    //@-----------------------------------------------------------------------------
    //@ First, you must place the BonusMod library in a custom-text trigger in your
    //@ map.
    //@
    //@ You must then save your map with ability generation enabled. After you save
    //@ your map with ability generation enabled, you must close your map in the
    //@ editor, and reopen it. You can then disable ability generation.
    //@ See the configuration section for information on how to enable and disable
    //@ ability generation.
    //@
    //@=============================================================================
    //@ Default bonuses:
    //@-----------------------------------------------------------------------------
    //@
    //@      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //@      | Bonus Type constants:       | Minimum bonus: | Maximum bonus: |
    //@      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //@      | BONUS_SIGHT_RANGE           |   -2048        |   +2047        |
    //@      | BONUS_ATTACK_SPEED          |   -512         |   +511         |
    //@      | BONUS_ARMOR                 |   -1024        |   +1023        |
    //@      | BONUS_MANA_REGEN_PERCENT    |   -512%        |   +511%        |
    //@      | BONUS_LIFE_REGEN            |   -256         |   +255         |
    //@      | BONUS_DAMAGE                |   -1024        |   +1023        |
    //@      | BONUS_STRENGTH              |   -256         |   +255         |
    //@      | BONUS_AGILITY               |   -256         |   +255         |
    //@      | BONUS_INTELLIGENCE          |   -256         |   +255         |
    //@      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //@
    //@      Notes:
    //@         - The bonuses for stength, agility, and intelligence can only be
    //@           applied to heroes. Attempting to add them to normal units will
    //@           fail to work completely.
    //@         - Using a negative BONUS_STRENGTH bonus can give a unit negative
    //@           maximum life. Don't do that. It really messes stuff up.
    //@         - Using a negative BONUS_INTELLIGENCE bonus can remove a hero's
    //@           mana. This is not a big issue, as mana will return when the
    //@           bonus is removed.
    //@         - The maximum effective sight range for a unit is 1800.
    //@         - There is a maximum attack speed. I have no idea what it is.
    //@
    //@ See the configuration section for information on how to change the range of
    //@ bonuses, as well as how to add new ability-based bonuses, and remove unused
    //@ ones.
    //@
    //@=============================================================================
    //@ Public API / Function list:
    //@-----------------------------------------------------------------------------
    //@ Note that BonusMod will only output error messages if JASS Helper is set to
    //@ compile in debug mode.
    //@
    //@ Bonus constants such as BONUS_DAMAGE have .min and .max properties which
    //@ are the minimum and maximum bonus that type of bonus can apply. Note that
    //@ for code based bonuses, these constants may not reflect the minimum or
    //@ maximum bonus for a specific unit. Use the IsBonusValid() function to check
    //@ if the given bonus value is okay for a given unit.
    //@
    //@ function SetUnitBonus
    //@ takes unit u, Bonus bonusType, integer amount
    //@ returns integer
    //@
    //@     This function sets the bonus of the type bonusType for the given unit to
    //@     the given amount. The returned integer is the unit's actual current
    //@     bonus, after it has been changed. If the given amount is above the
    //@     maximum possible bonus for this type, then the maximum possible bonus
    //@     is applied to the unit. The same is true if the given value is below
    //@     the minimum possible bonus.
    //@
    //@ function GetUnitBonus
    //@ takes unit u, Bonus bonusType
    //@ returns integer
    //@
    //@     Returns the given unit's current bonus of bonusType. A value of 0 means
    //@     that the given unit does not have a bonus of the given type.
    //@
    //@ function AddUnitBonus
    //@ takes unit u, Bonus bonusType, integer amount
    //@ returns integer
    //@
    //@     Increases the unit's bonus by the given amount. You can use a negitive
    //@     amount to subtract from the unit's current bonus. Note that the same
    //@     rules SetUnitBonus has apply for going over/under the maximum bonus.
    //@     The returned value is the unit's actual new bonus.
    //@
    //@ function RemoveUnitBonus
    //@ takes unit u, Bonus bonusType
    //@ returns nothing
    //@
    //@     Sets the bonus of the type bonusType to 0 for the given unit. This
    //@     function is faster then using SetUnitBonus(u, bonusType, 0).
    //@
    //@ function IsBonusValid
    //@ takes unit u, Bonus abstractBonus, integer value
    //@ returns boolean
    //@
    //@     Returns true if the given value is a valid bonus value for the given
    //@     unit. This will also return false if the given bonus type is a hero-
    //@     only bonus type, and the given unit is not a hero.
    //@
    //@=============================================================================
    //@ Writing code-based bonuses:
    //@-----------------------------------------------------------------------------
    //@ This section of the readme tells you how to create your own bonus types
    //@ that apply their bonuses using vJass code instead of abilities. You do not
    //@ need to read or understand this to use BonusMod as-is.
    //@
    //@ Creating a new bonus type is simple. Extend the Bonus struct, implement the
    //@ methods provided within it, and create a single instance of your struct
    //@ within a variable named BONUS_YOUR_BONUS_TYPES_NAME of the type Bonus.
    //@
    //@ The methods you must implement are:
    //@
    //@ method setBonus takes unit u, integer amount returns integer
    //@     This method sets the given unit's current bonus to amount, returning
    //@     the actual bonus that was applied. If the given amount is higher then
    //@     the maximum amount your bonus type can apply to a unit, you must apply
    //@     the maximum possible bonus, and return that amount. The same holds true
    //@     for the minimum bonus.
    //@
    //@ method getBonus takes unit u returns integer
    //@     This method returns the current bonus the given unit has.
    //@
    //@ method removeBonus takes unit u returns nothing
    //@     This method sets the current bonus of the given unit to 0.
    //@
    //@ method isValueInRange takes integer value returns boolean
    //@     This method returns true if the given integer is a valid bonus amount
    //@     for this bonus type, and false otherwise.
    //@
    //@ Note that it is your responsibility to do any clean up in the event a unit
    //@ dies or is removed with an active bonus on it. There is no guarantee that
    //@ removeBonus() will be called before a unit dies or is removed.
    //@
    //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    ////////////////////////////////////////////////////////////////////////////////

    //==============================================================================
    // Configuration:
    //==============================================================================

    //------------------------------------------------------------------------------
    // If the following constant is set to true, the abilities used by this library
    // will be preloaded at map initialization. This will slightly increase loading
    // time, but will prevent a slight to medium lag spike the first time a bonus
    // of a type is applied.
    //
    // Note that your map must contain either the xepreload library, or the
    // AbilityPreload library for preloading to work.
    //
    // It is highly recommended that you do not set this to false.
    //------------------------------------------------------------------------------
    globals
        private constant boolean PRELOAD_ABILITIES = false
    endglobals

    //------------------------------------------------------------------------------
    // 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")
        //--------------------------------------------------------------------------
        // Below are where bonus types are defined.
        //
        // The first parameter is the name of the bonus type. A constant will be
        // generated for each bonus type, that will take the form: BONUS_NAME
        //
        // The second parameter is the maximum power of 2 the bonus type can add
        // to a unit. For example, 8 abilities gives a range of -256 to +255.
        //
        // The third parameter is the base ability. The base ability must give the
        // desired effect when the given field is changed.
        //
        // The fourth parameter is the rawcode prefix of the bonuses generated
        // abilities. The prefix must be 3 characters long. Your map must not
        // already contain bonuses which start with the given prefix.
        //
        // The fifth parameter is the object field to modify for each generated
        // ability.
        //
        // The sixth parameter must be true of the bonus should only work on hero
        // units, and false otherwise.
        //
        // The final parameter is the icon that will be displayed in the object
        // editor. This has no effect on anything ingame.
        //--------------------------------------------------------------------------
     
        //                                    |     NAME     |ABILITY|SOURCE |PREFIX|FIELD  | HERO   |  ICON
        //                                    |              | COUNT |ABILITY|      |       |  ONLY  |
        //! runtextmacro BonusMod_DeclareBonus("ARMOR",        "10",  "AId1", "(A)", "Idef", "false", "BTNHumanArmorUpOne.blp")
        //! runtextmacro BonusMod_DeclareBonus("DAMAGE",       "10",  "AItg", "(B)", "Iatt", "false", "BTNSteelMelee.blp")
        //! runtextmacro BonusMod_DeclareBonus("SIGHT_RANGE",  "11",  "AIsi", "(C)", "Isib", "false", "BTNTelescope.blp")
        //! runtextmacro BonusMod_DeclareBonus("LIFE_REGEN",   "8",   "Arel", "(E)", "Ihpr", "false", "BTNRingSkull.blp")
        //! runtextmacro BonusMod_DeclareBonus("STRENGTH",     "8",   "AIa1", "(F)", "Istr", "true" , "BTNGoldRing.blp")
        //! runtextmacro BonusMod_DeclareBonus("AGILITY",      "8",   "AIa1", "(G)", "Iagi", "true" , "BTNGoldRing.blp")
        //! runtextmacro BonusMod_DeclareBonus("INTELLIGENCE", "8",   "AIa1", "(H)", "Iint", "true" , "BTNGoldRing.blp")
     
        //                                           |     NAME          |ABILITY|SOURCE |PREFIX|FIELD  |HERO   |  ICON
        //                                           |                   | COUNT |ABILITY|      |       | ONLY  |
        //! runtextmacro BonusMod_DeclarePercentBonus("ATTACK_SPEED",       "9", "AIsx",  "(I)", "Isx1", "false", "BTNGlove.blp")
        //! runtextmacro BonusMod_DeclarePercentBonus("MANA_REGEN_PERCENT", "9", "AIrm",  "(D)", "Imrp", "false", "BTNSobiMask.blp")
     
    //! runtextmacro BonusMod_EndBonuses()

    //==============================================================================
    // End of configuration
    //==============================================================================

    //! textmacro BonusMod_BeginBonuses takes SHOULD_GENERATE_ABILITIES
        private function Setup takes nothing returns nothing
     
        // The following is a lua script for the ObjectMerger, used to generate abilities
        //*
        //! externalblock extension=lua ObjectMerger $FILENAME$
        //! i if "$SHOULD_GENERATE_ABILITIES$" == "true" then
        //! i function FormatName(name)
        //! i     name = string.lower(name)
        //! i     name = string.gsub(name, "_", " ")
        //! i     s = name
        //! i     name = ""
        //! i     for w in string.gmatch(s, "%a%w*") do
        //! i         name = name .. string.upper(string.sub(w, 1, 1)) .. string.sub(w, 2, -1)
        //! i         name = name .. " "
        //! i     end
        //! i     name = string.sub(name, 1, string.len(name) - 1)
        //! i     return name
        //! i end
        //! i function SetupAbility(name, suffix, icon, hero)
        //! i     makechange(current, "anam", "BonusMod - " .. FormatName(name))
        //! i     makechange(current, "ansf", "(" .. suffix .. ")")
        //! i     makechange(current, "aart", "ReplaceableTextures\\CommandButtons\\" .. icon)
        //! i     makechange(current, "aite", 0)
        //! i     if hero then
        //! i         makechange(current, "Iagi", 1, 0)
        //! i         makechange(current, "Iint", 1, 0)
        //! i         makechange(current, "Istr", 1, 0)
        //! i     end
        //! i end
        //! i function CreateAbility(sourceAbility, prefix, field, abilityCount, name, icon)
        //! i     powOf2 = abilityCount - 1
        //! i     lengthOfMax = string.len(tostring(2^abilityCount))
        //! i     for i = 0, powOf2 do
        //! i         padding = ""
        //! i         for k = 0, lengthOfMax - string.len(tostring(2^i)) - 1 do
        //! i             padding = padding .. "0"
        //! i         end
        //! i         createobject(sourceAbility, prefix .. string.sub(chars, i + 1, i + 1))
        //! i         SetupAbility(name, "+" .. padding .. tostring(2 ^ i), icon, true)
        //! i         makechange(current, field, 1, tostring(2^i))
        //! i     end
        //! i     createobject(sourceAbility, prefix .. "-")
        //! i     SetupAbility(name, "-" .. tostring(2 ^ abilityCount), icon, true)
        //! i     makechange(current, field, 1, tostring(-(2^abilityCount)))
        //! i end
        //! i function CreatePercentageAbility(sourceAbility, prefix, field, abilityCount, name, icon)
        //! i     powOf2 = abilityCount - 1
        //! i     lengthOfMax = string.len(tostring(2^abilityCount))
        //! i     for i = 0, powOf2 do
        //! i         padding = ""
        //! i         for k = 0, lengthOfMax - string.len(tostring(2^i)) - 1 do
        //! i             padding = padding .. "0"
        //! i         end
        //! i         createobject(sourceAbility, prefix .. string.sub(chars, i + 1, i + 1))
        //! i         SetupAbility(name, "+" .. padding .. tostring(2 ^ i) .. "%", icon, false)
        //! i         makechange(current, field, 1, tostring((2 ^ i) / 100))
        //! i     end
        //! i     createobject(sourceAbility, prefix .. "-")
        //! i     SetupAbility(name, "-" .. tostring(2 ^ abilityCount) .. "%", icon, false)
        //! i     makechange(current, field, 1, tostring(-((2 ^ abilityCount) / 100)))
        //! i end
        //! i     setobjecttype("abilities")
        //! i     chars = "abcdefghijklmnopqrstuvwxyz"
        //! i
        // */
    //! endtextmacro

    //! textmacro BonusMod_DeclareBonus takes NAME, ABILITY_COUNT, SOURCE_ABILITY, RAWCODE_PREFIX, FIELD, HERO_ONLY, ICON
        //! i CreateAbility("$SOURCE_ABILITY$", "$RAWCODE_PREFIX$", "$FIELD$", $ABILITY_COUNT$, "$NAME$", "$ICON$")
        globals
            Bonus BONUS_$NAME$
        endglobals
        set BONUS_$NAME$ = AbilityBonus.create('$RAWCODE_PREFIX$a', $ABILITY_COUNT$, '$RAWCODE_PREFIX$-', $HERO_ONLY$)
    //! endtextmacro

    //! textmacro BonusMod_DeclarePercentBonus takes NAME, ABILITY_COUNT, SOURCE_ABILITY, RAWCODE_PREFIX, FIELD, HERO_ONLY, ICON
        //! i CreatePercentageAbility("$SOURCE_ABILITY$", "$RAWCODE_PREFIX$", "$FIELD$", $ABILITY_COUNT$, "$NAME$", "$ICON$")
        globals
            Bonus BONUS_$NAME$
        endglobals
        set BONUS_$NAME$ = AbilityBonus.create('$RAWCODE_PREFIX$a', $ABILITY_COUNT$, '$RAWCODE_PREFIX$-', $HERO_ONLY$)
    //! endtextmacro

    //! textmacro BonusMod_EndBonuses
        //*
        //! i end
        //! endexternalblock
        // */
     
        endfunction
    //! endtextmacro

    // ===
    //  Precomputed integer powers of 2
    // ===

    globals
        private integer array powersOf2
        private integer powersOf2Count = 0
    endglobals

    // ===
    //  Utility functions
    // ===

    private function ErrorMsg takes string func, string s returns nothing
        call BJDebugMsg("|cffFF0000BonusMod Error|r|cffFFFF00:|r |cff8080FF" + func + "|r|cffFFFF00:|r " + s)
    endfunction

    private function LoadAbility takes integer abilityId returns nothing
        static if PRELOAD_ABILITIES then
            static if LIBRARY_xepreload then
                call XE_PreloadAbility(abilityId)
            else
                static if LIBRARY_AbilityPreload then
                    call AbilityPreload(abilityId)
                endif
            endif
        endif
    endfunction

    // ===
    //  Bonus Types
    // ===

    private interface BonusInterface
        integer minBonus = 0
        integer maxBonus = 0
        private method destroy takes nothing returns nothing defaults nothing
    endinterface

    private keyword isBonusObject

    struct Bonus extends BonusInterface
        boolean isBonusObject = false
     
        public static method create takes nothing returns thistype
            local thistype this = thistype.allocate()
         
            set this.isBonusObject = true
         
            return this
        endmethod
     
        stub method setBonus takes unit u, integer amount returns integer
            debug call ErrorMsg("Bonus.setBonus()", "I have no idea how or why you did this, but don't do it.")
            return 0
        endmethod
     
        stub method getBonus takes unit u returns integer
            debug call ErrorMsg("Bonus.getBonus()", "I have no idea how or why you did this, but don't do it.")
            return 0
        endmethod
     
        stub method removeBonus takes unit u returns nothing
            call this.setBonus(u, 0)
        endmethod
     
        stub method isValidBonus takes unit u, integer value returns boolean
            return true
        endmethod
     
        method operator min takes nothing returns integer
            return this.minBonus
        endmethod
     
        method operator max takes nothing returns integer
            return this.maxBonus
        endmethod
    endstruct

    private struct AbilityBonus extends Bonus
        public integer count
     
        public integer rawcode
        public integer negativeRawcode
     
        public integer minBonus = 0
        public integer maxBonus = 0
     
        public boolean heroesOnly
     
        public static method create takes integer rawcode, integer count, integer negativeRawcode, boolean heroesOnly returns thistype
            local thistype bonus = thistype.allocate()
            local integer i
            debug local boolean error = false
         
            // Error messages
            static if DEBUG_MODE then
                if rawcode == 0 then
                    call ErrorMsg("AbilityBonus.create()", "Bonus constructed with a rawcode of 0?!")
                    call bonus.destroy()
                    return 0
                endif
             
                if count < 0 or count == 0 then
                    call ErrorMsg("AbilityBonus.create()", "Bonus constructed with an ability count <= 0?!")
                    call bonus.destroy()
                    return 0
                endif
            endif
         
            // Grow powers of 2
            if powersOf2Count < count then
                set i = powersOf2Count
                loop
                    exitwhen i > count
                 
                    set powersOf2[i] = 2 * powersOf2[i - 1]

                    set i = i + 1
                endloop
                set powersOf2Count = count
            endif
         
            // Preload this bonus' abilities
            static if PRELOAD_ABILITIES then
                set i = 0
                loop
                    exitwhen i == count
                 
                    call LoadAbility(rawcode + i)
                 
                    set i = i + 1
                endloop
             
                if negativeRawcode != 0 then
                    call LoadAbility(negativeRawcode)
                endif
            endif
         
            // Set up this bonus object
            set bonus.count = count
            set bonus.negativeRawcode = negativeRawcode
            set bonus.rawcode = rawcode
            set bonus.heroesOnly = heroesOnly
         
            // Calculate the minimum and maximum bonuses
            if negativeRawcode != 0 then
                set bonus.minBonus = -powersOf2[count]
            else
                set bonus.minBonus = 0
            endif
            set bonus.maxBonus = powersOf2[count] - 1
         
            // Return the bonus object
            return bonus
        endmethod
     
        // Interface methods:
     
        method setBonus takes unit u, integer amount returns integer
            return SetUnitBonus.evaluate(u, this, amount)
        endmethod
     
        method getBonus takes unit u returns integer
            return GetUnitBonus.evaluate(u, this)
        endmethod
     
        method removeBonus takes unit u returns nothing
            call RemoveUnitBonus.evaluate(u, this)
        endmethod
     
        public method isValidBonus takes unit u, integer value returns boolean
            return (value >= this.minBonus) and (value <= this.maxBonus)
        endmethod
    endstruct

    // ===
    //  Public API
    // ===

    function IsBonusValid takes unit u, Bonus abstractBonus, integer value returns boolean
        local AbilityBonus bonus = AbilityBonus(abstractBonus)
     
        static if DEBUG_MODE then
            if not abstractBonus.isBonusObject then
                call ErrorMsg("IsBonusValid()", "Invalid bonus type given")
            endif
        endif
     
        if abstractBonus.min > value or abstractBonus.max < value then
            return false
        endif
     
        if abstractBonus.getType() != AbilityBonus.typeid then
            return abstractBonus.isValidBonus(u, value)
        endif
     
        if bonus.heroesOnly and not IsUnitType(u, UNIT_TYPE_HERO) then
            return false
        endif
     
        return (value >= bonus.minBonus) and (value <= bonus.maxBonus)
    endfunction

    function RemoveUnitBonus takes unit u, Bonus abstractBonus returns nothing
        local integer i = 0
        local AbilityBonus bonus = AbilityBonus(abstractBonus)

        static if DEBUG_MODE then
            if not abstractBonus.isBonusObject then
                call ErrorMsg("RemoveUnitBonus()", "Invalid bonus type given")
            endif
        endif
     
        if abstractBonus.getType() != AbilityBonus.typeid then
            call abstractBonus.removeBonus(u)
            return
        endif
     
        if bonus.heroesOnly and not IsUnitType(u, UNIT_TYPE_HERO) then
            debug call ErrorMsg("RemoveUnitBonus()", "Trying to remove a hero-only bonus from a non-hero unit")
            return
        endif
     
        call UnitRemoveAbility(u, bonus.negativeRawcode)
     
        loop
            exitwhen i == bonus.count
         
            call UnitRemoveAbility(u, bonus.rawcode + i)

            set i = i + 1
        endloop
    endfunction

    function SetUnitBonus takes unit u, Bonus abstractBonus, integer amount returns integer
        local integer i
        local integer output = 0
        local AbilityBonus bonus = AbilityBonus(abstractBonus)
        local boolean applyMinBonus = false
     
        static if DEBUG_MODE then
            if not abstractBonus.isBonusObject then
                call ErrorMsg("SetUnitBonus()", "Invalid bonus type given")
            endif
        endif
     
        if amount == 0 then
            call RemoveUnitBonus(u, bonus)
            return 0
        endif
     
        if abstractBonus.getType() != AbilityBonus.typeid then
            return abstractBonus.setBonus(u, amount)
        endif
     
        if bonus.heroesOnly and not IsUnitType(u, UNIT_TYPE_HERO) then
            debug call ErrorMsg("SetUnitBonus()", "Trying to set a hero-only bonus on a non-hero unit")
            return 0
        endif
     
        if amount < bonus.minBonus then
            debug call ErrorMsg("SetUnitBonus()", "Attempting to set a bonus to below its min value")
            set amount = bonus.minBonus
        elseif amount > bonus.maxBonus then
            debug call ErrorMsg("SetUnitBonus()", "Attempting to set a bonus to above its max value")
            set amount = bonus.maxBonus
        endif
     
        if amount < 0 then
            set amount = -(bonus.minBonus - amount)
            set applyMinBonus = true
        endif
     
        call UnitRemoveAbility(u, bonus.negativeRawcode)
     
        set i = bonus.count - 1
        loop
            exitwhen i < 0
            if amount >= powersOf2[i] then
             
                call UnitAddAbility(u, bonus.rawcode + i)
                call UnitMakeAbilityPermanent(u, true, bonus.rawcode + i)
             
                static if DEBUG_MODE then
                    if GetUnitAbilityLevel(u, bonus.rawcode + i) <= 0 then
                        call ErrorMsg("SetUnitBonus()", "Failed to give the 2^" + I2S(i) + " ability to the unit!")
                    endif
                endif
             
                set amount = amount - powersOf2[i]
                set output = output + powersOf2[i]
            else
             
                call UnitRemoveAbility(u, bonus.rawcode + i)
                static if DEBUG_MODE then
                    if GetUnitAbilityLevel(u, bonus.rawcode + i) > 0 then
                        call ErrorMsg("SetUnitBonus()", "Unit still has the 2^" + I2S(i) + " ability after it was removed!")
                    endif
                endif
            endif

            set i = i - 1
        endloop
     
        if applyMinBonus then
            call UnitAddAbility(u, bonus.negativeRawcode)
            call UnitMakeAbilityPermanent(u, true, bonus.negativeRawcode)
        else
            call UnitRemoveAbility(u, bonus.negativeRawcode)
        endif
     
        return output
    endfunction

    function GetUnitBonus takes unit u, Bonus abstractBonus returns integer
        local integer i = 0
        local integer amount = 0
        local AbilityBonus bonus = AbilityBonus(abstractBonus)

        static if DEBUG_MODE then
            if not abstractBonus.isBonusObject then
                call ErrorMsg("GetUnitBonus()", "Invalid bonus type given")
            endif
        endif
     
        if abstractBonus.getType() != AbilityBonus.typeid then
            return abstractBonus.getBonus(u)
        endif
     
        if bonus.heroesOnly and not IsUnitType(u, UNIT_TYPE_HERO) then
            debug call ErrorMsg("GetUnitBonus()", "Trying to get a hero-only bonus from a non-hero unit")
            return 0
        endif
     
        if GetUnitAbilityLevel(u, bonus.negativeRawcode) > 0 then
            set amount = bonus.minBonus
        endif

        loop
            exitwhen i == bonus.count
         
            if GetUnitAbilityLevel(u, bonus.rawcode + i) > 0 then
                set amount = amount + powersOf2[i]
            endif

            set i = i + 1
        endloop

        return amount
    endfunction

    function AddUnitBonus takes unit u, Bonus bonus, integer amount returns integer
        return SetUnitBonus(u, bonus, GetUnitBonus(u, bonus) + amount)
    endfunction

    // ===
    //  Initialization
    // ===

    private function OnInit takes nothing returns nothing
        local integer i
     
        // Set up powers of 2
        set powersOf2[0] = 1
        set powersOf2Count = 1
     
        static if DEBUG_MODE and PRELOAD_ABILITIES and not LIBRARY_xepreload and not LIBRARY_AbilityPreload then
            call ErrorMsg("Initialization", "PRELOAD_ABILITIES is set to true, but neither usable preloading library is detected")
        endif
     
        // Setup bonuses
        call Setup()
    endfunction
    endlibrary

    library UnitMaxState initializer Initialize requires optional AbilityPreload, optional xepreload
    //==============================================================================
    // UnitMaxState v2.1
    //==============================================================================
    // Credits:
    //------------------------------------------------------------------------------
    // Written By:
    //     Earth-Fury
    //
    // Original System By:
    //     Blade.dk
    //
    // Intermittent Version By:
    //     Deaod
    //
    // With Thanks To:
    //     - weaaddar for BonusMod and thus inspiration
    //     - PitzerMike for the ObjectMerger
    //     - Vexorian for vJass and Jass Helper
    //     - PipeDream for Grimoire
    //     - SFilip for TESH
    //     - MindWorX for maintaining NewGen
    //------------------------------------------------------------------------------
    // If you use this library in your map, please at least give credit to Blade.dk.
    // Without him, this library would not exist.
    //==============================================================================
    // Introduction:
    //------------------------------------------------------------------------------
    // UnitMaxState is a library which allows you to modify a unit's maximum life,
    // or maximum mana. To achieve this, the library abuses a bug with the AIlf and
    // AImz abilities, which is too complex to explain here.
    //
    // I do believe it was indeed Blade.dk who initially found this bug. If not,
    // it's still his system I stole and rewrote. Further, let me thank Deaod for
    // writing up his version of this system, which inspired both the reality of
    // this rewrite, and the method abilities are handled within it.
    //
    //==============================================================================
    // Requirements:
    //------------------------------------------------------------------------------
    // UnitMaxState is written in vJass and requires the NewGen editor, or
    // Jass Helper with PitzerMike's Object Merger configured for it.
    //
    // UnitMaxState requires the latest version of Jass Helper.
    //
    // Preloading of abilities requires either AbilityPreload or xepreload. Neither
    // are required for the library to function; however, having one or the other
    // will remove the slight delay the first time a unit's max state is changed.
    //
    //==============================================================================
    // Using UnitMaxState:
    //------------------------------------------------------------------------------
    // UnitMaxState comes with two useful functions:
    //
    // nothing SetUnitMaxState(unit <target>, unitstate <state>, real <value>)
    //     Changes <target>'s unitstate <state> to be equal to <value>.
    //
    // nothing AddUnitMaxState(unit <target>, unitstate <state>, real <value>)
    //     Adds <value> to <target>'s <state> unitstate. Note that you can use
    //     negative values with this function.
    //
    // Both of these functions accept unitstate's other than UNIT_STATE_MAX_LIFE and
    // UNIT_STATE_MAX_MANA. There is a small performance penalty in using these over
    // direct usage of SetUnitState.
    //
    // You must not use life/mana boosting upgrades in combination with this system.
    //
    // Attempting to set a unit's maximum life below 1, or mana below 0 will do
    // nothing. A debug message will be output if the script is compiled in
    // debug mode.
    //==============================================================================



    //==============================================================================
    // Configuration:
    //------------------------------------------------------------------------------
    // The below textmacro call is an all-in-one configuration line.
    //------------------------------------------------------------------------------
    // The first parameter is a boolean.
    //
    // If true, the abilities used by this system will be created on save. This adds
    // a slight delay to saving your map. You only ever have to create the abilities
    // the first time this library is added to your map, or if you modify any of
    // the other configuration options.
    //
    // Note that to make the ability creation permanent, you must save with ability
    // creation enabled, close your map, and reopen it in the editor. You can then
    // disable ability creation, as the abilities will be permanently in your map.
    //------------------------------------------------------------------------------
    // The second parameter is an integer.
    //
    // This is the number of abilities this system will use for adding/removing
    // life/mana. Note that this system uses four sets of abilities, so the actual
    // number of abilities generated and used will be the value you pass here,
    // multiplied by 4.
    //
    // The higher this number, the faster large bonuses will be added. This number
    // should never have to go above 13. Between 3 and 5 will work fine for most
    // maps.
    //------------------------------------------------------------------------------
    // The fourth and fifth parameters are 3 character prefixes for rawcodes.
    //
    // The first one is for the life-modifying abilities, while the second is for
    // the mana-modifying abilities.
    //
    // Please, make sure your map has no abilities whose rawcodes begin with either
    // of these prefixes before saving! Otherwise, those abilities will be
    // overwritten. You can change these to any 3 character combination, if your
    // map does already contain abilities whose rawcodes begin with these prefixes.
    //------------------------------------------------------------------------------

    //! runtextmacro UnitMaxState_Configuration("false", "3", "ZxL", "ZxM")

    //------------------------------------------------------------------------------
    // End of configuration
    //------------------------------------------------------------------------------

    //! textmacro UnitMaxState_Configuration takes LOAD_ABILITIES, ABILITY_COUNT, LIFE_PREFIX, MANA_PREFIX
        //*
        //! externalblock extension=lua ObjectMerger $FILENAME$
        //! i function CreateAbilities(baseAbility, rawcodePrefix, field, name, icon)
        //! i     k = 0
        //! i     for sign = -1, 1, 2 do
        //! i         signStr = "+"
        //! i         if sign < 0 then
        //! i             signStr = "-"
        //! i         end
        //! i         j = 0
        //! i         for i = 0, (abilityCount - 1) * 3, 3 do
        //! i             j = j + 1
        //! i             createobject(baseAbility, rawcodePrefix .. string.sub(Chars, k + 1, k + 1))
        //! i             makechange(current, "anam", "UnitMaxState - " .. name)
        //! i             makechange(current, "ansf", "(" .. signStr .. tostring(j) .. ")")
        //! i             makechange(current, "aart", "ReplaceableTextures\\CommandButtons\\" .. icon)
        //! i             makechange(current, "aite", 0)
        //! i             makechange(current, "alev", 4)
        //! i             makechange(current, field, 1, 0)
        //! i             makechange(current, field, 2, 2^(i + 0) * sign)
        //! i             makechange(current, field, 3, 2^(i + 1) * sign)
        //! i             makechange(current, field, 4, 2^(i + 2) * sign)
        //! i             k = k + 1
        //! i         end
        //! i     end
        //! i end
        //! i if $LOAD_ABILITIES$ then
        //! i     setobjecttype("abilities")
        //! i     abilityCount = $ABILITY_COUNT$
        //! i     Chars = "abcdefghijklmnopqrstuvwxyz"
        //! i     CreateAbilities("AIlf", "$LIFE_PREFIX$", "Ilif", "Life", "BTNHealthStone.blp")
        //! i     CreateAbilities("AImz", "$MANA_PREFIX$", "Iman", "Mana", "BTNManaStone.blp")
        //! i end
        //! endexternalblock
        // */
     
        globals
            private constant integer RAWCODE_LIFE = '$LIFE_PREFIX$a'
            private constant integer RAWCODE_MANA = '$MANA_PREFIX$a'
         
            public constant integer ABILITY_COUNT = $ABILITY_COUNT$
        endglobals
    //! endtextmacro
    globals
        private constant boolean PRELOAD_ABILITIES = true
     
        private integer array POWERS_OF_2
    endglobals

    private function ErrorMsg takes string s returns nothing
        debug call BJDebugMsg("SetUnitMaxState: " + s)
    endfunction

    function SetUnitMaxState takes unit target, unitstate state, real targetValue returns nothing
        local integer difference
        local integer rawcode
     
        local integer abilityId
        local integer abilityLevel
     
        local integer currentAbility
     
        if state == UNIT_STATE_MAX_LIFE then
            set rawcode = RAWCODE_LIFE
         
            if targetValue < 1 then
                call ErrorMsg("You can not set a unit's max life to below 1")
                return
            endif
        elseif state == UNIT_STATE_MAX_MANA then
            set rawcode = RAWCODE_MANA
         
            if targetValue < 0 then
                call ErrorMsg("You can not set a unit's max mana to below 0")
                return
            endif
        else
            call SetUnitState(target, state, targetValue)
            return
        endif
     
        set difference = R2I(targetValue) - R2I(GetUnitState(target, state))
     
        if difference < 0 then
            set difference = -difference
            set rawcode = rawcode + ABILITY_COUNT
        endif
     
        set abilityId = ABILITY_COUNT - 1
        set abilityLevel = 4
        set currentAbility = rawcode + abilityId
        loop
            exitwhen difference == 0
         
            if difference >= POWERS_OF_2[abilityId * 3 + (abilityLevel - 2)] then
                call UnitAddAbility(target, currentAbility)
                call SetUnitAbilityLevel(target, currentAbility, abilityLevel)
                call UnitRemoveAbility(target, currentAbility)
             
                set difference = difference - POWERS_OF_2[abilityId * 3 + (abilityLevel - 2)]
            else
                set abilityLevel = abilityLevel - 1
                if abilityLevel <= 1 then
                    set abilityId = abilityId - 1
                    set abilityLevel = 4
                    set currentAbility = rawcode + abilityId
                endif
            endif
        endloop
    endfunction

    function AddUnitMaxState takes unit target, unitstate state, real additionalValue returns nothing
        call SetUnitMaxState(target, state, GetUnitState(target, state) + additionalValue)
    endfunction

    //! textmacro UnitMaxState_Preload takes RAWCODE
        set i = 0
        loop
            exitwhen i == ABILITY_COUNT * 2 - 1
         
            static if LIBRARY_AbilityPreload then
                call AbilityPreload($RAWCODE$ + i)
            elseif LIBRARY_xepreload then
                call XE_PreloadAbility($RAWCODE$ + i)
            endif
         
            set i = i + 1
        endloop
    //! endtextmacro

    private function Initialize takes nothing returns nothing
        local integer i
        local integer k
     
        set i = 1
        set POWERS_OF_2[0] = 1
        loop
            exitwhen i == ABILITY_COUNT * 2 * 2 * 3 + 1
         
            set POWERS_OF_2[i] = POWERS_OF_2[i - 1] * 2
            set i = i + 1
        endloop
     
        static if DEBUG_MODE and PRELOAD_ABILITIES and not LIBRARY_AbilityPreload and not LIBRARY_xepreload then
            call ErrorMsg("Ability preloading was enabled, but neither of the supported preload libraries are present")
        elseif PRELOAD_ABILITIES then
            //! runtextmacro UnitMaxState_Preload("RAWCODE_LIFE")
            //! runtextmacro UnitMaxState_Preload("RAWCODE_MANA")
        endif
    endfunction
    endlibrary
     


    And these are the errors:
    Screenshot_1.png
    It's pretty much the whole script. I'm using SharpCraft WEX. With JassHelper enabled.
     
  2. HappyTauren

    HappyTauren

    Joined:
    Nov 3, 2006
    Messages:
    8,408
    Resources:
    87
    Models:
    61
    Icons:
    23
    Packs:
    1
    Tutorials:
    2
    Resources:
    87
    I am pretty sure there's a damage detection system out there that detects whether the damage dealt is done through an attack or not, so use that.
     
  3. DaneTheBeast

    DaneTheBeast

    Joined:
    Dec 11, 2014
    Messages:
    608
    Resources:
    1
    Maps:
    1
    Resources:
    1
    I'll check if GUI's Damage Engine can help me, but the issue still remains that the BonusMod can't be implemented correctly. Even on the test maps they provided it won't compile, meaning the editor doesn't support it, so there's no way to use the mod?
     
  4. HappyTauren

    HappyTauren

    Joined:
    Nov 3, 2006
    Messages:
    8,408
    Resources:
    87
    Models:
    61
    Icons:
    23
    Packs:
    1
    Tutorials:
    2
    Resources:
    87
    BonusMod is in vjass, meaning your map requires a pjass compiler to be ran. You should get WEX editor from the tools section, since it has a pjass compiler.
     
  5. Dat-C3

    Dat-C3

    Joined:
    Mar 15, 2012
    Messages:
    2,567
    Resources:
    10
    Models:
    1
    Maps:
    5
    Spells:
    3
    Tutorials:
    1
    Resources:
    10
  6. DaneTheBeast

    DaneTheBeast

    Joined:
    Dec 11, 2014
    Messages:
    608
    Resources:
    1
    Maps:
    1
    Resources:
    1
    That's what I am using, is it not? WEX.png

    It can't run Implementation Macro triggers since it can't find the InitTrig function, thus it can't create all the needed abilities.

    Edit: I got it to work, by disabling Init function checking in the Extended Settings, it still gave errors because a function call was made to call the InitTrig, but it executed the macros and allowed me to be done with them.
    Now all that is left is to combine 3 systems to simply add max HP to a unit...
     
    Last edited: Jan 22, 2018
  7. HappyTauren

    HappyTauren

    Joined:
    Nov 3, 2006
    Messages:
    8,408
    Resources:
    87
    Models:
    61
    Icons:
    23
    Packs:
    1
    Tutorials:
    2
    Resources:
    87
    @DaneTheBeast I just realized that there is a much easier way to do this.

    1) Create an ability based on item life bonus or whatever it is
    2) Make it have two levels
    3) Set life bonus for lvl 1 to be the amount of life you want to give to a unit
    4) Set life bonus for lvl 2 to be zero
    5) To add the bonus, add the ability, set its level to 2, then remove the ability

    Voila, no need to mess with 1000 lines of code and 3 systems, this will work.
     
  8. DaneTheBeast

    DaneTheBeast

    Joined:
    Dec 11, 2014
    Messages:
    608
    Resources:
    1
    Maps:
    1
    Resources:
    1
    Thank you, but I still need it to be basic-attack only so a system is a must, though having no need for the CSS system makes things easier.. Too bad I already finished it
    Forget about this. The solution is in the post below

    • DCCfg
      • Events
        • Map initialization
      • Conditions
      • Actions
        • Set DC_Health[1] = 1
        • Set DC_Health[2] = 2
        • Set DC_Health[3] = 3
        • Set DC_Health[4] = 4
        • Set DC_Health[5] = 5


    • DC
      • Events
        • Game - AfterDamageEvent becomes Equal to 1.00
      • Conditions
        • (Unit-type of DamageEventSource) Equal to <YourUnit>
        • IsDamageSpell Equal to False
        • (DamageEventTarget is alive) Equal to False
      • Actions
        • Set UNITTemp = DamageEventSource
        • Set NUMBERTemp = (Level of <ThePassiveAbility> for UNITTemp)
        • Custom script: call CSS_AddBonus (udg_UNITTemp, udg_DC_Health[udg_NUMBERTemp], 8)
     
    Last edited: Feb 20, 2018
  9. DaneTheBeast

    DaneTheBeast

    Joined:
    Dec 11, 2014
    Messages:
    608
    Resources:
    1
    Maps:
    1
    Resources:
    1
    Just a small update for anyone who stumbles here in the future: HappyTauren's solution is much more simple and I could get rid of all the bulky systems and item abilities imported by them.

    • SetAbility
      • Events
      • Conditions
      • Actions
        • Set LifeBonus[1] = LifeBonus 1
        • Set LifeBonus[2] = LifeBonus 2
        • Set LifeBonus[3] = LifeBonus 3
        • Set LifeBonus[4] = LifeBonus 4
        • Set LifeBonus[5] = LifeBonus 5


    • DC
      • Events
        • Game - AfterDamageEvent becomes Equal to 1.00
      • Conditions
        • (Unit-type of DamageEventSource) Equal to <YourUnit>
        • IsDamageSpell Equal to False
        • (Level of <PassiveAbility> for DamageEventSource) Greater than 0
        • (DamageEventTarget is dead) Equal to True
      • Actions
        • Set TempUnit = DamageEventSource
        • Set TempInteger = (Level of <PassiveAbility> for TempUnit)
        • Unit - Add LifeBonus[TempInteger] to TempUnit
        • Unit - Set level of LifeBonus[TempInteger] for TempUnit to 2
        • Unit - Remove LifeBonus[TempInteger] from TempUnit