HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

vJass Spell Problem

11-08-2008, 10:33 PM#1
Tiku
Hello, I've been trying to go from handlevars to vJass, and so far, its kinda weird :P

Well i tried to make a spell, a simple WoW type spell... Its like a warlocks Corruption:
-------
Ability Type: Active
Target Type: Unit
Effect: Damage Over Time
Description: Corrupts the target, causing Shadow damage over 12 seconds.
Level 1: 40 Shadow damage every 3 seconds.
Level 2: 60 Shadow damage every 3 seconds.
Level 3: 80 Shadow damage every 3 seconds.
Cooldown: 15 Seconds.
-------

Well, i wanted to make it straight from vJass, and just use a dummy spell to cast it.

Here's the script:
Collapse JASS:
//---------------------------------------//
//         Corruption                    //
// Level 1 - 40 Damage every 3 Seconds.  //
// Level 2 - 60 Damage every 3 Seconds.  //
// Level 1 - 80 Damage every 3 Seconds.  //
//---------------------------------------//

scope Corruption
    
globals
    private constant integer AbiId = 'A001'
    private constant string SfxId1 = "Abilities\\Weapons\\BansheeMissile\\BansheeMissile.mdl"
endglobals

struct Cdata
    unit target
    unit caster
    real damage
    integer interval
endstruct

function Trig_Corruption_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == AbiId
endfunction

function Corruption_DoT takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local Cdata c = Cdata(GetHandleInt(t, "c"))
    local real dmg = c.damage
    local unit targ = c.target
    local unit caster = c.caster
    local integer interval = c.interval
    local texttag tt
    
     set tt = CreateTextTagUnitBJ("-"+I2S(R2I(dmg))+"!", targ, 0.0, 10.0, 0.0, 100.0, 0.0, 0.0)
     call SetTextTagPermanentBJ(tt, false)
     call SetTextTagVelocityBJ(tt, 35.0, 90.0)
     call SetTextTagFadepointBJ(tt, 1.5)
     call SetTextTagLifespanBJ(tt, 2.5)
     call UnitDamageTarget(caster, targ, dmg/2, false, true, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
     call DestroyEffect(AddSpecialEffect(SfxId1, GetUnitX(targ), GetUnitY(targ)))
     set c.interval = interval+1
     if IsUnitAliveBJ(targ) == false or interval == 3 then
      call c.destroy()
      call DestroyTimer(t)
     endif    
    
    set tt = null
    set targ = null
    set caster = null
    set t = null 
endfunction

function Trig_Corruption_Actions takes nothing returns nothing
    local unit caster = GetTriggerUnit()
    local unit target = GetSpellTargetUnit()
    local Cdata c = Cdata.create()
    local integer level = GetUnitAbilityLevel(caster, AbiId)
    local timer t = CreateTimer()
    local texttag tt
    
    if level == 1 then
      set c.damage = 40
    endif
    if level == 2 then
      set c.damage = 60
    endif 
    if level == 3 then
      set c.damage = 80
    endif 
    
    set tt = CreateTextTagUnitBJ("-"+I2S(R2I(c.damage))+"!", target, 0.0, 10.0, 0.0, 100.0, 0.0, 0.0)
    call SetTextTagPermanentBJ(tt, false)
    call SetTextTagVelocityBJ(tt, 35.0, 90.0)
    call SetTextTagFadepointBJ(tt, 1.5)
    call SetTextTagLifespanBJ(tt, 2.5)
    call UnitDamageTarget(caster, target, c.damage/2, false, true, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
    call DestroyEffect(AddSpecialEffect(SfxId1, GetUnitX(target), GetUnitY(target)))
    
    set c.interval = 1
    set c.caster = caster
    set c.target = target
    
      
    call SetHandleInt(t, "c", c)
    call TimerStart(t, 3.0, true, function Corruption_DoT)
    
    set t = null
    set caster = null
    set target = null
endfunction

//===========================================================================
function InitTrig_Corruption takes nothing returns nothing
    set gg_trg_Corruption = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Corruption, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Corruption, Condition( function Trig_Corruption_Conditions ) )
    call TriggerAddAction( gg_trg_Corruption, function Trig_Corruption_Actions )
endfunction

endscope

I'm not sure what i did, but before i did something, it was working quite fine...
But for some reason, Im not sure, it stopped working... I tried to test, but it wouldnt open warcraft 3, and if i manually opened Wc3, i couldnt enter the game... it would bring me back to the Game Selection screen...

Also, i know there are probably lots of things i should change, and if anyone could help me/show me the things to change that'd be great :)
If there is a way to make it more efficient, then perhaps someone can recode it, to show me a cleanr/better way? That'd be great also :D

So Thank you in Advance :D
11-08-2008, 11:28 PM#2
Zerzax
Well, I don't know if this will solve your problem but I can definitely help you optimize some aspects of your code. First off: in your action function you define what quantity of damage your spell will deal: you use

Collapse JASS:
    if level == 1 then
      set c.damage = 40
    endif
    if level == 2 then
      set c.damage = 60
    endif 
    if level == 3 then
      set c.damage = 80
    endif 
Instead you can try:
Collapse JASS:
    if level == 1 then
      set c.damage = 40
    elseif level == 2 then
      set c.damage = 60
    elseif level == 3 then
      set c.damage = 80
    endif 
Even better would be:
Collapse JASS:
    set c.damage= 20.00 + level * 20.00
which is only one line of code.

Next: You forgot to null tt in your action function, it will leak slightly.

You use BJ functions for your text tags, I believe you probably do not need them, only the natives they are based off of, because most BJ's are actually function wrappers that add useless function calls. In case that you do actually need to perform multiple actions (like about half of the BJ's do), then you can perform those actions without the use of a BJ by just following what the BJ does (TESH in the newer JNGP download can show you what each BJ does).

Most of your variables in your DoT timer callback are unnecessary. Values for dmg, caster, and target do not need to be set to variables because you can find them by simply referencing them as struct members (instead of caster variable just use c.caster, etc.)

So far I think thats it, I will continue to look at it. Very good though, I like it :D.

EDIT: setting a variable to c.interval is also unnecessary, use c.interval. It looks like your spell will end after three seconds though... I think you need to call c.destroy() when interval == 12, not 3.

Instead of using HandleVars, I would reccommend using Vexorian's TimerUtils, you can find it in the scripts section. TimerUtils stores data using an associative array without the use of gamecache, it is much faster, and now that you are using vJass it is the way to go.

EDIT 2: You do not need a "t" variable in your callback either it turns out, try using
Collapse JASS:
local Cdata c = Cdata(GetHandleInt(GetExpiredTimer(), "c"))
That way you don't need to null your "t" variable, which in extremely rare cases is said to cause a hideous bug in-game. Since you can't destroy "t" now without calling GetExpiredTimer(), try destroying "t" before you destroy c, and make "timer" a member of your struct. That way in your action you can set "c.timer" equal to your corruption timer, and call DestroyTimer(c.timer). I hope I'm not overloading you :P.

EDIT 3: I looked at what I just wrote and it seems confusing as hell. I'll write it out in code:

Collapse JASS:
struct Cdata
    unit target
    unit caster
    real damage
    integer interval
    timer damage_timer
endstruct

// In the action

    set c.damage_timer=CreateTimer()

// In the callback

    call PauseTimer(c.damage_timer) // In case you destroy a running timer, which causes bad things
    call DestroyTimer(c.damage_timer)  // This isn't the best way to do it, again I reccommend TimerUtils
11-09-2008, 12:46 AM#3
Tiku
[edit]: Nvm, i fixed it...

But i still wouldnt mind if someone would rewrite it, to make it better, and show me how it could be better :) Ty
11-09-2008, 01:00 AM#4
Zerzax
hmmm now I understand the timer thing, I guess since it procs once in the beginning the spell does damage 4 times but only lasts 9 seconds?

As for the loading, I'm not really sure though usually those problems arise because of faulty initialization.

I forgot to mention that you can use initializers in vJASS, and naming your init function InitTrig_.... is no longer necessary. It's better to delcare your scope as "scope Corruption initializer init" and rename your function at the bottom "init".

EDIT: I see your edit now, glad you fixed it. I forgot to mention a few variables that you don't need but I'm sure you can find em. So far the code looks fine, further optimizations would be minor.