• 🏆 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] Optomization for Starfall Spell

Status
Not open for further replies.
Level 13
Joined
Jul 26, 2008
Messages
1,009
I've been creating a starfall spell. So far it's graphically fine, but when it starts to damage targets there's a major issue with the innacurracy of the damage radius. The stars will land right on the enemy and won't hurt them. So other than general fine-tuning to fix this map, is there any way to make it so the area being damage is more accurate?

I'd assume it has to do with the D.x1 and y1 being set new before the damage occurs, though I have my doubts about that. Thanks.

JASS:
scope Starfall initializer InitTrig_Starfall

globals
    private constant integer SPELLID        = 'StFa'
    private constant real tick              = 0.6
endglobals

private struct Data extends xedamage

    unit c
    real x
    real y
    real x1
    real y1

    static method Star takes nothing returns nothing
     local xedamage d=xedamage.create()
     local group g = NewGroup()
     local timer tim = GetExpiredTimer()
     local Data D = Data(GetTimerData(tim))
     local integer lvl = GetUnitAbilityLevel(D.c, SPELLID)
     local real dam = lvl*10+15+SpellStat(D.c, true)*(0.4+0.1*lvl)
        call d.factor( UNIT_TYPE_STRUCTURE, 0.2 )
        call d.atype( ATTACK_TYPE_NORMAL )
        call d.dtype( DAMAGE_TYPE_MAGIC )
        call d.damageAOE(D.c, D.x1, D.y1, 32, dam)
        call ReleaseTimer(tim)
        call d.destroy()
        call D.destroy()
        call ReleaseGroup(g)
    endmethod

    static method Timer takes nothing returns nothing
     local xecast xc = xecast.createA()
     local timer tim = GetExpiredTimer()
     local timer tim1 = NewTimer()
     local Data D = Data(GetTimerData(tim))
     local integer lvl = GetUnitAbilityLevel(D.c, SPELLID)
     local real ang = GetRandomReal(0,360)*bj_DEGTORAD
     set D.x1 = D.x+GetRandomReal(50,400)*Cos(ang)
     set D.y1 = D.y+GetRandomReal(50,400)*Sin(ang)
        if GetUnitCurrentOrder(D.c) == OrderId("starfall") then
            call DestroyEffect(AddSpecialEffect(GetAbilityEffectById(SPELLID, EFFECT_TYPE_MISSILE, 0), D.x1, D.y1))
            call SetTimerData(tim1, D)
            call TimerStart(tim1, 0.15, false, function Data.Star)
        else
            set D.c = null
            call D.destroy()
            call ReleaseTimer(tim)
        endif
    endmethod

    static method create takes unit c, real x, real y, integer i returns Data
     local Data D = Data.allocate()
     local timer tim = NewTimer()
        set D.c = c
        set D.x = x
        set D.y = y
        call SetTimerData(tim,D)
        call TimerStart(tim, 0.3*i+GetRandomReal(0.1,-0.1), true, function Data.Timer)
     return D
    endmethod

endstruct

private function Conditions takes nothing returns boolean
 local integer i = 1
 local integer lvl = GetUnitAbilityLevel(GetTriggerUnit(), SPELLID)
    if GetSpellAbilityId() == SPELLID then
        loop
            call Data.create(GetTriggerUnit(), GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), i)
        exitwhen i > lvl*10+8
            set i = i + 1
        endloop
    endif
 return false
endfunction

//===========================================================================
public function InitTrig_Starfall takes nothing returns nothing
 local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_CHANNEL )
    call TriggerAddCondition( t, function Conditions )
 set t = null
 call XE_PreloadAbility(SPELLID)
endfunction

endscope
 
I'm not sure about the damage problem (I haven't looked into it), but here's some code suggestions.
  • Is there any reason your InitTrig is public and has an ugly name? InitTrig or onInit would look much better.
  • Your conditions function would be better off named Actions, while it's a conditions thread you are treating it as an actions.
  • Store GetUnitX(GetTriggerUnit()) in a local and reference it in the create method, this will save function calls.
  • Your indentation could use a bit of work (TAB key helps), though I'm not sure if the indentation was just messed up by the fourm.
  • I don't see the point of your group in the Star method.
  • All of your constant variables should be named IN_ALL_CAPS.
 
Level 13
Joined
Jul 26, 2008
Messages
1,009
A few of them are named their normal call name because when I disable it I don't want to get a message.

I usually don't worry about the conditions function. I never did understand if TriggerAddAction would cause problems instead of using TriggerAddCondition when I do it like this.

Will do with the x and y.

I have a personal indention method for local calls and cleanup calls. It's not very organized though. However it can help when reading my code for issues.

Group removed, was from when I was doing the damage via a GroupEnum call.

I do tick in undercase. Not sure why, should just do it in caps from now on.

Thanks :) Hopefully you can help me find the answer for my problem.
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
I would suggest that you make another struct like Star which does the actual damaging and is independent of Data.

It's still possible to do it with one struct only (especially because of the timer periods you're using) but I think it would be less confusing to do it in a different struct.

Some errors I saw in your code:

  • Destroying Data D in your Star method regardless of the spell's channeling being finished or not. This is most likely the problem.Didn't see that you created multiple Data D structs. I would have only tried to use one struct but then your spell might have a different look.
  • You don't need to extend xedamage.
  • Things you're not using yet:
    • xecast xc in Timer.
    • lvl in Timer
  • You probably should store lvl as a struct member.
  • You could use radians directly in ang. Just replace 360 with two*PI.
 
Status
Not open for further replies.
Top