• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

Very laggy spell, with a few other problems...

Status
Not open for further replies.
Level 4
Joined
Jan 29, 2007
Messages
98
Hi!

I'm very new to this forum (Though have looked around at the various systems/scripts and models and stuff for a long time).

So I thought I'd search for some help here with my second vJASS spell (I've submitted my first on at thehelper.net).

So here it is:
JASS:
scope SearingDash initializer init

globals
    private constant integer ABIL_ID = 'A000' // The rawcode of the ability!
    private constant integer CARGO_ID = 'Abun' // The rawcode of the "Cargo Hold" ability!
    
    private constant string EFFECT_1 = "Environment\\LargeBuildingFire\\LargeBuildingFire2.mdl"
    private constant string ATTACH_POINT = "origin"
    private constant real PERIOD = .1 //Time between effects being created.
    private constant real DAMAGE_PERIOD = 0.03125 // How often the effects deal damage.
    private constant real EFFECT_DURATION = 1.5 // How long each effect lasts.
    
    private constant string DMG_EFFECT = "Abilities\\Spells\\Items\\AIfb\\AIfbSpecialArt.mdl"
    private constant string ATTACH_POINT2 = "chest"
    
    private constant real DURATION = 5. //How long the spell lasts
    
    private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL  // Explains itself i think XD
    private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL  // Same here :P
    private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS// And same here :D
    
    private constant real DMG_FACTOR = 1. // An easy way of changing the damage!
    private constant real RNG_FACTOR = 1. // An easy way of changing the damage range!
    
    private constant real TRANSPARENCY = 45. // In %, how transparent the caster becomes!
    private constant real SCALE = 1.65 // How much bigger the caster becomes when casting this spell. (Has to end with 0 or 5!)
    
    private constant boolean KNOCKBACK = true // Wether it should knockback units or not!
    private constant real DISTANCE = 200 // How far the get "knockbacked".
    private constant real SPEED = 1 // How long the knockback takes.
    
    private constant boolean EXTRA_MOVEMENT = false // If the caster should have movement-speed above 522.
    private constant real EXTRA_MOVE_SPEED = 7.5 // How far the caster is moves each PERIOD... Increased movement-speed above 522 !
    private constant real MOVE_SPEED = 522. // How fast the caster should move if EXTRA_MOVEMENT = false !
    private constant real MOVE_PERIOD = 0.03125
    
endglobals

globals
    private group g = CreateGroup()
    private group gr = CreateGroup()
    private integer TempStruct
    private filterfunc Filterz
    private real tick = 0
endglobals

private struct Data
    real speed
    real time = 1
    unit caster
    player owner
    integer lvl
    //Moving checksum
    real origX
    real origY
    real x
    real y
    real angle
    real scale = 1.
    boolean on
    
    static method create takes unit u returns Data
        local Data d = Data.allocate()
        set d.caster = u
        set d.owner = GetOwningPlayer(d.caster)
        set d.speed = GetUnitMoveSpeed(u)
        set d.lvl = GetUnitAbilityLevel(d.caster, ABIL_ID)
        return d
    endmethod
    
    method onDestroy takes nothing returns nothing
        if EXTRA_MOVEMENT == false then
            call SetUnitMoveSpeed(.caster, .speed)
        endif
        call SetUnitPathing(.caster,true)
        call SetUnitVertexColor(.caster,255,255,255,255)
        call SetPlayerAbilityAvailable(.owner, ABIL_ID, true)
        call UnitRemoveAbility(.caster, CARGO_ID)
        set .on = false
    endmethod
endstruct

private struct Dam
    unit caster
    player owner
    real x
    real y
    integer lv
    real tick
endstruct

private function Damage takes nothing returns real
    return I2R(Dam(TempStruct).lv) * DMG_FACTOR * 1.171875
endfunction

private function Range takes nothing returns real
    return RNG_FACTOR * 100.
endfunction

private function Range_Big takes nothing returns real
    return RNG_FACTOR *150.
endfunction

private function Filters takes nothing returns boolean
    return GetWidgetLife(GetFilterUnit()) > 0.405 and IsUnitEnemy(GetFilterUnit(), Dam(TempStruct).owner) and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false
endfunction

private function Filters_Enum takes nothing returns boolean
    return GetWidgetLife(GetEnumUnit()) > 0.405 and IsUnitEnemy(GetEnumUnit(), Dam(TempStruct).owner)
endfunction

private function Spell_Check takes nothing returns boolean
    return GetSpellAbilityId() == ABIL_ID
endfunction

private function Deal_Damage takes nothing returns nothing
    call UnitDamageTarget(Dam(TempStruct).caster, GetEnumUnit(), Damage(), true, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
    call DestroyEffect(AddSpecialEffectTarget(DMG_EFFECT, GetEnumUnit(), ATTACH_POINT2))
    call BJDebugMsg("Damage!")
endfunction

private function Damage_Period takes nothing returns boolean
    local Dam dd = KT_GetData()
    local boolean b
    if dd.tick > 0 then
        set TempStruct = dd
        call GroupEnumUnitsInRange(g, dd.x, dd.y, Range(),Filterz)
        if FirstOfGroup(g) != null then
            call ForGroup(g,function Deal_Damage)
            set dd.tick = dd.tick - DAMAGE_PERIOD
        endif
        set b = false
    else
        set b = true
        call dd.destroy()
    endif
    return b
endfunction

private function Descaling takes nothing returns boolean
    local Data d = KT_GetData()
    local boolean b
    if d.scale > 1. then
        set d.scale = d.scale - 0.05
        call SetUnitScale(d.caster, d.scale, d.scale, d.scale)
        set b = false
    else
        set b = true
    endif
    return b
endfunction

private function Scaling takes nothing returns boolean
    local Data d = KT_GetData()
    local boolean b
    if d.scale < SCALE then
        set d.scale = d.scale + 0.05
        call SetUnitScale(d.caster, d.scale, d.scale, d.scale)        
        set b = false
    else
        set b = true
    endif
    return b
endfunction

private function Movement takes nothing returns boolean
    local Data d = KT_GetData()
    local Dam dd = TempStruct
    local boolean b
    if d.on == true then
        set dd.caster = d.caster
        set dd.x = GetUnitX(d.caster)
        set dd.y = GetUnitY(d.caster)
        set d.angle = GetUnitFacing(d.caster)
        set d.x = d.origX - dd.x
        set d.y = d.origY - dd.y
        if (d.x * d.x + d.y * d.y) > 20. and EXTRA_MOVEMENT == true then
            set d.x = dd.x + EXTRA_MOVE_SPEED * Cos(d.angle * 0.0175)
            set d.y = dd.y + EXTRA_MOVE_SPEED * Sin(d.angle * 0.0175)
            call SetUnitX(d.caster,d.x)
            call SetUnitY(d.caster,d.y)
            set d.origX = d.x
            set d.origY = d.y
       endif
        set b = false
    else
        set b = true
    endif
    return b
endfunction

private function Knockback takes nothing returns nothing
    local unit u = GetEnumUnit()
    local real angle = 57.2958 * Atan2(GetUnitY(u) - GetUnitY(Data(TempStruct).caster), GetUnitX(u) - GetUnitX(Data(TempStruct).caster))
    if KBS_IsUnitSliding(u) == false and Filters_Enum() and (angle >= GetUnitFacing(Data(TempStruct).caster) + 25. or angle <= GetUnitFacing(Data(TempStruct).caster) - 25.) then
        call KBS_BeginCommon(u,DISTANCE,SPEED,angle)
    elseif angle >= GetUnitFacing(Data(TempStruct).caster) + 25. then
        set angle = angle + 25.
        call KBS_BeginCommon(u,DISTANCE,SPEED,angle)
    elseif angle <= GetUnitFacing(Data(TempStruct).caster) - 25. then
        set angle = angle - 25.
        call KBS_BeginCommon(u,DISTANCE,SPEED,angle)
    endif
endfunction

private function Periodic takes nothing returns boolean
    local Data d = KT_GetData()
    local Dam dd
    local boolean b
    if d.time <= DURATION - PERIOD then
        set d.time = d.time + PERIOD
        set dd = Dam.create()
        set dd.caster = d.caster
        set dd.owner = d.owner
        set dd.x = GetUnitX(d.caster)
        set dd.y = GetUnitY(d.caster)
        set dd.tick = R2I(EFFECT_DURATION / DAMAGE_PERIOD)
        call KT_Add(function Damage_Period, dd, DAMAGE_PERIOD)
        call TE_TimedEffect(AddSpecialEffect(EFFECT_1,dd.x,dd.y), EFFECT_DURATION)
        set d.angle = GetUnitFacing(d.caster)
        set TempStruct = d
        if KNOCKBACK == true then
            set TempStruct = d
            call GroupEnumUnitsInRange(gr, GetUnitX(d.caster), GetUnitY(d.caster), Range_Big(), Filterz)
            call ForGroup(gr, function Knockback)
            call GroupClear(gr)
        endif
        set b = false
    else
        call d.destroy()
        
        if SCALE != 1. then 
            call KT_Add(function Descaling, d, MOVE_PERIOD)
        endif
        set b = true
    endif
    return b
endfunction

private function Spell takes nothing returns nothing
    local Data D = Data.create(GetTriggerUnit())
    set D.on = true
    call SetUnitPathing(D.caster,false)
    call SetUnitVertexColor(D.caster,255,255,255,R2I(TRANSPARENCY * 2.55))
    call UnitAddAbility(D.caster, CARGO_ID)
    call SetPlayerAbilityAvailable(D.owner, ABIL_ID, false)
    if EXTRA_MOVEMENT == false then
        call SetUnitMoveSpeed(D.caster, MOVE_SPEED)
    else
        call KT_Add(function Movement,D, MOVE_PERIOD)
    endif
    call KT_Add(function Periodic, D, PERIOD)
    if SCALE != 1. then 
        call KT_Add(function Scaling, D, MOVE_PERIOD)
    endif
endfunction

private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t,Condition (function Spell_Check))
    call TriggerAddAction(t, function Spell)
    set Filterz = Filter(function Filters)
endfunction
endscope

And currently it's using 4, yes I said it, 4 different systems, which I really want to decrease to 2, maybe 3 :D

The systems used are:
BoundSentinel
Knockback System (KBS)
KeyTimers2

And my very own (But very small) snippet:

TimedEffect

JASS:
library TE requires KT

private struct SFX
    effect sfx

    method onDestroy takes nothing returns nothing
        call DestroyEffect(.sfx)
    endmethod
endstruct

private function Destroy takes nothing returns boolean
    call SFX(KT_GetData()).destroy()
    return true
endfunction

public function TimedEffect takes effect e, real duration returns nothing
    local SFX d = SFX.create()
    set d.sfx = e
    call KT_Add(function Destroy,d,duration)
endfunction

endlibrary

So, here are the problems with it:

To start with, it currently knockbackes all units which comes in range, but I'd like it to only knockback units which are infront of it, like +- 30-40 degrees of the caster facing.

Secondly, somehow the point where the fire-effects are created behind the caster seems to not get removed, because the effects that appear on the units that walk on the fires, seems to still recieve it when the fire is gone :(

And lastly, after some uses of this spell, it appears to start to build up handle leaks, any ideas ?

Thanks for the help !

I've also attached the map to the thread, so you can see for yourself if there are stuff that's still unclear for you :D
 

Attachments

  • Second Spell, by Komaqtion!.w3x
    56.3 KB · Views: 46
Last edited:
Level 8
Joined
Feb 15, 2009
Messages
463
for the units in +/- 30 angle try this function by Vexorian:
JASS:
function GroupAddUnitsInTriangle_AngleCheck takes real angle, real angle1, real angle2, real PI2 returns boolean
 local real x
    if (angle1>angle2) then
        set x=angle1
        set angle1=angle2
        set angle2=x
    endif
    if (angle2-angle1>angle1 - (angle2-PI2)) then
        set angle2=angle2-PI2
        if (angle < bj_PI) then
            set angle=angle-PI2
        endif
        return (angle>=angle2) and (angle<=angle1)
    endif
 return (angle>=angle1) and (angle<=angle2)
endfunction

function GetRectThatLimitsTriangle takes real x1, real y1, real x2, real y2, real x3, real y3 returns rect
 local real maxx
 local real minx
    if (x1>x2) then
        if (x2>x3) then     //x1>x2>x3
            set maxx=x1
            set minx=x3
        elseif (x3>x1) then //x3>x1>x2
            set maxx=x3
            set minx=x2
        else                //x3>x1>x2
            set maxx=x1
            set minx=x2
        endif
    elseif (x1>x3) then //x2>x1>x3
        set maxx=x2
        set minx=x3
    elseif (x3>x2) then //x3>x2>x1
        set maxx=x3
        set minx=x1
    else                //x2>x3>x1
        set maxx=x2
        set minx=x1
    endif

    if (y1>y2) then
        if (y2>y3) then     //y1>y2>y3
            return Rect(minx,y3,maxx,y1)
        elseif (y3>y1) then //y3>y1>y2
            return Rect(minx,y2,maxx,y3)
        else                //y3>y1>y2
            return Rect(minx,y2,maxx,y1)
        endif
    elseif (y1>y3) then //y2>y1>y3
        return Rect(minx,y3,maxx,y2)
    elseif (y3>y2) then //y3>y2>y1
        return Rect(minx,y1,maxx,y3)
    endif
 //y2>y3>y1
 return Rect(minx,y1,maxx,y2)
endfunction



function GroupAddUnitsInTriangle takes group whichGroup, real x1, real y1, real x2, real y2, real x3, real y3 returns nothing
 local rect semi=GetRectThatLimitsTriangle(x1,y1,x2,y2,x3,y3)
 local group inrect=CreateGroup()
 local unit picked
 local real x
 local real y
 local real alpha=Atan2(y2-y1,x2-x1)
 local real beta =Atan2(y3-y1,x3-x1)
 local real gama =Atan2(y1-y2,x1-x2)
 local real delta=Atan2(y3-y2,x3-x2)
 local real PI2=bj_PI+bj_PI

    call GroupEnumUnitsInRect( inrect, semi,null)
    loop
        set picked=FirstOfGroup(inrect)
        exitwhen picked==null
        set x=GetUnitX(picked)
        set y=GetUnitY(picked)
        if IsUnitInGroup(picked,whichGroup) then
        elseif (GroupAddUnitsInTriangle_AngleCheck(Atan2(y-y1,x-x1),alpha,beta,PI2) and GroupAddUnitsInTriangle_AngleCheck( Atan2(y-y2,x-x2) ,gama,delta,PI2)) then
            call GroupAddUnit( whichGroup, picked)
        endif
        call GroupRemoveUnit(inrect,picked)
    endloop
 call RemoveRect(semi)
 call DestroyGroup(inrect)
 set whichGroup=null
 set picked=null
 set semi=null
 set inrect=null
endfunction

just use polar projections(the center + distance * Cos/Sin(angle) for the xy2 and 3)

to question2
i didnt know what u mean seems fine for me but after 3rd cast it lagged too much=D

the thing for the leaks is the amount of effects u create i think and even destroyed and nulled efects leak a bit(posted this fact sometimes ago coz gexxo made a leaktest once) also the debugmessages mess up with me(so many!!)

i tested now something(removed the effect creation and debug messages):
now there are no more leaks test it urself i uploaded it

man this must be a lot of rep for me=D joke:spell_breaker::xxd:
 

Attachments

  • Second Spell, by Komaqtion!.w3x
    56.4 KB · Views: 39
Level 4
Joined
Jan 29, 2007
Messages
98
But now it doesn't seem to damage at all :(

And I'd really like people to see when they get damaged :S
But, then I might just add a buff to them that has an buff effect looking like fire, or something :D

You couldn't try to help me with the polar projection do you think ? :eek:

Anyways, thanks for the help :D And no lag at all now :D

EDIT: Just discovered something, this is probably why the damaging goes on, without the spell being on.
The debug msg in this function never appears :(

JASS:
private function Damage_Period takes nothing returns boolean
    local Dam dd = KT_GetData()
    local boolean b
    if dd.tick > 0 then
        set TempStruct = dd
        call GroupEnumUnitsInRange(g, dd.x, dd.y, Range(),Filterz)
        if FirstOfGroup(g) != null then
            call ForGroup(g,function Deal_Damage)
        //    set dd.tick = dd.tick - DAMAGE_PERIOD
        endif
        set dd.tick = dd.tick - DAMAGE_PERIOD
        set b = false
    else
        set b = true
        call dd.destroy()
        call BJDebugMsg("It's destroyed!")
    endif
    return b
endfunction
Which means that the struct "Dam" is never destroyed...

I also think that the answer might be in this function:

JASS:
private function Periodic takes nothing returns boolean
    local Data d = KT_GetData()
    local Dam dd
    local boolean b
    if d.time <= DURATION - PERIOD then
        set d.time = d.time + PERIOD
        set dd = Dam.create()
        set dd.caster = d.caster
        set dd.owner = d.owner
        set dd.x = GetUnitX(d.caster)
        set dd.y = GetUnitY(d.caster)
        set dd.tick = R2I(EFFECT_DURATION / DAMAGE_PERIOD)
        call KT_Add(function Damage_Period, dd, DAMAGE_PERIOD)
        call TE_TimedEffect(AddSpecialEffect(EFFECT_1,dd.x,dd.y), EFFECT_DURATION)
        set d.angle = GetUnitFacing(d.caster)
        set TempStruct = d
        if KNOCKBACK == true then
            set TempStruct = d
            call GroupEnumUnitsInRange(gr, GetUnitX(d.caster), GetUnitY(d.caster), Range_Big(), Filterz)
            call ForGroup(gr, function Knockback)
            call GroupClear(gr)
        endif
        set b = false
    else
        call d.destroy()
        
        if SCALE != 1. then 
            call KT_Add(function Descaling, d, MOVE_PERIOD)
        endif
        set b = true
    endif
    return b
endfunction

But I'm quite unsure, and can't see what the problem is myself XD
 
Last edited:
Level 8
Joined
Feb 15, 2009
Messages
463
i dont know keytimers and what that tick is but it seems too me that the thing is only true in the beginning --> in fact when it dd.tick is null,or is it going from
.... 8-->7-->....-->1-->0 ?? now i have seen that you substract it from dd.tick so it can be that -0.035 doesnt come to a total value only numbers with loads of decimal places

1.

change this
private constant real MOVE_PERIOD = 0.03125

to this

private constant real MOVE_PERIOD = 0.035


2. change the first if to:

dd.tick>=0.035

and the else to:

elseif dd.tick< 0.035


for the polars_:
JASS:
globals
    private constant real TRIANGLE_AOE_RANGE = 600.
    private constant real TRIANGLE_ANGLE_IMPROVE = 30.
//sorry for my namings cant find any better
endglobals

local real a = GetUnitFacing(caster)
local real x1 = GetUnitX(caster)
local real y1 = GetUnitY(caster)
local real x2 = x1 + TRIANGLE_AOE_RANGE * Cos( (a + TRIANGLE_ANGLE_IMPROVE)*bj_DEGTORAD )
local real y2 = y1 + TRIANGLE_AOE_RANGE * Sin( (a + TRIANGLE_ANGLE_IMPROVE)*bj_DEGTORAD )
local real x3 = x1 + TRIANGLE_AOE_RANGE * Cos( (a - TRIANGLE_ANGLE_IMPROVE)*bj_DEGTORAD )
local real y3 = y1 + TRIANGLE_AOE_RANGE * Sin( (a - TRIANGLE_ANGLE_IMPROVE)*bj_DEGTORAD )

for the effect: add a hidden aure(e.g. in a spellbook but not necessary just no button)
to hero while duration showing flames on enemies make the range of aura(AOE) just as the one when units are caught by GroupEnumUnitsInRange

thats it =D
 
Level 8
Joined
Feb 15, 2009
Messages
463
JASS:
private function Damage_Period takes nothing returns boolean
    local Dam dd = KT_GetData()
    local boolean b
    if dd.tick >= 0.035 then
        set TempStruct = dd
        call GroupEnumUnitsInRange(g, dd.x, dd.y, Range(),Filterz)
        if FirstOfGroup(g) != null then
            call ForGroup(g,function Deal_Damage)
        //    set dd.tick = dd.tick - DAMAGE_PERIOD
        endif
        set dd.tick = dd.tick - DAMAGE_PERIOD
        set b = false
    elseif dd.tick < 0.035 then
        set b = true
        call dd.destroy()
        call BJDebugMsg("It's destroyed!")
    endif
    return b
endfunction

should work u just forget the then =D
EDIT:eek:k u got it urself
for the damage im to lazy to view whole script but maybe not all members of the struct needed by deal dmg function are assigned

is the thing with polars now clear for you?
 
Status
Not open for further replies.
Top