HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

[vJass] Returning from a timer x-x.

10-02-2007, 03:22 AM#1
Blackroot
Ok, this is an issue I had in a previous post, and it seems it comes up alot in my style of jass.

The basic issue is, if you use one timer to loop through several instances of something (Say a spell), how do you know when your spell is done through the timer loop?

Sure you could make a struct, have a certain id attached to it, loop through with TriggerSleepAction until a boolean in your struct has been flagged, but that destroys the point of using a timer (Accuracy).

What I'd like to do is pause my calling trigger's thread (Only possible via TriggerSleepAction() is seems) and unpause the calling trigger's thread when I'm done. However, there's no such way to resume from a TriggerSleepAction, or to pause your trigger. So, I'm rather stuck. How do you create a callback for a timer using vJass?

I'm hopeless, I know . Thanks for any help.
10-02-2007, 03:24 AM#2
Pyrogasm
Use ExecuteFunc and temp globals, I'd say.
10-02-2007, 03:57 AM#3
Vexorian
Quote:
Originally Posted by Blackroot
Ok, this is an issue I had in a previous post, and it seems it comes up alot in my style of jass.

The basic issue is, if you use one timer to loop through several instances of something (Say a spell), how do you know when your spell is done through the timer loop?

Sure you could make a struct, have a certain id attached to it, loop through with TriggerSleepAction until a boolean in your struct has been flagged, but that destroys the point of using a timer (Accuracy).

What I'd like to do is pause my calling trigger's thread (Only possible via TriggerSleepAction() is seems) and unpause the calling trigger's thread when I'm done. However, there's no such way to resume from a TriggerSleepAction, or to pause your trigger. So, I'm rather stuck. How do you create a callback for a timer using vJass?

I'm hopeless, I know . Thanks for any help.
How about, you just don't wait in the other trigger but instead of having 2 things, have 3, initial part, timer, and final part.

Not too related to vJass..

Quote:
Use ExecuteFunc and temp globals, I'd say.
how would that help, at all?
10-02-2007, 06:15 AM#4
Blackroot
I can't have a final part, I'm using this for an API, it needs to return after finishing because I don't know what the user wants to be the 'final part'. The only alternative I've come up with is saving a trigger in my struct and executing it, but that'd mean switching between several triggers, which may not even be possible depending on the situation.

I really don't see much of a solution to this unfortunantly, I may have to revert to using handle vars -,-. Why coulden't blizzard have implemented just a few more natives damnit >.<.
10-02-2007, 07:09 AM#5
cohadar
You are simply doing something wrong....
I suggest you change your programming approach.
10-02-2007, 07:47 AM#6
Blackroot
Well I can't get around the issue that I need a timer, if I use trigger sleep action, it won't be accurate waiting periods, not to mention it's bad practice. (Not to mention is hard to mult-instance) The only way I can actualy use this is if I have a callback from a timer. The problem is using globals, I have absolutely no idea how I'd do this.

On another note, the only issue I have is that my timer is running and if I wait for it to stop, it's possible I'm going to wait to long (if several things are being processed, it wont end until all of them have been) Additionaly, and type of global structure or anything requires I continuously check to see if it's been updated. Basicaly, timers are the end of my thread with no possible way to exit out of them with accurate timing. Handle vars has the same problem, but you can attach a variable to a timer, so you end up with the ability to wait for the timer. Globals has no such nicety it seems.

(I just said the same thing twice didin't I?)

Maybe I'll do something incredibly stupid, that usualy works. *Starts making a polled wait loop, screw efficiency!* Or maybe TriggerWaitForSound would work if I used a null sound file.. Hmm? I could create a global callback id and send it to my function to begin it, and have my trigger wait for a null sound afterwards... Brilliant! I'll get on it. Haha, improvisation, blizzard always makes a way! God I hope this works...
10-02-2007, 10:26 AM#7
PitzerMike
Quote:
Originally Posted by Blackroot
I can't have a final part, I'm using this for an API, it needs to return after finishing because I don't know what the user wants to be the 'final part'.

That's why you have the user pass a callback function that gets called after finishing.
10-02-2007, 01:00 PM#8
grim001
What you are trying to do is not possible Blackroot, otherwise people would have already made an accurate wait function by now.
10-02-2007, 01:24 PM#9
Vexorian
Quote:
but you can attach a variable to a timer, so you end up with the ability to wait for the timer
That's not true, to wait for it you would have to use TriggerSleepAction anyways and that's pretty innacurate.
10-02-2007, 07:21 PM#10
Pyrogasm
I misunderstood what he needed, Vex. I thought he needed to iterate though N instances of a struct and then call a function each time that had a wait in it... but that he wanted the wait to happen simultaneously instead of having a wait before going to the next instance.
10-02-2007, 11:44 PM#11
Blackroot
Quote:
Originally Posted by PitzerMike
That's why you have the user pass a callback function that gets called after finishing.

If nothing else, that may be my only option.
10-03-2007, 04:08 AM#12
Blackroot
Well I give up. This was the only option I could use. Even if I passed a function to execute, It would wait for it to finish, and if I used ExecuteFunc i coulden't pass function arguments.

So, here's my surrenderence, blizzard.

Collapse JASS:
//! library cast
function CastString takes real r returns string
 local string e = ""
 local integer i = 0

 loop
  set e = e + "*"
  set r = r - .1
  exitwhen(r <= 0)
 endloop

 return e
endfunction

function BC_CancelledCast takes real x, real y returns nothing
 local texttag ct = CreateTextTag()

 call SetTextTagPermanent(ct, false)
 call SetTextTagPos(ct, x, y, BASE_TEXTTAG_SIZE)
 call SetTextTagLifespan(ct, 2.25)
 call SetTextTagVelocity(ct, 0, -.004)
 call SetTextTagText(ct, "|cFFFF0000Cancelled|r", BASE_TEXTTAG_SIZE)
 call SetTextTagVisibility(ct, true)
endfunction

struct Casting_Struct
 real x
 real y
 real time
 real spd
 real s_spd
 texttag tag
 integer return = 0
 unit u
 boolean cancell = false
 boolean this_tick = false
endstruct

globals
 Casting_Struct array BC_CS
 integer BC_Casting_Total = 0
 timer BC_Casting_Timer = CreateTimer()
endglobals

function BC_CancellCast takes nothing returns nothing
 local unit u = GetTriggerUnit()
 local integer I = GetUnitUserData(u)
 local trigger t = GetTriggeringTrigger()

 set BC_CS[i].cancell = true
 call ResetTrigger(t)
 call DestroyTrigger(t)
endfunction

function BC_F_Timer takes nothing returns nothing
 local integer i = 0
 local Casting_Struct cs

 loop
  exitwhen(i >= BC_Casting_Total)
  set cs = BC_CS[i]

  if(cs.this_tick == true)then
   set BC_Casting_Total = BC_Casting_Total - 1
   set BC_CS[i]  = BC_CS[BC_Casting_Total]
   call DestroyTextTag(cs.tag)
   set cs.tag = null
  elseif(cs.cancell == true)then
   call BC_CancelledCast(cs.x, cs.y)
   set cs.this_tick = true
  else
   set cs.spd = cs.spd - .05

   if(cs.spd <= 0.0)then
    set cs.time = cs.time - cs.s_spd
    set cs.spd = cs.s_spd

    if(cs.time <= cs.s_spd)then
     //********************************************FINISHED IF THIS IS TRUE
     set cs.this_tick = true
    else
     call SetTextTagText(cs.tag, "|cFF35FF35" + CastString(cs.time) + "|r", BASE_TEXTTAG_SIZE)
    endif

   endif

  endif
  set i = i + 1
 endloop

 if(BC_Casting_Total == 0)then
  call PauseTimer(BC_Casting_Timer)
 endif
endfunction

function BeginCast takes unit u, real time, real spd returns Casting_Struct
 local Casting_Struct cs
 local trigger t

 if(time < .25)then
  return -1
 endif

 call UnitAddType(u, UNIT_TYPE_PEON)
 call IssueImmediateOrder(u, "stop")

 set cs = Casting_Struct.create()
 set cs.x = GetUnitX(u) - (time * 7)
 set cs.y = GetUnitY(u)
 set cs.time = time
 set cs.spd = spd
 set cs.s_spd = spd
 set cs.u = u

 set cs.tag = CreateTextTag()
 call SetTextTagPos(cs.tag, cs.x, cs.y, BASE_TEXTTAG_SIZE)
 call SetTextTagPermanent(cs.tag, true)
 call SetTextTagText(cs.tag, "|cFF35FF35" + CastString(time) + "|r", BASE_TEXTTAG_SIZE)
 call SetTextTagVisibility(cs.tag, true)

 set t = CreateTrigger()
 call TriggerAddAction(t, function BC_CancellCast)
 call TriggerRegisterUnitEvent(t, u, EVENT_UNIT_ISSUED_TARGET_ORDER)
 call TriggerRegisterUnitEvent(t, u, EVENT_UNIT_ISSUED_POINT_ORDER)
 call SetUnitUserData(u, BC_Casting_Total)

 if(BC_Casting_Total == 0)then
  call TimerStart(BC_Casting_Timer, .05, true, function BC_F_Timer)
 endif

 set BC_CS[BC_Casting_Total] = cs
 set BC_Casting_Total = BC_Casting_Total + 1
 return cs
endfunction

function PolledWait2 takes real duration returns nothing
 local timer t = CreateTimer()
 local real remaining

 call TimerStart(t, duration, false, null)
 loop
  set remaining = TimerGetRemaining(t)
  exitwhen(remaining <= 0)
  if(remaining > .35)then
   call TriggerSleepAction(.1 * remaining)
  else
   call TriggerSleepAction(-1)
  endif
 endloop

 call PauseTimer(t)
 call DestroyTimer(t)
 set t = null
endfunction

function FinishCast takes real time, Casting_Struct cs returns integer I
 call PolledWait2(time - .2)
 loop
  if(cs.this_tick == true) and (cs.cancell == false)then
   call UnitRemoveType(cs.u, UNIT_TYPE_PEON)
   call IssueImmediateOrder(cs.u, "stop")
   call cs.destroy()
   return 1
  endif

  if(cs.cancell == true)then
   call UnitRemoveType(cs.u, UNIT_TYPE_PEON)
   call IssueImmediateOrder(cs.u, "stop")
   call cs.destroy()
   return 0
  endif
  call TriggerSleepAction(-1)
 endloop

  call UnitRemoveType(cs.u, UNIT_TYPE_PEON)
  call IssueImmediateOrder(cs.u, "stop")
  call cs.destroy()
 return 0
endfunction
//! endlibrary

It works to... There's always a way damnit, even if it's retarded! I just wish there was a better way, but I can't think of one that's plausable :(.

Well thanks for the help guys, but triggersleepaction appears to be the only choice. 3 cheers for polled wait though.
10-03-2007, 06:55 AM#13
Pyrogasm
Quote:
Originally Posted by Blackroot
function FinishCast takes real time, Casting_Struct cs returns integer I
How in god's name did you get that to compile?
10-03-2007, 07:11 AM#14
Blackroot
Lol... I think my compiler is on the fritz O_o. Fixed haha. Maybe I should upgrade from vJass 0.9.6.2 ;p.
10-03-2007, 12:42 PM#15
Here-b-Trollz
if you do something with custom vJass syntax (scope, struct, or pass a struct through a function), vJass changes the line, and, during that process, seems to eliminate any mistakes after the line:

Collapse JASS:
scope IT '
    private struct S `'
        code func ''
        unit it '
        method pork takes nothing returns nothing |
            call .func.execute() *
        endmethod `
    endstruct *

    function beef takes S s returns nothing N  
        call s.pork() '+ 
    endfunction //This is the only line that has to be good
endscope '''

That will compile, as far as I know...