Warcraft 3 documentation

vJASS & Zinc Documentation
For the latest documentation about how it works vJASS and Zinc language layers for Warcraft III, please follow these links:
Jasshelper documentation - Zinc documentation - WC3 Optimizer documentation

BonusMod

moyack · 666

0 Members and 1 Guest are viewing this topic.

Rating

Average Score - 5 / 5

« Created: January 04, 2018, 11:43:24 PM by moyack »

BonusMod
on: April 14, 2012, 09:05:36 AM
Category: Units, System
Language: vJASS
Download Demo Map

Related Topics or Resources



by

by

Version 3.3.1

Introduction

BonusMod is written in vJass and requires the NewGen editor, or Jass Helper with PitzerMike's Object Merger configured for it. BonusMod requires the latest version of Jass Helper.

BonusMod is a system for applying reversible bonuses to stats, such as damage, for specific units. Most of the bonuses provided by this system show green or red numbers in the command card, much like the bonuses provided by items. BonusMod is limited in the range of bonuses it can apply. The more abilities a bonus type uses, the larger the maximum and minimum bonuses.

BonusMod can also grant bonuses through code. For example, five optional bonus types are distributed with the basic BonusMod library. They are maximum life and mana, absolute mana per second regeneration, percentage of life per second regeneration, and movement speed. Even more bonus types can be provided by external libraries. The minimum and maximum bonuses these can apply differ depending on the library providing them.

Further explanation, and a guide to the API, is in the libraries documentation.


Credits
  • weaaddar for the original BonusMod
  • PitzerMike for the ObjectMerger
  • Earth-Fury for the rewrite of BonusMod
  • Vexorian for vJass / Jass Helper
  • All of the contributors to the NewGen editor

The BonusMod Library

Requirements:

  • Optionally, either:
    • AbilityPreload
    • xepreload

The BonusMod library comes with the following bonus types with the given minimum and maximum values:

[btable=Bonus Types and Ranges]Bonus Constant:[c] Minimum:[c]Maximum:[r]
BONUS_DAMAGE[c]
-1024
[c]
+1023
[r]
BONUS_ARMOR[c]
-1024
[c]
+1023
[r]
BONUS_SIGHT_RANGE[c]
-2048
[c]
+2047
[r]
BONUS_LIFE_REGEN[c]
-256
[c]
+255
[r]
BONUS_AGILITY[c]
-256
[c]
+255
[r]
BONUS_STRENGTH[c]
-256
[c]
+255
[r]
BONUS_INTELLIGENCE[c]
-256
[c]
+255
[r]
BONUS_ATTACK_SPEED[c]
-512%
[c]
+511%
[r]
BONUS_MANA_REGEN_PERCENT[c]
-512%
[c]
+511%
[/btable]
Note that you can easily remove unused bonuses, and easily increase or decrease the range of bonuses individually. Information on how is within the libraries documentation.

To add BonusMod to your map, copy and paste the below library in to a custom-text trigger in your map.

You will want to close your map after the first time you save it with BonusMod in it, reopen it, and disable ability (re)generation in the configuration section. If you fail to do that, a small delay will be added every time you save your map.


BonusMod
Code: jass
  1. library BonusMod initializer OnInit requires optional AbilityPreload, optional xepreload
  2. private keyword AbilityBonus
  3. ////////////////////////////////////////////////////////////////////////////////
  4. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  5. //@ BonusMod - v3.3.1
  6. //@=============================================================================
  7. //@ Credits:
  8. //@-----------------------------------------------------------------------------
  9. //@    Written by:
  10. //@        Earth-Fury
  11. //@    Based on the work of:
  12. //@        weaaddar
  13. //@-----------------------------------------------------------------------------
  14. //@ If you use this system, please at least credit weaaddar. Without him, this
  15. //@ system would not exist. I would be happy if you credited me as well.
  16. //@=============================================================================
  17. //@ Requirements:
  18. //@-----------------------------------------------------------------------------
  19. //@ This library is written in vJass and thus requires JASS Helper in order to
  20. //@ function correctly. This library also uses the ObjectMerger created by
  21. //@ PitzerMike. The ObjectMerger must be configured as an external tool for
  22. //@ JASS Helper.
  23. //@
  24. //@ All of these things are present in the NewGen world editor.
  25. //@
  26. //@=============================================================================
  27. //@ Introduction:
  28. //@-----------------------------------------------------------------------------
  29. //@ BonusMod is a system for applying reversible bonuses to certain stats, such
  30. //@ as attack speed or mana regen, for specific units. Most of the bonuses
  31. //@ provided by BonusMod show green or red numbers in the command card, exactly
  32. //@ like the bonuses provided by items.
  33. //@
  34. //@ BonusMod has two kinds of bonuses:
  35. //@   1. Ability based bonuses
  36. //@   2. Code based bonuses
  37. //@
  38. //@ All of the bonuses in the configuration section for the basic BonusMod
  39. //@ library are ability-based bonuses. Code-based bonuses are provided by
  40. //@ additional libraries.
  41. //@
  42. //@ Ability based bonuses have a limit to how much of a bonus they can apply.
  43. //@ The actual limit depends on the number of abilities that type of bonus uses.
  44. //@ See the "Default bonuses" section of this readme for the default limits
  45. //@ of the bonuses that come with BonusMod. For changing the limits of the
  46. //@ default bonuses, or for adding new types of bonuses, see the below
  47. //@ configuration section.
  48. //@
  49. //@ Code based bonuses may or may not have a limit to how much of a bonus they
  50. //@ can apply. The limits for code based bonuses depend entirely on how the
  51. //@ bonus is implemented. See their documentation for more information.
  52. //@
  53. //@=============================================================================
  54. //@ Adding BonusMod to your map:
  55. //@-----------------------------------------------------------------------------
  56. //@ First, you must place the BonusMod library in a custom-text trigger in your
  57. //@ map.
  58. //@
  59. //@ You must then save your map with ability generation enabled. After you save
  60. //@ your map with ability generation enabled, you must close your map in the
  61. //@ editor, and reopen it. You can then disable ability generation.
  62. //@ See the configuration section for information on how to enable and disable
  63. //@ ability generation.
  64. //@
  65. //@=============================================================================
  66. //@ Default bonuses:
  67. //@-----------------------------------------------------------------------------
  68. //@
  69. //@      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  70. //@      | Bonus Type constants:       | Minimum bonus: | Maximum bonus: |
  71. //@      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  72. //@      | BONUS_SIGHT_RANGE           |   -2048        |   +2047        |
  73. //@      | BONUS_ATTACK_SPEED          |   -512         |   +511         |
  74. //@      | BONUS_ARMOR                 |   -1024        |   +1023        |
  75. //@      | BONUS_MANA_REGEN_PERCENT    |   -512%        |   +511%        |
  76. //@      | BONUS_LIFE_REGEN            |   -256         |   +255         |
  77. //@      | BONUS_DAMAGE                |   -1024        |   +1023        |
  78. //@      | BONUS_STRENGTH              |   -256         |   +255         |
  79. //@      | BONUS_AGILITY               |   -256         |   +255         |
  80. //@      | BONUS_INTELLIGENCE          |   -256         |   +255         |
  81. //@      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  82. //@
  83. //@      Notes:
  84. //@         - The bonuses for stength, agility, and intelligence can only be
  85. //@           applied to heroes. Attempting to add them to normal units will
  86. //@           fail to work completely.
  87. //@         - Using a negative BONUS_STRENGTH bonus can give a unit negative
  88. //@           maximum life. Don't do that. It really messes stuff up.
  89. //@         - Using a negative BONUS_INTELLIGENCE bonus can remove a hero's
  90. //@           mana. This is not a big issue, as mana will return when the
  91. //@           bonus is removed.
  92. //@         - The maximum effective sight range for a unit is 1800.
  93. //@         - There is a maximum attack speed. I have no idea what it is.
  94. //@
  95. //@ See the configuration section for information on how to change the range of
  96. //@ bonuses, as well as how to add new ability-based bonuses, and remove unused
  97. //@ ones.
  98. //@
  99. //@=============================================================================
  100. //@ Public API / Function list:
  101. //@-----------------------------------------------------------------------------
  102. //@ Note that BonusMod will only output error messages if JASS Helper is set to
  103. //@ compile in debug mode.
  104. //@
  105. //@ Bonus constants such as BONUS_DAMAGE have .min and .max properties which
  106. //@ are the minimum and maximum bonus that type of bonus can apply. Note that
  107. //@ for code based bonuses, these constants may not reflect the minimum or
  108. //@ maximum bonus for a specific unit. Use the IsBonusValid() function to check
  109. //@ if the given bonus value is okay for a given unit.
  110. //@
  111. //@ function SetUnitBonus
  112. //@ takes unit u, Bonus bonusType, integer amount
  113. //@ returns integer
  114. //@
  115. //@     This function sets the bonus of the type bonusType for the given unit to
  116. //@     the given amount. The returned integer is the unit's actual current
  117. //@     bonus, after it has been changed. If the given amount is above the
  118. //@     maximum possible bonus for this type, then the maximum possible bonus
  119. //@     is applied to the unit. The same is true if the given value is below
  120. //@     the minimum possible bonus.
  121. //@
  122. //@ function GetUnitBonus
  123. //@ takes unit u, Bonus bonusType
  124. //@ returns integer
  125. //@
  126. //@     Returns the given unit's current bonus of bonusType. A value of 0 means
  127. //@     that the given unit does not have a bonus of the given type.
  128. //@
  129. //@ function AddUnitBonus
  130. //@ takes unit u, Bonus bonusType, integer amount
  131. //@ returns integer
  132. //@
  133. //@     Increases the unit's bonus by the given amount. You can use a negitive
  134. //@     amount to subtract from the unit's current bonus. Note that the same
  135. //@     rules SetUnitBonus has apply for going over/under the maximum bonus.
  136. //@     The returned value is the unit's actual new bonus.
  137. //@
  138. //@ function RemoveUnitBonus
  139. //@ takes unit u, Bonus bonusType
  140. //@ returns nothing
  141. //@
  142. //@     Sets the bonus of the type bonusType to 0 for the given unit. This
  143. //@     function is faster then using SetUnitBonus(u, bonusType, 0).
  144. //@
  145. //@ function IsBonusValid
  146. //@ takes unit u, Bonus abstractBonus, integer value
  147. //@ returns boolean
  148. //@
  149. //@     Returns true if the given value is a valid bonus value for the given
  150. //@     unit. This will also return false if the given bonus type is a hero-
  151. //@     only bonus type, and the given unit is not a hero.
  152. //@
  153. //@=============================================================================
  154. //@ Writing code-based bonuses:
  155. //@-----------------------------------------------------------------------------
  156. //@ This section of the readme tells you how to create your own bonus types
  157. //@ that apply their bonuses using vJass code instead of abilities. You do not
  158. //@ need to read or understand this to use BonusMod as-is.
  159. //@
  160. //@ Creating a new bonus type is simple. Extend the Bonus struct, implement the
  161. //@ methods provided within it, and create a single instance of your struct
  162. //@ within a variable named BONUS_YOUR_BONUS_TYPES_NAME of the type Bonus.
  163. //@
  164. //@ The methods you must implement are:
  165. //@
  166. //@ method setBonus takes unit u, integer amount returns integer
  167. //@     This method sets the given unit's current bonus to amount, returning
  168. //@     the actual bonus that was applied. If the given amount is higher then
  169. //@     the maximum amount your bonus type can apply to a unit, you must apply
  170. //@     the maximum possible bonus, and return that amount. The same holds true
  171. //@     for the minimum bonus.
  172. //@
  173. //@ method getBonus takes unit u returns integer
  174. //@     This method returns the current bonus the given unit has.
  175. //@
  176. //@ method removeBonus takes unit u returns nothing
  177. //@     This method sets the current bonus of the given unit to 0.
  178. //@
  179. //@ method isValueInRange takes integer value returns boolean
  180. //@     This method returns true if the given integer is a valid bonus amount
  181. //@     for this bonus type, and false otherwise.
  182. //@
  183. //@ Note that it is your responsibility to do any clean up in the event a unit
  184. //@ dies or is removed with an active bonus on it. There is no guarantee that
  185. //@ removeBonus() will be called before a unit dies or is removed.
  186. //@
  187. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  188. ////////////////////////////////////////////////////////////////////////////////
  189.  
  190. //==============================================================================
  191. // Configuration:
  192. //==============================================================================
  193.  
  194. //------------------------------------------------------------------------------
  195. // If the following constant is set to true, the abilities used by this library
  196. // will be preloaded at map initialization. This will slightly increase loading
  197. // time, but will prevent a slight to medium lag spike the first time a bonus
  198. // of a type is applied.
  199. //
  200. // Note that your map must contain either the xepreload library, or the
  201. // AbilityPreload library for preloading to work.
  202. //
  203. // It is highly recommended that you do not set this to false.
  204. //------------------------------------------------------------------------------
  205. globals
  206.     private constant boolean PRELOAD_ABILITIES = true
  207. endglobals
  208.  
  209. //------------------------------------------------------------------------------
  210. // The BonusMod_BeginBonuses macro takes a single boolean type parameter.
  211. // If set to true, bonus abilities will be created (or recreated) on save.
  212. // If set to false, abilities will not be generated.
  213. //
  214. // If you modify any of the bonus declaration macros, or add new ones, you must
  215. // regenerate abilities.
  216. //
  217. // Note that if you remove a bonus, the abilities it had created will not be
  218. // automatically removed. This is also true of reducing the number of abilities
  219. // a bonus uses.
  220. //
  221. // After you generate abilities, you must close your map and reopen it in the
  222. // editor. You can then disable ability generation until the next time you
  223. // modify the bonus types.
  224. //------------------------------------------------------------------------------
  225. //! runtextmacro BonusMod_BeginBonuses("true")
  226.     //--------------------------------------------------------------------------
  227.     // Below are where bonus types are defined.
  228.     //
  229.     // The first parameter is the name of the bonus type. A constant will be
  230.     // generated for each bonus type, that will take the form: BONUS_NAME
  231.     //
  232.     // The second parameter is the maximum power of 2 the bonus type can add
  233.     // to a unit. For example, 8 abilities gives a range of -256 to +255.
  234.     //
  235.     // The third parameter is the base ability. The base ability must give the
  236.     // desired effect when the given field is changed.
  237.     //
  238.     // The fourth parameter is the rawcode prefix of the bonuses generated
  239.     // abilities. The prefix must be 3 characters long. Your map must not
  240.     // already contain bonuses which start with the given prefix.
  241.     //
  242.     // The fifth parameter is the object field to modify for each generated
  243.     // ability.
  244.     //
  245.     // The sixth parameter must be true of the bonus should only work on hero
  246.     // units, and false otherwise.
  247.     //
  248.     // The final parameter is the icon that will be displayed in the object
  249.     // editor. This has no effect on anything ingame.
  250.     //--------------------------------------------------------------------------
  251.    
  252.     //                                    |     NAME     |ABILITY|SOURCE |PREFIX|FIELD  | HERO   |  ICON
  253.     //                                    |              | COUNT |ABILITY|      |       |  ONLY  |
  254.     //! runtextmacro BonusMod_DeclareBonus("ARMOR",        "10",  "AId1", "(A)", "Idef", "false", "BTNHumanArmorUpOne.blp")
  255.     //! runtextmacro BonusMod_DeclareBonus("DAMAGE",       "10",  "AItg", "(B)", "Iatt", "false", "BTNSteelMelee.blp")
  256.     //! runtextmacro BonusMod_DeclareBonus("SIGHT_RANGE",  "11",  "AIsi", "(C)", "Isib", "false", "BTNTelescope.blp")
  257.     //! runtextmacro BonusMod_DeclareBonus("LIFE_REGEN",   "8",   "Arel", "(E)", "Ihpr", "false", "BTNRingSkull.blp")
  258.     //! runtextmacro BonusMod_DeclareBonus("STRENGTH",     "8",   "AIa1", "(F)", "Istr", "true" , "BTNGoldRing.blp")
  259.     //! runtextmacro BonusMod_DeclareBonus("AGILITY",      "8",   "AIa1", "(G)", "Iagi", "true" , "BTNGoldRing.blp")
  260.     //! runtextmacro BonusMod_DeclareBonus("INTELLIGENCE", "8",   "AIa1", "(H)", "Iint", "true" , "BTNGoldRing.blp")
  261.    
  262.     //                                           |     NAME          |ABILITY|SOURCE |PREFIX|FIELD  |HERO   |  ICON
  263.     //                                           |                   | COUNT |ABILITY|      |       | ONLY  |
  264.     //! runtextmacro BonusMod_DeclarePercentBonus("ATTACK_SPEED",       "9", "AIsx",  "(I)", "Isx1", "false", "BTNGlove.blp")
  265.     //! runtextmacro BonusMod_DeclarePercentBonus("MANA_REGEN_PERCENT", "9", "AIrm",  "(D)", "Imrp", "false", "BTNSobiMask.blp")
  266.    
  267. //! runtextmacro BonusMod_EndBonuses()
  268.  
  269. //==============================================================================
  270. // End of configuration
  271. //==============================================================================
  272.  
  273. //! textmacro BonusMod_BeginBonuses takes SHOULD_GENERATE_ABILITIES
  274.     private function Setup takes nothing returns nothing
  275.    
  276.     // The following is a lua script for the ObjectMerger, used to generate abilities
  277.     //*
  278.     //! externalblock extension=lua ObjectMerger $FILENAME$
  279.     //! i if "$SHOULD_GENERATE_ABILITIES$" == "true" then
  280.     //! i function FormatName(name)
  281.     //! i     name = string.lower(name)
  282.     //! i     name = string.gsub(name, "_", " ")
  283.     //! i     s = name
  284.     //! i     name = ""
  285.     //! i     for w in string.gmatch(s, "%a%w*") do
  286.     //! i         name = name .. string.upper(string.sub(w, 1, 1)) .. string.sub(w, 2, -1)
  287.     //! i         name = name .. " "
  288.     //! i     end
  289.     //! i     name = string.sub(name, 1, string.len(name) - 1)
  290.     //! i     return name
  291.     //! i end
  292.     //! i function SetupAbility(name, suffix, icon, hero)
  293.     //! i     makechange(current, "anam", "BonusMod - " .. FormatName(name))
  294.     //! i     makechange(current, "ansf", "(" .. suffix .. ")")
  295.     //! i     makechange(current, "aart", "ReplaceableTextures\\CommandButtons\\" .. icon)
  296.     //! i     makechange(current, "aite", 0)
  297.     //! i     if hero then
  298.     //! i         makechange(current, "Iagi", 1, 0)
  299.     //! i         makechange(current, "Iint", 1, 0)
  300.     //! i         makechange(current, "Istr", 1, 0)
  301.     //! i     end
  302.     //! i end
  303.     //! i function CreateAbility(sourceAbility, prefix, field, abilityCount, name, icon)
  304.     //! i     powOf2 = abilityCount - 1
  305.     //! i     lengthOfMax = string.len(tostring(2^abilityCount))
  306.     //! i     for i = 0, powOf2 do
  307.     //! i         padding = ""
  308.     //! i         for k = 0, lengthOfMax - string.len(tostring(2^i)) - 1 do
  309.     //! i             padding = padding .. "0"
  310.     //! i         end
  311.     //! i         createobject(sourceAbility, prefix .. string.sub(chars, i + 1, i + 1))
  312.     //! i         SetupAbility(name, "+" .. padding .. tostring(2 ^ i), icon, true)
  313.     //! i         makechange(current, field, 1, tostring(2^i))
  314.     //! i     end
  315.     //! i     createobject(sourceAbility, prefix .. "-")
  316.     //! i     SetupAbility(name, "-" .. tostring(2 ^ abilityCount), icon, true)
  317.     //! i     makechange(current, field, 1, tostring(-(2^abilityCount)))
  318.     //! i end
  319.     //! i function CreatePercentageAbility(sourceAbility, prefix, field, abilityCount, name, icon)
  320.     //! i     powOf2 = abilityCount - 1
  321.     //! i     lengthOfMax = string.len(tostring(2^abilityCount))
  322.     //! i     for i = 0, powOf2 do
  323.     //! i         padding = ""
  324.     //! i         for k = 0, lengthOfMax - string.len(tostring(2^i)) - 1 do
  325.     //! i             padding = padding .. "0"
  326.     //! i         end
  327.     //! i         createobject(sourceAbility, prefix .. string.sub(chars, i + 1, i + 1))
  328.     //! i         SetupAbility(name, "+" .. padding .. tostring(2 ^ i) .. "%", icon, false)
  329.     //! i         makechange(current, field, 1, tostring((2 ^ i) / 100))
  330.     //! i     end
  331.     //! i     createobject(sourceAbility, prefix .. "-")
  332.     //! i     SetupAbility(name, "-" .. tostring(2 ^ abilityCount) .. "%", icon, false)
  333.     //! i     makechange(current, field, 1, tostring(-((2 ^ abilityCount) / 100)))
  334.     //! i end
  335.     //! i     setobjecttype("abilities")
  336.     //! i     chars = "abcdefghijklmnopqrstuvwxyz"
  337.     //! i
  338.     // */
  339. //! endtextmacro
  340.  
  341. //! textmacro BonusMod_DeclareBonus takes NAME, ABILITY_COUNT, SOURCE_ABILITY, RAWCODE_PREFIX, FIELD, HERO_ONLY, ICON
  342.     //! i CreateAbility("$SOURCE_ABILITY$", "$RAWCODE_PREFIX$", "$FIELD$", $ABILITY_COUNT$, "$NAME$", "$ICON$")
  343.     globals
  344.         Bonus BONUS_$NAME$
  345.     endglobals
  346.     set BONUS_$NAME$ = AbilityBonus.create('$RAWCODE_PREFIX$a', $ABILITY_COUNT$, '$RAWCODE_PREFIX$-', $HERO_ONLY$)
  347. //! endtextmacro
  348.  
  349. //! textmacro BonusMod_DeclarePercentBonus takes NAME, ABILITY_COUNT, SOURCE_ABILITY, RAWCODE_PREFIX, FIELD, HERO_ONLY, ICON
  350.     //! i CreatePercentageAbility("$SOURCE_ABILITY$", "$RAWCODE_PREFIX$", "$FIELD$", $ABILITY_COUNT$, "$NAME$", "$ICON$")
  351.     globals
  352.         Bonus BONUS_$NAME$
  353.     endglobals
  354.     set BONUS_$NAME$ = AbilityBonus.create('$RAWCODE_PREFIX$a', $ABILITY_COUNT$, '$RAWCODE_PREFIX$-', $HERO_ONLY$)
  355. //! endtextmacro
  356.  
  357. //! textmacro BonusMod_EndBonuses
  358.     //*
  359.     //! i end
  360.     //! endexternalblock
  361.     // */
  362.    
  363.     endfunction
  364. //! endtextmacro
  365.  
  366. // ===
  367. //  Precomputed integer powers of 2
  368. // ===
  369.  
  370. globals
  371.     private integer array powersOf2
  372.     private integer powersOf2Count = 0
  373. endglobals
  374.  
  375. // ===
  376. //  Utility functions
  377. // ===
  378.  
  379. private function ErrorMsg takes string func, string s returns nothing
  380.     call BJDebugMsg("|cffFF0000BonusMod Error|r|cffFFFF00:|r |cff8080FF" + func + "|r|cffFFFF00:|r " + s)
  381. endfunction
  382.  
  383. private function LoadAbility takes integer abilityId returns nothing
  384.     static if PRELOAD_ABILITIES then
  385.         static if LIBRARY_xepreload then
  386.             call XE_PreloadAbility(abilityId)
  387.         else
  388.             static if LIBRARY_AbilityPreload then
  389.                 call AbilityPreload(abilityId)
  390.             endif
  391.         endif
  392.     endif
  393. endfunction
  394.  
  395. // ===
  396. //  Bonus Types
  397. // ===
  398.  
  399. private interface BonusInterface
  400.     integer minBonus = 0
  401.     integer maxBonus = 0
  402.     private method destroy takes nothing returns nothing defaults nothing
  403. endinterface
  404.  
  405. private keyword isBonusObject
  406.  
  407. struct Bonus extends BonusInterface
  408.     boolean isBonusObject = false
  409.    
  410.     public static method create takes nothing returns thistype
  411.         local thistype this = thistype.allocate()
  412.        
  413.         set this.isBonusObject = true
  414.        
  415.         return this
  416.     endmethod
  417.    
  418.     stub method setBonus takes unit u, integer amount returns integer
  419.         debug call ErrorMsg("Bonus.setBonus()", "I have no idea how or why you did this, but don't do it.")
  420.         return 0
  421.     endmethod
  422.    
  423.     stub method getBonus takes unit u returns integer
  424.         debug call ErrorMsg("Bonus.getBonus()", "I have no idea how or why you did this, but don't do it.")
  425.         return 0
  426.     endmethod
  427.    
  428.     stub method removeBonus takes unit u returns nothing
  429.         call this.setBonus(u, 0)
  430.     endmethod
  431.    
  432.     stub method isValidBonus takes unit u, integer value returns boolean
  433.         return true
  434.     endmethod
  435.    
  436.     method operator min takes nothing returns integer
  437.         return this.minBonus
  438.     endmethod
  439.    
  440.     method operator max takes nothing returns integer
  441.         return this.maxBonus
  442.     endmethod
  443. endstruct
  444.  
  445. private struct AbilityBonus extends Bonus
  446.     public integer count
  447.    
  448.     public integer rawcode
  449.     public integer negativeRawcode
  450.    
  451.     public integer minBonus = 0
  452.     public integer maxBonus = 0
  453.    
  454.     public boolean heroesOnly
  455.    
  456.     public static method create takes integer rawcode, integer count, integer negativeRawcode, boolean heroesOnly returns thistype
  457.         local thistype bonus = thistype.allocate()
  458.         local integer i
  459.         debug local boolean error = false
  460.        
  461.         // Error messages
  462.         static if DEBUG_MODE then
  463.             if rawcode == 0 then
  464.                 call ErrorMsg("AbilityBonus.create()", "Bonus constructed with a rawcode of 0?!")
  465.                 call bonus.destroy()
  466.                 return 0
  467.             endif
  468.            
  469.             if count < 0 or count == 0 then
  470.                 call ErrorMsg("AbilityBonus.create()", "Bonus constructed with an ability count <= 0?!")
  471.                 call bonus.destroy()
  472.                 return 0
  473.             endif
  474.         endif
  475.        
  476.         // Grow powers of 2
  477.         if powersOf2Count < count then
  478.             set i = powersOf2Count
  479.             loop
  480.                 exitwhen i > count
  481.                
  482.                 set powersOf2[i] = 2 * powersOf2[i - 1]
  483.  
  484.                 set i = i + 1
  485.             endloop
  486.             set powersOf2Count = count
  487.         endif
  488.        
  489.         // Preload this bonus' abilities
  490.         static if PRELOAD_ABILITIES then
  491.             set i = 0
  492.             loop
  493.                 exitwhen i == count
  494.                
  495.                 call LoadAbility(rawcode + i)
  496.                
  497.                 set i = i + 1
  498.             endloop
  499.            
  500.             if negativeRawcode != 0 then
  501.                 call LoadAbility(negativeRawcode)
  502.             endif
  503.         endif
  504.        
  505.         // Set up this bonus object
  506.         set bonus.count = count
  507.         set bonus.negativeRawcode = negativeRawcode
  508.         set bonus.rawcode = rawcode
  509.         set bonus.heroesOnly = heroesOnly
  510.        
  511.         // Calculate the minimum and maximum bonuses
  512.         if negativeRawcode != 0 then
  513.             set bonus.minBonus = -powersOf2[count]
  514.         else
  515.             set bonus.minBonus = 0
  516.         endif
  517.         set bonus.maxBonus = powersOf2[count] - 1
  518.        
  519.         // Return the bonus object
  520.         return bonus
  521.     endmethod
  522.    
  523.     // Interface methods:
  524.    
  525.     method setBonus takes unit u, integer amount returns integer
  526.         return SetUnitBonus.evaluate(u, this, amount)
  527.     endmethod
  528.    
  529.     method getBonus takes unit u returns integer
  530.         return GetUnitBonus.evaluate(u, this)
  531.     endmethod
  532.    
  533.     method removeBonus takes unit u returns nothing
  534.         call RemoveUnitBonus.evaluate(u, this)
  535.     endmethod
  536.    
  537.     public method isValidBonus takes unit u, integer value returns boolean
  538.         return (value >= this.minBonus) and (value <= this.maxBonus)
  539.     endmethod
  540. endstruct
  541.  
  542. // ===
  543. //  Public API
  544. // ===
  545.  
  546. function IsBonusValid takes unit u, Bonus abstractBonus, integer value returns boolean
  547.     local AbilityBonus bonus = AbilityBonus(abstractBonus)
  548.    
  549.     static if DEBUG_MODE then
  550.         if not abstractBonus.isBonusObject then
  551.             call ErrorMsg("IsBonusValid()", "Invalid bonus type given")
  552.         endif
  553.     endif
  554.    
  555.     if abstractBonus.min > value or abstractBonus.max < value then
  556.         return false
  557.     endif
  558.    
  559.     if abstractBonus.getType() != AbilityBonus.typeid then
  560.         return abstractBonus.isValidBonus(u, value)
  561.     endif
  562.    
  563.     if bonus.heroesOnly and not IsUnitType(u, UNIT_TYPE_HERO) then
  564.         return false
  565.     endif
  566.    
  567.     return (value >= bonus.minBonus) and (value <= bonus.maxBonus)
  568. endfunction
  569.  
  570. function RemoveUnitBonus takes unit u, Bonus abstractBonus returns nothing
  571.     local integer i = 0
  572.     local AbilityBonus bonus = AbilityBonus(abstractBonus)
  573.  
  574.     static if DEBUG_MODE then
  575.         if not abstractBonus.isBonusObject then
  576.             call ErrorMsg("RemoveUnitBonus()", "Invalid bonus type given")
  577.         endif
  578.     endif
  579.    
  580.     if abstractBonus.getType() != AbilityBonus.typeid then
  581.         call abstractBonus.removeBonus(u)
  582.         return
  583.     endif
  584.    
  585.     if bonus.heroesOnly and not IsUnitType(u, UNIT_TYPE_HERO) then
  586.         debug call ErrorMsg("RemoveUnitBonus()", "Trying to remove a hero-only bonus from a non-hero unit")
  587.         return
  588.     endif
  589.    
  590.     call UnitRemoveAbility(u, bonus.negativeRawcode)
  591.    
  592.     loop
  593.         exitwhen i == bonus.count
  594.        
  595.         call UnitRemoveAbility(u, bonus.rawcode + i)
  596.  
  597.         set i = i + 1
  598.     endloop
  599. endfunction
  600.  
  601. function SetUnitBonus takes unit u, Bonus abstractBonus, integer amount returns integer
  602.     local integer i
  603.     local integer output = 0
  604.     local AbilityBonus bonus = AbilityBonus(abstractBonus)
  605.     local boolean applyMinBonus = false
  606.    
  607.     static if DEBUG_MODE then
  608.         if not abstractBonus.isBonusObject then
  609.             call ErrorMsg("SetUnitBonus()", "Invalid bonus type given")
  610.         endif
  611.     endif
  612.    
  613.     if amount == 0 then
  614.         call RemoveUnitBonus(u, bonus)
  615.         return 0
  616.     endif
  617.    
  618.     if abstractBonus.getType() != AbilityBonus.typeid then
  619.         return abstractBonus.setBonus(u, amount)
  620.     endif
  621.    
  622.     if bonus.heroesOnly and not IsUnitType(u, UNIT_TYPE_HERO) then
  623.         debug call ErrorMsg("SetUnitBonus()", "Trying to set a hero-only bonus on a non-hero unit")
  624.         return 0
  625.     endif
  626.    
  627.     if amount < bonus.minBonus then
  628.         debug call ErrorMsg("SetUnitBonus()", "Attempting to set a bonus to below its min value")
  629.         set amount = bonus.minBonus
  630.     elseif amount > bonus.maxBonus then
  631.         debug call ErrorMsg("SetUnitBonus()", "Attempting to set a bonus to above its max value")
  632.         set amount = bonus.maxBonus
  633.     endif
  634.    
  635.     if amount < 0 then
  636.         set amount = -(bonus.minBonus - amount)
  637.         set applyMinBonus = true
  638.     endif
  639.    
  640.     call UnitRemoveAbility(u, bonus.negativeRawcode)
  641.    
  642.     set i = bonus.count - 1
  643.     loop
  644.         exitwhen i < 0
  645.         if amount >= powersOf2[i] then
  646.            
  647.             call UnitAddAbility(u, bonus.rawcode + i)
  648.             call UnitMakeAbilityPermanent(u, true, bonus.rawcode + i)
  649.            
  650.             static if DEBUG_MODE then
  651.                 if GetUnitAbilityLevel(u, bonus.rawcode + i) <= 0 then
  652.                     call ErrorMsg("SetUnitBonus()", "Failed to give the 2^" + I2S(i) + " ability to the unit!")
  653.                 endif
  654.             endif
  655.            
  656.             set amount = amount - powersOf2[i]
  657.             set output = output + powersOf2[i]
  658.         else
  659.            
  660.             call UnitRemoveAbility(u, bonus.rawcode + i)
  661.             static if DEBUG_MODE then
  662.                 if GetUnitAbilityLevel(u, bonus.rawcode + i) > 0 then
  663.                     call ErrorMsg("SetUnitBonus()", "Unit still has the 2^" + I2S(i) + " ability after it was removed!")
  664.                 endif
  665.             endif
  666.         endif
  667.  
  668.         set i = i - 1
  669.     endloop
  670.    
  671.     if applyMinBonus then
  672.         call UnitAddAbility(u, bonus.negativeRawcode)
  673.         call UnitMakeAbilityPermanent(u, true, bonus.negativeRawcode)
  674.     else
  675.         call UnitRemoveAbility(u, bonus.negativeRawcode)
  676.     endif
  677.    
  678.     return output
  679. endfunction
  680.  
  681. function GetUnitBonus takes unit u, Bonus abstractBonus returns integer
  682.     local integer i = 0
  683.     local integer amount = 0
  684.     local AbilityBonus bonus = AbilityBonus(abstractBonus)
  685.  
  686.     static if DEBUG_MODE then
  687.         if not abstractBonus.isBonusObject then
  688.             call ErrorMsg("GetUnitBonus()", "Invalid bonus type given")
  689.         endif
  690.     endif
  691.    
  692.     if abstractBonus.getType() != AbilityBonus.typeid then
  693.         return abstractBonus.getBonus(u)
  694.     endif
  695.    
  696.     if bonus.heroesOnly and not IsUnitType(u, UNIT_TYPE_HERO) then
  697.         debug call ErrorMsg("GetUnitBonus()", "Trying to get a hero-only bonus from a non-hero unit")
  698.         return 0
  699.     endif
  700.    
  701.     if GetUnitAbilityLevel(u, bonus.negativeRawcode) > 0 then
  702.         set amount = bonus.minBonus
  703.     endif
  704.  
  705.     loop
  706.         exitwhen i == bonus.count
  707.        
  708.         if GetUnitAbilityLevel(u, bonus.rawcode + i) > 0 then
  709.             set amount = amount + powersOf2[i]
  710.         endif
  711.  
  712.         set i = i + 1
  713.     endloop
  714.  
  715.     return amount
  716. endfunction
  717.  
  718. function AddUnitBonus takes unit u, Bonus bonus, integer amount returns integer
  719.     return SetUnitBonus(u, bonus, GetUnitBonus(u, bonus) + amount)
  720. endfunction
  721.  
  722. // ===
  723. //  Initialization
  724. // ===
  725.  
  726. private function OnInit takes nothing returns nothing
  727.     local integer i
  728.    
  729.     // Set up powers of 2
  730.     set powersOf2[0] = 1
  731.     set powersOf2Count = 1
  732.    
  733.     static if DEBUG_MODE and PRELOAD_ABILITIES and not LIBRARY_xepreload and not LIBRARY_AbilityPreload then
  734.         call ErrorMsg("Initialization", "PRELOAD_ABILITIES is set to true, but neither usable preloading library is detected")
  735.     endif
  736.    
  737.     // Setup bonuses
  738.     call Setup()
  739. endfunction
  740. endlibrary


Additional Bonus Types

Bonus Maximum Life / Mana

Requirements:

  • BonusMod
  • AutoIndex

This library provides two new bonus types:
[btable=Bonus Types and Ranges]Bonus Constant:[r]
BONUS_LIFE[r]
BONUS_MANA[/btable]

The minimum bonus these bonus types can apply depends on the unit. You can apply any positive or negative bonus that does not result in a unit's maximum life or maximum mana going below 1.

To add these bonuses to BonusMod, simply copy and paste the following library in to a custom-text trigger in your map.

Bonus Max Life / Mana
Code: jass
  1. library UnitMaxStateBonuses initializer OnInit requires BonusMod, UnitMaxState, AutoIndex
  2. ////////////////////////////////////////////////////////////////////////////////
  3. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  4. //@ UnitMaxStateBonuses for BonusMod
  5. //@=============================================================================
  6. //@ Credits:
  7. //@-----------------------------------------------------------------------------
  8. //@    Written by:
  9. //@        Earth-Fury
  10. //@=============================================================================
  11. //@ Requirements:
  12. //@-----------------------------------------------------------------------------
  13. //@ This library requires the BonusMod library, the UnitMaxState library by
  14. //@ Earth-Fury, and the AutoIndex library by grim001.
  15. //@
  16. //@=============================================================================
  17. //@ Readme:
  18. //@-----------------------------------------------------------------------------
  19. //@ This library provides two new bonus types:
  20. //@
  21. //@   - BONUS_LIFE
  22. //@   - BONUS_MANA
  23. //@
  24. //@ These bonuses, of course, raise a unit's maximum life and mana.
  25. //@
  26. //@ Note that if you simply wish to permanently increase or decrease the maximum
  27. //@ life or mana of a unit, you are likely best off using UnitMaxState directly.
  28. //@
  29. //@ The minimum life and mana bonuses are 1 more than -(unit's max state).
  30. //@ That is to say, these bonuses can not fully remove a unit's life or mana.
  31. //@
  32. //@ There is no maximum bonus.
  33. //@
  34. //@ There is nothing to configure.
  35. //@
  36. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  37. ////////////////////////////////////////////////////////////////////////////////
  38.  
  39. globals
  40.     Bonus BONUS_LIFE
  41.     Bonus BONUS_MANA
  42. endglobals
  43.  
  44. private function ErrorMsg takes string func, string s returns nothing
  45.     call BJDebugMsg("|cffFF0000UnitMaxStateBonus Error|r|cffFFFF00:|r |cff8080FF" + func + "|r|cffFFFF00:|r " + s)
  46. endfunction
  47.  
  48. private struct BonusValues
  49.     public integer mana = 0
  50.     public integer life = 0
  51.    
  52.     public unit owner
  53.    
  54.     private static thistype array owners
  55.    
  56.     private static method create takes unit u returns thistype
  57.         local thistype this = thistype.allocate()
  58.        
  59.         set this.owner = u
  60.        
  61.         set thistype.owners[GetUnitId(u)] = this
  62.        
  63.         return this
  64.     endmethod
  65.    
  66.     private method onDestroy takes nothing returns nothing
  67.         set thistype.owners[GetUnitId(this.owner)] = thistype(0)
  68.         set this.owner = null
  69.     endmethod
  70.    
  71.     public static method getInstance takes unit u returns thistype
  72.         if thistype.owners[GetUnitId(u)] == 0 then
  73.             return thistype.create(u)
  74.         else
  75.             return thistype.owners[GetUnitId(u)]
  76.         endif
  77.     endmethod
  78.    
  79.     public static method operator[] takes unit u returns thistype
  80.         return thistype.owners[GetUnitId(u)]
  81.     endmethod
  82.    
  83.     public static method operator[]= takes unit u, thistype i returns nothing
  84.         set thistype.owners[GetUnitId(u)] = i
  85.     endmethod
  86. endstruct
  87.  
  88. //! textmacro UnitMaxStateBonus_DefineBonus takes NAME, STATE, MIN
  89. private struct MaxStateBonus_$NAME$ extends Bonus
  90.     integer minBonus = -2147483648
  91.     integer maxBonus =  2147483647
  92.    
  93.     method setBonus takes unit u, integer amount returns integer
  94.         local BonusValues values
  95.         local integer actual
  96.         local integer new
  97.         local real factor
  98.        
  99.         if not IsUnitIndexed(u) then
  100.             debug call ErrorMsg("MaxStateBonus_$NAME$.setBonus()", "Unit that is not indexed by AutoIndex given")
  101.             return 0
  102.         endif
  103.        
  104.         set values = BonusValues.getInstance(u)
  105.        
  106.         set actual = R2I(GetUnitState(u, UNIT_STATE_MAX_$STATE$)) - values.$NAME$
  107.         set new = actual + amount
  108.        
  109.         set factor = GetUnitState(u, UNIT_STATE_$STATE$) / GetUnitState(u, UNIT_STATE_MAX_$STATE$)
  110.        
  111.         if new < $MIN$ then
  112.             if actual < $MIN$ then
  113.                 set values.$NAME$ = 0
  114.             else
  115.                 set values.$NAME$ = -actual + $MIN$
  116.             endif
  117.            
  118.             call SetUnitState(u, UNIT_STATE_$STATE$, $MIN$)
  119.             call SetUnitMaxState(u, UNIT_STATE_MAX_$STATE$, $MIN$)
  120.             return values.$NAME$
  121.         else
  122.             set values.$NAME$ = amount
  123.            
  124.             call SetUnitMaxState(u, UNIT_STATE_MAX_$STATE$, new)
  125.             call SetUnitState(u, UNIT_STATE_$STATE$, new * factor)
  126.            
  127.             return values.$NAME$
  128.         endif
  129.     endmethod
  130.    
  131.     method getBonus takes unit u returns integer
  132.         local BonusValues values
  133.         local integer actual
  134.         local integer new
  135.         local real factor
  136.        
  137.         if not IsUnitIndexed(u) then
  138.             debug call ErrorMsg("MaxStateBonus_$NAME$.getBonus()", "Unit that is not indexed by AutoIndex given")
  139.             return 0
  140.         endif
  141.        
  142.         set values = BonusValues[u]
  143.        
  144.         if values == 0 then
  145.             return 0
  146.         endif
  147.        
  148.         set values.$NAME$ = R2I(GetUnitState(u, UNIT_STATE_MAX_$STATE$)) - (R2I(GetUnitState(u, UNIT_STATE_MAX_$STATE$)) - values.$NAME$)
  149.        
  150.         return values.$NAME$
  151.     endmethod
  152.    
  153.     method removeBonus takes unit u returns nothing
  154.         call this.setBonus(u, 0)
  155.     endmethod
  156.    
  157.     method isValidBonus takes unit u, integer value returns boolean
  158.         local integer currentBonus
  159.        
  160.         if not IsUnitIndexed(u) then
  161.             return false
  162.         endif
  163.        
  164.         set currentBonus = this.getBonus(u)
  165.        
  166.         return R2I(GetUnitState(u, UNIT_STATE_MAX_$STATE$)) - currentBonus + value >= $MIN$
  167.     endmethod
  168. endstruct
  169. //! endtextmacro
  170.  
  171. //! runtextmacro UnitMaxStateBonus_DefineBonus("life", "LIFE", "1")
  172. //! runtextmacro UnitMaxStateBonus_DefineBonus("mana", "MANA", "1")
  173.  
  174. private function OnLeaveMap takes unit u returns nothing
  175.     if BonusValues[u] != 0 then
  176.         call BonusValues[u].destroy()
  177.     endif
  178. endfunction
  179.  
  180. private function OnInit takes nothing returns nothing
  181.     call OnUnitDeindexed(OnLeaveMap)
  182.    
  183.     set BONUS_LIFE = MaxStateBonus_life.create()
  184.     set BONUS_MANA = MaxStateBonus_mana.create()
  185. endfunction
  186. endlibrary


Bonus Life Regen (%) and Mana Regen (Absolute)

Requirements:

  • BonusMod
  • AutoIndex

This library provides two new bonus types:
[btable=Bonus Types and Ranges]Bonus Constant:[r]
BONUS_MANA_REGEN[r]
BONUS_LIFE_REGEN_PERCENT[/btable]
These bonuses do not have minimum or maximum values. Any bonus amount is valid.

To add these bonuses to BonusMod, simply copy and paste the following library in to a custom-text trigger in your map. You may wish to change the refresh delay of the system, to either increase or decrease the time between updates.

Bonus Life Regen (%) and Mana Regen (Absolute)
Code: jass
  1. library RegenBonuses initializer OnInit requires BonusMod, AutoIndex
  2. ////////////////////////////////////////////////////////////////////////////////
  3. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  4. //@ RegenBonuses for BonusMod
  5. //@=============================================================================
  6. //@ Credits:
  7. //@-----------------------------------------------------------------------------
  8. //@    Written by:
  9. //@        Earth-Fury
  10. //@=============================================================================
  11. //@ Requirements:
  12. //@-----------------------------------------------------------------------------
  13. //@ This library requires the BonusMod library, and the AutoIndex library.
  14. //@
  15. //@=============================================================================
  16. //@ Readme:
  17. //@-----------------------------------------------------------------------------
  18. //@ This library provides two new bonus types:
  19. //@
  20. //@   - BONUS_MANA_REGEN
  21. //@         Regenerates an absolute amount of mana every second
  22. //@
  23. //@   - BONUS_LIFE_REGEN_PERCENT
  24. //@         Regenerates a percent of a unit's maximum life every second
  25. //@
  26. //@ Any value is a valid bonus. There are no limits.
  27. //@
  28. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  29. ////////////////////////////////////////////////////////////////////////////////
  30.  
  31. //==============================================================================
  32. // Configuration:
  33. //==============================================================================
  34.  
  35. //------------------------------------------------------------------------------
  36. // The following constant determines how often the life and mana bonuses are
  37. // applied to units. Note that this will not effect the values of the bonuses.
  38. // The values of the bonuses will always be mana per second/percentage of life
  39. // per second. This constant simply determines how often the values are updated.
  40. //------------------------------------------------------------------------------
  41. globals
  42.     private real REGEN_PERIOD = 0.1
  43. endglobals
  44.  
  45. //==============================================================================
  46. // End of configuration
  47. //==============================================================================
  48.  
  49. globals
  50.     Bonus BONUS_MANA_REGEN
  51.     Bonus BONUS_LIFE_REGEN_PERCENT
  52. endglobals
  53.  
  54. private function ErrorMsg takes string func, string s returns nothing
  55.     call BJDebugMsg("|cffFF0000RegenBonuses Error|r|cffFFFF00:|r |cff8080FF" + func + "|r|cffFFFF00:|r " + s)
  56. endfunction
  57.  
  58. globals
  59.     private timer regenTimer = CreateTimer()
  60. endglobals
  61.  
  62. private keyword BonusValues
  63.  
  64. private function DoRegen takes nothing returns nothing
  65.     local integer i
  66.     local BonusValues values
  67.    
  68.     // Loop over all active bonuses
  69.     set i = 0
  70.     loop
  71.         exitwhen i == BonusValues.count
  72.        
  73.         set values = BonusValues.all[i]
  74.        
  75.         if GetWidgetLife(values.owner) > 0.0 then
  76.             if values.manaRegen > 0 then
  77.                 // Do mana regen:
  78.                 call SetUnitState(values.owner, UNIT_STATE_MANA, GetUnitState(values.owner, UNIT_STATE_MANA) + (values.manaRegen * REGEN_PERIOD))
  79.             endif
  80.            
  81.             if values.lifeRegen > 0 then
  82.                 // Do life regen:
  83.                 call SetUnitState(values.owner, UNIT_STATE_LIFE, GetUnitState(values.owner, UNIT_STATE_LIFE) + (GetUnitState(values.owner, UNIT_STATE_MAX_LIFE) * (values.lifeRegen / 100.0)) * REGEN_PERIOD)
  84.             endif
  85.         endif
  86.        
  87.         set i = i + 1
  88.     endloop
  89. endfunction
  90.  
  91. private struct BonusValues
  92.     public integer manaRegen = 0
  93.     public integer lifeRegen = 0
  94.    
  95.     public unit owner
  96.    
  97.     private static thistype array owners
  98.    
  99.     public static thistype array all
  100.     public static integer count = 0
  101.     public integer index
  102.    
  103.     private static method create takes unit u returns thistype
  104.         local thistype this = thistype.allocate()
  105.        
  106.         set this.owner = u
  107.        
  108.         set thistype.owners[GetUnitId(u)] = this
  109.        
  110.         if thistype.count == 0 then
  111.             call TimerStart(regenTimer, REGEN_PERIOD, true, function DoRegen)
  112.         endif
  113.        
  114.         set thistype.all[thistype.count] = this
  115.         set this.index = thistype.count
  116.         set thistype.count = thistype.count + 1
  117.        
  118.         return this
  119.     endmethod
  120.    
  121.     private method onDestroy takes nothing returns nothing
  122.         set thistype.owners[GetUnitId(this.owner)] = thistype(0)
  123.        
  124.         set thistype.all[this.index] = thistype.all[thistype.count]
  125.         set thistype.count = thistype.count - 1
  126.        
  127.         if thistype.count == 0 then
  128.             call PauseTimer(regenTimer)
  129.         endif
  130.        
  131.         set this.owner = null
  132.     endmethod
  133.    
  134.     public static method getInstance takes unit u returns thistype
  135.         if thistype.owners[GetUnitId(u)] == 0 then
  136.             return thistype.create(u)
  137.         else
  138.             return thistype.owners[GetUnitId(u)]
  139.         endif
  140.     endmethod
  141.    
  142.     public static method operator[] takes unit u returns thistype
  143.         return thistype.owners[GetUnitId(u)]
  144.     endmethod
  145.    
  146.     public static method operator[]= takes unit u, thistype i returns nothing
  147.         set thistype.owners[GetUnitId(u)] = i
  148.     endmethod
  149. endstruct
  150.  
  151. //! textmacro RegenBonuses_RegenBonusDefine takes NAME
  152. private struct RegenBonus_$NAME$ extends Bonus
  153.     integer minBonus = -2147483648
  154.     integer maxBonus =  2147483647
  155.    
  156.     method setBonus takes unit u, integer amount returns integer
  157.         local BonusValues values
  158.        
  159.         if not IsUnitIndexed(u) then
  160.             debug call ErrorMsg("RegenBonus_$NAME$.setBonus()", "Unit that is not indexed by AutoIndex given")
  161.             return 0
  162.         endif
  163.        
  164.         set values = BonusValues.getInstance(u)
  165.         set values.$NAME$Regen = amount
  166.        
  167.         return amount
  168.     endmethod
  169.    
  170.     method getBonus takes unit u returns integer
  171.         local BonusValues values
  172.        
  173.         if not IsUnitIndexed(u) then
  174.             debug call ErrorMsg("RegenBonus_$NAME$.getBonus()", "Unit that is not indexed by AutoIndex given")
  175.             return 0
  176.         endif
  177.        
  178.         set values = BonusValues[u]
  179.        
  180.         if values == 0 then
  181.             return 0
  182.         endif
  183.        
  184.         return values.$NAME$Regen
  185.     endmethod
  186.    
  187.     method removeBonus takes unit u returns nothing
  188.         call this.setBonus(u, 0)
  189.     endmethod
  190.    
  191.     method isValidBonus takes unit u, integer value returns boolean
  192.         return IsUnitIndexed(u)
  193.     endmethod
  194. endstruct
  195. //! endtextmacro
  196.  
  197. //! runtextmacro RegenBonuses_RegenBonusDefine("life")
  198. //! runtextmacro RegenBonuses_RegenBonusDefine("mana")
  199.  
  200. private function OnLeaveMap takes unit u returns nothing
  201.     if BonusValues[u] != 0 then
  202.         call BonusValues[u].destroy()
  203.     endif
  204. endfunction
  205.  
  206. private function OnInit takes nothing returns nothing
  207.     call OnUnitDeindexed(OnLeaveMap)
  208.    
  209.     set BONUS_MANA_REGEN         = RegenBonus_mana.create()
  210.     set BONUS_LIFE_REGEN_PERCENT = RegenBonus_life.create()
  211. endfunction
  212. endlibrary

Bonus Movement Speed

Requirements:

  • BonusMod
  • AutoIndex

This library provides one new bonus type:
[btable=Bonus Types and Ranges]Bonus Constant:[r]
BONUS_MOVEMENT_SPEED[/btable]

The maximum and minimum bonus depends on a unit's base movement speed, and the maximum and minimum movement speed set in the gameplay constants. A unit's movement speed can not go below or above the minimum or maximum movement speed as defined in the gameplay constants.

To add this bonus to BonusMod, simply copy and paste the following library in to a custom-text trigger in your map. You must change the constants for maximum/minimum movement speed if you change the gameplay constants from their defaults.

Bonus Movement Speed
Code: jass
  1. library MovementBonus initializer OnInit requires BonusMod, AutoIndex
  2. ////////////////////////////////////////////////////////////////////////////////
  3. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  4. //@ MovementBonus for BonusMod
  5. //@=============================================================================
  6. //@ Credits:
  7. //@-----------------------------------------------------------------------------
  8. //@    Written by:
  9. //@        Earth-Fury
  10. //@=============================================================================
  11. //@ Requirements:
  12. //@-----------------------------------------------------------------------------
  13. //@ This library requires the BonusMod library, and the AutoIndex library.
  14. //@
  15. //@=============================================================================
  16. //@ Readme:
  17. //@-----------------------------------------------------------------------------
  18. //@ This library provides one new bonus type:
  19. //@
  20. //@   - BONUS_MOVEMENT_SPEED
  21. //@         Modifies a unit's movement speed.
  22. //@
  23. //@ A unit's movement speed can never go below or above the values configured
  24. //@ in the gameplay constants for a map.
  25. //@
  26. //@ You should not modify a unit's movement speed any way other than via
  27. //@ BonusMod. Doing so will cause issues.
  28. //@
  29. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  30. ////////////////////////////////////////////////////////////////////////////////
  31.  
  32. //==============================================================================
  33. // Configuration:
  34. //==============================================================================
  35.  
  36. //------------------------------------------------------------------------------
  37. // The following constants must be equal to the equivalent gameplay constants.
  38. // By default, these are set to the default vlues for the gameplay constants.
  39. //------------------------------------------------------------------------------
  40. globals
  41.     constant integer MAX_UNIT_MOVEMENT = 400
  42.     constant integer MIN_UNIT_MOVEMENT = 150
  43.     constant integer MAX_BUILDING_MOVEMENT = 400
  44.     constant integer MIN_BUILDING_MOVEMENT = 25
  45. endglobals
  46.  
  47. //==============================================================================
  48. // End of configuration
  49. //==============================================================================
  50. globals
  51.     Bonus BONUS_MOVEMENT_SPEED
  52. endglobals
  53.  
  54. private function ErrorMsg takes string func, string s returns nothing
  55.     call BJDebugMsg("|cffFF0000MovementBonus Error|r|cffFFFF00:|r |cff8080FF" + func + "|r|cffFFFF00:|r " + s)
  56. endfunction
  57.  
  58. private struct BonusValue
  59.     public integer speed = 0
  60.    
  61.     public unit owner
  62.    
  63.     private static thistype array owners
  64.    
  65.     public static thistype array all
  66.     public static integer count = 0
  67.     public integer index
  68.    
  69.     private static method create takes unit u returns thistype
  70.         local thistype this = thistype.allocate()
  71.        
  72.         set this.owner = u
  73.        
  74.         set thistype.owners[GetUnitId(u)] = this
  75.        
  76.         set thistype.all[thistype.count] = this
  77.         set this.index = thistype.count
  78.         set thistype.count = thistype.count + 1
  79.        
  80.         return this
  81.     endmethod
  82.    
  83.     private method onDestroy takes nothing returns nothing
  84.         set thistype.owners[GetUnitId(this.owner)] = thistype(0)
  85.        
  86.         set thistype.all[this.index] = thistype.all[thistype.count]
  87.         set thistype.count = thistype.count - 1
  88.        
  89.         set this.owner = null
  90.     endmethod
  91.    
  92.     public static method getInstance takes unit u returns thistype
  93.         if thistype.owners[GetUnitId(u)] == 0 then
  94.             return thistype.create(u)
  95.         else
  96.             return thistype.owners[GetUnitId(u)]
  97.         endif
  98.     endmethod
  99.    
  100.     public static method operator[] takes unit u returns thistype
  101.         return thistype.owners[GetUnitId(u)]
  102.     endmethod
  103.    
  104.     public static method operator[]= takes unit u, thistype i returns nothing
  105.         set thistype.owners[GetUnitId(u)] = i
  106.     endmethod
  107. endstruct
  108.  
  109. private struct MovementBonus extends Bonus
  110.     integer minBonus
  111.     integer maxBonus
  112.    
  113.     static method create takes integer min, integer max returns thistype
  114.         local thistype this = allocate()
  115.        
  116.         set this.minBonus = min
  117.         set this.maxBonus = max
  118.        
  119.         return this
  120.     endmethod
  121.    
  122.     method setBonus takes unit u, integer amount returns integer
  123.         local BonusValue value
  124.         local integer min
  125.         local integer max
  126.        
  127.         local integer actualSpeed
  128.        
  129.         if not IsUnitIndexed(u) then
  130.             debug call ErrorMsg("MovementBonus.setBonus()", "Unit that is not indexed by AutoIndex given")
  131.             return 0
  132.         endif
  133.        
  134.         set value = BonusValue.getInstance(u)
  135.        
  136.         if IsUnitType(u, UNIT_TYPE_STRUCTURE) then
  137.             set min = MIN_BUILDING_MOVEMENT
  138.             set max = MAX_BUILDING_MOVEMENT
  139.         else
  140.             set min = MIN_UNIT_MOVEMENT
  141.             set max = MAX_UNIT_MOVEMENT
  142.         endif
  143.        
  144.         set actualSpeed = R2I(GetUnitMoveSpeed(u)) - value.speed
  145.        
  146.         if actualSpeed + amount < min then
  147.             debug call ErrorMsg("MovementBonus.setBonus()", "Attempting to set a unit's speed below it's minimum")
  148.             set amount = -actualSpeed + min
  149.         elseif actualSpeed + amount > max then
  150.             debug call ErrorMsg("MovementBonus.setBonus()", "Ateempting to set a unit's speed above it's maximum")
  151.             set amount = max - actualSpeed
  152.         endif
  153.        
  154.         call SetUnitMoveSpeed(u, actualSpeed + amount)
  155.         set value.speed = amount
  156.        
  157.         return amount
  158.     endmethod
  159.    
  160.     method getBonus takes unit u returns integer
  161.         local BonusValue value
  162.        
  163.         if not IsUnitIndexed(u) then
  164.             debug call ErrorMsg("MovementBonus.getBonus()", "Unit that is not indexed by AutoIndex given")
  165.             return 0
  166.         endif
  167.        
  168.         set value = BonusValue[u]
  169.        
  170.         if value == 0 then
  171.             return 0
  172.         endif
  173.        
  174.         return value.speed
  175.     endmethod
  176.    
  177.     method removeBonus takes unit u returns nothing
  178.         call this.setBonus(u, 0)
  179.     endmethod
  180.    
  181.     method isValidBonus takes unit u, integer value returns boolean
  182.         local integer min
  183.         local integer max
  184.        
  185.         local integer currentBonus
  186.         local integer actualSpeed
  187.        
  188.         if not IsUnitIndexed(u) then
  189.             return false
  190.         endif
  191.        
  192.         if IsUnitType(u, UNIT_TYPE_STRUCTURE) then
  193.             set min = MIN_BUILDING_MOVEMENT
  194.             set max = MAX_BUILDING_MOVEMENT
  195.         else
  196.             set min = MIN_UNIT_MOVEMENT
  197.             set max = MAX_UNIT_MOVEMENT
  198.         endif
  199.        
  200.         set actualSpeed = R2I(GetUnitMoveSpeed(u)) - this.getBonus(u)
  201.        
  202.         if actualSpeed + value < min then
  203.             return false
  204.         elseif actualSpeed + value > max then
  205.             return false
  206.         else
  207.             return true
  208.         endif
  209.     endmethod
  210. endstruct
  211.  
  212. private function OnLeaveMap takes unit u returns nothing
  213.     if BonusValue[u] != 0 then
  214.         call BonusValue[u].destroy()
  215.     endif
  216. endfunction
  217.  
  218. private function OnInit takes nothing returns nothing
  219.     local integer min
  220.     local integer max
  221.    
  222.     call OnUnitDeindexed(OnLeaveMap)
  223.    
  224.     if MAX_UNIT_MOVEMENT > MAX_BUILDING_MOVEMENT then
  225.         set max = MAX_UNIT_MOVEMENT
  226.     else
  227.         set max = MAX_BUILDING_MOVEMENT
  228.     endif
  229.    
  230.     if MIN_UNIT_MOVEMENT < MIN_BUILDING_MOVEMENT then
  231.         set min = MIN_UNIT_MOVEMENT
  232.     else
  233.         set min = MIN_BUILDING_MOVEMENT
  234.     endif
  235.    
  236.     set BONUS_MOVEMENT_SPEED = MovementBonus.create(min, max)
  237. endfunction
  238. endlibrary

Demo Map

Below is the demo map for BonusMod. You can download it to test out the functionality.

Change Log

BonusMod & Additional Bonuses Change Log
  • 3.3.1:
    • Movement Speed bonus added

  • 3.3.0:
    • Switched ability creation to lua
    • Minor optimizations

  • 3.0 - 3.2:
    • Complete rewrite
    • Bug fixes

  • 1.0 - 2.0:
    • Ancient versions
« Last Edit: January 04, 2018, 11:45:02 PM by moyack »



 

Vivir aprendiendo.co - A place for learning stuff, in Spanish   Chaos Realm - The world of Game modders and wc3 addicts   Diplo, a gaming community   Power of Corruption, an altered melee featuring Naga and Demon. Play it now!!!   WC3JASS.com - The JASS Vault + vJASS and Zinc   Jetcraft - A Starcraft II mod   WormTastic Clan (wTc)