HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Still need help with re-creating chain lightning!

08-18-2004, 05:19 PM#1
wheee
Hey,

I thought of another approach to re-creating chain lightning, but alas it doesn't seem possible. This isn't exactly a trigger help, as the trigger part is pretty easy to do once you can set up the ability. Hence, my question pertains to creating the ability, namely the buff stats.

I was thinking of creating a custom chain lightning, that would use a buff, ie. curse. I've tried to, to no avail. Ideally, I want to have the chain lightning also cast the buff (ie. curse) on all the targets it hits. Then, I can assign a trigger which will wait for the chain lightning to be cast, detect all units with the curse buff within the casting area and then do the damage calculations.

SO, is this possible? I've tried to mess around with the AOE spells of the chain-sort, and assigning a value to the buff stats makes no difference. What are the guidelines in this area?

(the reason why I want a custom chain lightning is because I want to deal damage based on variable values, such as the caster's INT attribute, and so on)

Please help. Thanks.
08-18-2004, 05:28 PM#2
Coffein
You could use Vex's Caster System, launch a projectile out from the caster to the target unit, from that unit check if there are any units around that one within a specified range and so on
08-18-2004, 07:25 PM#3
Vexorian
For my project I am converting all the object editor spells into flexible trigger enhanced ones that can have varied damage depending on other factors.

You can remake chain lightning using a chain system, or you can just keep chain lightning for the effects, then do a trigger that guesses the targets of the chain lightning, I did that and Worked the 100% of my tests.

I will bring you the trigger (inside a map) by tomorrow I think, it is completelly multi instanceable btw
08-18-2004, 08:09 PM#4
wheee
Quote:
Originally Posted by Lord Vexorian
For my project I am converting all the object editor spells into flexible trigger enhanced ones that can have varied damage depending on other factors.

You can remake chain lightning using a chain system, or you can just keep chain lightning for the effects, then do a trigger that guesses the targets of the chain lightning, I did that and Worked the 100% of my tests.

I will bring you the trigger (inside a map) by tomorrow I think, it is completelly multi instanceable btw

That would be great, thanks. I was thinking of trying to "calculate" the targets of chain lightning, ie. with buffs or something, but I'm very much interested to see how you did it.

How did you handle spells like stomp/blizzard (both which have circular AOE) and shockwave which has a rectangular AOE...?
08-18-2004, 08:32 PM#5
Vexorian
Stomp is easy (pick all the units in range of triggering unit), blizzard is a little more difficult and I didn't do it yet, but I will for sure.

For Shockwave I sacrifized the speed to be 522 instead of 800 and I used a unit with the shockwave model and the A unit comes within range of () event, so I could do the damage when they got close.
08-18-2004, 08:40 PM#6
wheee
Quote:
Originally Posted by Lord Vexorian
Stomp is easy (pick all the units in range of triggering unit), blizzard is a little more difficult and I didn't do it yet, but I will for sure.

For Shockwave I sacrifized the speed to be 522 instead of 800 and I used a unit with the shockwave model and the A unit comes within range of () event, so I could do the damage when they got close.

Alright then, what about evasion, and drunken haze...! =)

Actually, I do want to know about those two especially. I want to be able to dynamically adjust the % rate of evasion based on the owner's agility for instance.

The problem, I'm thinking, is that if you use the event "spell effect", then it's already too late - as the evasion % has already been calculated.

However, now that I've thought about it abit more, isn't it just simpler to create a standard trigger which occurs when the owner of the evasion skill gets "attacked" then you calculate what kind of attack (ie, spell or melee/range) then calculate whether it's a hit or miss? Lemme know what you think on those two skills.

Thanks
08-18-2004, 09:11 PM#7
wheee
Actually, evasion seems to work nicely...

Untitled Trigger 001
Events
Unit - A unit Is attacked
Conditions
((Attacked unit) is A Hero) Equal to True
Actions
Unit - Create 1 Dummy Caster for Player 1 (Red) at (Position of (Attacking unit)) facing Default building facing degrees
Unit - Add a 1.00 second Generic expiration timer to (Last created unit)
Unit - Add Mega curse to (Last created unit)
Unit - Order (Last created unit) to Undead Banshee - Curse (Attacking unit)
Unit - Remove Curse buff from (Attacking unit)

Surprisingly, you don't need a wait command or anything. With this trigger, the attacking unit missed 100% of the time as the "curse" ability I used had a 100% mioss rate. So, you just have to add the condition ("Attacked Unit" has evasion), then in the Actions section, calculate based on the hero's ability level (and other stuff) whether it's a hit or miss.

Do your forsee any problems with that?

Anyway, I just mentioned that since you said you were trying to convert all the spells to allow for variable damages/rates/etc.

Now, I'm gonna work on increasing the speed of something by a variable amount.
08-18-2004, 09:23 PM#8
volatile
It's wierd that the trigger above works because the event "unit is attacked" gives you the impression that the attack has just occurred. Whereas it must really mean "unit is attacked but attacker has not actually attacked yet." If casting curse on them works .1 before they actually attack then removing it the second the attack is finished... Very strange, wish these events were worded better.
08-19-2004, 01:19 PM#9
Vexorian
Actually I decided to do not do that for passive abilities, infinite level on evasion ends being 100% chance and that's not right, the same with critical strike and other passive abilities.
08-19-2004, 07:23 PM#10
Vexorian
Ok, here we have the trigger :

Code:
constant function ChainLightning_SpellId takes nothing returns integer
    return 'A01I'
endfunction

constant function ChainLightning_N takes integer level returns integer
    return 2+2*level
endfunction

constant function ChainLightning_Dmg takes real level, real str, real int, real agi returns real
    return 60 + (25+level*15)*level + str*0 + int*0 + agi*0
endfunction

constant function ChainLightning_fct takes real l returns real
    return 0.75
endfunction

constant function ChainLightning_Area takes real level returns real
    return 500.0
endfunction

//=================================================================================================
function Trig_Chain_Lightning_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == ChainLightning_SpellId()
endfunction

function ChainLightning_GetTimerPlayer takes timer t returns player
    return GetHandleHandle(t,"player")
endfunction

function ChainLightning_GetTimerUnit takes timer t,string s returns unit
    return GetHandleHandle(t,s)
endfunction

function ChainLightning_GetTimerGroup takes timer t returns group
    return GetHandleHandle(t,"group")
endfunction

function ChainLightning_Timer takes nothing returns nothing
 local timer c=GetExpiredTimer()
 local unit t=ChainLightning_GetTimerUnit(c,"unit")
 local unit u=ChainLightning_GetTimerUnit(c,"u")
 local player p=GetOwningPlayer(u)
 local real dmg=GetHandleReal(c,"dmg")
 local group log=ChainLightning_GetTimerGroup(c)
 local group g=CreateGroup()
 local real a
 local real b
 local unit picked
 local unit closest
 local integer l=GetHandleInt(c,"l")
 local integer times= GetHandleInt(c,"times")-1
    call SetHandleInt(c,"times",times)
    call DamageUnit( p, dmg ,t )
    //call UnitDamageTarget(u, t, dmg, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_LIGHTNING, WEAPON_TYPE_WHOKNOWS)
    call SetHandleReal(c, "dmg", dmg*ChainLightning_fct(l) )
    call GroupAddUnit( log, t)
    if times>0 then
        call GroupEnumUnitsInRange(g,GetUnitX(t),GetUnitY(t) , ChainLightning_Area(l), null)
        set b=1000000
        set closest=null
        loop
            set picked=FirstOfGroup(g)
            exitwhen picked==null
            call GroupRemoveUnit(g,picked)
            if IsUnitEnemy(picked,p) and IsUnitAliveBJ(picked) and not(IsUnitInGroup(picked,log)) and IsUnitVisible(picked,p) then
                set a= SquareRoot( Pow(GetUnitX(t)-GetUnitX(picked),2) + Pow(GetUnitY(t)-GetUnitY(picked),2) ) 
                if a<b then
                    set b=a
                    set closest=picked
                endif
            endif
        endloop
    endif
    if times==0 or closest==null then
        call FlushHandleLocals(c)
        call DestroyTimer(c)
    else
        call SetHandleHandle(c,"unit", closest )
        call TimerStart(c, b/1500, false, function ChainLightning_Timer )
    endif
 call DestroyGroup(g)
 set g=null
 set c=null
endfunction

function Trig_Chain_Lightning_Actions takes nothing returns nothing
 local unit u=GetTriggerUnit()
 local unit t=GetSpellTargetUnit()
 local integer s=GetSpellAbilityId()
 local integer l=GetUnitAbilityLevel(u,s)
 local timer ti
    set ti=CreateTimer()
    call SetHandleHandle(ti,"u", u )
    call SetHandleHandle(ti,"unit", t )
    call SetHandleReal(ti,"dmg", ChainLightning_Dmg(l,GetHeroStr(u,true),GetHeroInt(u,true),GetHeroAgi(u,true)) )
    call SetHandleHandle(ti,"group",CreateGroup())
    call SetHandleInt(ti,"times",ChainLightning_N(l))
    call SetHandleInt(ti,"l",l)
    call SetHandleHandle(ti,"unit", t )
    call TimerStart(ti, SquareRoot( Pow(GetUnitX(u)-GetUnitX(t),2) + Pow(GetUnitY(u)-GetUnitY(t),2)   ) /1500, false, function ChainLightning_Timer )
 set t=null
 set ti=null
 set u=null
endfunction

//===========================================================================
function InitTrig_Chain_Lightning takes nothing returns nothing
    set gg_trg_Chain_Lightning = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Chain_Lightning, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Chain_Lightning, Condition( function Trig_Chain_Lightning_Conditions ) )
    call TriggerAddAction( gg_trg_Chain_Lightning, function Trig_Chain_Lightning_Actions )
endfunction

Make a new trigger called Chain Lightning , convert it to custom text, and replace it with the thing above, now before saving copy the handle variables ( http://www.wc3sear.ch/index.php?p=JASS&ID=218
) To the Custom Script Section .

The trigger needs the caster system unless you have patch 1.17 , find the caster system in my signature .

If you have the patch 1.17 find this place in the trigger :
Code:
    call DamageUnit( p, dmg ,t )
    //call UnitDamageTarget(u, t, dmg, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_LIGHTNING, WEAPON_TYPE_WHOKNOWS)

Remove the call DamageUnit(p,dmg,t) line, then remove the first // of the next line , that way the trigger will use the new native instead of needing the caster system.

Now on the important thing:
In
Code:
constant function ChainLightning_SpellId takes nothing returns integer
    return 'A01I'
endfunction
You have to replace A01I with the rawcode of the chain lightning ability you are using

in
Code:
constant function ChainLightning_N takes integer level returns integer
    return 2+2*level
endfunction

constant function ChainLightning_Dmg takes real level, real str, real int, real agi returns real
    return 60 + (25+level*15)*level + str*0 + int*0 + agi*0
endfunction

constant function ChainLightning_fct takes real l returns real
    return 0.75
endfunction

constant function ChainLightning_Area takes real level returns real
    return 500.0
endfunction
You change the stats , Area ,speed and N (number of targets) should match the ones of the spell , I made ChainLightning_Dmg so you can use str , agi , int as the Strenght , Agility and intelligence of the heroe
08-19-2004, 09:25 PM#11
wheee
Hey,

I'm looking over the code... just a few questions:

1. Your Get/SetHandle functions, are those basically hashing functions? Stores values (regardless of type), with a key into the gamecache? So that you can retrieve the values later using the right key? That's pretty handy, if I'm correct.

2. I'm a bit confused as to the purpose of using a timer. Hence, the design of this spell is a bit unclear. Could you explain the timer, and why you used it? I thought the timer is what the name specifies... an action that occurs during a specified duration of time, or an action that occurs after a specified duration of time.

*edit* Wait, I see how you're "guessing" now - you find the next closest unit. And you're using a timer to deal the damage consequectively with a slight delay between each one... the (distance)/1500 where 1500 is based on some number from the chain lightning animation speed, I assume. The other constraint with your chain-lightning-version is that the # of targets per chain lightning use isn't variable. It's hard-coded in the chain-lightning-stats. Hence, you couldn't use this code to make a chain lightning that hits a minium of 5 units to a maxium of 7 units at lvl 1, right? I'm guessing you would have to use dummy casters to handle that. (I'm not trying to nit-pick or anything, I'm just making sure I understand it completely...! =)

3. Lastly, I was looking at your other jass files, the one that interests me is the Special Events functions that you made. Er, I'm still looking over it, and I'm not even sure what questions to ask yet. =) but it still looks useful.

I guess, if there's a question to ask, it's this...

From my preliminary design, it looks like I'll be dealing with alot of passive trigger spells. MANY triggers that use events like, "unit attacks unit". For example, if a hero has a certain skill, (ie. lightning imbue) then every time he attacks something, there's a chance that he will deal "lightning damage" on the unit. Likewise, other spells, (ie. ice aura) where if a hero gets hit then there's a chance that the attacker will iced/slowed/blocked/nova/etc. I'm designing alot of passive spells/abilities, and the spells and damage/duration are all variable and hence I need to use alot of triggers. Will your "Special Events" functions be of benefit? Because, for the most part, the events aren't looking for "spell being casted" and so on, just "unit attacks unit".

Do you forsee any lag issues with having so many "Unit attack unit" triggers? I'm a bit worried, as EVERY attack regardless of who will cause a cascade of if-else checks. In a game such as an AOS/DOTA type, there'll be alot of attacking units in the map per every game tick = alot of processing.

Thanks for your help. Sorry for asking so many questions, it's hard to find any reliable _official_ documentation on JASS and its functions/limitations. =)
08-20-2004, 04:48 PM#12
Vexorian
I didn't use casters to make the chain lightning total targets flexible because:

1) It did not look like the real chain lightning
2) The number of targets is not something I am interested in being increased.

And I reccomend you to do not do this for passive abilities really, not because they are impossible, it is mostly because of balance