14 years
edited 8 years
Version 3.3.1
Introduction
[INDENT]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.[/INDENT]
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
[indent]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.[/indent]
BonusMod
1 library BonusMod initializer OnInit requires optional AbilityPreload, optional xepreload
2 private keyword AbilityBonus
3 ////////////////////////////////////////////////////////////////////////////////4 //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@5 //@ BonusMod - v3.3.16 //@=============================================================================7 //@ Credits:8 //@-----------------------------------------------------------------------------9 //@ Written by:10 //@ Earth-Fury11 //@ Based on the work of:12 //@ weaaddar13 //@-----------------------------------------------------------------------------14 //@ If you use this system, please at least credit weaaddar. Without him, this15 //@ 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 to20 //@ function correctly. This library also uses the ObjectMerger created by21 //@ PitzerMike. The ObjectMerger must be configured as an external tool for22 //@ 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, such30 //@ as attack speed or mana regen, for specific units. Most of the bonuses31 //@ provided by BonusMod show green or red numbers in the command card, exactly32 //@ like the bonuses provided by items.33 //@34 //@ BonusMod has two kinds of bonuses:35 //@ 1. Ability based bonuses36 //@ 2. Code based bonuses37 //@ 38 //@ All of the bonuses in the configuration section for the basic BonusMod39 //@ library are ability-based bonuses. Code-based bonuses are provided by40 //@ 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 limits45 //@ of the bonuses that come with BonusMod. For changing the limits of the46 //@ default bonuses, or for adding new types of bonuses, see the below47 //@ configuration section.48 //@ 49 //@ Code based bonuses may or may not have a limit to how much of a bonus they50 //@ can apply. The limits for code based bonuses depend entirely on how the51 //@ 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 your57 //@ map.58 //@59 //@ You must then save your map with ability generation enabled. After you save60 //@ your map with ability generation enabled, you must close your map in the61 //@ editor, and reopen it. You can then disable ability generation.62 //@ See the configuration section for information on how to enable and disable63 //@ 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 be85 //@ applied to heroes. Attempting to add them to normal units will86 //@ fail to work completely.87 //@ - Using a negative BONUS_STRENGTH bonus can give a unit negative88 //@ maximum life. Don't do that. It really messes stuff up.89 //@ - Using a negative BONUS_INTELLIGENCE bonus can remove a hero's90 //@ mana. This is not a big issue, as mana will return when the91 //@ 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 of96 //@ bonuses, as well as how to add new ability-based bonuses, and remove unused97 //@ ones.98 //@ 99 //@=============================================================================100 //@ Public API / Function list:101 //@-----------------------------------------------------------------------------102 //@ Note that BonusMod will only output error messages if JASS Helper is set to103 //@ compile in debug mode.104 //@105 //@ Bonus constants such as BONUS_DAMAGE have .min and .max properties which106 //@ are the minimum and maximum bonus that type of bonus can apply. Note that107 //@ for code based bonuses, these constants may not reflect the minimum or108 //@ maximum bonus for a specific unit. Use the IsBonusValid() function to check109 //@ if the given bonus value is okay for a given unit.110 //@111 //@ function SetUnitBonus112 //@ takes unit u, Bonus bonusType, integer amount113 //@ returns integer114 //@ 115 //@ This function sets the bonus of the type bonusType for the given unit to116 //@ the given amount. The returned integer is the unit's actual current117 //@ bonus, after it has been changed. If the given amount is above the118 //@ maximum possible bonus for this type, then the maximum possible bonus119 //@ is applied to the unit. The same is true if the given value is below120 //@ the minimum possible bonus.121 //@122 //@ function GetUnitBonus123 //@ takes unit u, Bonus bonusType124 //@ returns integer125 //@126 //@ Returns the given unit's current bonus of bonusType. A value of 0 means127 //@ that the given unit does not have a bonus of the given type.128 //@ 129 //@ function AddUnitBonus130 //@ takes unit u, Bonus bonusType, integer amount131 //@ returns integer132 //@ 133 //@ Increases the unit's bonus by the given amount. You can use a negitive134 //@ amount to subtract from the unit's current bonus. Note that the same135 //@ 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 RemoveUnitBonus139 //@ takes unit u, Bonus bonusType140 //@ returns nothing141 //@ 142 //@ Sets the bonus of the type bonusType to 0 for the given unit. This143 //@ function is faster then using SetUnitBonus(u, bonusType, 0).144 //@145 //@ function IsBonusValid146 //@ takes unit u, Bonus abstractBonus, integer value147 //@ returns boolean148 //@149 //@ Returns true if the given value is a valid bonus value for the given150 //@ 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 types157 //@ that apply their bonuses using vJass code instead of abilities. You do not158 //@ 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 the161 //@ methods provided within it, and create a single instance of your struct162 //@ 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 integer167 //@ This method sets the given unit's current bonus to amount, returning168 //@ the actual bonus that was applied. If the given amount is higher then169 //@ the maximum amount your bonus type can apply to a unit, you must apply170 //@ the maximum possible bonus, and return that amount. The same holds true171 //@ for the minimum bonus.172 //@173 //@ method getBonus takes unit u returns integer174 //@ This method returns the current bonus the given unit has.175 //@176 //@ method removeBonus takes unit u returns nothing177 //@ This method sets the current bonus of the given unit to 0.178 //@179 //@ method isValueInRange takes integer value returns boolean180 //@ This method returns true if the given integer is a valid bonus amount181 //@ for this bonus type, and false otherwise.182 //@183 //@ Note that it is your responsibility to do any clean up in the event a unit184 //@ dies or is removed with an active bonus on it. There is no guarantee that185 //@ 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 library196 // will be preloaded at map initialization. This will slightly increase loading197 // time, but will prevent a slight to medium lag spike the first time a bonus198 // of a type is applied.199 // 200 // Note that your map must contain either the xepreload library, or the201 // AbilityPreload library for preloading to work.202 // 203 // It is highly recommended that you do not set this to false.204 //------------------------------------------------------------------------------205 globals206 private constant boolean PRELOAD_ABILITIES = true
207 endglobals208 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 must215 // regenerate abilities.216 // 217 // Note that if you remove a bonus, the abilities it had created will not be218 // automatically removed. This is also true of reducing the number of abilities219 // a bonus uses.220 // 221 // After you generate abilities, you must close your map and reopen it in the222 // editor. You can then disable ability generation until the next time you223 // 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 be230 // generated for each bonus type, that will take the form: BONUS_NAME231 // 232 // The second parameter is the maximum power of 2 the bonus type can add233 // 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 the236 // desired effect when the given field is changed.237 // 238 // The fourth parameter is the rawcode prefix of the bonuses generated239 // abilities. The prefix must be 3 characters long. Your map must not240 // already contain bonuses which start with the given prefix.241 // 242 // The fifth parameter is the object field to modify for each generated243 // ability.244 // 245 // The sixth parameter must be true of the bonus should only work on hero246 // units, and false otherwise.247 // 248 // The final parameter is the icon that will be displayed in the object249 // editor. This has no effect on anything ingame.250 //--------------------------------------------------------------------------251
252 // | NAME |ABILITY|SOURCE |PREFIX|FIELD | HERO | ICON253 // | | 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 | ICON263 // | | 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 configuration271 //==============================================================================272 273 //! textmacro BonusMod_BeginBonuses takes SHOULD_GENERATE_ABILITIES274 private function Setup takes nothing returns nothing
275
276 // The following is a lua script for the ObjectMerger, used to generate abilities277 //*278 //! externalblock extension=lua ObjectMerger $FILENAME$279 //! i if "$SHOULD_GENERATE_ABILITIES$" == "true" then280 //! i function FormatName(name)281 //! i name = string.lower(name)282 //! i name = string.gsub(name, "_", " ")283 //! i s = name284 //! i name = ""285 //! i for w in string.gmatch(s, "%a%w*") do286 //! i name = name .. string.upper(string.sub(w, 1, 1)) .. string.sub(w, 2, -1)287 //! i name = name .. " "288 //! i end289 //! i name = string.sub(name, 1, string.len(name) - 1)290 //! i return name291 //! i end292 //! 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 then298 //! i makechange(current, "Iagi", 1, 0)299 //! i makechange(current, "Iint", 1, 0)300 //! i makechange(current, "Istr", 1, 0)301 //! i end302 //! i end303 //! i function CreateAbility(sourceAbility, prefix, field, abilityCount, name, icon)304 //! i powOf2 = abilityCount - 1305 //! i lengthOfMax = string.len(tostring(2^abilityCount))306 //! i for i = 0, powOf2 do307 //! i padding = ""308 //! i for k = 0, lengthOfMax - string.len(tostring(2^i)) - 1 do309 //! i padding = padding .. "0"310 //! i end311 //! 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 end315 //! i createobject(sourceAbility, prefix .. "-")316 //! i SetupAbility(name, "-" .. tostring(2 ^ abilityCount), icon, true)317 //! i makechange(current, field, 1, tostring(-(2^abilityCount)))318 //! i end319 //! i function CreatePercentageAbility(sourceAbility, prefix, field, abilityCount, name, icon)320 //! i powOf2 = abilityCount - 1321 //! i lengthOfMax = string.len(tostring(2^abilityCount))322 //! i for i = 0, powOf2 do323 //! i padding = ""324 //! i for k = 0, lengthOfMax - string.len(tostring(2^i)) - 1 do325 //! i padding = padding .. "0"326 //! i end327 //! 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 end331 //! 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 end335 //! i setobjecttype("abilities")336 //! i chars = "abcdefghijklmnopqrstuvwxyz"337 //! i 338 // */339 //! endtextmacro340 341 //! textmacro BonusMod_DeclareBonus takes NAME, ABILITY_COUNT, SOURCE_ABILITY, RAWCODE_PREFIX, FIELD, HERO_ONLY, ICON342 //! i CreateAbility("$SOURCE_ABILITY$", "$RAWCODE_PREFIX$", "$FIELD$", $ABILITY_COUNT$, "$NAME$", "$ICON$")343 globals344 Bonus BONUS_$NAME$
345 endglobals346 set BONUS_$NAME$ = AbilityBonus.create('$RAWCODE_PREFIX$a', $ABILITY_COUNT$, '$RAWCODE_PREFIX$-', $HERO_ONLY$)
347 //! endtextmacro348 349 //! textmacro BonusMod_DeclarePercentBonus takes NAME, ABILITY_COUNT, SOURCE_ABILITY, RAWCODE_PREFIX, FIELD, HERO_ONLY, ICON350 //! i CreatePercentageAbility("$SOURCE_ABILITY$", "$RAWCODE_PREFIX$", "$FIELD$", $ABILITY_COUNT$, "$NAME$", "$ICON$")351 globals352 Bonus BONUS_$NAME$
353 endglobals354 set BONUS_$NAME$ = AbilityBonus.create('$RAWCODE_PREFIX$a', $ABILITY_COUNT$, '$RAWCODE_PREFIX$-', $HERO_ONLY$)
355 //! endtextmacro356 357 //! textmacro BonusMod_EndBonuses358 //*359 //! i end360 //! endexternalblock361 // */362
363 endfunction364 //! endtextmacro365 366 // ===367 // Precomputed integer powers of 2368 // ===369 370 globals371 private integer array powersOf2
372 private integer powersOf2Count = 0
373 endglobals374 375 // ===376 // Utility functions377 // ===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 endfunction382 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 else388 static if LIBRARY_AbilityPreload then
389 call AbilityPreload(abilityId)
390 endif391 endif392 endif393 endfunction394 395 // ===396 // Bonus Types397 // ===398 399 private interface BonusInterface
400 integer minBonus = 0
401 integer maxBonus = 0
402 private method destroy takes nothing returns nothing defaults nothing
403 endinterface404 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 endmethod417
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 endmethod422
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 endmethod427
428 stub method removeBonus takes unit u returns nothing
429 call this.setBonus(u, 0)
430 endmethod431
432 stub method isValidBonus takes unit u, integer value returns boolean
433 return true
434 endmethod435
436 method operator min takes nothing returns integer
437 return this.minBonus
438 endmethod439
440 method operator max takes nothing returns integer
441 return this.maxBonus
442 endmethod443 endstruct444 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 messages462 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 endif468
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 endif474 endif475
476 // Grow powers of 2477 if powersOf2Count < count then
478 set i = powersOf2Count
479 loop480 exitwhen i > count
481
482 set powersOf2[i] = 2 * powersOf2[i - 1]
483 484 set i = i + 1
485 endloop486 set powersOf2Count = count
487 endif488
489 // Preload this bonus' abilities490 static if PRELOAD_ABILITIES then
491 set i = 0
492 loop493 exitwhen i == count
494
495 call LoadAbility(rawcode + i)
496
497 set i = i + 1
498 endloop499
500 if negativeRawcode != 0 then
501 call LoadAbility(negativeRawcode)
502 endif503 endif504
505 // Set up this bonus object506 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 bonuses512 if negativeRawcode != 0 then
513 set bonus.minBonus = -powersOf2[count]
514 else515 set bonus.minBonus = 0
516 endif517 set bonus.maxBonus = powersOf2[count] - 1
518
519 // Return the bonus object520 return bonus521 endmethod522
523 // Interface methods:524
525 method setBonus takes unit u, integer amount returns integer
526 return SetUnitBonus.evaluate(u, this, amount)
527 endmethod528
529 method getBonus takes unit u returns integer
530 return GetUnitBonus.evaluate(u, this)
531 endmethod532
533 method removeBonus takes unit u returns nothing
534 call RemoveUnitBonus.evaluate(u, this)
535 endmethod536
537 public method isValidBonus takes unit u, integer value returns boolean
538 return (value >= this.minBonus) and (value <= this.maxBonus)
539 endmethod540 endstruct541 542 // ===543 // Public API544 // ===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 endif553 endif554
555 if abstractBonus.min > value or abstractBonus.max < value then
556 return false
557 endif558
559 if abstractBonus.getType() != AbilityBonus.typeid then
560 return abstractBonus.isValidBonus(u, value)
561 endif562
563 if bonus.heroesOnly and not IsUnitType(u, UNIT_TYPE_HERO) then
564 return false
565 endif566
567 return (value >= bonus.minBonus) and (value <= bonus.maxBonus)
568 endfunction569 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 endif578 endif579
580 if abstractBonus.getType() != AbilityBonus.typeid then
581 call abstractBonus.removeBonus(u)
582 return583 endif584
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 return588 endif589
590 call UnitRemoveAbility(u, bonus.negativeRawcode)
591
592 loop593 exitwhen i == bonus.count
594
595 call UnitRemoveAbility(u, bonus.rawcode + i)
596 597 set i = i + 1
598 endloop599 endfunction600 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 endif611 endif612
613 if amount == 0 then
614 call RemoveUnitBonus(u, bonus)
615 return 0
616 endif617
618 if abstractBonus.getType() != AbilityBonus.typeid then
619 return abstractBonus.setBonus(u, amount)
620 endif621
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 endif626
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 endif634
635 if amount < 0 then
636 set amount = -(bonus.minBonus - amount)
637 set applyMinBonus = true
638 endif639
640 call UnitRemoveAbility(u, bonus.negativeRawcode)
641
642 set i = bonus.count - 1
643 loop644 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 endif654 endif655
656 set amount = amount - powersOf2[i]
657 set output = output + powersOf2[i]
658 else659
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 endif665 endif666 endif667 668 set i = i - 1
669 endloop670
671 if applyMinBonus then
672 call UnitAddAbility(u, bonus.negativeRawcode)
673 call UnitMakeAbilityPermanent(u, true, bonus.negativeRawcode)
674 else675 call UnitRemoveAbility(u, bonus.negativeRawcode)
676 endif677
678 return output679 endfunction680 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 endif690 endif691
692 if abstractBonus.getType() != AbilityBonus.typeid then
693 return abstractBonus.getBonus(u)
694 endif695
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 endif700
701 if GetUnitAbilityLevel(u, bonus.negativeRawcode) > 0 then
702 set amount = bonus.minBonus
703 endif704 705 loop706 exitwhen i == bonus.count
707
708 if GetUnitAbilityLevel(u, bonus.rawcode + i) > 0 then
709 set amount = amount + powersOf2[i]
710 endif711 712 set i = i + 1
713 endloop714 715 return amount716 endfunction717 718 function AddUnitBonus takes unit u, Bonus bonus, integer amount returns integer
719 return SetUnitBonus(u, bonus, GetUnitBonus(u, bonus) + amount)
720 endfunction721 722 // ===723 // Initialization724 // ===725 726 private function OnInit takes nothing returns nothing
727 local integer i
728
729 // Set up powers of 2730 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 endif736
737 // Setup bonuses738 call Setup()
739 endfunction740 endlibrary
Additional Bonus Types
[indent]Bonus Maximum Life / Mana
[indent]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.[/indent]
Bonus Max Life / Mana
1 library UnitMaxStateBonuses initializer OnInit requires BonusMod, UnitMaxState, AutoIndex
2 ////////////////////////////////////////////////////////////////////////////////3 //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@4 //@ UnitMaxStateBonuses for BonusMod5 //@=============================================================================6 //@ Credits:7 //@-----------------------------------------------------------------------------8 //@ Written by:9 //@ Earth-Fury10 //@=============================================================================11 //@ Requirements:12 //@-----------------------------------------------------------------------------13 //@ This library requires the BonusMod library, the UnitMaxState library by14 //@ Earth-Fury, and the AutoIndex library by grim001.15 //@16 //@=============================================================================17 //@ Readme:18 //@-----------------------------------------------------------------------------19 //@ This library provides two new bonus types:20 //@21 //@ - BONUS_LIFE22 //@ - BONUS_MANA23 //@ 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 maximum27 //@ 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 globals40 Bonus BONUS_LIFE
41 Bonus BONUS_MANA
42 endglobals43 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 endfunction47 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 endmethod65
66 private method onDestroy takes nothing returns nothing
67 set thistype.owners[GetUnitId(this.owner)] = thistype(0)
68 set this.owner = null
69 endmethod70
71 public static method getInstance takes unit u returns thistype
72 if thistype.owners[GetUnitId(u)] == 0 then
73 return thistype.create(u)
74 else75 return thistype.owners[GetUnitId(u)]
76 endif77 endmethod78
79 public static method operator[] takes unit u returns thistype
80 return thistype.owners[GetUnitId(u)]
81 endmethod82
83 public static method operator[]= takes unit u, thistype i returns nothing
84 set thistype.owners[GetUnitId(u)] = i
85 endmethod86 endstruct87 88 //! textmacro UnitMaxStateBonus_DefineBonus takes NAME, STATE, MIN89 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 values95 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 endif103
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 else115 set values.$NAME$ = -actual + $MIN$
116 endif117
118 call SetUnitState(u, UNIT_STATE_$STATE$, $MIN$)
119 call SetUnitMaxState(u, UNIT_STATE_MAX_$STATE$, $MIN$)
120 return values.$NAME$
121 else122 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 endif129 endmethod130
131 method getBonus takes unit u returns integer
132 local BonusValues values133 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 endif141
142 set values = BonusValues[u]
143
144 if values == 0 then
145 return 0
146 endif147
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 endmethod152
153 method removeBonus takes unit u returns nothing
154 call this.setBonus(u, 0)
155 endmethod156
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 endif163
164 set currentBonus = this.getBonus(u)
165
166 return R2I(GetUnitState(u, UNIT_STATE_MAX_$STATE$)) - currentBonus + value >= $MIN$
167 endmethod168 endstruct169 //! endtextmacro170 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 endif178 endfunction179 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 endfunction186 endlibrary
Bonus Life Regen (%) and Mana Regen (Absolute)
[indent]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.[/indent]
Bonus Life Regen (%) and Mana Regen (Absolute)
1 library RegenBonuses initializer OnInit requires BonusMod, AutoIndex
2 ////////////////////////////////////////////////////////////////////////////////3 //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@4 //@ RegenBonuses for BonusMod5 //@=============================================================================6 //@ Credits:7 //@-----------------------------------------------------------------------------8 //@ Written by:9 //@ Earth-Fury10 //@=============================================================================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_REGEN21 //@ Regenerates an absolute amount of mana every second22 //@23 //@ - BONUS_LIFE_REGEN_PERCENT24 //@ Regenerates a percent of a unit's maximum life every second25 //@ 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 are37 // 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 life39 // per second. This constant simply determines how often the values are updated.40 //------------------------------------------------------------------------------41 globals42 private real REGEN_PERIOD = 0.1
43 endglobals44 45 //==============================================================================46 // End of configuration47 //==============================================================================48 49 globals50 Bonus BONUS_MANA_REGEN
51 Bonus BONUS_LIFE_REGEN_PERCENT
52 endglobals53 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 endfunction57 58 globals59 private timer regenTimer = CreateTimer()
60 endglobals61 62 private keyword BonusValues
63 64 private function DoRegen takes nothing returns nothing
65 local integer i
66 local BonusValues values67
68 // Loop over all active bonuses69 set i = 0
70 loop71 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 endif80
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 endif85 endif86
87 set i = i + 1
88 endloop89 endfunction90 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 endif113
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 endmethod120
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 endif130
131 set this.owner = null
132 endmethod133
134 public static method getInstance takes unit u returns thistype
135 if thistype.owners[GetUnitId(u)] == 0 then
136 return thistype.create(u)
137 else138 return thistype.owners[GetUnitId(u)]
139 endif140 endmethod141
142 public static method operator[] takes unit u returns thistype
143 return thistype.owners[GetUnitId(u)]
144 endmethod145
146 public static method operator[]= takes unit u, thistype i returns nothing
147 set thistype.owners[GetUnitId(u)] = i
148 endmethod149 endstruct150 151 //! textmacro RegenBonuses_RegenBonusDefine takes NAME152 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 values158
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 endif163
164 set values = BonusValues.getInstance(u)
165 set values.$NAME$Regen = amount
166
167 return amount168 endmethod169
170 method getBonus takes unit u returns integer
171 local BonusValues values172
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 endif177
178 set values = BonusValues[u]
179
180 if values == 0 then
181 return 0
182 endif183
184 return values.$NAME$Regen
185 endmethod186
187 method removeBonus takes unit u returns nothing
188 call this.setBonus(u, 0)
189 endmethod190
191 method isValidBonus takes unit u, integer value returns boolean
192 return IsUnitIndexed(u)
193 endmethod194 endstruct195 //! endtextmacro196 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 endif204 endfunction205 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 endfunction212 endlibrary
Bonus Movement Speed
[indent]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.[/indent]
Bonus Movement Speed
1 library MovementBonus initializer OnInit requires BonusMod, AutoIndex
2 ////////////////////////////////////////////////////////////////////////////////3 //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@4 //@ MovementBonus for BonusMod5 //@=============================================================================6 //@ Credits:7 //@-----------------------------------------------------------------------------8 //@ Written by:9 //@ Earth-Fury10 //@=============================================================================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_SPEED21 //@ Modifies a unit's movement speed. 22 //@ 23 //@ A unit's movement speed can never go below or above the values configured24 //@ in the gameplay constants for a map.25 //@ 26 //@ You should not modify a unit's movement speed any way other than via27 //@ 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 globals41 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 endglobals46 47 //==============================================================================48 // End of configuration49 //==============================================================================50 globals51 Bonus BONUS_MOVEMENT_SPEED
52 endglobals53 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 endfunction57 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 endmethod82
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 endmethod91
92 public static method getInstance takes unit u returns thistype
93 if thistype.owners[GetUnitId(u)] == 0 then
94 return thistype.create(u)
95 else96 return thistype.owners[GetUnitId(u)]
97 endif98 endmethod99
100 public static method operator[] takes unit u returns thistype
101 return thistype.owners[GetUnitId(u)]
102 endmethod103
104 public static method operator[]= takes unit u, thistype i returns nothing
105 set thistype.owners[GetUnitId(u)] = i
106 endmethod107 endstruct108 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 endmethod121
122 method setBonus takes unit u, integer amount returns integer
123 local BonusValue value124 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 endif133
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 else140 set min = MIN_UNIT_MOVEMENT
141 set max = MAX_UNIT_MOVEMENT
142 endif143
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 endif153
154 call SetUnitMoveSpeed(u, actualSpeed + amount)
155 set value.speed = amount
156
157 return amount158 endmethod159
160 method getBonus takes unit u returns integer
161 local BonusValue value162
163 if not IsUnitIndexed(u) then
164 debug call ErrorMsg("MovementBonus.getBonus()", "Unit that is not indexed by AutoIndex given")
165 return 0
166 endif167
168 set value = BonusValue[u]
169
170 if value == 0 then
171 return 0
172 endif173
174 return value.speed
175 endmethod176
177 method removeBonus takes unit u returns nothing
178 call this.setBonus(u, 0)
179 endmethod180
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 endif191
192 if IsUnitType(u, UNIT_TYPE_STRUCTURE) then
193 set min = MIN_BUILDING_MOVEMENT
194 set max = MAX_BUILDING_MOVEMENT
195 else196 set min = MIN_UNIT_MOVEMENT
197 set max = MAX_UNIT_MOVEMENT
198 endif199
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 else207 return true
208 endif209 endmethod210 endstruct211 212 private function OnLeaveMap takes unit u returns nothing
213 if BonusValue[u] != 0 then
214 call BonusValue[u].destroy()
215 endif216 endfunction217 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 else227 set max = MAX_BUILDING_MOVEMENT
228 endif229
230 if MIN_UNIT_MOVEMENT < MIN_BUILDING_MOVEMENT then
231 set min = MIN_UNIT_MOVEMENT
232 else233 set min = MIN_BUILDING_MOVEMENT
234 endif235
236 set BONUS_MOVEMENT_SPEED = MovementBonus.create(min, max)
237 endfunction238 endlibrary
[/indent]
Demo Map
[indent]Below is the demo map for BonusMod. You can download it to test out the functionality.
[/indent]
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