Starting JASS

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Looks nice.
For preloading abilities, I suggest you to make a library which is specialized for preloading.
This can prevent too much of dummies being used to preload abilities.
 

Ayanami

칼리
Reaction score
288
Alright, now proceeding on using timers. So I decided to make a simple area knock back ability. Now the problem is, how do I actually add the units in a group and move them. I was told to use this method when handling groups, but this method only works when it isn't periodic, right? So, do I use ForGroup?
 

13lade619

is now a game developer :)
Reaction score
398
just make use of a timer system and a struct.

KeyTimers2 by Jesus4Lyf is good.

Make a struct with the caster and the group.
forward the struct to the callback function through the KT_Add() function.
retrieve the struct on the callback function.

EDIT: *easier.

grab a knockback system.
run through your unitgroup as usual,
use the knockback function on the individual units.
 

Ayanami

칼리
Reaction score
288
Hmm, although I roughly know what structs are, I didn't use them before, so It's quite confusing :/

You know in GUI action, there is a "Pick Every Unit UnitGroup and Do Actions" right? Is it inefficient to use that?
 

13lade619

is now a game developer :)
Reaction score
398
IIRC, there is no way to pass 'stuff' from one function to another.

*editing*

First, there were Global vars. But using them does not permit multi instanciability.

Then, Local Handle Vars were created. Primarily using the gamcache to 'store' stuff temporarily so that you can use them in another function.

What's used up to now is Timer-Struct attachment. Basically, you have a struct and pass it to a timer then you can retrieve the data you passed on the callback using the timer as reference.
 

Ayanami

칼리
Reaction score
288
Alright, finished the a simple area knockback using KeyTimers2. Didn't take deceleration into account yet, just need to check if the codes are okay. Here it is:

JASS:

library WarStomp initializer InitTrig

globals
    private constant integer ABIL_ID = 'ABMS'
    private constant integer DUMMY_ID = 'h001'
    private constant real AOE = 300.00
    private constant real DAMAGE = 200.00
    private constant real DISTANCE = 500.00
    private constant real TIME = 1.00
endglobals

globals
    private real x
    private real y
    private filterfunc ff
endglobals

private struct knockback
    real a
    real d
    real s
    unit u
endstruct

private function Periodic takes nothing returns boolean
    local knockback d = KT_GetData()
    if d.d <= 0 then
        call d.destroy()
        return true
    else
        set x = GetUnitX(d.u) + d.s * Cos(d.a * bj_DEGTORAD)
        set y = GetUnitY(d.u) + d.s * Sin(d.a * bj_DEGTORAD)
        call SetUnitPosition(d.u, x, y)
        set d.d = d.d - d.s
    endif
    return false
endfunction

private function Start takes unit caster, unit target, real dist, real time, real damage returns nothing
    local knockback d = knockback.create()
    local location cl = GetUnitLoc(caster)
    local location tl = GetUnitLoc(target)
    call UnitDamageTarget(caster, target, damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
    set d.d = dist
    set d.s = dist/time * 0.03
    set d.a = AngleBetweenPoints(cl, tl)
    set d.u = target
    call KT_Add(function Periodic, d, 0.03)
    call RemoveLocation(cl)
    call RemoveLocation(tl)
    set cl = null
    set tl = null
endfunction

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

private function Execute takes nothing returns boolean
    local unit c = GetTriggerUnit()
    local unit u = GetFilterUnit()
    if not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not IsUnitType(u, UNIT_TYPE_DEAD) and IsUnitEnemy(u, GetOwningPlayer(c)) then
        call Start(c, u, DISTANCE, TIME, DAMAGE)
    endif
    return false
endfunction

private function Actions takes nothing returns nothing
    call GroupEnumUnitsInRange(GROUP, GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), AOE, ff)
endfunction

//===========================================================================
private function InitTrig takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function Conditions))
    call TriggerAddAction(t, function Actions)
    set ff = Filter(function Execute)
endfunction

endlibrary
 

13lade619

is now a game developer :)
Reaction score
398
1 Scopes are better for spells generally

2

would be for simplicity
JASS:
 call GroupEnumUnitsInRange(GROUP, GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), AOE, Condition(function Execute))


3 Does triggering unit get passed to Execute? i dont recall since i dont use this method... i use the loop construct for groups generally.

4 Use real coordinates directly, not locations to avoid leak removal.

5 SetUnitPosition() interrupts orders though.
SetUnitX() and SetUnitY() would ignore pathing at first so you have to have extra checks.
 

Ayanami

칼리
Reaction score
288
3 Does triggering unit get passed to Execute? i dont recall since i dont use this method... i use the loop construct for groups generally.

Yup, it does.

4 Use real coordinates directly, not locations to avoid leak removal.

How would I work around doing AngleBetweenPoints check without using locations?

5 SetUnitPosition() interrupts orders though.
SetUnitX() and SetUnitY() would ignore pathing at first so you have to have extra checks.

So basically, use SetUnitX() and SetUnitY()?
 

hgkjfhfdsj

Active Member
Reaction score
55
How would I work around doing AngleBetweenPoints check without using locations?
JASS:
    //..
    set x = IsPathable(GetUnitX(d.u) + d.x) //some condition
    set y = IsPathable(GetUnitY(d.u) + d.y)//some condition
   
    call SetUnitX(d.u, d.x)
    call SetUnitY(d.u, d.y)
    // -----
    local real angle = Atan2(GetUnitY(target) - GetUnitY(caster), GetUnitX(target) - GetUnitX(caster)) //radian
    //can probably store calculated values since d.s & angle doesnt change
    set d.x = dist/time * 0.03 + Cos(angle)
    set d.y = dist/time * 0.03 + Sin(angle)


EDIT
+Post 81
TESH also comes with a function list
 

Bribe

vJass errors are legion
Reaction score
67
Crack open the good ol' blizzard.j file (a copy of it comes with JassHelper or JNGP, or you can use an MPQ extractor to grab it from the .mpq file). Inside of this "magical" file, you will find [ljass]AngleBetweenPoints[/ljass] to be a load of crap as that converts your locations to coordinates before doing any calculations.

Same with [ljass]PolarProjectionBJ[/ljass], [ljass]DistanceBetweenPoints[/ljass] and all the others. There are a lot of BJ functions that serve a purpose, but the majority of them are more or less useless :p
 

tooltiperror

Super Moderator
Reaction score
231
Or, you can just click on them in the (L)JASS tags and get brought to the wiki page and read the actions they call.
 

Ayanami

칼리
Reaction score
288
Just asking, how do I retrieve the damage source and the damaged unit when using J4L's Damage System?
 

Ayanami

칼리
Reaction score
288
Need help again. I have this trigger so far.

JASS:

scope ChargingStrikes initializer InitTrig

globals
    private constant integer ABIL_ID1 = 'ABCS' // raw code of Ability "Charging Strikes"
    private constant integer ABIL_ID2 = 'ACS1' // raw code of Ability "Charging Strikes (Attack Speed)"
    private constant real MINDMG = 23.00 // minimum damage dealt
    private constant real MAXDMG = 25.00 // maximum damage dealt
    private constant real TIME = 0.25 // time taken for charge
    private constant real AOE = 200.00 // area of effect of the damage
    private constant boolean STR = false // true if the hero's primary attribute is strength
    private constant boolean AGI = true // true if the hero's primary attribute is agility
    private constant boolean INT = false // true if the hero's primary attribute is intelligence
    // if all is set to false, damage dealt will be random number between MINDMG and MAXDMG
endglobals

private struct cs
    real offsetx
    real offsety
    real dist
    real speed
    unit u
endstruct

private function Slide takes nothing returns boolean
    local cs d = KT_GetData()
    local real x = GetUnitX(d.u) + d.offsetx
    local real y = GetUnitY(d.u) + d.offsety
    if d.dist <= 0 then
        call SetUnitPathing(d.u, true)
        call d.destroy()
        return true
    elseif not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) then
        call SetUnitPathing(d.u, false)
        call SetUnitX(d.u, x)
        call SetUnitY(d.u, y)
    endif
    set d.dist = d.dist - d.speed
    return false
endfunction

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

private function Actions takes nothing returns nothing
    local cs d = cs.create()
    local location t = GetSpellTargetLoc()
    local real dx = GetLocationX(t)
    local real dy = GetLocationY(t)
    local real angle
    local real x
    local real y
    set d.u = GetTriggerUnit()
    set x = GetUnitX(d.u)
    set y = GetUnitY(d.u)
    set angle = Atan2(dy - y, dx - x)
    set d.dist = SquareRoot(((x - dx) * (x - dx)) + ((y - dy) * (y - dy)))
    set d.speed = d.dist / TIME * 0.03
    set d.offsetx = d.speed * Cos(angle)
    set d.offsety = d.speed * Sin(angle)
    call KT_Add(function Slide, d, 0.03)
    call RemoveLocation(t)
    set t = null
endfunction

private function GetDamage takes unit caster returns real
    if STR then
        return GetRandomReal(MINDMG, MAXDMG) + I2R(GetHeroStr(caster, true)) 
    elseif AGI then
        return GetRandomReal(MINDMG, MAXDMG) + I2R(GetHeroAgi(caster, true)) 
    elseif INT then
        return GetRandomReal(MINDMG, MAXDMG) + I2R(GetHeroInt(caster, true)) 
    endif
    return GetRandomReal(MINDMG, MAXDMG)
endfunction

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

endscope


Now I'm having problems with the damaging part. This trigger is supposed to make the caster "slide" to the targeted point and dealing damage. However, I'm having trouble with dealing the damage as I need a method to check if the enemy has been already hit. Also, how would I deal damage without memory leaks?
 

13lade619

is now a game developer :)
Reaction score
398
I'm having trouble with dealing the damage as I need a method to check if the enemy has been already hit.
I find that using indexing systems (like AIDS, by J4L again) to perform simple integer or boolean checks for each unit works well.

like if [ljass]ChargingStrikesHit[target]==true[/ljass] or something.
 

Laiev

Hey Listen!!
Reaction score
188
instead [ljass]GetSpellTargetLoc()[/ljass] use [ljass]GetSpellTargetX()[/ljass] and [ljass]GetSpellTargetY()[/ljass] (i think is those natives)

EDIT:
JASS:
private function Actions takes nothing returns nothing
    local cs d = cs.create()
    local location t = GetSpellTargetLoc()
    local real dx = GetLocationX(t)
    local real dy = GetLocationY(t)
    local real angle
    local real x
    local real y
    set d.u = GetTriggerUnit()
    set x = GetUnitX(d.u)
    set y = GetUnitY(d.u)
    set angle = Atan2(dy - y, dx - x)
    set d.dist = SquareRoot(((x - dx) * (x - dx)) + ((y - dy) * (y - dy)))
    set d.speed = d.dist / TIME * 0.03
    set d.offsetx = d.speed * Cos(angle)
    set d.offsety = d.speed * Sin(angle)
    call KT_Add(function Slide, d, 0.03)
    call RemoveLocation(t)
    set t = null
endfunction

>>
JASS:
private function Actions takes nothing returns nothing
    local cs d = cs.create()
    local real dx = GetSpellTargetX()
    local real dy = GetSpellTargetY()
    local real x = GetUnitX(d.u)
    local real y = GetUnitY(d.u)
    local real = angle Atan2(dy - y, dx - x)

    set d.u = GetTriggerUnit()
    set d.dist = SquareRoot(((x - dx) * (x - dx)) + ((y - dy) * (y - dy)))
    set d.speed = d.dist / TIME * 0.03
    set d.offsetx = d.speed * Cos(angle)
    set d.offsety = d.speed * Sin(angle)

    call KT_Add(function Slide, d, 0.03)
endfunction
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Because it is static method, just like normal functions.
Can you put call BJDebugMsg(R2S(this)) in normal functions?
I think you know the answer..
Methods are actually
JASS:
static method my takes thistype this returns nothing
endmethod

That's why you can call the debug msg in methods.
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • WildTurkey WildTurkey:
    is there a stephen green in the house?
    +1
  • The Helper The Helper:
    What is up WildTurkey?
  • The Helper The Helper:
    Looks like Google fixed whatever mistake that made the recipes on the site go crazy and we are no longer trending towards a recipe site lol - I don't care though because it motivated me to spend alot of time on the site improving it and at least now the content people are looking at is not stupid and embarrassing like it was when I first got back into this like 5 years ago.
  • The Helper The Helper:
    Plus - I have a pretty bad ass recipe collection now! That section of the site is 10 thousand times better than it was before
  • The Helper The Helper:
    We now have a web designer at my job. A legit talented professional! I am going to get him to redesign the site theme. It is time.
  • Varine Varine:
    I got one more day of community service and then I'm free from this nonsense! I polished a cop car today for a funeral or something I guess
  • Varine Varine:
    They also were digging threw old shit at the sheriff's office and I tried to get them to give me the old electronic stuff, but they said no. They can't give it to people because they might use it to impersonate a cop or break into their network or some shit? idk but it was a shame to see them take a whole bunch of radios and shit to get shredded and landfilled
  • The Helper The Helper:
    whatever at least you are free
  • Monovertex Monovertex:
    How are you all? :D
    +1
  • Ghan Ghan:
    Howdy
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top