| 11-10-2006, 08:36 PM | #1 |
Here is the script: JASS:function EnergySphere_cond takes nothing returns boolean return GetSpellAbilityId()=='A000' endfunction function EnergySphere_Detonate_UnitFilter takes unit target, unit caster returns boolean if not ( IsUnitEnemy( target, GetOwningPlayer( caster ) ) ) then return false endif if IsUnitType( target, UNIT_TYPE_STRUCTURE ) or IsUnitType( target, UNIT_TYPE_MAGIC_IMMUNE ) or IsUnitType( target, UNIT_TYPE_DEAD ) then return false endif return true endfunction function EnergySphere_Detonate_Knockback_MoveTimer takes nothing returns nothing local timer move = GetExpiredTimer() local unit target = GetAttachedUnit( move, "unit" ) local unit caster = GetAttachedUnit( move, "caster" ) local real speed = GetAttachedReal( move, "speed" ) local real angle = GetAttachedReal( move, "angle" ) local integer index = GetAttachedInteger( move, "index" ) local real x1 = GetUnitX( target ) local real y1 = GetUnitY( target ) local real x2 = x1 + speed * Cos( angle * bj_DEGTORAD ) local real y2 = y1 + speed * Sin( angle * bj_DEGTORAD ) if not ( IsTerrainPathable( x2, y2, PATHING_TYPE_WALKABILITY ) or ( speed <= 0.2 ) ) then call MoveUnit( target, x2, y2, true ) if ModuloInteger( index, 20 ) == 0 then call DestroyEffect( AddSpecialEffect( "", x2, y2 ) ) endif set speed = speed - 0.6 call AttachReal( move, "speed", speed ) call AttachInteger( move, "index", index + 1 ) else call FlushObjectCache( move ) call PauseTimer( move ) call DestroyTimer( move ) endif set move = null set target = null set caster = null endfunction function EnergySphere_Detonate_Knockback takes unit target, unit caster, real sourceX, real sourceY returns nothing local timer move = CreateTimer() local real x = GetUnitX( target ) local real y = GetUnitY( target ) local location l = Location( x, y ) local location m = Location( sourceX, sourceY ) local real angle = Atan2( y - sourceY, x - sourceX ) * bj_RADTODEG local real dist = DistanceBetweenPoints( l, m ) local real speed = 28 - ( dist / 20 ) if ( speed > 30 ) then set speed = 30 endif call AttachObject( move, "unit", target ) call AttachObject( move, "caster", caster ) call AttachInteger( move, "index", 0 ) call AttachReal( move, "angle", angle ) call AttachReal( move, "speed", speed ) call TimerStart( move, 0.025, true, function EnergySphere_Detonate_Knockback_MoveTimer ) call RemoveLocation( l ) call RemoveLocation( m ) set l = null set m = null set move = null endfunction function EnergySphere_Detonate takes unit caster, unit sphere, real damage returns nothing local group units1 = CreateGroup() local group units2 = CreateGroup() local real x = GetUnitX( sphere ) local real y = GetUnitY( sphere ) local integer index = 0 local unit temp local unit detonation set detonation = CreateUnit( GetOwningPlayer( caster ), 'h001', x, y, GetUnitFacing( sphere ) ) call SetUnitX( detonation, x ) call SetUnitY( detonation, y ) call KillUnit( detonation ) call KillUnit( sphere ) call GroupEnumUnitsInRange( units1, x, y, 275, null ) //call PolledWait( 0.10 ) //I use the polled wait so that it will not screw up in BNet games; the problem here is that //if the polled wait IS used, then nothing past the call PolledWait(..) will work. loop set temp = FirstOfGroup( units1 ) exitwhen ( temp == null ) if EnergySphere_Detonate_UnitFilter( temp, caster ) then set index = index + 1 call GroupAddUnit( units2, temp ) endif call GroupRemoveUnit( units1, temp ) endloop call DestroyGroup( units1 ) loop set temp = FirstOfGroup( units2 ) exitwhen ( temp == null ) call UnitDamageTarget( caster, temp, ( damage / index ), false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_FORCE, WEAPON_TYPE_WHOKNOWS ) call EnergySphere_Detonate_Knockback( temp, caster, x, y ) call GroupRemoveUnit( units2, temp ) endloop call DestroyGroup( units2 ) set units1 = null set units2 = null set temp = null endfunction function EnergySphere_MoveTimer takes nothing returns nothing local timer move = GetExpiredTimer() local unit caster = GetAttachedUnit( move, "caster" ) local unit sphere = GetAttachedUnit( move, "sphere" ) local real random = GetAttachedReal( move, "random" ) local real counter = GetAttachedReal( move, "counter" ) local real angle = GetAttachedReal( move, "angle" ) local real damage = GetAttachedReal( move, "damage" ) local integer quit = GetAttachedInteger( move, "quit" ) local real stopTime = GetAttachedReal( move, "stopTime" ) local real endTime = counter / 40 local real x1 = GetUnitX( sphere ) local real y1 = GetUnitY( sphere ) local real x2 = x1 + 7 * Cos( angle * bj_DEGTORAD ) local real y2 = y1 + 7 * Sin( angle * bj_DEGTORAD ) if ( ( counter / 40 ) > ( random ) or IsTerrainPathable( x2, y2, PATHING_TYPE_WALKABILITY ) ) then if ( quit == 0 ) then set quit = 1 call AttachInteger( move, "quit", quit ) call AttachReal( move, "stopTime", endTime ) endif else call MoveUnit( sphere, x2, y2, true ) set counter = counter + 1.00 call AttachReal( move, "counter", counter ) endif if ( ( endTime - stopTime ) == 1.50 ) then call PauseTimer( move ) call FlushObjectCache( move ) call DestroyTimer( move ) call EnergySphere_Detonate( caster, sphere, damage ) endif set move = null set caster = null set sphere = null endfunction function EnergySphere_main takes nothing returns nothing local unit caster = GetTriggerUnit() local unit sphere local location target = GetSpellTargetLoc() local timer move = CreateTimer() local real x1 = GetUnitX( caster ) local real y1 = GetUnitY( caster ) local real x2 = GetLocationX( target ) local real y2 = GetLocationY( target ) local real angle = Atan2( y2 - y1, x2 - x1 ) * bj_RADTODEG local real x3 = x1 + 40 * Cos( angle * bj_DEGTORAD ) local real y3 = y1 + 40 * Sin( angle * bj_DEGTORAD ) local real counter = 0 local real random = GetRandomReal( 1, 2.5 ) local real cost = GetHeroInt( caster, true ) * 7 call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Spells\\Human\\ManaFlare\\ManaFlareMissile.mdl", caster, "hand,right" ) ) set sphere = CreateUnit( GetOwningPlayer( caster ), 'h002', x3, y3, angle ) call SetUnitX( sphere, x3 ) call SetUnitY( sphere, y3 ) call AttachObject( move, "caster", caster ) call AttachObject( move, "sphere", sphere ) call AttachReal( move, "random", random ) call AttachReal( move, "counter", counter ) call AttachReal( move, "angle", angle ) call AttachReal( move, "damage", cost ) call TimerStart( move, 0.025, true, function EnergySphere_MoveTimer ) call RemoveLocation( target ) set caster = null set sphere = null set target = null set move = null endfunction function InitTrig_EnergySphere takes nothing returns nothing local trigger spell = CreateTrigger() call TriggerRegisterAnyUnitEventBJ( spell, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( spell, Condition( function EnergySphere_cond ) ) call TriggerAddAction( spell, function EnergySphere_main ) endfunction |
| 11-10-2006, 08:39 PM | #2 |
I dont see what PolledWait is helping you do here, it does nothing to help small parts of code like yours, i would only use it to aviod op limit, and its inaccurate. And please use [jass] tags in future, it really makes your code easier to read. Code:
Jass tags:
[jass]CODE[/jass]
Example:
[jass]function Hi takes nothing returns nothing
call SomeFunc()
endfunction[/jass] |
| 11-10-2006, 08:41 PM | #3 |
Threads created from timer expirations (not from trigger events, though) break on waits. |
| 11-10-2006, 08:44 PM | #4 |
Okay, I changed it to for you, but I think this guy solved my problem already, thanks.. Though it really sucks =S :: edit :: Oh hold on, are you saying that if you create a thread FROM a timer expiration function, it will pause the thread created? or the timer? |
| 11-10-2006, 10:03 PM | #5 |
Functions that are called when a timer expires, and all the functions that are called from that function (and all functions called from those functions etc... all these functions are executed in one thread), will just die if they hit a wait action. Not sure how it works if you use ExecuteFunc(), though, since that creates a new thread, maybe functions in that thread can then call PolledWait(). |
| 11-10-2006, 10:48 PM | #6 |
I'm just wondering why this happens, shouldn't it just pause the whole thread for the given wait time? Not completely stop it? |
| 11-11-2006, 02:13 AM | #7 |
Use a trigger with a periodic event instead of the timer ... , make sure you don't EVER destroy the trigger before it and every single thread created by the trigger or by a thread created by the trigger ends, though. |
| 11-11-2006, 04:07 AM | #8 |
Wow, thanks this one helped me, I didn't know how to do knockback functions lol |
| 11-11-2006, 05:28 AM | #9 |
trigger is save to destroy if it stored in some array. just make 64off array with cyclic use and destroy trigger will be always safe. just becouse trigger leave pointer in this array. |
| 11-11-2006, 11:04 AM | #10 |
That is awful, he could just not set the trigger references to null... |
| 11-11-2006, 06:56 PM | #11 |
Actually what I did was (when I want the wait) I took all of my actions that I wanted happening after the wait and put them into a new function, then created a timer that would expire in my desired wait time; then it would call the function where all my new actions are... Just for the record, is PolledWait exactly the same as TriggerSleepAction except on BNet or something when somebody lags it will actually take heed of the lag; It uses a timer so I'm pretty sure that it does, but I wanted to clarify. |
| 11-11-2006, 07:06 PM | #12 |
JASS:function PolledWait takes real duration returns nothing local timer t local real timeRemaining if (duration > 0) then set t = CreateTimer() call TimerStart(t, duration, false, null) loop set timeRemaining = TimerGetRemaining(t) exitwhen timeRemaining <= 0 // If we have a bit of time left, skip past 10% of the remaining // duration instead of checking every interval, to minimize the // polling on long waits. if (timeRemaining > bj_POLLED_WAIT_SKIP_THRESHOLD) then call TriggerSleepAction(0.1 * timeRemaining) else call TriggerSleepAction(bj_POLLED_WAIT_INTERVAL) endif endloop call DestroyTimer(t) endif endfunction |
| 11-11-2006, 08:01 PM | #13 |
constant real bj_POLLED_WAIT_INTERVAL = 0.10 constant real bj_POLLED_WAIT_SKIP_THRESHOLD = 2.00 As well. |
| 11-11-2006, 08:17 PM | #14 |
Okay, well I know this is getting a little off-topic (but its still on the original theme of polls and waits); Isn't the smallest possible TriggerSleepAction and PolledWait value 0.27? I could have swarn it was. I know I could probably set up a timer to detect it but I think its easier to ask; so then also, my question was no answered fully, does PolledWait account for players lagging (and bringing up the lag screen, hence pausing the game) as well as being accurate? |
| 11-11-2006, 08:20 PM | #15 |
It accounts for it more. Tends to be 0.2-0.4 seconds too late, while TriggerSleepAction on it's own can vary wildly. TriggerSleepAction can get down to about 0.1, but it isn't accurate at all. |
