question about call UnitDamageTarget

cleeezzz

The Undead Ranger.
Reaction score
268
JASS:


what im wondering is,

1.) what does the first boolean do? it says boolean attack.
2.) second boolean? it says boolean ranged (what does this affect)
3.) and the last one, weapon type?, what does that affect? (Sound?) i just want it to do universal dmg without decrease in damage from armor.

(in other words, the equivalent to this)

Code:
Unit - Cause Unit to damage (Triggering unit), dealing 25.00 damage of attack type Chaos and damage type Universal

also

how would i check if a group is empty or not?

preferable in an if/then/else statement

heh. another question

JASS:
local group DU = GetUnitsInRangeOfLocMatching(4000.00, TP, )

im missing the condition, it says boolexpr filter, how do i do this? for example, the conditions, Unit is Alive, and Matching unit belongs to enemy of triggering player?
 

Kenny

Back for now.
Reaction score
202
1.) what does the first boolean do? it says boolean attack.

Im not entirely sure what is does, but i believe that it is not necessary for spells, so setting it to false would be ok. It might have something to do with AI.

2.) second boolean? it says boolean ranged (what does this affect)

I believe it affects how AI may read the damage dealt, as they may react differently to ranged attacks. For spells and such, normally both the attack and ranged booleans are left as false.

3.) and the last one, weapon type?, what does that affect? (Sound?) i just want it to do universal dmg without decrease in damage from armor.

Yes it just affects the sound, you may null it instead of WEAPON_TYPE_WHOKNOWS. If you want universal damage, just do what your doing, CHAOS and UNIVERSAL.

*EDIT*

how would i check if a group is empty or not?

JASS:
set <your local unit> = FirstOfGroup(<your group>)

if <your local unit> == null then
...
endif


Im pretty sure that would check to see if there are any units around.

im missing the condition, it says boolexpr filter, how do i do this? for example, the conditions, Unit is Alive, and Matching unit belongs to enemy of triggering player?

JASS:
Condition(function YourFilter)


You would put something like that in the boolexpr argument, and then make a function that checks for what units you want in the group.

This is taken from one of my spells:
JASS:
private function FilterEnemies takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(Caster)) and GetWidgetLife(GetFilterUnit())>0.405 and (IsUnitType(GetFilterUnit(),UNIT_TYPE_FLYING)==false)
endfunction


Caster in that filter is a global unit that has been get to GetTriggerUnit() in the Actions function.

*EDIT 2*

This may not be important to you at the moment, but instead of using GetUnitsInRangeOfLocMatching() you should get used to using GroupEnumUnitsInRange(). All that is needed for that is for you to create a group using CreateGroup(), then refer to it as an argument. Its not much different, but i believe it is more efficient.
 

PurgeandFire

zxcvmkgdfg
Reaction score
509
how would i check if a group is empty or not?

preferable in an if/then/else statement

heh. another question

JASS:
local group DU = GetUnitsInRangeOfLocMatching(4000.00, TP, )

im missing the condition, it says boolexpr filter, how do i do this? for example, the conditions, Unit is Alive, and Matching unit belongs to enemy of triggering player?

You can use this function:
JASS:
function IsUnitGroupEmptyBJ takes group g returns boolean
    // If the user wants the group destroyed, remember that fact and clear
    // the flag, in case it is used again in the callback.
    local boolean wantDestroy = bj_wantDestroyGroup
    set bj_wantDestroyGroup = false

    set bj_isUnitGroupEmptyResult = true
    call ForGroup(g, function IsUnitGroupEmptyBJEnum)

    // If the user wants the group destroyed, do so now.
    if (wantDestroy) then
        call DestroyGroup(g)
    endif
    return bj_isUnitGroupEmptyResult
endfunction


Returns true if it is empty and false if it isn't. But I haven't tested if this works. For a bit more shortening, you can also use this:
JASS:
function IsUnitGroupEmptyBJ takes group g returns boolean
    set bj_isUnitGroupEmptyResult = true
    call ForGroup(g, function IsUnitGroupEmptyBJEnum)
    return bj_isUnitGroupEmptyResult
endfunction


For the next question, first you would create a function for it:
JASS:
function Filter takes nothing returns boolean
    return GetWidgetLife(GetFilterUnit()) > 0 
//GetFilterUnit() returns the unit that you are grouping
endfunction


Then just use it like this:
JASS:
local group DU = GetUnitsInRangeOfLocMatching(4000.00, TP,Condition(function Filter))


It is similar to the "TriggerAddAction". No you don't need to destroy them because they are reused rather than created each time and it doesn't leak. ;)
 

cleeezzz

The Undead Ranger.
Reaction score
268
ok thanks,

JASS:
scope SA

struct SAData
    unit Caster
    real x
    real y
    real Angle
    unit Arrow
    real Offset
    real Offset_Max
    real Interval
    real Damage
    method onDestroy takes nothing returns nothing
        set .Arrow = null
    endmethod       
endstruct


private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A011'
endfunction     

private function Move takes nothing returns nothing
    local SAData data = GetCSData(GetExpiredTimer())
    local real px = data.x + data.Offset * Cos(data.Angle) 
    local real py = data.y + data.Offset * Sin(data.Angle)
    local location TP = GetUnitLoc(data.Arrow)
    local group DU = GetUnitsInRangeOfLocMatching( 25, TP, Condition(function Matching))
    if data.Offset <= data.Offset_Max then
        if IsUnitGroupEmptyBJ(DU) == true then 
            set data.Offset = data.Offset + data.Interval
            call ForGroup(DU, function Damage)
        endif
    else
        call RemoveUnit(data.Arrow)
        call ReleaseTimer(GetExpiredTimer())
        call data.destroy()             
    endif
endfunction

private function Matching takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(data.Caster)) and GetWidgetLife(GetFilterUnit()) > 0.405
endfunction   

private function Damage takes nothing returns nothing
    call UnitDamageTarget(data.Arrow, GetEnumUnit(), data.Damage, false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)  
endfunction  

 
    
private function Actions takes nothing returns nothing
    local location Cast_Point = GetSpellTargetLoc()      
    local real x2 = GetLocationX(Cast_Point)
    local real y2 = GetLocationY(Cast_Point)
    local timer t = NewTimer ()
    local SAData data = SAData.create()
    
    set data.Caster = GetTriggerUnit()    
    set data.x = GetUnitX(Caster)
    set data.y = GetUnitY(Caster)
    set data.Angle = Atan2(y2 - data.y, x2 - data.x)  
    set data.Offset = 0
    set data.Interval = 44
    set data.Offset_Max = (333.33 + ( 666.66 * GetUnitAbilityLevel(Caster, GetSpellAbilityId())))
    set data.Damage = (133.33 + ( 66.66 * GetUnitAbilityLevel(Caster, GetSpellAbilityId())))
    set data.Arrow = CreateUnit(GetOwningPlayer(Caster),'h00J', data.x, data.y, data.Angle)
    call SetUnitPathing( data.Arrow, false ) 
            
    call UnitApplyTimedLife(data.Arrow,'BTLF',20)
               
    call TimerStart( t, 0.04, true, function Move )
    call SetCSData(t, data)
    
    call RemoveLocation(Cast_Point)
    call RemoveLocation(Caster_Loc)
endfunction

//===========================================================================
public function InitTrig takes nothing returns nothing
    local trigger SA = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( SA, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( SA, Condition( function Conditions ) )
    call TriggerAddAction( SA, function Actions )
endfunction

endscope


in the functions Move and Matching, it says syntax with the data.Caster

which tells me the struct was never loaded in the function so it cannot be used.

how do i use the struct in those functions?

(man all this code just to make a unit Shockwave. T_T, dont ask "why not just use shockwave?" i want to be able to manipulate it, turn it and whatnot xd)
 

Kenny

Back for now.
Reaction score
202
In the Matching function: You cannot pass struct data into that function. So data.Caster will not be a valid argument. you must use a global unit. Something like this:

JASS:
globals
    private unit Caster = null
endglobals


Put that at the top, just above the struct or where-ever actually, it doesnt matter. then in your actions function, use:

JASS:
set Caster = data.Caster


underneath where you have set data.Caster = GetTriggerUnit()

*EDIT*

Also your Matching and Damage function need to be above the Move function, so move them. Actually while im here, there is not need for that damage function, you are just calling a single native, so just get rid of that and call that native within the Move function. Which brings me to something else, read my post above, right at the bottom, if you use groups the way i said, then that would allow you to use ForGroup loops, which makes group work a bit easier, as you do not have to pass struct info into different function.

Is this for Archer Wars by any chance? Cause my little brother was playing a game with you today :) just thought i'd let you know.

Actually looking through this thing, there is a bit move that may need to be done, i can't explain it right know because i got an exam tomorrow, but if i can ill get a working script up for you, but if not then hopefully someone else will help out.

*EDIT 2*

Your in luck :) i had this lying around and i decided to change it up a bit to suit what you needed, well i hope it is:

JASS:
scope SA initializer InitTrig

globals
    // Configurables:
    private constant integer Abil_id = 'A011'  // Your spells raw code 
    private constant integer Unit_id = 'h00J'  // Your dummy unit
    private constant real Period = 0.04        // Interval on the periodic timer
    private constant real Start_dist = 10.00   // Don't worry about this really, distance dummy unit starts away from the hero, i guess you would want this low
    private constant real Max_dist = 1800.00   // Max Distance obviously
    private constant real Move_dist = 12.50    // distance moved per interval
    private constant real Radius = 25.00       // Radius obviously
    private constant real Scale = 3.50         // Scale size of the arrow
    private constant real Fly_height = 65.00   // Fly height of the arrow
    private constant attacktype A_type = ATTACK_TYPE_CHAOS
    private constant damagetype D_type = DAMAGE_TYPE_UNIVERSAL
    // Needed Globals (DO NOT TOUCH):
    private unit Caster
    private real Game_MaxX                              // Needed to keep things in map
    private real Game_MinX                              // Needed to keep things in map
    private real Game_MaxY                              // Needed to keep things in map
    private real Game_MinY                              // Needed to keep things in map
endglobals

//=======================================================================
private function Damage takes integer lvl returns real
    return 70.00*lvl
endfunction

private function FilterEnemies takes nothing returns boolean
	return IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(Caster)) and GetWidgetLife(GetFilterUnit())>0.405 and (IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)==false) and GetUnitFlyHeight(GetFilterUnit())<150.00
endfunction  

//=======================================================================
private function Angle takes real x, real y, real xx, real yy returns real
    return Atan2((yy-y),(xx-x))*57.29583
endfunction

private function SafeX takes real x returns real
    if x<Game_MinX then
        return Game_MinX
    elseif x>Game_MaxX then   
        return Game_MaxX
    endif
    return x
endfunction

private function SafeY takes real y returns real
    if y<Game_MinY then
        return Game_MinY
    elseif y>Game_MaxY then 
        return Game_MaxY
    endif
    return y
endfunction

//=======================================================================
private struct Data
    timer t
    unit cast
    unit dummy
    real castx
    real casty
    real targx
    real targy
    real sin
    real cos
    real dist = Start_dist
    integer level
    group Group1 = CreateGroup()
    group Group2 = CreateGroup()
    
    static method create takes nothing returns Data
        local Data d = Data.allocate()
        local location targ = GetSpellTargetLoc()
        local real angle
        
        set d.cast = GetTriggerUnit()
        set d.castx = GetUnitX(d.cast)
        set d.casty = GetUnitY(d.cast)
        set d.targx = GetLocationX(targ)
        set d.targy = GetLocationY(targ)
        set angle = Angle(d.castx,d.casty,d.targx,d.targy)
        set d.sin = Sin(angle*bj_DEGTORAD)
        set d.cos = Cos(angle*bj_DEGTORAD)
        set d.level = GetUnitAbilityLevel(d.cast,Abil_id)
        set Caster = d.cast
        
        set d.dummy = CreateUnit(GetOwningPlayer(d.cast),Unit_id,d.castx+Start_dist*d.cos,d.casty+Start_dist*d.sin,0.00)
        call SetUnitFacing(d.dummy,angle)
        call SetUnitPathing(d.dummy,false)
        call SetUnitScale(d.dummy,Scale,Scale,Scale)
        call SetUnitFlyHeight(d.dummy,Fly_height,0.00)
        
        call RemoveLocation(targ)
        set targ = null
        return d
    endmethod
    
    private method onDestroy takes nothing returns nothing
        call KillUnit(.dummy)
        call GroupClear(.Group1)
        call DestroyGroup(.Group1)
        call ReleaseTimer(.t)
    endmethod
endstruct

//=======================================================================
private function Move takes nothing returns nothing
    local Data d = GetCSData(GetExpiredTimer())
    local unit u
    local real dumx = GetUnitX(d.dummy)
    local real dumy = GetUnitY(d.dummy)
    
    set d.dist = d.dist + Move_dist
    if d.dist >= Max_dist then
        call d.destroy()
        return
    endif
    
    set dumx = dumx+Move_dist*d.cos
    set dumy = dumy+Move_dist*d.sin
    
    call SetUnitX(d.dummy,SafeX(dumx))
    call SetUnitY(d.dummy,SafeY(dumy))
    call GroupClear(d.Group2)
    call GroupEnumUnitsInRange(d.Group2,SafeX(dumx),SafeY(dumy),Radius,Condition(function FilterEnemies))
    loop
        set u = FirstOfGroup(d.Group2)
        exitwhen u == null
        if not(IsUnitInGroup(u,d.Group1)) then
            call GroupAddUnit(d.Group1,u)
            call UnitDamageTarget(d.cast,u,Damage(d.level),false,false,A_type,D_type,null)
            call GroupRemoveUnit(d.Group2,u)
        endif
            call GroupRemoveUnit(d.Group2,u)
    endloop
endfunction
    
//=======================================================================
private function Actions takes nothing returns nothing
    local Data d = Data.create()
    
    set d.t = NewTimer()
    call TimerStart(d.t,Period,true,function Move)
    call SetCSData(d.t,d)
endfunction

//=======================================================================
private function Conditions takes nothing returns boolean
    return GetSpellAbilityId()== Abil_id
endfunction


//=======================================================================
private function InitTrig takes nothing returns nothing
    local trigger trig = CreateTrigger()
    
    set Game_MaxX = GetRectMaxX(bj_mapInitialPlayableArea)-50.00
    set Game_MinX = GetRectMinX(bj_mapInitialPlayableArea)+50.00
    set Game_MaxY = GetRectMaxY(bj_mapInitialPlayableArea)-50.00
    set Game_MinY = GetRectMinY(bj_mapInitialPlayableArea)+50.00
    
    call TriggerRegisterAnyUnitEvent(trig,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(trig,Condition(function Conditions))
    call TriggerAddAction(trig,function Actions)
endfunction

endscope

Um i did it in notepad so just tell me if something is wrong, and feel free to ask questions. So yeah do wot you want with it.
 

cleeezzz

The Undead Ranger.
Reaction score
268
haha yes its for Archer Wars (whats your bro's bnet name? i might recognize it haha) anyway, if you played it, theres a rank system based on kills and everyones telling me that they are too lazy to write down the save code because it litterally does nothing except give bragging rights. So, ive decided to switch from simple spells like shockwave/carrion swarm, and completely trigger the spell so i can manipulate almost everything xd. This is also the reason im learning vJASS, cuz an arrow movement system in GUI is just lame and hard.

hopefully, ill be able to add a character that is unlockable by ranks. (which will finally give a reason to save)



anyway back on topic

just for future reference
GetTriggerUnit = Triggering Unit
GetFilterUnit = matching unit
GetEnumUnit = is this Picked Unit? Whats Enum anyway lol

and about the order of the functions, Whats the 'rule' of structure?

scope at top
globals next
structs next
Functions called by the Callbacks? o_o
Callback functions
Conditions
Actions
TrigInit
endscope
?

ill try the GroupEnum thing you mentioned earlier.

EDIT: haha i was writing my post when you edited, reading now.
 

Kenny

Back for now.
Reaction score
202
I edited my above post with a code you may feel like using or learning off.

Enum is like random unit really, so yeah picked unit. lol

The script i posted shows how i like to 'structure' my spells, but that does not mean that everyone does it like that.

One thing though, functions that are called by other functions MUST be above the functions they are called in.
 

cleeezzz

The Undead Ranger.
Reaction score
268
haha im a little lost in reading it, but im slowly getting it.

just a question, if i want Distance to be based on ability level, i should remove it from globals and create a function like the Damage function?

man i still needa learn static, private, constant, i never know when to use it.

private constant is a variable that can only be accessed within the trigger? and it is a global that cannot be changed

no idea what static does.

still didn't tell me your bros bnet name xd
 

Kenny

Back for now.
Reaction score
202
just a question, if i want Distance to be based on ability level, i should remove it from globals and create a function like the Damage function?

Yes, so it would look like:

JASS:
private function MaxDist takes integer lvl returns real
    return 333.33+(666.66*lvl)
endfunction


then in the code you must find:

JASS:
if d.dist >= Max_dist then // Change Max_dist to MaxDist(d.level)
    call d.destroy()
    return
endif


man i still needa learn static, private, constant, i never know when to use it.

I still dont understand a lot of things.

private constant is a variable that can only be accessed within the trigger? and it is a global that cannot be changed


Yes, basically.

no idea what static does.

Me either :p.

Oh yeah and my bros gaming name is Ph4nt0m. (with the fullstop)
 

cleeezzz

The Undead Ranger.
Reaction score
268
lol.

just reading it for the 10th time and i understand 70% of it, getting there.

for the Angle function, would it be wise to make that function into a library so in future spells, they can all use Angle(x,xx,y,yy), cuz so far in all my other spells, that math is done in each trigger.

i dont really understand libraries either xd, ive just seen them used as separate functions that can be called by other triggers.

hmm was that on USeast?, my friend borrowed my cd key so i was forced to play on USeast for 1 game. i think i remember the name though xd, either he left or he died. forgot.

EDIT: yea definately remember the name, i think he was gray too. haha
 

Kenny

Back for now.
Reaction score
202
Yes it would be easier to put it into a library, in fact i made one with a whole bunch of functions that come in handy for a lot of different spells. I could give it to you if you want, theres no point in keeping it to myself.
 

cleeezzz

The Undead Ranger.
Reaction score
268
lol okay, hope it has polar projections too, those suck -_-

something like
x + offset * cos(Angle)
y + offset * sin(Angle)

edit: im sleeping after this post lol, thanks for your help (and fast replies) +rep
 

Kenny

Back for now.
Reaction score
202
It doesn't have offsets yet, cause i hardly use it. It has been in an old map for ages. It just has some handly functions that i use all to often, and its not too well detailed, but it helps.

JASS:
library HandyFunctions initializer Init

globals
    // CONFIGURABLES:
    private constant integer FlyTrick = 'Amrf'  // Raw code of Crow Form
    private constant integer Dummy_id = 'n000'  // Raw code of your maps dummy unit
    // DON'T NEED TO BE CHANGED:
    private timer gametime = null
    private rect Trees_in_rect = null
    private real Game_maxX
    private real Game_maxY
    private real Game_minX
    private real Game_minY
    private unit Caster
    private group Damage_group = CreateGroup()
endglobals

// Returns a safe X location, so units do not go outside map bounds
function SafeX takes real x returns real
    if (x<Game_minX) then
        return Game_minX
    elseif (x>Game_maxX) then
            return Game_maxX
    endif
    return(x)
endfunction

// Returns a safe Y location, so units do not go outside map bounds
function SafeY takes real y returns real
    if (y<Game_minY) then
        return Game_minY
    elseif (y>Game_maxY) then
            return Game_maxY
    endif
    return(y)
endfunction

// Creates a dummy caster needed for Preload (below)
function CreateCaster takes real x, real y returns unit
    set Caster = CreateUnit(Player(15),Dummy_id,x,y,0.00)       
    call UnitAddAbility(Caster,FlyTrick)
    call UnitRemoveAbility(Caster,FlyTrick)
    call UnitApplyTimedLife(Caster,'BTLF',5.00)
    return Caster
endfunction

// Preloads an ability, reduces lag
function PreLoadAbil takes integer abil returns nothing
    set Caster = CreateCaster(0.00,0.00)
    call UnitAddAbility(Caster,abil)
endfunction   

// Angle between co-ordinates
function AngleXY takes real x, real y, real xx, real yy returns real
    return Atan2((yy-y),(xx-x))*57.29583
endfunction

// Distance between co-ordinates
function DistanceXY takes real x1, real y1, real x2, real y2 returns real
        return SquareRoot((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2))
endfunction

// Used with below function
function KillEnumDestructable takes nothing returns nothing
        call KillDestructable(GetEnumDestructable())    
endfunction

// Kills trees/destructables
function KillTrees takes real x, real y, real radius returns nothing
        set Trees_in_rect = Rect(x-radius,y-radius,x+radius,y+radius)
        call EnumDestructablesInRect(Trees_in_rect,null,function KillEnumDestructable)
        call RemoveRect(Trees_in_rect)
endfunction

// Checks for pathability (very basic)
function Pathability takes real x, real y returns boolean
    return IsTerrainPathable(x,y, PATHING_TYPE_WALKABILITY)
endfunction

// Used with below function
function IsPointWater takes real x, real y returns boolean
        return IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) and not(IsTerrainPathable(x,y,PATHING_TYPE_AMPHIBIOUSPATHING))
endfunction

// Checks if point is water
function IsPointWaterLoc takes location loc returns boolean
        return IsPointWater(GetLocationX(loc),GetLocationY(loc))
endfunction

// filters for enemies, who are alive and are not structures
function FilterIsEnemy takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), bj_groupEnumOwningPlayer) and GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)>.405 and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)==false
endfunction 

// Damages an area, uses the above filter
function DamageArea takes unit Damager, real Area, real x, real y, real Dmg, attacktype Attacktype, damagetype Damagetype returns nothing
    local unit FoG
    
    set bj_groupEnumOwningPlayer = GetOwningPlayer(Damager)
    call GroupClear(Damage_group)
    call GroupEnumUnitsInRange(Damage_group, x, y, Area, Condition(function FilterIsEnemy)) 
                                                                                                  // Function that loops through the CreateGroup() 
    loop                                                                                          // and deals damage to each enemy in the area.                                                                                          //
        set FoG = FirstOfGroup(Damage_group)
        exitwhen FoG == null
        call GroupRemoveUnit(Damage_group,FoG)
        call UnitDamageTarget(Damager,FoG,Dmg,false,false,Attacktype,Damagetype,null)
    endloop
endfunction

// Adds Text tags over a unit
function TextTagUnit takes string text, unit targ, integer red, integer green, integer blue, integer alpha, real velocity, real duration returns nothing
    local texttag t = CreateTextTag()
                
    call SetTextTagText(t, text, 0.025)
    call SetTextTagPosUnit(t, targ,15)
    call SetTextTagColor(t, red, green, blue, alpha)
    call SetTextTagVelocity(t, 0, velocity)
    call SetTextTagVisibility(t, true)
    call SetTextTagFadepoint(t, 2)
    call SetTextTagLifespan(t, duration)
    call SetTextTagPermanent(t, false)
                
    set t = null
endfunction

// Better alternative to PolledWait()
function PolledWait2 takes real duration returns nothing
    local real timeRemaining
    local real st = TimerGetElapsed(gametime)
                
    if duration > 0. then
        loop
            set timeRemaining = duration - TimerGetElapsed(gametime) + st
            exitwhen timeRemaining <= 0
            if timeRemaining > 2.00 then
                call TriggerSleepAction(0.1 * timeRemaining)
            else
                call TriggerSleepAction(0.0)
            endif
        endloop
    endif
endfunction

// Replicates a sim error
function SimError takes player ForPlayer, string msg returns nothing
    local sound error = CreateSoundFromLabel("InterfaceError",false,false,false,10,10)
    
    if (GetLocalPlayer() == ForPlayer) then
        call ClearTextMessages()
        call DisplayTimedTextToPlayer(ForPlayer,0.52,-1.00,2.00,"|cffffcc00"+msg+"|r")
        call StartSound(error)
    endif
    
    call KillSoundWhenDone(error)
    set error=null
endfunction

// Starts the game timer, and sets boundaries
private function Init takes nothing returns nothing
    set gametime = CreateTimer()
    call TimerStart(gametime,1000000.00,false,null)
    set Game_maxX = GetRectMaxX(bj_mapInitialPlayableArea)-50.00
    set Game_maxY = GetRectMaxY(bj_mapInitialPlayableArea)-50.00
    set Game_minX = GetRectMinX(bj_mapInitialPlayableArea)+50.00
    set Game_minY = GetRectMinY(bj_mapInitialPlayableArea)+50.00
endfunction

endlibrary

Hope it helps.
 

PurgeandFire

zxcvmkgdfg
Reaction score
509
haha im a little lost in reading it, but im slowly getting it.

just a question, if i want Distance to be based on ability level, i should remove it from globals and create a function like the Damage function?

man i still needa learn static, private, constant, i never know when to use it.

private constant is a variable that can only be accessed within the trigger? and it is a global that cannot be changed

no idea what static does.

Static = For methods, it means that it doesn't use an instance. So basically, you can't refer to the struct members just using ".memberName". You have to use something like this:
JASS:
    local Data D = Data.allocate()


Read the manual for more about static members.

Private = Only accessible within the scope. So if you have something out of the scope or library, you can't refer to the private member within the scope or library.

Constant = Something that doesn't change in the code on execution.
 

cleeezzz

The Undead Ranger.
Reaction score
268
alright, i can add offset myself, and thanks for the explanation, but im confused why a person would choose to make it static? it just makes you type the data.<name>
 

cleeezzz

The Undead Ranger.
Reaction score
268
ok so its necessary, ill keep that in mind.

also, i noticed kenny used scope SA initializer InitTrig

it was also something thedamien mentioned i should do, so i tried it on other spells but they all gave me syntax errors. except the SA lol.

it says

Undeclared function Spread_InitTrig

JASS:
scope Spread initializer InitTrig

private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == &#039;A00D&#039; or GetSpellAbilityId() == &#039;A006&#039;
endfunction

private function Actions takes nothing returns nothing
    local unit Caster = GetTriggerUnit()
    local location Cast_Point = GetSpellTargetLoc()
    local real x = GetUnitX(Caster)
    local real y = GetUnitY(Caster)
    local real x1 = GetLocationX(Cast_Point)
    local real y1 = GetLocationY(Cast_Point)
    local real Angle = Atan2(y1 - y, x1 - x)
    local real px1 = x1 + 400 * Cos(Angle + 0.34906)
    local real py1 = y1 + 400 * Sin(Angle + 0.34906)
    local real px2 = x1 + 400 * Cos(Angle - 0.34906)
    local real py2 = y1 + 400 * Sin(Angle - 0.34906)
    local unit Dummy = CreateUnit(GetOwningPlayer(Caster), &#039;h001&#039;, x, y, 0)
    call UnitApplyTimedLife(Dummy, &#039;BTLF&#039;, 4.00 )
    call SetUnitAbilityLevel(Dummy, &#039;A009&#039;, GetUnitAbilityLevel(Caster, GetSpellAbilityId()) )
    call IssuePointOrder(Dummy, &quot;breathoffrost&quot;, px1, py1)
    call IssuePointOrder(Dummy, &quot;breathoffrost&quot;, px2, py2)
    call RemoveLocation(Cast_Point)
    set Caster = null
    set Cast_Point = null
    set Dummy = null
endfunction

//===========================================================================
public function InitTrig takes nothing returns nothing
    local trigger trig = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( trig, Condition( function Conditions ) )
    call TriggerAddAction( trig, function Actions )
endfunction

endscope
 

cleeezzz

The Undead Ranger.
Reaction score
268
oh thanks

hmm i configured it a bit and the first time testing, the arrow doesn't move..

JASS:
scope SA initializer InitTrig

globals
    // Configurables:
    private constant integer Abil_id = &#039;A011&#039;  // Your spells raw code
    private constant integer Unit_id = &#039;h00J&#039;  // Your dummy unit
    private constant real Period = 0.04        // Interval on the periodic timer
    private constant real Start_dist = 10.00   // Don&#039;t worry about this really, distance dummy unit starts away from the hero, i guess you would want this low
    private constant real Radius = 25.00       // Radius obviously
    private constant real Scale = 1            // Scale size of the arrow
    private constant real Fly_height = 60.00   // Fly height of the arrow
    private constant attacktype A_type = ATTACK_TYPE_CHAOS
    private constant damagetype D_type = DAMAGE_TYPE_UNIVERSAL
    private unit Caster
endglobals

//=======================================================================
private function Damage takes integer lvl returns real
    return 133.33+(66.66*lvl)
endfunction

private function Max_dist takes integer lvl returns real
    return 333.33+(666.66*lvl) 
endfunction

//=======================================================================
private struct Data
    timer t
    unit cast
    unit dummy
    real castx
    real casty
    real targx
    real targy
    real Move_dist
    real dist = Start_dist
    real angle
    integer level
    group Group1 = CreateGroup()
    group Group2 = CreateGroup()
   
    static method create takes nothing returns Data
        local Data d = Data.allocate()
        local location targ = GetSpellTargetLoc()
        local real angle
        set d.cast = GetTriggerUnit()
        set d.castx = GetUnitX(d.cast)
        set d.casty = GetUnitY(d.cast)
        set d.targx = GetLocationX(targ)
        set d.targy = GetLocationY(targ)
        set d.angle = AngleXY(d.castx,d.casty,d.targx,d.targy)
        set d.Move_dist = 44
        set d.level = GetUnitAbilityLevel(d.cast,Abil_id)
        set Caster = d.cast
       
        set d.dummy = CreateUnit(GetOwningPlayer(d.cast),Unit_id, PolarProjectionX (d.castx, Start_dist, d.angle), PolarProjectionY (d.casty, Start_dist, d.angle) , 0.00)
        call SetUnitFacing(d.dummy,angle)
        call SetUnitPathing(d.dummy,false)
        call SetUnitScale(d.dummy,Scale,Scale,Scale)
        call SetUnitFlyHeight(d.dummy,Fly_height,0.00)
       
        call RemoveLocation(targ)
        set targ = null
        return d
    endmethod
   
    private method onDestroy takes nothing returns nothing
        call KillUnit(.dummy)
        call GroupClear(.Group1)
        call DestroyGroup(.Group1)
        call ReleaseTimer(.t)
    endmethod
endstruct

//=======================================================================
private function Move takes nothing returns nothing
    local Data d = GetCSData(GetExpiredTimer())
    local unit u
    local real x = GetUnitX(d.dummy)
    local real y = GetUnitY(d.dummy)
   
    set d.dist = d.dist + d.Move_dist
    if d.dist &gt;= Max_dist(d.level) then
        call d.destroy()
        return
    endif
   
    set x = PolarProjectionX(x, d.Move_dist, d.angle)
    set y = PolarProjectionY(y, d.Move_dist, d.angle)
   
    call SetUnitX(d.dummy,SafeX(x))
    call SetUnitY(d.dummy,SafeY(y))
    call GroupClear(d.Group2)
    call GroupEnumUnitsInRange(d.Group2,SafeX(x),SafeY(y),Radius,Condition(function FilterIsEnemyAlive))
        loop
            set u = FirstOfGroup(d.Group2)
            exitwhen u == null
            if not(IsUnitInGroup(u,d.Group1)) then
                call GroupAddUnit(d.Group1,u)
                call UnitDamageTarget(d.cast,u,Damage(d.level),false,false,A_type,D_type,null)
                call GroupRemoveUnit(d.Group2,u)
            endif
                call GroupRemoveUnit(d.Group2,u)
        endloop
endfunction
   
//=======================================================================
private function Actions takes nothing returns nothing
    local Data d = Data.create()
   
    set d.t = NewTimer()
    call TimerStart(d.t,Period,true,function Move)
    call SetCSData(d.t,d)
endfunction

//=======================================================================
private function Conditions takes nothing returns boolean
    return GetSpellAbilityId()== Abil_id
endfunction


//=======================================================================
private function InitTrig takes nothing returns nothing
    local trigger trig = CreateTrigger()   
    call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(trig,Condition(function Conditions))
    call TriggerAddAction(trig,function Actions)
endfunction

endscope


JASS:
function PolarProjectionX takes real x, real distance, real angle returns real
    return x + distance * Cos(angle)
endfunction

function PolarProjectionY takes real y, real distance, real angle returns real
    return y + distance * Sin(angle)
endfunction


my polarprojection functions


JASS:
function FilterIsEnemyAlive takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), bj_groupEnumOwningPlayer) and GetWidgetLife(GetFilterUnit())&gt;0.405
endfunction


and the filter.

btw, i finally 100% understand your trigger, but i dont see the problem. seems like the timer isn't running?
 

Kenny

Back for now.
Reaction score
202
Im not 100% sure of the problem but you may want to use a custom Filter for the spell, as the one there refers to bj_groupEnumOwningPlayer which has not been specified in the spell.

If that filter is the one from my library thing, then it should only be used in the DamageArea function underneath.

Change bj_groupEnumOwningPlayer to GetOwningPlayer(Caster) and see how it goes. Otherwise, check to see if i attached the struct properly using CSData, because i have never used it before so i just took a guess.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top