| 11-08-2008, 10:33 PM | #1 |
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: 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 |
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 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
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
JASS:
set c.damage= 20.00 + level * 20.00
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 JASS:local Cdata c = Cdata(GetHandleInt(GetExpiredTimer(), "c")) EDIT 3: I looked at what I just wrote and it seems confusing as hell. I'll write it out in code: 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 |
[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 |
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. |
