| 09-20-2007, 08:15 AM | #1 |
Ok so I finally figured out the local handle vars, they have been a blessing thus far. Ive been working on a spell called "Da Bomb", which is basically an exploding bomb nova. It works exactly as intended, except I can't think of a good way to check to see if the units that it is supposed to damage is an enemy. Here it is.. JASS:function DaBombCond takes nothing returns boolean local integer i = GetSpellAbilityId() return (i == 'A03T') or (i == 'A03V') or (i == 'A03W') or (i == 'A03X') or (i == 'A03Y') endfunction function DaBombEnemyCheck takes nothing returns boolean local unit u = GetFilterUnit() local player p = GetTriggerPlayer() if IsUnitEnemy(u, p) then set u = null set p = null return true endif set u = null set p = null return false endfunction function DaBombExplosions takes nothing returns nothing local timer t = GetExpiredTimer() local unit v local unit u = GetHandleUnit(t, "caster") local integer i = 1 local integer loops = GetHandleInt(t, "loops") local integer distance = GetHandleInt(t, "distance") local integer angle = GetHandleInt(t, "angle") local integer damage = GetHandleInt(t, "damage") local player p = GetOwningPlayer(u) local location l = GetUnitLoc(u) local group g = CreateGroup() loop exitwhen i > loops set l = PolarProjectionBJ(l, distance, angle * I2R(i)) call DestroyEffect(AddSpecialEffectLoc("Abilities\\Weapons\\FragDriller\\FragDriller.mdl" , l)) set g = GetUnitsInRangeOfLocMatching(90, l, Condition(function DaBombEnemyCheck)) loop set v = FirstOfGroup(g) exitwhen v == null call UnitDamageTarget(u, v, damage, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS) call GroupRemoveUnit(g, v) endloop set l = GetUnitLoc(u) set i = i + 1 endloop call FlushHandleLocals(t) call RemoveLocation(l) call DestroyGroup(g) call DestroyTimer(t) set t = null set v = null set u = null set p = null set l = null set g = null endfunction function StartExplosions takes unit caster, real timerstart, integer loops, integer distance, integer angle, integer damage returns nothing local timer t = CreateTimer() call TimerStart(t, timerstart, true, function DaBombExplosions) call SetHandleHandle(t, "caster", caster) call SetHandleInt(t, "loops", loops) call SetHandleInt(t, "distance", distance) call SetHandleInt(t, "angle", angle) call SetHandleInt(t, "damage", damage) set t = null endfunction function DaBomb takes nothing returns nothing local unit u = GetSpellAbilityUnit() local integer i = GetSpellAbilityId() local integer d if (i == 'A03T') then set d = 250 elseif (i == 'A03V') then set d = 650 elseif (i == 'A03W') then set d = 1950 elseif (i == 'A03X') then set d = 5750 elseif (i == 'A03Y') then set d = 17200 endif call StartExplosions(u, .15, 6, 110, 60, d) call StartExplosions(u, .30, 10, 220, 36, d) call StartExplosions(u, .45, 20, 330, 18, d) call StartExplosions(u, .60, 24, 440, 15, d) call StartExplosions(u, .75, 30, 550, 12, d) set u = null endfunction function InitTrig_BombDaBombCast takes nothing returns nothing set gg_trg_BombDaBombCast = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(gg_trg_BombDaBombCast, EVENT_PLAYER_UNIT_SPELL_CAST) call TriggerAddCondition(gg_trg_BombDaBombCast, Condition(function DaBombCond)) call TriggerAddAction(gg_trg_BombDaBombCast, function DaBomb) endfunction Everything works great and it's really fast. The problem is with the function "DaBombEnemyCheck" when creating the group to damage around the explosion. In it's current state, this trigger hurts player units. Obviously, using a timer would not take the triggering player with it. Since it's a function outside of the timer function, what would be a good method to check if the unit is an enemy? The simple problems are always the hardest for me... |
| 09-20-2007, 11:34 AM | #2 |
Well, one option would be to pick all units in range, without DaBombEnemyCheck, but instead put that check into the loop where you damage your units and only damage them if they're an enemy of p. |
| 09-20-2007, 02:28 PM | #3 |
Haha yeah I missed that last night, after I woke up the same answer came to me. After staring at this stuff for hours it sometimes starts to scramble my brain. |
| 09-20-2007, 03:28 PM | #4 |
That's well coded..... Just get rid of locations and start using coordinates Also, GetSpellAbilityUnit() is same as GetTriggerUnit() It's kinda weird seeing someone who actually clean leaks and use natives.....I haven't seen that for a long time :) Well, except location BJs, because locations can only be handled with those..... JASS:function DaBombCond takes nothing returns boolean local integer i = GetSpellAbilityId() return (i == 'A03T') or (i == 'A03V') or (i == 'A03W') or (i == 'A03X') or (i == 'A03Y') endfunction Omg I'm used to seeing: JASS:if ( not ( something ) ) then return false endif return true all the time.......it's very new to me seeing someone who can actually code well........ (I'm used to noobs) Well this was a useless post....... |
| 09-20-2007, 07:06 PM | #5 |
No no it makes me feel like I'm on the right track to this whole JASS jazz. And to think I just learned how to use handle vars like 2 days ago. But of course I couldn't have done anything like this without reading the 1000s of examples the past (God only knows) how many hours. Before I tried using all kinds of crazy methods to attempt to achieve something like this... let me tell ya didnt' work... Here's the final version in case anyone ever stumbles across the thread and wants to use it. Of course they would have to understand how to alter it. The downside is it uses 5 different abilities instead of 5 levels of an ability, for reasons I don't feel like explaining. But that wouldn't be too hard to alter anyway.... JASS:function BombDaBombCond takes nothing returns boolean local integer i = GetSpellAbilityId() return (i == 'A03T') or (i == 'A03V') or (i == 'A03W') or (i == 'A03X') or (i == 'A03Y') endfunction function DaBombExplosions takes nothing returns nothing local timer t = GetExpiredTimer() local unit v local unit u = GetHandleUnit(t, "caster") local integer i = 1 local integer loops = GetHandleInt(t, "loops") local integer distance = GetHandleInt(t, "distance") local integer angle = GetHandleInt(t, "angle") local integer damage = GetHandleInt(t, "damage") local player p = GetOwningPlayer(u) local location l = GetUnitLoc(u) local group g = CreateGroup() loop exitwhen i > loops set l = PolarProjectionBJ(l, distance, angle * I2R(i)) call DestroyEffect(AddSpecialEffectLoc("Abilities\\Weapons\\FragDriller\\FragDriller.mdl" , l)) set g = GetUnitsInRangeOfLocMatching(90, l, null) loop set v = FirstOfGroup(g) exitwhen v == null if IsUnitEnemy(v, p) then call UnitDamageTarget(u, v, damage, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS) endif call GroupRemoveUnit(g, v) endloop set l = GetUnitLoc(u) set i = i + 1 endloop call FlushHandleLocals(t) call RemoveLocation(l) call DestroyGroup(g) call PauseTimer(t) call DestroyTimer(t) set t = null set v = null set u = null set p = null set l = null set g = null endfunction function StartExplosions takes unit caster, real timerstart, integer loops, integer distance, integer angle, integer damage returns nothing local timer t = CreateTimer() call TimerStart(t, timerstart, true, function DaBombExplosions) call SetHandleHandle(t, "caster", caster) call SetHandleInt(t, "loops", loops) call SetHandleInt(t, "distance", distance) call SetHandleInt(t, "angle", angle) call SetHandleInt(t, "damage", damage) set t = null endfunction function BombDaBomb takes nothing returns nothing local unit u = GetSpellAbilityUnit() local integer i = GetSpellAbilityId() local integer d if (i == 'A03T') then set d = 250 elseif (i == 'A03V') then set d = 650 elseif (i == 'A03W') then set d = 1950 elseif (i == 'A03X') then set d = 5750 elseif (i == 'A03Y') then set d = 17200 endif call StartExplosions(u, .15, 6, 110, 60, d) call StartExplosions(u, .30, 10, 220, 36, d) call StartExplosions(u, .45, 20, 330, 18, d) call StartExplosions(u, .60, 24, 440, 15, d) call StartExplosions(u, .75, 30, 550, 12, d) set u = null endfunction function InitTrig_BombDaBombCast takes nothing returns nothing set gg_trg_BombDaBombCast = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(gg_trg_BombDaBombCast, EVENT_PLAYER_UNIT_SPELL_CAST) call TriggerAddCondition(gg_trg_BombDaBombCast, Condition(function BombDaBombCond)) call TriggerAddAction(gg_trg_BombDaBombCast, function BombDaBomb) endfunction |
| 09-20-2007, 07:20 PM | #6 | |
You are on the right track with JASS, you actually have a good piece of JASS knowledge, things will go pretty smooth from now on, the hardest part was starting to learn JASS and memory leaks. A little more practice, and you may go to vJass maybe...... EDTI1: Now I have to catch up with your edit :) JASS:function InitTrig_BombDaBombCast takes nothing returns nothing set gg_trg_BombDaBombCast = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(gg_trg_BombDaBombCast, EVENT_PLAYER_UNIT_SPELL_CAST) call TriggerAddCondition(gg_trg_BombDaBombCast, Condition(function BombDaBombCond)) call TriggerAddAction(gg_trg_BombDaBombCast, function BombDaBomb) endfunction Yeah! That's what I like to see, the removal of those ugly GUI-to-JASS spacings. Remember what I said? Quote:
That means that you should replace local unit u = GetSpellAbilityUnit() with local unit u = GetTriggerUnit() in BombDaBomb function. GetSpellAbilityUnit() should by all means be a BJ, but for some reason it's not.....but it's still slower than GetTriggerUnit, which is the fastest event response (you know there is casting unit, attacked unit, entering unit...... they can all be replaced with triggering unit, because that is the fastest). I can point you to a tutorial about coordinates, it's really not hard, it's very useful and efficient. When you learn them, you can completely avoid BJs :). Though there are useful BJs which are better to leave the way they are (like GroupAddGroup, CinematicModeBJ, CreateQuestBJ, those darn multiboard functions......) EDIT2: Omg you're even pausing the timer before destroying it......nice job! :) EDIT3: Found a leak! Well, I guess nobody is perfect...... JASS:loop exitwhen i > loops set l = PolarProjectionBJ(l, distance, angle * I2R(i)) call DestroyEffect(AddSpecialEffectLoc("Abilities\\Weapons\\FragDriller\\FragDriller.mdl" , l)) set g = GetUnitsInRangeOfLocMatching(90, l, null) loop set v = FirstOfGroup(g) exitwhen v == null if IsUnitEnemy(v, p) then call UnitDamageTarget(u, v, damage, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS) endif call GroupRemoveUnit(g, v) endloop set l = GetUnitLoc(u) set i = i + 1 endloop Put call RemoveLocation(l) before call PolarProjectionBJ(l, distance, angle * I2R(i)) If you were using coordinates, you wouldn't have to worry about leaks like that :) (because they don't leak) EDIT4: Also, when using integers in calculations with a real result, there is no need to I2R them, because that happens by itself. If it was other way around, then you would have to R2I it. Darn, to many edits :) |
| 09-20-2007, 08:41 PM | #7 |
Yeah i read if you dont pause a timer before you destroy it, it can cause some "mysterious, undesirable effects". I have a question on that leak.. I'll copy the part from where my concern starts to where it ends. JASS:
local location l = GetUnitLoc(u)
set l = PolarProjectionBJ(l, distance, angle * I2R(i))
You say to remove the location before the polarproject, but won't it be needed in the that function? If I remove the location, "l" doesn't exist anymore. Or does it now I'm confused on something, something that I should have gotten cleared up long ago. I do remove the location at the end of the function, but from what you are saying I'm assuming that every time you set a location pointer, you have to remove that particular one... I can't explain very well without an example. JASS://right?? local location l = GetUnitLoc(u) --Actions with l call RemoveLocation(l) set l = GetUnitLoc(v) --Actions with l call RemoveLocation(l) set l = GetUnitLoc(w) --Actions with l call RemoveLocation(l) //wrong?? local location l = GetUnitLoc(u) --Actions with l set l = GetUnitLoc(v) --Actions with l set l = GetUnitLoc(w) --Actions with l call RemoveLocation(l) I tried something similar to the "right" above in, as a matter of fact thats how I did it for the longest time, lots of RemoveLocations everytime I set it and I'm done with it. But then when I test the map in newgen editor I get error messages saying "Double free of location "l" in function XX". So I figured whoever designed the error checking knew what he was doing... now I'm confused all over again. Maybe I should just learn about coords now... |
| 09-20-2007, 09:00 PM | #8 |
Your assumption is right, as both of those functions creates a new location, so you have to destroy it both times. To make that using locations, you would have to use two locations, one with the intial point and one with the polar projection, and then destroy them both. The best solution would be to just use X and Y coordinates, and use cosine/sine instead of PolarProjection. It's faster and you don't have to mess with locations. |
