• 🏆 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!

[JASS] Triggered Chain Lightning

Status
Not open for further replies.
Level 28
Joined
Jan 26, 2007
Messages
4,789
Hey,

I was working on a completely triggered chain lightning, where you can upgrade the number of targets, damage, damage reduction and mana cost, but it doesn't work.

I'm a JASS-noob and still willing to learn more, but I need your help for that ;)

This is my code:

JASS:
function ChainLightning takes nothing returns nothing
    local location p = (GetUnitLoc(GetTriggerUnit()))
    local group g = CreateGroup()
    local unit caster = GetTriggerUnit()
    local unit target = GetSpellTargetUnit()
    local unit dummy
    local integer i = 0

    call SetUnitManaBJ(caster, GetUnitState(caster, UNIT_STATE_MANA) - ((GetUnitAbilityLevel(caster, 'A016')*100) - (udg_Mana[1]*30)))
    set dummy = CreateUnitAtLoc(GetOwningPlayer(GetTriggerUnit()), 'h000', p, 270.)
    call UnitApplyTimedLife(dummy, 'BTLF', 2.00)
    call IssueTargetOrder(dummy, "chainlightning", target)
    call GroupEnumUnitsInRangeOfLoc(g, GetUnitLoc(target), 500, null)
    call GroupRemoveUnit(g, target)
    call UnitDamageTarget(caster, target, ((GetUnitAbilityLevel(caster, 'A001') * 150) + I2R(GetHeroInt(caster, true)) + udg_Damage[1]), true, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
    set p = null
    set g = null
    set dummy = null
    
    loop
        exitwhen i >= 1 + (GetUnitAbilityLevel(caster, 'A001') + (udg_Targets[1]))
        set i = i + 1
        call GroupEnumUnitsInRangeOfLoc(g, GetUnitLoc(target), 500, null)
        set p = GetUnitLoc(target)
        set dummy = CreateUnitAtLoc(GetOwningPlayer(GetTriggerUnit()), 'h000', p, 270.)
        set target = FirstOfGroup(g)
        call IssueTargetOrder(dummy, "chainlightning", target)
        call UnitApplyTimedLife(dummy, 'BTLF', 1.00)
        call UnitDamageTarget(caster, target, ((GetUnitAbilityLevel(caster, 'A016') * 150) + I2R(GetHeroInt(caster, true)) + udg_Damage[1]), true, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
        set p = null
        set g = null
        set dummy = null
    endloop
    
    set dummy = null
    set target = null
    set caster = null
endfunction
(I know there is a BJ, but I don't know how to do it else).

What does it do at the moment?

Well, it creates 1 chain lightning to the targetted unit, but that's it... it stops after that, even if I increase the exitwhen amount.

The damage also isn't correct, it does 50 damage at level 2, while it should be at least 300 (Ability Level * 150 + Int + Variable).
This is probably a crappy code... but it would help if you say what's wrong ^^

Notes

If there are some things not efficient, feel free to say so - if I (you) get this to work, I will probably trigger other abilities and I need all information I can get for that.

Is there a problem with the hive's JASS script code?
The array indicators have become the ASCII-codes of the square brackets...

Thanks in advance.
 
Level 5
Joined
Dec 18, 2007
Messages
205
hey ap0calypse, so we meet again:)
i looked through your code and cleaned it up completely.
the problem is: i couldn't test, it so i could have messed up something very easily.
you still have to replace the udg_variables!

it does the following (at least if it works ;) ):
-chain lightning on the amount you wanted (via global)
-damage you wanted (via global)
-cannot target the same unit multiple times
-does not target dead units, magic immune units, friendly units

finally: the code

JASS:
function ChainLightning takes nothing returns nothing
    local unit caster = GetTriggerUnit()
    local unit target = GetSpellTargetUnit()
    local unit dummy
    local location p = GetUnitLoc(caster)
    local group g = CreateGroup()
    local group h = CreateGroup()
    local group i = CreateGroup()  
    local integer i = 0

    call SetUnitState(caster, UNIT_STATE_MANA, GetUnitState(caster, UNIT_STATE_MANA) - ((GetUnitAbilityLevel(caster, 'A016')*100) - (udg_MANAVARIABLE))) // the variable you mentioned, that was converted to ascii?
    set dummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h000', p, 0.00)
    call UnitApplyTimedLife(dummy, 'BTLF', 2.00)
    call IssueTargetOrder(dummy, "chainlightning", target)
    call UnitDamageTarget(caster, target, ((GetUnitAbilityLevel(caster, 'A001') * 150) + I2R(GetHeroInt(caster, true)) + udg_DAMAGEVARIABLE), true, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
    call RemoveLocation(p)
    call GroupAddUnit(i, target)
    
    loop
        set p = GetUnitLoc(target)
        set g = GetUnitsInRangeOfLocAll(500.00, p)
        loop
            set target = FirstOfGroup(g)
            if IsUnitEnemy(target, GetOwningPlayer(caster)) and IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE) == false and GetUnitState(target, UNIT_STATE_LIFE)>0 and IsUnitInGroup(target, i)==false then
                call GroupAddUnit(h, target)
            endif
            call GroupRemoveUnit(g, target)
        endloop
        set target = FirstOfGroup(h)
        exitwhen i >= 1 + (GetUnitAbilityLevel(caster, 'A001') + (udg_TARGETSVARIABLE)) or target==null
        set i = i + 1
        set dummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h000', p, 0.00)
        call IssueTargetOrder(dummy, "chainlightning", target)
        call UnitApplyTimedLife(dummy, 'BTLF', 2.00)
        call UnitDamageTarget(caster, target, ((GetUnitAbilityLevel(caster, 'A016') * 150) + I2R(GetHeroInt(caster, true)) + udg_DAMAGEVARIABLE), true, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
        call RemoveLocation(p)
    endloop

    set caster = null
    set target = null
    set dummy = null
    call RemoveLocation(p)
    set p=null
    call DestroyGroup(g)
    set g=null
    call DestroyGroup(h)
    set h=null
    call DestroyGroup(i)
    set i=null
endfunction

if you get problems then please post the complete trigger because this is just the action, i'd like to check event & condition then too.
and please look up the IDs for the spell once again and that the IDs are correct because you used multiple IDs.


greetings,
breath
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
Nice helping, bReathl3sS, but..

This is not good :D

JASS:
        loop
            set target = FirstOfGroup(g)
            if IsUnitEnemy(target, GetOwningPlayer(caster)) and IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE) == false and GetUnitState(target, UNIT_STATE_LIFE)>0 and IsUnitInGroup(target, i)==false then
                call GroupAddUnit(h, target)
            endif
            call GroupRemoveUnit(g, target)
        endloop

Missing exitwhen :p. This isn't good either:

set g = GetUnitsInRangeOfLocAll(500.00, p)


He wanted the location of the target not the caster.

Hellooo ap0calypse, prepare yourself.. :D

This is how your locals declarations should look like:

JASS:
local group g = CreateGroup()
local unit caster = GetTriggerUnit()
local unit target = GetSpellTargetUnit()
local location p = GetUnitLoc(caster)
local location q = GetUnitLoc(target)
local unit dummy
local integer i = 0

You need the location of "target" too, otherwise you're leaking a point here:

call GroupEnumUnitsInRangeOfLoc(g, GetUnitLoc(target), 500, null)


So it should be like this:

call GroupEnumUnitsInRangeOfLoc(g, q, 500, null)


Apparently, passing "null" as a boolexpr parameter sometimes leak, so this is safer:

JASS:
function ReturnTrue takes nothing returns boolean
    return true
endfunction

// ...
// ...

call GroupEnumUnitsInRangeOfLoc(g, q, 500, Filter(ReturnTrue))

Also, you didn't destroy the p location, you need to do that (also with q location). Put these when you're done with the locations:

JASS:
call RemoveLocation(p)
call RemoveLocation(q)

Don't forget to null q too, thought that's not so important.

Now, a big mistake you're doing is that you're "overnulling" variables. It's bad to not null them, but it's even worse to overnull them, because you're losing the pointer that way.

A quick explanation: for example, the "caster" variable is actually a pointer which points to the triggering unit (or casting unit, whatever). As this pointer takes a tiny bit of memory, you can remove it with nulling the variable. But if you're nulling it before you've stopped using it, the second time you use that variable it will be empty (null). That's what happened to your group variable, I think. Also, you don't have to nullify variables when you're assigning a new value during the function, you only need to nullify it at the end of the function when you're completely done with it. Get it? That's probably why your code isn't working.

You also have a leak in your loop, you should destroy the location at the end of the loop. Also, don't forget to destroy your group at the end of the function (call DestroyGroup(g)).


I don't have much time to check the functionality of the code, but try to do as bReathl3sS and I told you and tell if something's not working.
 
Level 28
Joined
Jan 26, 2007
Messages
4,789
paladons chain system is a good idea too and it's in GUI :p
I'd rather make it myself - with some help of the people here, of course ^^
We all know Paladon is a great spell-maker, but by copy/pasting his GUI-spells I don't learn anything about JASS ><


@ Br34thl3Ss: thanks a lot, you've cleared some stupid mistakes ^^ (magic immunity, for example).

These are the answers of some questions:
  • I've checked all raw-codes: 'h000' is the dummy, 'A016' is the hero ability and the 'A001' is wrong, that's what caused the damage bug.
  • The mana-variable is a real variable.
  • Event: unit starts the effect of an ability - conditions: ability equal to chain lightning and mana greater than or equal to the mana cost.
For the exitwhen in the loop: I've set it to when the unit group is empty.


Yeah, I didn't really clear all leaks, since the code didn't work... after it worked, I would've removed the leaks ^^
The ReturnTrue-function is weird, I've never heard of that, but I'll keep it in mind - it's a short function, so adding it is not a big deal, especially if it covers a leak :)

Allright, I've done most of the things you have said and this is how it looks like now:

JASS:
function ReturnTrue takes nothing returns boolean
    return true
endfunction

function ChainLightning takes nothing returns nothing
    local unit caster = GetTriggerUnit()
    local unit target = GetSpellTargetUnit()
    local unit dummy
    local location p = GetUnitLoc(caster)
    local location q = GetUnitLoc(target)
    local group g = CreateGroup()
    local group h = CreateGroup()
    local group f = CreateGroup()
    local integer i = 0

    call SetUnitState(caster, UNIT_STATE_MANA, GetUnitState(caster, UNIT_STATE_MANA) - ((GetUnitAbilityLevel(caster, 'A016')*100) - (udg_Mana[1])))
    set dummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h000', p, 0.00)
    call UnitApplyTimedLife(dummy, 'BTLF', 2.00)
    call IssueTargetOrder(dummy, "chainlightning", target)
    call UnitDamageTarget(caster, target, ((GetUnitAbilityLevel(caster, 'A016') * 150) + I2R(GetHeroInt(caster, true)) + udg_Damage[1]), true, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
    call RemoveLocation(p)
    call GroupAddUnit(f, target)

    loop
        set p = GetUnitLoc(target)
        set g = GetUnitsInRangeOfLocAll(500.00, p)
        loop
            exitwhen CountUnitsInGroup(g) == 0
            set target = FirstOfGroup(g)
            if IsUnitEnemy(target, GetOwningPlayer(caster)) and IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE) == false and GetUnitState(target, UNIT_STATE_LIFE)>0 and IsUnitInGroup(target, f)==false then
                call GroupAddUnit(h, target)
            endif
            call GroupRemoveUnit(g, target)
        endloop
        set target = FirstOfGroup(h)
        exitwhen i >= 1 + (GetUnitAbilityLevel(caster, 'A016') + (udg_Targets[1])) or target==null
        set i = i + 1
        set dummy = CreateUnitAtLoc(GetOwningPlayer(caster), 'h000', p, 0.00)
        call IssueTargetOrder(dummy, "chainlightning", target)
        call UnitApplyTimedLife(dummy, 'BTLF', 2.00)
        call UnitDamageTarget(caster, target, ((GetUnitAbilityLevel(caster, 'A016') * 150) + I2R(GetHeroInt(caster, true)) + udg_Damage[1]), true, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
        call RemoveLocation(p)
    endloop

    set caster = null
    set target = null
    set dummy = null
    call RemoveLocation(p)
    set p = null
    call DestroyGroup(g)
    set g = null
    call DestroyGroup(h)
    set h = null
    call RemoveLocation(q)
    set q = null
    call DestroyGroup(g)
    set g = null
endfunction
(I couldn't get the "call GroupEnumUnitsInRangeOfLoc(g, q, 500, Filter(ReturnTrue))" to work, it gave a critical error for some reason...
There's still a BJ: "CountUnitsInGroup(g)").

It works! (hooray), but it doesn't look really smooth;
The damage is dealt before the special effect, which doesn't look really good and if the ability kills the unit, you won't see the special effect.
If the targets/hero are moving, the chain lightning won't be at the correct position.

Any idea how to fix any of those? ^^

Erm, that might be a little much to ask, but that's what you guys are for, right? :cute:
 
Level 5
Joined
Dec 18, 2007
Messages
205
everything's fine now? i hope so APoC@1yPS3 .
everyone is talking about vjass and that it is much simpler than jass.
would you recommend everyone to change to vjass after programming some jass code? because i'm actually thinking whether i should, too. and would you sugggest any tuts or sth.?

greetings
 
Level 28
Joined
Jan 26, 2007
Messages
4,789
everything's fine now? i hope so APoC@1yPS3 .
everyone is talking about vjass and that it is much simpler than jass.
would you recommend everyone to change to vjass after programming some jass code? because i'm actually thinking whether i should, too. and would you sugggest any tuts or sth.?

greetings

Nope, sorry... 5b doesn't work for me :s
(It has something to do with japi - should I install that firs? I don't get any results when googling it, though...).
I think you should create all your new codes in vJass, but leave the old ones as they are ^^
 
Status
Not open for further replies.
Top