1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still haven't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. The reforging of the races is complete. Come see the 14th Techtree Contest Results.
    Dismiss Notice
  4. It's time to choose your horse in the race - the 32nd Modeling Contest Poll is up!
    Dismiss Notice
  5. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[System] Damage Control

Discussion in 'Graveyard' started by PurgeandFire, Oct 2, 2011.

  1. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,426
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Damage Control

    This library allows you to manipulate the damage caused and received by units. It works by setting the target's life to the appropriate value before they receive the damage, which effectively produces the same output as dealing that amount of damage.

    Of course, there are complications when you hit someone for more than their health or if you want to reduce the damage taken, and that is why this system was created. It eases the process.

    This is meant for rapid spell creation, and spell ingenuity. There are some spell ideas that people discard because it is way too much work. For example, turning damage received into damage gained, or increasing the amount of damage a unit deals for their next 3 attacks.. things along those lines.

    Before anyone says it, yes this is exactly like DamageModifiers. However, there are some key differences in both the features and the way each is used. I do give due credit to DamageModifiers for the basis, but I felt that I personally wanted a few extra features.

    Requirements:

    This system is still kind of a work in progress (some features still can be added), but it works and works well.

    Code (vJASS):
    library DamageControl /* v2.1.0.0
    *************************************************************************************
    *
    *   This library allows you to modify the damage output or intake of a unit
    *   for any attack, and provides a very neat interface.
    *
    *************************************************************************************
    *
    *   */
    uses/*
    *  
    *       */
    UnitIndexer /*       hiveworkshop.com/forums/jass-functions-413/system-unit-indexer-172090/
    *       */
    DamageEvent /*       hiveworkshop.com/forums/jass-functions-413/snippet-damageevent-186829/
    *       */
    Event /*             hiveworkshop.com/forums/jass-functions-413/snippet-event-186555/
    *
    ************************************************************************************
    *
    *   Configuration
    */

    globals
        private constant integer ABILITY_LIFE_BONUS           = 'DcLB'     // rawcode of the life bonus ability
                         boolean NEGATIVE_DAMAGE_TO_HEAL      = false      // causes negative damage to heal the unit
                                                                           // for the next damaging attack
                         integer DAMAGE_CONTROL_PRIORITY_LAST = 0xaa289    // this will automatically force the damage control
                                                                           // struct to be issued last, after the other ones
    endglobals
    /*
    ************************************************************************************
    *
    *   struct DamageControl extends array
    *
    *        -   This struct handles the execution of all Damage Control structs,
    *        -   and has a few functions and methods for you to work with.
    *
    *       static Event MOD
    *            -   Fired before the system processes damage modifications.
    *       static Event FINAL
    *            -   Fired after the system completes all damage modifications.
    *       static real result
    *            -   The resulting damage of an attack after modifications. Use with
    *            -   the FINAL event.
    *       static unit source
    *            -   The source of the damage. You can use this or DamageEvent.source
    *       static unit target
    *            -   The target of the damage. You can use this or DamageEvent.target
    *       static integer sourceId
    *            -   The index of the source unit. You can use this or DamageEvent.sourceId
    *       static integer targetId
    *            -   The index of the target unit. You can use this or DamageEvent.targetId
    *       static boolean enabled
    *            -   Tells whether or not the system is enabled in general.
    *       static boolean enabledNext
    *            -   Tells whether or not the system is enabled for the next attack.
    *
    *       static method enable takes nothing returns nothing
    *            -   Enables the DamageControl system completely.
    *       static method disable takes nothing returns nothing
    *            -   Disables the DamageControl system completely.
    *       static method enableNext takes nothing returns nothing
    *            -   Enables the DamageControl system for the next damaging attack. This
    *            -   function is mostly useless, except in rare cases when you want to
    *            -   counteract a disableNext() call.
    *       static method disableNext takes nothing returns nothing
    *            -   Disables the DamageControl system for the next damaging attack.
    *            -   It will automatically reset the system to be enabled afterward.
    *
    ********************************************************************
    *
    *    module DamageControlModule
    *
    *        -    To access the damage control features, you must implement this module
    *        -    at the bottom of your struct. It unlocks two methods for you to define:
    *           static method onDamageDealt takes unit source, unit target, real amount returns real
    *           static method onDamageTaken takes unit source, unit target, real amount returns real
    *        -    onDamageDealt is executed whenever a unit, source, deals damage.
    *        -    onDamageTaken is executed whenever a unit, target, takes damage.
    *        -    Both functions should return the resulting amount of damage.
    *
    *        static boolean array enabled
    *             -   To enable your damage control struct for a unit, you simply will set
    *             -   this boolean to true, corresponding to the user data of the unit:
    *                     set enabled[GetUnitUserData(unit)] = boolean
    *             -   All damage control structs are initially disabled for each unit.
    *
    *        static integer array dealtCount
    *        static integer array takenCount
    *             -   This keeps track of how many times each unit has had their damage
    *             -   modified by this system. To retrieve each value, simply input the
    *             -   user data of the unit as the array value. See the demo spells for
    *             -   clear examples on how to use this. Note that these are automatically
    *             -   incremented for you every time that struct is used by the unit.
    *
    ********************************************************************
    *
    *    module DamageControlPriorityModule (added in v.2.0.0.0)
    *
    *        -    Everything is exactly the same as DamageControlModule, however,
    *        -    this module allows you to specify a priority which determines
    *        -    when the damage control functions of your struct will be fired
    *        -    in relation to the other damage control structs.
    *
    *        -    You MUST define an integer variable named PRIORITY in your struct
    *        -    for this module. For example:
    *           static integer PRIORITY = 1
    *        -    The number determines what "slot" it will be fit into in terms
    *        -    of evaluation. The lower values are always the first ones to be
    *        -    evaluated. For example, if there are 3 structs about to be evaluated,
    *        -    and one has a priority of 0, the second a priority of 50, and the
    *        -    third a priority of 2, then it will fire the structs in order of
    *        -    priority: 0, then 2, then 50. By default, all priority structs will
    *        -    be fired BEFORE non-priority structs, with one case as an exception:
    *
    *        -    This will also allow you to evalute structs AFTER all of the other
    *        -    structs. To do so, simply use this as the value for PRIORITY:
    *           static integer PRIORITY = DAMAGE_CONTROL_PRIORITY_LAST
    *        -    This will fire at the end, after all of the integer priority structs
    *        -    and after the non-priority structs.
    *
    ********************************************************************
    *
    *       struct SampleStruct extends array
    *
    *           static method onDamageDealt takes unit source, unit target, real amount returns real
    *               return amount + 100.
    *           endmethod
    *               -   This increases the damage dealt by the unit by 100.
    *
    *           static method onDamageTaken takes unit source, unit target, real amount returns real
    *               if takenCount[DamageEvent.targetId] == 3 then
    *                   set takenCount[DamageEvent.targetId] = 0
    *                   set enabled[DamageEvent.targetId]    = false
    *               endif
    *               return amount - 30.
    *           endmethod
    *               -   This reduces the damage taken by the unit by 30 for the next 3
    *               -   damaging attacks he receives. Once it reaches 3, it will disable
    *               -   the unit from receiving the damage control of this struct.
    *
    *           implement DamageControlModule
    *
    *       endstruct
    *
    ********************************************************************
    *
    *    Credits
    *
    *       -   Anitarf: DamageModifiers (ideas and basis)
    *       -   Nestharus: AdvDamageEvent (ideas and basis)
    *       -   Nestharus: UnitIndexer, DamageEvent, Event
    *       -   Bribe: For his ingenious method
    *
    ************************************************************************************/


        globals
            private constant boolean DEFAULT          = NEGATIVE_DAMAGE_TO_HEAL
            private          trigger damageTrigger    = CreateTrigger()
            private          timer   lifeBonusTimer   = CreateTimer()
        endglobals

        private module DamageControlSystemInit
            private static method onInit takes nothing returns nothing
                set  thistype.FINAL = CreateEvent()
                set  thistype.MOD   = CreateEvent()
                call DamageEvent.ANY.register(Condition(function thistype.onDamage))
            endmethod
        endmodule
       
        private struct PriorityList
            static  integer  LAST = DAMAGE_CONTROL_PRIORITY_LAST // random number
       
            static  thistype head = 0
            static  thistype last = 0
            private thistype next
            private integer  prio
            private trigger  curr
           
            static method insert takes integer priority, trigger evaluate returns nothing
                local thistype node = thistype.allocate()
                local thistype this = head.next
                set node.prio = priority
                set node.curr = evaluate
                if this == 0 then
                    set head.next = node
                    set node.next = 0
                    set last      = node
                    return
                elseif priority == LAST then
                    set last.next = node
                    set node.next = 0
                    set last      = node
                    return
                endif
                loop
                    exitwhen this == 0
                    if this.prio == priority or this.prio == LAST then
                        set node.next = this.next
                        set this.next = node
                        return
                    endif
                    set this = this.next
                endloop
            endmethod
           
            static method evaluate takes nothing returns nothing
                local thistype this = head.next
                if this != 0 then
                    loop
                        exitwhen this.prio == LAST      // evaluate up until the ones
                        call TriggerEvaluate(this.curr) // that should be last
                        set this = this.next
                    endloop
                endif
                call TriggerEvaluate(damageTrigger) // evaluate the non-priority ones
                loop
                    exitwhen this == 0              // evaluate the ones that
                    call TriggerEvaluate(this.curr) // should be evaluated last
                    set this = this.next
                endloop
            endmethod
        endstruct

        struct DamageControl extends array
            static Event   FINAL   = 0
            static Event   MOD     = 0
            static real    result  = 0
           
            private static integer       size        = 0
            private static unit    array lifeUnits
            private static integer array unitSize
           
            static boolean enabled     = true
            static boolean enabledNext = true
           
            static method operator source takes nothing returns unit
                return DamageEvent.source
            endmethod
            static method operator target takes nothing returns unit
                return DamageEvent.target
            endmethod
            static method operator sourceId takes nothing returns integer
                return DamageEvent.sourceId
            endmethod
            static method operator targetId takes nothing returns integer
                return DamageEvent.targetId
            endmethod
           
            static method enable takes nothing returns nothing
                set enabled = true
            endmethod
            static method disable takes nothing returns nothing
                set enabled = false
            endmethod
            static method enableNext takes nothing returns nothing
                set enabledNext = true
            endmethod
            static method disableNext takes nothing returns nothing
                set enabledNext = false
            endmethod
           
            private static method manageLife takes nothing returns nothing
                local real    life
                local integer id
                loop
                    exitwhen size == 0
                    set id = GetUnitUserData(lifeUnits[size])
                    if unitSize[id] == 1 then
                        set life = GetWidgetLife(lifeUnits[size])
                        call UnitRemoveAbility(lifeUnits[size], ABILITY_LIFE_BONUS)
                        call SetWidgetLife(lifeUnits[size], life)
                    endif
                    set unitSize[id] = unitSize[id] - 1
                    set size = size - 1
                endloop
            endmethod
           
            private static method fireEvent takes nothing returns nothing
                if unitSize[DamageEvent.targetId] > 1 then
                    call UnitRemoveAbility(DamageEvent.target, ABILITY_LIFE_BONUS)
                endif
                call FINAL.fire()
                if unitSize[DamageEvent.targetId] > 0 then
                    call UnitAddAbility(DamageEvent.target, ABILITY_LIFE_BONUS)
                endif
            endmethod
           
            private static method onDamage takes nothing returns boolean
                local unit target   = DamageEvent.target
                local real damage   = DamageEvent.amount
                local real life     = GetWidgetLife(target)
                local real temp     = result
                set result          = damage

                if damage <= 0 or not enabled then
                    call thistype.fireEvent()
                    set result      = temp
                    set target      = null
                    return false
                endif
               
                if not enabledNext then       // this is separate from the above block
                    set enabledNext = true    // because it is meant to prevent the
                    call thistype.fireEvent() // modification of the next damaging attack,
                    set result = temp         // so it should not be used up on 0 damage
                    set target = null         // events such as debuffing.
                    return false
                endif

                call MOD.fire()
                call PriorityList.evaluate()
               
                if (damage - 0.1) <= result and result <= (damage + 0.1) then
                    call thistype.fireEvent()
                    set result     = temp
                    set target     = null
                    return false
                endif
               
                set life = life + damage - result
                if result < damage then
                    set size                           = size + 1
                    set lifeUnits[size]                = target
                    set unitSize[DamageEvent.targetId] = unitSize[DamageEvent.targetId] + 1
                    if result < 0 and not NEGATIVE_DAMAGE_TO_HEAL then
                        set result = 0
                        set life   = life + result
                    endif
                    call TimerStart(lifeBonusTimer, 0., false, function thistype.manageLife)
                elseif life < 0.405 then
                    set life = 0.5
                endif
               
                call thistype.fireEvent()
                call SetWidgetLife(target, life)
                set result = temp
                set target = null
                set NEGATIVE_DAMAGE_TO_HEAL = DEFAULT
                return false
            endmethod
           
            implement DamageControlSystemInit
        endstruct
       
        module DamageControlModule
            static boolean array enabled
           
            static if thistype.onDamageDealt.exists() then
                static integer array dealtCount  
            endif
           
            static if thistype.onDamageTaken.exists() then
                static integer array takenCount
            endif
       
            private static method onDamage takes nothing returns boolean
                local real damage = DamageControl.result
                static if thistype.onDamageDealt.exists() then
                    if thistype.enabled[DamageEvent.sourceId] then
                        set dealtCount[DamageEvent.sourceId] = dealtCount[DamageEvent.sourceId] + 1
                        set DamageControl.result = thistype.onDamageDealt(DamageEvent.source, DamageEvent.target, damage)
                    endif
                endif
                static if thistype.onDamageTaken.exists() then
                    if thistype.enabled[DamageEvent.targetId] then
                        set takenCount[DamageEvent.targetId] = takenCount[DamageEvent.targetId] + 1
                        set DamageControl.result = thistype.onDamageTaken(DamageEvent.source, DamageEvent.target, damage)
                    endif
                endif
                return false
            endmethod
           
            private static method onInit takes nothing returns nothing
                call TriggerAddCondition(damageTrigger, Condition(function thistype.onDamage))
            endmethod
        endmodule
       
        module DamageControlPriorityModule
            static boolean array enabled
           
            static if thistype.onDamageDealt.exists() then
                static integer array dealtCount
            endif
           
            static if thistype.onDamageTaken.exists() then
                static integer array takenCount
            endif
           
            private static method onDamage takes nothing returns boolean
                local real damage = DamageControl.result
                static if thistype.onDamageDealt.exists() then
                    if thistype.enabled[DamageEvent.sourceId] then
                        set dealtCount[DamageEvent.sourceId] = dealtCount[DamageEvent.sourceId] + 1
                        set DamageControl.result = thistype.onDamageDealt(DamageEvent.source, DamageEvent.target, damage)
                    endif
                endif
                static if thistype.onDamageTaken.exists() then
                    if thistype.enabled[DamageEvent.targetId] then
                        set takenCount[DamageEvent.targetId] = takenCount[DamageEvent.targetId] + 1
                        set DamageControl.result = thistype.onDamageTaken(DamageEvent.source, DamageEvent.target, damage)
                    endif
                endif
                return false
            endmethod
           
            private static method onInit takes nothing returns nothing
                local trigger t = CreateTrigger()
                call TriggerAddCondition(t, Condition(function thistype.onDamage))
                call PriorityList.insert(thistype.PRIORITY, t)
                set t = null
            endmethod
        endmodule
    endlibrary


    As of v.2.0.0.0, priorities have been added. This feature allows you to tell the system in what order you want your damage control structs to be run. For certain ones, you may want it to run first, and for others, you may want it to run last. Now this system has the ability to do that. Read the documentation for more info.

    Why are priorities important? Well, resulting damage varies depending on the order in which damage controls are applied. It is sometimes crucial to have certain things run before or after others, else it will lead to the wrong results. With the previous method, there was no way of having that occur without simple luck or extra work. For example, struct A reduces damage taken by 50% and struct B increases damage taken by 25. A unit damages a unit, who has both those structs enabled, for an unmodified 100 damage. If A executes before B, the resulting damage will be 100 * 0.5 + 25 = 75. If B executes before A, the resulting damage will be (100 + 25) * 0.5 = 62.5. See the difference?

    Why would someone choose not to use priorities? Well, yes, uniformity is good and I could make it so that all structs require priorities. (and then just add a WHO_KNOWS priority) However, the priority structs have one extra trigger, and they are entered into a list. I decided that if someone doesn't care about priorities, then they can just ignore it and use a normal damage control module. Sometimes, it doesn't really matter, especially when you are not modifying damages by percentages. (flat increases/reductions don't need priorities) That way, the implementation is slightly easier (you don't have to type an extra integer variable, lol) and it is slightly more efficient. Although, I might change this in the future if people feel that uniformity would be the better choice.

    In addition, I made a very detailed demo map. It features 4 basic spells:
    • Enrage - Causes the unit to deal 50 extra damage. Lasts for the next 4 attacks.
    • Mutated Blood - Causes any attacks the caster receives to heal the caster instead, for twice as much damage as it would have done. Lasts for the next 5 attacks received.
    • Phoenix Blast - Deals 125 damage to a target, but causes target's next 2 attacks to deal 30 extra damage.
    • Lightning Armor - Creates a protective barrier around the caster, reducing the damage he takes by 50%. In addition, all attackers are struck back for 50 damage.

    All of those spells are made relatively easily, and require only a fraction of the code it would normally require. They are heavily commented and each demonstrate interesting ways to take advantage of the system's features.

    Attached below is the demo map. Enjoy!

    Changelog
    2.1.0.0
    • Added better multiple-instance support.
    • Added operators to read the event data to avoid unnecessary mixing.
    • The event now fires in the correct order, allowing GetWidgetLife() to read the appropriate life before the actual modifications. Please update to 2.1.0.0 if you are using any earlier version.
    2.0.0.0
    • Added priorities and reworked the system using Bribe's method to eliminate the need for custom SetUnitLife/GetUnitLife functions.
    1.1.2.0
    • Code Optimizations and redocumented.
    1.1.1.1
    • Big bug fix. Please update to 1.1.1.1 if you are using 1.1.01.
    • Added a GetUnitMaxLife function to receive a unit's maximum hp without interference from the system.
    1.1.0.1
    • Minor Code Optimizations
    1.1.0.0
    • Bug Fix
    1.0.0.0
    • Initial Release
     

    Attached Files:

    Last edited by a moderator: Nov 30, 2011
  2. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Code (vJASS):
    if not enabled then
        call enable()
    endif
     


    To reduce the text that is processed by the Jass Interpreter, you could shorten it to this:
    set enabled = true

    ^^

    This looks pretty good by the way.
     
  3. Switch33

    Switch33

    Joined:
    Dec 3, 2006
    Messages:
    334
    Resources:
    0
    Resources:
    0
    So you finally developed a new system out of all that custom damage modifiers stuff sorta. Looks very nice.

    On a side note:
    Does this mean your still working on Ardent Heroes? The forums for it seem dead sorta. If you want you can contact me on skype and we can collaborate on some stuff.
     
  4. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    This is actually well coded except that this part can be slightly improved =)

    ->
    call ResumeTimer(lifeBonusTimer)


    That is actually slower than TimerStart.
     
  5. Dirac

    Dirac

    Joined:
    Jun 20, 2011
    Messages:
    249
    Resources:
    3
    JASS:
    3
    Resources:
    3
    static method onDamage should be private.

    I guess this is a lot faster than the OnUnitEvent snippet i submitted recently since it avoids trigger evaluations.

    Personally I like it and use it, after some clean up and updates
     
  6. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Is the speed difference marginal or considerable? :p

    Code (vJASS):
    call DamageEvent.ANY.registerTrigger(systemTrigger)
    call TriggerAddCondition( systemTrigger, Condition(function thistype.onDamage) )


    ->

    call DamageEvent.ANY.register(Filter(function thistype.onDamage))
     
  7. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Well, ResumeTimer is considerably slower than TimerStart, but it is a marginal speed increase. However, it's such an easy change that you might as well do it >.>.
     
  8. Dirac

    Dirac

    Joined:
    Jun 20, 2011
    Messages:
    249
    Resources:
    3
    JASS:
    3
    Resources:
    3
    This system would cause lots of problems if AoE damage is done: Notice how the timer part works, in order to remove the ability from an unit it reaches for lifeUnits[size] and since the damage done runs first and after that the timers expire the lifeUnits[size] aims towards only one unit, not every unit that had AoE damage received. IMO this system needs TimerUtils.

    Here, a version that fixes this issue plus some other stuff
    EDIT: code removed.
     
    Last edited: Oct 3, 2011
  9. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    It doesn't need TimerUtils -.-, it just needs a stack.


    Dirac, you have much to learn : P



    Also, we are experienced enough to code this stuff on our own. Don't you have better things to do than recode people's resources for them? I personally wouldn't waste my time fixing someone else's resource up. Let them fix it themselves ; ). You can just tell them what needs to be fixed and then it's their responsibility to do so.
     
  10. Dirac

    Dirac

    Joined:
    Jun 20, 2011
    Messages:
    249
    Resources:
    3
    JASS:
    3
    Resources:
    3
    You speak truth. I just needs a stack. I fixed it because i need it and currently malfunctions.
     
  11. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,426
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Ty guys for the responses, I'll fix them tomorrow.

    Hmm... I don't know if this problem applies. It should work fine with AoE damage, as each unit who received the AoE should be assigned a slot in the lifeUnits[] array. Then it will just loop through them and reduce the hp accordingly if necessary.

    I am not 100% sure though (since my brain is kind of not working at the moment), so I will run more bug-tests tomorrow.
     
  12. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Yea ur right Purge. You have a stack implemented right now = ).

    Sry, I didn't really read any of the code ; P. It just looked aesthetically pleasing and I figured that you code well enough for me to not have to bother since I've walked you through making 2 resources better.
     
  13. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,426
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    I've made the necessary optimizations. :D

    Yes, I am still working on it. Although, progress is at snail's pace, but I don't think there is any rush. I haven't heard from anyone for a while, but I have been still working on it here and there whenever I have spare time. Sadly, the amount of spare time I've had has become drastically lower. :(
     
  14. Switch33

    Switch33

    Joined:
    Dec 3, 2006
    Messages:
    334
    Resources:
    0
    Resources:
    0
    Code (vJASS):
    library Offense initializer Init requires DamageControl, UnitIndexer
        globals
            Event MissEvent
            Event CritEvent
        endglobals

       
        struct Miss extends array
            static boolean is = false
            static real array chance
           
            static method onDamageDealt takes unit source, unit target, real amount returns real
                local integer rand = GetRandomInt(1,100)
                if rand < chance[DamageEvent.sourceId] then
                    call MissEvent.fire()
                    set Miss.is = true // set the miss hit to true for the TextCombat library
                    set amount = amount * 0   // multiply the damage by 0
               endif
                return amount // return the amount of damage done
            endmethod
            implement DamageControlModule
        endstruct    
     
        struct CriticalHit extends array // extend array so it doesn't create useless create/destroy funcs
            static boolean is = false // tells TextCombat whether or not the attack was a critical hit
            static real array chance
            static real array percentage
           
            static method onDamageDealt takes unit source, unit target, real amount returns real
                local integer rand = GetRandomInt(1,100)
                if rand < chance[DamageEvent.sourceId] and Miss.is == false then
                    call CritEvent.fire()
                    set CriticalHit.is = true // set the critical hit to true for the TextCombat library
                    set amount = amount * percentage[DamageEvent.sourceId]   // multiply the damage by critical strike multiplier
                endif
                return amount // return the amount of damage done
            endmethod
       
            implement DamageControlModule //implement the damage control module at the bottom of your struct
        endstruct
       
     
       
        private function Init takes nothing returns nothing
            set MissEvent = Event.create()
            set CritEvent = Event.create()
        endfunction
       
         
        //Trigger wrappers
        function TriggerRegisterMissEvent takes trigger t returns nothing
            call MissEvent.registerTrigger(t)
        endfunction
        function TriggerRegisterCritEvent takes trigger t returns nothing
            call CritEvent.registerTrigger(t)
        endfunction
        //Data Wrappers
        function GetOffenseUnit takes nothing returns unit
            return DamageEvent.source //the unit who missed the attack or caused the critical strike
        endfunction
        function GetOffenseAttacked takes nothing returns unit
            return DamageEvent.target //returns the unit who was attacked by the misser/critical striker
        endfunction
        function GetCritDamage takes nothing returns real
            return DamageEvent.amount //returns the amount of damage dealt by the crit
        endfunction    
    endlibrary


    Would something like this work?

    Mostly this part:
    Code (vJASS):
     if rand < chance[DamageEvent.sourceId] and Miss.is == false then
    Is the part that i'm wondering about. Cause the syntax for it seems fine; but i'm just not sure if its really how i'm thinking it would work.
     
    Last edited: Oct 16, 2011
  15. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    That'd work right, you just aren't modding the damage anywhere ;p.


    Also, rather than Miss.is == false, you can do not Miss.is


    There are a couple of other things too. You don't need a variable to store the chance, you can just calculate it in the if statement, etc.
     
  16. Switch33

    Switch33

    Joined:
    Dec 3, 2006
    Messages:
    334
    Resources:
    0
    Resources:
    0
    Ok good. Yeah i haven't added in setting any of the chance variables or anything yet. I just was wondering if i understood it right. I'm gonna have to re-code it more to add in damage types like Fire(a pure dmg over time attack), Cold(a slowing attack), Light(a more randomish type damage), Nature(poison), and Magic for my map but this helps me understand how to do it.

    I think i do if i want items to effect it. :D
     
  17. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,192
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    You could change one of your blocks to this:

    Code (vJASS):
                    if lifeBonus[id] then
                        call UnitRemoveAbility(curr, ABILITY_LIFE_BONUS)
                        call SetWidgetLife(curr, 9999999)
                        set lifeBonus[id] = false
                    endif


    If the amount is higher than his max life, then SetWidgetLife simply sets its health to its max life. I am not sure why you need to use the minimum between the two.
     
  18. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    A unit can have more than 9999999 life :p
    2^31 is suitable.
     
  19. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,192
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Well then cry to the people who build Damage blocking engines that only block up to 500,000 damage :p
     
  20. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,426
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Fixed. I used a different value though because it is supposed to have current life - 100000 instead of max life. That if-block was there before because I was trying to troubleshoot a problem and forgot to take it out lol.

    Heh, I suppose I can add more. Or I will just make it configurable or something. Although, if I make it at 2^31 it might end up hitting the cap if they have their own life bonus applied. So I might just change it to something higher, but not too high in the next update.