HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Custom Launch Projectile problem (advanced Jass)

05-19-2006, 10:43 PM#1
The)TideHunter(
Ok im sorry for this, its confusing, i probly have 100 leaks and big mistakes, but i dont mind about the leaks just yet, its just the mistakes.

I get no compile errors, but nothings happening.
Please please could somebody point me in the right direction.
Iv split this up into 3 sections of code.

1) Basic stuff:

Collapse JASS:
// Globals (Only used for Jass Editing Programs)
globals
    gamecache udg_GC = null
endglobals

// Constants
constant function MoveProjectileSpeed takes nothing returns real
    return 0.04
endfunction

constant function DummyAbilityID takes nothing returns integer
    return 'nzin'
endfunction

constant function FlyAbilityID takes nothing returns integer
    return 'amrf'
endfunction

constant function MinRangeProjectileCollision takes nothing returns real
    return 25.
endfunction

constant function DistanceMovedPerInterval takes real speed returns real
    return speed / 1000
endfunction

// Game Cache Return
function GC takes nothing returns gamecache
    if(udg_GC == null) then
        call FlushGameCache(InitGameCache("GC"))
        set udg_GC = InitGameCache("GC")
    endif
    return udg_GC
endfunction

// Handle Variables
function H2I takes handle H returns integer
    return H
    return 0
endfunction

function I2Effect takes integer I returns effect
    return I
    return null
endfunction

function I2Unit takes integer I returns unit
    return I
    return null
endfunction

function I2AttackType takes integer I returns attacktype
    return I
    return null
endfunction

function I2DamageType takes integer I returns damagetype
    return I
    return null
endfunction

Then i have the midiumish type code, just to save some space and time:

Collapse JASS:
// Well Used Functions Helpers   
function SafeX takes real x returns boolean
    local rect r = bj_mapInitialPlayableArea
    local real maxX = GetRectMaxX(r)
    local real minX = GetRectMinX(r)
    if(x > maxX) then
        return false
    elseif(x < minX) then
        return false
    endif
    set r = null
    return true     
endfunction

function SafeY takes real y returns boolean
    local rect r = bj_mapInitialPlayableArea
    local real maxY = GetRectMaxY(r)
    local real minY = GetRectMinY(r)
    if(y > maxY) then
        return false
    elseif(y < minY) then
        return false
    endif
    set r = null
    return true
endfunction

function SafeLoc takes real x, real y returns boolean
    local boolean xUnsafe = true
    local boolean yUnsafe = true
    set xUnsafe = SafeX(x)
    set yUnsafe = SafeY(y)
    if(xUnsafe == false) and (yUnsafe == false) then
        return true
    endif
    return false
endfunction

function SafeLocEx takes location l returns boolean
    return SafeLoc(GetLocationX(l), GetLocationY(l))
endfunction

function MoveUnit takes unit whichUnit, real x, real y returns nothing
    if(SafeLoc(x, y) == true) then
        call SetUnitX(whichUnit, x)
        call SetUnitY(whichUnit, y)
    endif
endfunction

function ReturnEffectWithHeight takes string modelPath, real x, real y, real height returns effect
    local unit u = CreateUnit(Player(11), DummyAbilityID(), x, y, 0.)
    local effect e = AddSpecialEffectTarget(modelPath, u, "overhead")
    if(SafeLoc(x, y) == false) then
        call KillUnit(u)
        call DestroyEffect(e)
        set u = null
        set e = null
    else
        call UnitAddAbility(u, FlyAbilityID())
        call SetUnitFlyHeight(u, height, 0.)
        call StoreReal(GC(), I2S(H2I(e)), "EffectHeight", height)
        call StoreString(GC(), I2S(H2I(e)), "EffectModel", modelPath)
        call StoreInteger(GC(), I2S(H2I(e)), "EffectAttachedUnit", H2I(u))
        return e
    endif
    return null
endfunction

function CopyHeightEffectWithCoords takes effect e, real x, real y returns effect
    local effect sourceEffect = e
    local string sourceModel = GetStoredString(GC(), I2S(H2I(e)), "EffectModel")
    local real sourceHeight = GetStoredReal(GC(), I2S(H2I(e)), "EffectHeight")
    return ReturnEffectWithHeight(sourceModel, x, y, sourceHeight)
endfunction

function DestroyEffectEx takes effect e returns nothing
    local unit attachedUnit = I2Unit(GetStoredInteger(GC(), I2S(H2I(e)), "EffectAttachedUnit"))
    call FlushStoredMission(GC(), I2S(H2I(e)))
    call DestroyEffect(e)
    call KillUnit(attachedUnit)
    set attachedUnit = null
endfunction

function GetEffectLoc takes effect whichEffect returns location
    return GetUnitLoc(I2Unit(GetStoredInteger(GC(), I2S(H2I(whichEffect)), "EffectAttachedUnit")))
endfunction

function IsRealInBetween takes real whichReal, real min, real max returns boolean
    if(whichReal > max) then
        return false
    endif
    if(whichReal < min) then
        return false
    endif
    return true
endfunction

and then i have the main launch projectile functions, using a timer as a loop type function.

Collapse JASS:
function LaunchProjectile_Adult takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit targ = I2Unit(GetStoredInteger(GC(), I2S(H2I(t)), "LaunchProjectile_Target"))
    local unit credit = I2Unit(GetStoredInteger(GC(), I2S(H2I(t)), "LaunchProjectile_Credit"))
    local real targX = GetUnitX(targ)
    local real targY = GetUnitY(targ)
    local location targLoc = Location(targX, targY)
    local real newX
    local real newY
    local real speed = GetStoredInteger(GC(), I2S(H2I(t)), "LaunchProjectile_Speed")
    local effect oldEffect = I2Effect(GetStoredInteger(GC(), I2S(H2I(t)), "LaunchProjectile_Effect"))
    local effect newEffect
    local location effectLoc = GetEffectLoc(oldEffect)
    local real currentX = GetLocationX(effectLoc)
    local real currentY = GetLocationY(effectLoc)
    local real amount = GetStoredReal(GC(), I2S(H2I(t)), "LaunchProjectile_Damage")
    local attacktype attackType = I2AttackType(GetStoredInteger(GC(), I2S(H2I(t)), "LaunchProjectile_AttackType"))
    local damagetype damageType = I2DamageType(GetStoredInteger(GC(), I2S(H2I(t)), "LaunchProjectile_DamageType"))
    set newX = currentX + DistanceMovedPerInterval(speed) * Cos(AngleBetweenPoints(targLoc, effectLoc) * bj_DEGTORAD)
    set newY = currentY + DistanceMovedPerInterval(speed) * Sin(AngleBetweenPoints(targLoc, effectLoc) * bj_DEGTORAD)
    if(IsRealInBetween(newX, (targX + MinRangeProjectileCollision()), (targX - MinRangeProjectileCollision())) == true) and (IsRealInBetween(newY, (targY + MinRangeProjectileCollision()), (targY - MinRangeProjectileCollision())) == true) then
        call FlushStoredMission(GC(), I2S(H2I(t)))
        call UnitDamageTarget(credit, targ, amount, true, false, attackType, damageType, WEAPON_TYPE_WHOKNOWS)
        call DestroyEffect(newEffect)
        call DestroyTimer(t)
        set newEffect = null
        set t = null
        set attackType = null
        set damageType = null
    else
        set newEffect = CopyHeightEffectWithCoords(oldEffect, newX, newY)
        call StoreInteger(GC(), I2S(H2I(t)), "LaunchProjectile_Effect", H2I(newEffect))
        call TimerStart(t, MoveProjectileSpeed(), false, function LaunchProjectile_Adult)
    endif
    call DestroyEffectEx(oldEffect)
    call RemoveLocation(targLoc)
    call RemoveLocation(effectLoc)
    set targLoc = null
    set oldEffect = null
    set effectLoc = null   
endfunction

function LaunchProjectile_Child takes unit credit, unit target, real damage, real x, real y, real height, real speed, string modelPath, attacktype attackType, damagetype damageType returns nothing
    local timer t = CreateTimer()
    local effect e = ReturnEffectWithHeight(modelPath, x, y, height)
    call StoreInteger(GC(), I2S(H2I(t)), "LaunchProjectile_AttackType", H2I(attackType))
    call StoreInteger(GC(), I2S(H2I(t)), "LaunchProjectile_DamageType", H2I(damageType))
    call StoreInteger(GC(), I2S(H2I(t)), "LaunchProjectile_Credit", H2I(credit))
    call StoreInteger(GC(), I2S(H2I(t)), "LaunchProjectile_Target", H2I(target))
    call StoreReal(GC(), I2S(H2I(t)), "LaunchProjectile_Damage", damage)
    call StoreInteger(GC(), I2S(H2I(t)), "LaunchProjectile_Effect", H2I(e))
    call StoreReal(GC(), I2S(H2I(t)), "LaunchProjectile_Speed", speed)
    call TimerStart(t, MoveProjectileSpeed(), false, function LaunchProjectile_Adult) 
endfunction
05-19-2006, 11:15 PM#2
MysticGeneral
What exactly is this "Custom Launch Projectile" and what's it supposed to do? Can't help you if we don't know what you want to do.
05-19-2006, 11:24 PM#3
Naakaloh
Well, I have some criticisms to start. I'm not sure if they will help, but I'm mentioning them because I'm a little confused.

First, look at ReturnEffectWithHeight. If your effect with height is going to be an effect attached to a unit, why not simply create a single unit with an attached effect and move the unit instead of creating a bunch of units that get left over and you can't do anything about?

Second, also dealing with ReturnEffectWithHeight, it might just be me but it seems counterproductive to test for a safe location after creating the unit.

Another thing, just some notation things really, so it's up to you in the end, but usually the Parent function calls the Child function, you seem to have the order reversed. MoveProjectileSpeed probably should be called something like TimerDuration or TimerPeriod, it's a little confusing otherwise because one might thing that's the speed that the projectile's supposed to move instead of how often.

Anyway, interesting naming conventions aside, DistanceMovedPerInterval is the definition of speed, so to get the distance moved you want to multiply the speed by the period. That way, you don't have to worry about doing any other calculations.

It looks like you have the right idea, but I'm not sure about what's going on with IsRealBetween because for that method you'd need to check direction to know which way is the maximum and which way is minimum. Instead I'd suggest simply using the Pythagorean Theorem (Distance formula) and seeing if the distance between the projectile and the target is less than the collision radius.

That last thing I mentioned is the only problem that might be preventing your projectile from moving unless the value you used for speed is too small so the distance moved is too small to be noticed.

If your problem is completely different and you can't even get an effect to appear, it may have something to do with the effect your using or the event or condition of your trigger (assuming you're using a trigger).
05-19-2006, 11:42 PM#4
The)TideHunter(
@ MysticGeneral, Custom Launch function i created should have the same effect of the "attack" method, create a projectile that follows the unit until it hits it and when it does it damages it.

@ Naakaloh, Wow, thanks for the great reply , alot of feedback their.
I do have alot of things muddeled up, but its the first time iv gone that advanced, i just normally stick to abit of attaching handles to timers and thats about it.
I really couldent figure out a way of making the effect follow a unit, because if the unit moves, the projectile must change its course.
So i decided to use Polar offset.
I will change it in the morning, i have to sleep now.
Thanks for the infomation.

The function IsRealBetween is a lame function name, i couldent come up with a good 1, all it really does is checks if real whichReal is inbetween real min and real max, if it is return true else return false.

Sorry for the mix ups.
05-20-2006, 12:04 AM#5
Naakaloh
You're quite welcome. About IsRealBetween, I see what it's doing now, at first I thought you were checking it in a different way. I was suggesting just doing something like this so you don't have to check as many conditions:

Collapse JASS:
if( DistanceBetweenPoints( effectLoc, targLoc ) < CollisionRange() == true ) then
...
endif

As for getting an effect to follow a unit:

Collapse JASS:
native AddSpecialEffectTarget (string modelName, widget targetWidget, string attachPointName) returns effect 

In most cases you can just use attachPointName = "origin" and the effect will move with the unit.
05-20-2006, 07:12 AM#6
The)TideHunter(
Well, the reason i dident make the effect move with the unit is:

I started making my code, and was going to make a effect every 0.04 secs.
Then i realised i needed height for the effect, so i had to create a dummy unit and attach the effect.
By then i dident have the code sorted out for the "just make the unit move" solution.

I might just change the units speed and order him to move to position of targ.
Its probally easier.

Thanks again