• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Trigger] Will hash tables help with this?

Status
Not open for further replies.
Level 8
Joined
Apr 30, 2009
Messages
338
I am building a Guild Wars Arena map, and there is a specific mechanic in Guild Wars which I think I could use hash tables to replicate. I want to know if I'm right about this from someone who knows them better.

The mechanic in Guild Wars I am trying to trigger is called "conditions," which are a family of debuffs that are caused by many different skills. They are like this:

Disease - 8 health loss per second, can spread to nearby units
Burning - 14 health loss per second
Blindness - 90% chance to miss on attacks


Now, there are many more that cause damage or some other status effect, but these are just examples. I know that Blindness would be very easy to trigger without hash tables by just using Drunken Haze via a dummy unit. What I am concerned with is the damaging conditions.

For example, the Burning condition can be applied by several different abilities, and can last for varying durations based on these abilities. What I want to do with a hash table is link the unit that applied Burning to the unit that is being burned so I can cause the caster to damage the victim (via a trigger) for 2.8 every 0.20 seconds.


Two heroes, Hero_A and Hero_B, each have a different spell that causes burning:
Spell_A - causes burning condition for 7 seconds
Spell_B - causes burning condition for 3 seconds


Hero_A casts Spell_A on Target_A, and 2 seconds later, Hero_B casts Spell_B on Target_B. So I need a trigger that can do this:

Detects when a spell that causes burning is cast.
- Since all my spells will be triggered, this will almost be intrinsic to the spells anyway.

Place the Burning buff on the target for the duration specified.
- Easy with dummy units.

Run a trigger which causes every unit with the Burning buff to be damaged for 2.8 every 0.20 seconds by the unit which caused Burning.
- This is where I think I can use a hash table to key the target with the caster. If this is possible, I would not have to use dynamic indexing to achieve proper damage credit.

Detect when no more units are burning and shut off the 0.20 second loop, to avoid performance issues.
- Easy with unit groups, just attach a condition at the end of the loop to shut it off, and then a condition on all Burning spells to turn the loop back on if it isn't already on.


Am I right in assuming hash tables will make it possible to pair target and caster so that triggered periodic damage will be doable without indexing?
 
Level 10
Joined
Jan 21, 2007
Messages
576
Sounds like you just need a system that deals a custom damage over time =p. Lucky for you I made one recently in my coding endeavors.
JASS:
library EasyDot initializer Init
//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\\
//                                   EasyDot                                       \\
//                                   By: Gost                                      \\
//   A simple system allowing the user to apply a d/hot to a target with a single  \\
//                         line of code, or take one away.                         \\
//                                                                                 \\
//        Requirements: JNGP (If you plan on editing or using this that is.)       \\
//                                   course.                                       \\
//                                                                                 \\
// The LowestInterval global is the minimum amount of time between two ticks of a  \\
// DoT possible. This can be lowered down however low you want but there really is \\
//                    normaly no need for an interval below .05                    \\
//                                                                                 \\
//               To apply a DoT to a unit use this function                        \\
// function CreateDot takes unit Caster, widget Target, real Dpi, real Interval,   \\
//     real Dur, string SpecEfec, string AttachPoint, AttackType returns nothing   \\
//                                                                                 \\
//  Dpi is the damage per interval, interval is how long between each instance of  \\
//                  damage, and duration is how long the dot lasts                 \\
//                                                                                 \\
//                                  Version: 1.0                                   \\
//                                                                                 \\
//                                                                                 \\
//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\\
globals
    private Dot array DOTS
    private integer   total = 0
    //SETUP
    private real LowestInterval = .05
    //ENDSETUP
endglobals
//================================System Begings=====================================
struct Dot
widget       Target
unit         Caster
real         Dpi
real         Interval
real         Dur
real         CurrentWait = 0
string       SpecEfec
string       AttachPoint
string       Flag
attacktype   AttackType
static timer Tim         = null
//Main system loop, don't touch unless you know what you are doing.
static method Loop takes nothing returns nothing
    local Dot dat
    local integer i = 0
    //runs through the
    loop
        exitwhen i >= total
        set dat = DOTS[i]
        if GetWidgetLife(dat.Target) <= .405 or dat.Dur <= 0 then
            //Should it heal, or damage.
            if dat.Dpi < 0 then
                //It should heal:
                call SetWidgetLife(dat.Target, GetWidgetLife(dat.Target) - dat.Dpi)
            else
                //It should damage:
                call UnitDamageTarget(dat.Caster, dat.Target, dat.Dpi, false, false, dat.AttackType, DAMAGE_TYPE_NORMAL, null)
            endif
            call DestroyEffect(AddSpecialEffectTarget(dat.SpecEfec, dat.Target, dat.AttachPoint))
            call dat.destroy()
            set total = total - 1
            set DOTS[i] = DOTS[total]
            set i = i - 1
        else
            if dat.CurrentWait >= dat.Interval then
            //Should it heal, or damage.
                if dat.Dpi < 0 then
                    //It should heal:
                    call SetWidgetLife(dat.Target, GetWidgetLife(dat.Target) - dat.Dpi)
                else
                    //It should damage:
                    call UnitDamageTarget(dat.Caster, dat.Target, dat.Dpi, false, false, dat.AttackType, DAMAGE_TYPE_NORMAL, null)
                endif
                call DestroyEffect(AddSpecialEffectTarget(dat.SpecEfec, dat.Target, dat.AttachPoint))
                set dat.CurrentWait = 0
                set dat.Dur = dat.Dur - LowestInterval
                set dat.CurrentWait = dat.CurrentWait + LowestInterval
            else
               set dat.CurrentWait = dat.CurrentWait + LowestInterval
               set dat.Dur = dat.Dur - LowestInterval
            endif
        endif
            set i = i + 1
    endloop

            if total == 0 then
                call PauseTimer(dat.Tim)
            endif
endmethod

method onDestroy takes nothing returns nothing
    set this.Target      = null
    set this.Caster      = null
    set this.Dpi         = 0
    set this.Interval    = 0
    set this.Dur         = 0
    set this.CurrentWait = 0
    set this.SpecEfec    = ""
    set this.AttachPoint = ""
    set this.Flag        = ""
    set this.AttackType  = null
endmethod

endstruct
//===================================================================================
//This is the only function that you will need to use.
function CreateDot takes unit Caster, widget Target, real Dpi, real Interval, real Dur, string SpecEfec, string AttachPoint, attacktype AttackType, string Flag returns nothing
        local Dot dat
        local integer i = 0
        local boolean continue = true
        loop
            exitwhen i >= total or continue == false
            set dat = DOTS[i]
            if dat.Target == Target then
                if SubString(Flag, 2,StringLength(Flag)) == SubString(dat.Flag, 2,StringLength(dat.Flag)) then
                    if SubString(Flag, 0,1) == "" then
                        set continue = true
                    else
                        set continue = false
                    endif
                endif
            endif
            set i = i + 1
        endloop
        if continue == true then
            set dat             = Dot.create()
            set dat.Target      = Target
            set dat.Caster      = Caster
            set dat.Dpi         = Dpi
            set dat.Interval    = Interval
            set dat.Dur         = Dur
            set dat.SpecEfec    = SpecEfec
            set dat.AttachPoint = AttachPoint
            set dat.Flag        = Flag
            set DOTS[total]     = dat
            if total == 0 then
                call TimerStart(Dot.Tim, LowestInterval, true, function Dot.Loop)
            endif
            set total = total + 1
        endif
endfunction
//===================================================================================
function RemoveDot takes unit u returns nothing
    local integer i = 0
    local Dot dat
    loop
        exitwhen i >= total
        if DOTS[i].Target == u then
            set dat = DOTS[i]
            set total = total - 1
            set DOTS[i] = DOTS[total]
            call dat.destroy()
        endif
        set i = i + 1
    endloop
endfunction
//===================================================================================
private function Init takes nothing returns nothing
    set Dot.Tim = CreateTimer()
endfunction
//===================================================================================
endlibrary

Here is an example of me easily using it for a spell, in gui none-the-less.

This particular dot would deal 100 damage/second for 8 seconds for a total of 800 damage. Creating a blood effect on the target each tick.
  • Rend
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Rend
    • Actions
      • Custom script: call CreateDot(GetTriggerUnit(), GetSpellTargetUnit(),100,1,8,"Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl","origin",ATTACK_TYPE_NORMAL,"rend")
And I will take it apart to explain it.
call CreateDot(GetTriggerUnit(), The Casting Unit, who would get credit for the kill.
GetSpellTargetUnit(), The Target.
100, The damage done each interval.
1, The interveral (1 second, can be anything you want but has to be above the LowestInterval globals. But you can lower that to so it doesn't matter).
8, The duration.
"Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl", The special effect shown each damage interval.
"origin", The attachment point.
ATTACK_TYPE_NORMAL, The attack type, obviously.
"rend") And the spells flag. If I casted this spell on a unit, and then another unit casted the same spell on the same unit, before it creates the dot it checks if the target unit already has this flag, if it does it doesn't create the dot. So if you enter a flag, that spell doesn't stack with itself. If you leave the flag blank, "", it stacks with itself.

As for buffs, this system doesn't apply the buff, if there is a predetermined duration on your spells you could just have your spells apply the buff. I might get around to making it so this system applies buffs and has an option to renew a dots duration if a non stacking spell is casted on the same unit. But I am busy atm with a map of my own.

Also keep in mind this is one of my earliest creations and hasn't been looked at it in a bit, but it is lag free and optimal enough for our circumstances.

And if this doesn't help you at all (=O) thats fine, I had this already made so w/e =).
 
Status
Not open for further replies.
Top