• 🏆 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!

Projectile System (spell based)

Level 11
Joined
May 31, 2008
Messages
698
shoot stuff, triggered by casting a spell :D
should work on unit target, location target, and instant cast spells
includes speed, duration, damage, and aoe of projectile
It also changes the projectiles height based on the terrain height below it, so it actually moves straight and doesnt go up and down when going over cliffs or raised terrain. And the projectile will die if it hits a unit/doodad or the ground/cliff

just in regular jass, do i have to make it vjass to make it more efficient and stuff? cause i dont know how to do that lol..

JASS:
function Cond takes nothing returns boolean
        return GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0 and IsPlayerEnemy(GetOwningPlayer(GetFilterUnit()), GetOwningPlayer(udg_Caster)) == true
endfunction

function doodadcount takes nothing returns nothing
    if GetDestructableLife(GetEnumDestructable()) > 0 then
        set udg_doodadcount = udg_doodadcount + 1
    endif
endfunction

function dmg takes nothing returns nothing
    set udg_TargetZ = (GetUnitFlyHeight(GetEnumUnit()) + GetLocationZ(GetUnitLoc(GetEnumUnit())))
    if GetUnitState(GetEnumUnit(), UNIT_STATE_LIFE) > 0 and ((udg_MissileZ > udg_TargetZ) and (udg_MissileZ < (udg_TargetZ + 190))) then
        call UnitDamageTarget(udg_Caster, GetEnumUnit(), udg_damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
    endif
endfunction

function unitcount takes nothing returns nothing
    local location temploc
    set temploc = GetUnitLoc(GetEnumUnit())
    set udg_TargetZ = (GetUnitFlyHeight(GetEnumUnit()) + GetLocationZ(temploc))
    if GetUnitState(GetEnumUnit(), UNIT_STATE_LIFE) > 0 and ((udg_MissileZ > udg_TargetZ) and (udg_MissileZ < (udg_TargetZ + 190))) then
        set udg_unitcount = udg_unitcount + 1
        set udg_Target = GetEnumUnit()
    endif
    call RemoveLocation(temploc)
endfunction

function Projectile takes real speed, real duration, real damage, real aoe returns nothing
    local integer i = (GetPlayerId(GetOwningPlayer(GetEnumUnit())) + 1)
    local group units = CreateGroup()
    local real dist
    local real z
    local real z2
    local real x
    local real y
    local real x2
    local real y2
    local real x3
    local real y3
    local real x4
    local real y4
    local real x5
    local real y5
    local real dx
    local real dy
    local real missile_h //CHANGE
    local real facing = GetUnitFacing(GetEnumUnit())
    local location loca
    set udg_unitcount = 0
    set udg_doodadcount = 0
    set udg_damage = damage
    set x = GetUnitX(GetEnumUnit()) // loc3
    set y = GetUnitY(GetEnumUnit()) // loc3
    call MoveRectTo(udg_Rect1, x, y)
    call MoveRectTo(udg_Rect2, x, y)
    set x2 = x + speed * Cos(facing * bj_DEGTORAD) // loc6
    set y2 = y + speed * Sin(facing * bj_DEGTORAD) // loc6
    call MoveLocation(udg_LocZ, x2, y2)
    set loca = Location(x2, y2)
    set z = GetLocationZ(loca)
    call UnitApplyTimedLife(GetEnumUnit(), 'BTLF', duration)
    call SetUnitFlyHeight( GetEnumUnit(), (udg_InitialHeight[GetUnitUserData(GetEnumUnit())] - z), 0.00 )
    set udg_Caster = GetEnumUnit()
    set udg_TempLoc = GetUnitLoc(GetEnumUnit())
    set udg_MissileZ = GetUnitFlyHeight(GetEnumUnit()) + z
    set missile_h = GetUnitFlyHeight(GetEnumUnit()) //CHANGE
    set x3 = x + speed * Cos(facing * bj_DEGTORAD) // moveloc
    set y3 = y + speed * Sin(facing * bj_DEGTORAD) // moveloc
    set udg_MoveLoc = Location(x3, y3)
    call GroupEnumUnitsInRange(units, x, y, 75, Condition(function Cond)) // units
    call DestroyBoolExpr(Condition(function Cond))
    if missile_h < 290 then //CHANGE
        call EnumDestructablesInRect(udg_Rect1, null, function doodadcount)
    endif
    call ForGroup(units, function unitcount)
    call DestroyGroup(units)
    if ( (udg_doodadcount != 0) or (udg_unitcount != 0) ) then
        call UnitDamagePoint(udg_Hunter[i], 0, aoe, x, y, damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
        call KillUnit(GetEnumUnit())
        call GroupRemoveUnit(udg_ProjectileGroup, GetEnumUnit())
    endif
    if (GetUnitFlyHeight(GetEnumUnit()) <= 1) or (IsPointBlighted(x, y)) then
        set udg_damage = damage
        set units = CreateGroup()
        call GroupEnumUnitsInRange(units, x, y, aoe, null)
        call ForGroup(units, function dmg)
        call KillUnit(GetEnumUnit())
        call GroupRemoveUnit(udg_ProjectileGroup, GetEnumUnit())
        call DestroyGroup(units)
    endif
    call RemoveLocation(udg_TempLoc)
    call DestroyGroup(units)
    set udg_Caster = null
endfunction

function Temp takes nothing returns nothing
    if GetUnitTypeId(GetEnumUnit()) == 'XXXX' then // check which projectile is being picked
        call Projectile(20, 3, 50, 250) // (speed, duration, damage, area of effect)
    endif                       // max distance = duration * (speed * 33.33)
    call SetUnitPositionLoc(GetEnumUnit(), udg_MoveLoc) // NOTE: Projectile aoe will damage allied units, but projectiles will not explode on allied units
    call RemoveLocation(udg_MoveLoc)
endfunction

function Pick takes nothing returns nothing
    call ForGroup(udg_ProjectileGroup, function Temp)
endfunction

function Set2 takes integer abilityId, integer unitId, boolean two, real off, real h, boolean loccast, boolean targetcast, boolean instantcast returns nothing
    local unit u = GetTriggerUnit()
    local integer i = (GetPlayerId(GetOwningPlayer(GetTriggerUnit())) + 1)
    local real height
    local integer chance
    local unit u1
    local unit u2 = null
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real x2
    local real y2
    local real mana
    local real mana1
    local real mana2
    local location loc = GetUnitLoc(u)
    local location targetloc = GetSpellTargetLoc()
    local real locx = GetLocationX(targetloc)
    local real locy = GetLocationY(targetloc)
    local location targetunitloc = GetUnitLoc(GetSpellTargetUnit())
    local real unitx = GetLocationX(targetunitloc)
    local real unity = GetLocationY(targetunitloc)
    local unit target = GetSpellTargetUnit()
    local real angle
    local real offset
    if loccast == true then // if casted on a location
        set angle = bj_RADTODEG * Atan2(locy - y, locx - x)
    endif
    if target != null and targetcast == true then // if casted on a unit
        set angle = bj_RADTODEG * Atan2(unity - y, unitx - x)
    endif
    if instantcast == true then // if casted instantly (no target)
        set angle = GetUnitFacing(u)
    endif
    if GetSpellAbilityId() == abilityId then  //projectile 1
        set offset = off // how far to the left/right of the unit the projectile is created
        set x = GetUnitX(u) + offset * Cos((angle + 90) * bj_DEGTORAD) // for the first projectile launched
        set y = GetUnitY(u) + offset * Sin((angle + 90) * bj_DEGTORAD) // (this will be to the left of the caster if offset > 0)
        set x2 = GetUnitX(u) + offset * Cos((angle - 90) * bj_DEGTORAD) // for the second projectile launched
        set y2 = GetUnitY(u) + offset * Sin((angle - 90) * bj_DEGTORAD) // (this is optional, if you want to launch 2 projectiles, one on each side of the caster)
    endif
    if GetUnitState(u, UNIT_STATE_LIFE) > 0 then // creates projectiles if the caster is alive
        if ((GetSpellAbilityId() == abilityId))then // creates projectile 1
            set u1 = CreateUnit(Player(i - 1), unitId, x, y, angle)
            if two == true then
                set u2 = CreateUnit(Player(i - 1), unitId, x2, y2, angle) // put "//" in front of this line if you want only one projectile
            endif
            set height = h
        endif
        if two == true then
            call UnitAddAbility(u2, 'Arav')
            call SetUnitFlyHeight( u2, GetUnitFlyHeight(u) + height, 0.00 )
            call UnitRemoveAbility(u2, 'Arav')
            call SetUnitPosition(u2, x2, y2)
            call GroupAddUnit(udg_ProjectileGroup, u2)
            set udg_CustomValue = udg_CustomValue + 1
            call SetUnitUserData( u2, udg_CustomValue )
            set udg_InitialHeight[udg_CustomValue] = GetLocationZ(loc) + height + GetUnitFlyHeight(u)
        endif
        call UnitAddAbility(u1, 'Arav')
        call SetUnitFlyHeight( u1, GetUnitFlyHeight(u) + height, 0.00 )
        call UnitRemoveAbility(u1, 'Arav')
        call SetUnitPosition(u1, x, y)
        call GroupAddUnit(udg_ProjectileGroup, u1)
        set udg_CustomValue = udg_CustomValue + 1
        call SetUnitUserData( u1, udg_CustomValue )
        if udg_CustomValue >= 4950 then
            set udg_CustomValue = 0
        endif
        set udg_InitialHeight[udg_CustomValue] = GetLocationZ(loc) + height + GetUnitFlyHeight(u)
        call TimerStart(udg_Timer, .03, true, function Pick)
    endif
    set u1 = null
    set u2 = null
    set u = null
    call RemoveLocation(loc)
    set target = null
endfunction

function Set takes nothing returns nothing
    call Set2('A003', 'h000', false, 0, 140, false, false, true)
    // (Ability ID, Unit ID, Create Two Projectiles?, Offset Of Projectiles, Projectile Height, Location Cast?, Unit Cast?, Instant Cast?)
    // if you create 2 projectiles, make an offset.  Typical offset around 100
    // To launch one projectile from one side, make an offset. Positive offset = left side, negative offset = right side
endfunction

//===========================================================================
function InitTrig_ProjectileSystem takes nothing returns nothing
    set gg_trg_ProjectileSystem = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( gg_trg_ProjectileSystem, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction(gg_trg_ProjectileSystem, function Set)
endfunction


Edit:
Should this be in spells section?? if so could someone please move it?
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
Sigh..
udg_

That is why you only use vjass for JASS resources... this too

JASS:
//===========================================================================
function InitTrig_ProjectileSystem takes nothing returns nothing
    set gg_trg_ProjectileSystem = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( gg_trg_ProjectileSystem, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction(gg_trg_ProjectileSystem, function Set)
endfunction

Then ofc there are tons of problems..
JASS:
    local location loc = GetUnitLoc(u)
    local location targetloc = GetSpellTargetLoc()

etc...

there are already a couple of decent projectile systems, and they are assuredly better than this one =)


Here is another major no
call SetUnitUserData( u1, udg_CustomValue )

you never ever do that -.-. SetUnitUserData is off limits. Regard it as a syntax error, a big no no.


Yea, this system pretty much merits a total rewrite >.>, and ofc, it should be in vjass. Only thing acceptable not as vjass are like little tiny single functions ;D.

Yea, you don't even do group enum right
JASS:
    call GroupEnumUnitsInRange(units, x, y, 75, Condition(function Cond)) // units
    call DestroyBoolExpr(Condition(function Cond))
    if missile_h < 290 then //CHANGE
        call EnumDestructablesInRect(udg_Rect1, null, function doodadcount)
    endif
    call ForGroup(units, function unitcount)
    call DestroyGroup(units)

And really, there are much better ways than a group enum >.>.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Oh, for what you'd need to learn, it's rather simple.

You can use regular jass global blocks in vjass.
JASS:
globals
endglobals

so rather than the udg, you can just put your globals into the global blocks

JASS:
globals
    integer x //this is a global var
endglobals

here
http://www.hiveworkshop.com/forums/pastebin.php?id=s8dwa3
http://www.hiveworkshop.com/forums/pastebin.php?id=q0b0i9
http://www.hiveworkshop.com/forums/pastebin.php?id=kaxwrh

Read those chapters and you'll be almost good to go ; ).

Do you have newgen set up? If not, there is also a chapter on getting it up and running ;p.

And here is a unit indexer: http://www.hiveworkshop.com/forums/jass-functions-413/unit-indexer-172090/
 
Level 11
Joined
May 31, 2008
Messages
698
Yeah i have newgen
and okay thanks, i will take a look at that :D
but idk if it would be worth it to make this better and re-submit it, cause your right, theres already a better system by Berb lol
his has homing and arcs too, plus everything mine has, so recreating mine would be kind of pointless lol
 

sentrywiz

S

sentrywiz

Ah, jass. I don't know jass yet, so I can't comment on whether this will be good or not in what I plan to do with projectiles. Thanks for the offer though wolfman
 
Top