HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

[vJass] System issues -,-

10-01-2007, 08:32 AM#1
Blackroot
Ok, first off I'd like to say this is my first time using purely vJass to handle passing between functions/timers ect. I read vex's tutorial on it, and I thought I understood, but I was mistaken!

This code I'm trying to make is simple, what I'm attempting (in psuedocode) is:

Get an x/y point
Create a texttag at that point
Update the texttag every (amount of time)
Make sure the unit that initiated the function hasn't been issued an order.

So! This is as far as I've gotten, but it doesn't work correctly. First off it skips over far faster then intended (Or it could be skipping it completely, it's to fast to really tell), second if I set cancelled to default true in my Casting_Struct, my game basicaly freezes.

Keep in mind this is all in the header, here you go:

Collapse JASS:
//Create the string
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

struct CancelledTag
 texttag t
 boolean destroythis = false
endstruct

globals
 CancelledTag array BC_CS_CT
 integer BC_CS_CT_Total = 0
 timer BC_CS_CT_Timer = CreateTimer()
endglobals

//loop to see if the cancelled cast text tag needs to be destroyed
function BC_CancelledCast_Finish takes nothing returns nothing
 local integer i = 0
 local CancelledTag ct

 loop
  exitwhen(i == BC_CS_CT_Total)
  set ct = BC_CS_CT[i]
  if(ct.destroythis == true)then
   call DestroyTextTag(ct.t)
   call ct.destroy()
   set BC_CS_CT_Total = BC_CS_CT_Total - 1
   set BC_CS_CT[i] = BC_CS_CT[BC_CS_CT_Total]
  else
   set ct.destroythis = true
  endif
  set i = i + 1
 endloop

 if(BC_CS_CT_Total == 0)then
  call PauseTimer(BC_CS_CT_Timer)
 endif
endfunction

//Triggered when a cast is cancelled
function BC_CancelledCast takes real x, real y returns nothing
 local CancelledTag ct = CancelledTag.create()

 call SetTextTagPos(ct.t, x, y, BASE_TEXTTAG_SIZE)
 call SetTextTagLifespan(ct.t, 1)
 call SetTextTagVelocity(ct.t, 0, -.004)
 call SetTextTagText(ct.t, "|cFFFF0000Cancelled|r", BASE_TEXTTAG_SIZE)
 call SetTextTagVisibility(ct.t, true)

 if(BC_CS_CT_Total == 0)then
  call TimerStart(BC_CS_CT_Timer, .50, true, function BC_CancelledCast_Finish)
 endif
 set BC_CS_CT[BC_CS_CT_Total] = ct
 set BC_CS_CT_Total = BC_CS_CT_Total + 1
endfunction

struct Casting_Struct
 real x
 real y
 real time
 real spd
 real s_spd
 texttag tag
 integer return = 0
 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

//Sets cancelled cast to true if the unit receives an order
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


//The primary loop.
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)
   call cs.destroy()
   set i = i + 1
  elseif(cs.cancell == true)then
   call BC_CancelledCast(cs.x, cs.y)
  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
    call BJDebugMsg("Tick")

    if(cs.time <= cs.s_spd)then
     //********************************************FINISHED IF THIS IS TRUE
     // (I'd like to return a value to my original callfunction here)
     set cs.this_tick = true
    else
     call SetTextTagText(cs.tag, CastString(cs.time), BASE_TEXTTAG_SIZE)
    endif

   endif

  endif
 endloop

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

//Called to start the whole shibang.
function BeginCast2 takes unit u, real time, real spd returns integer
 local Casting_Struct cs
 local trigger t
 if(time < 1)then
  return -1
 endif

 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.tag = CreateTextTag()
 call SetTextTagPos(cs.tag, cs.x, cs.y, BASE_TEXTTAG_SIZE)
 call SetTextTagPermanent(cs.tag, true)
 call SetTextTagText(cs.tag, CastString(time), 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 BJDebugMsg("Timer Started, BC_Casting_Timer")
  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 0
endfunction

Now there's a two problems that I have sence I switched from handels to vjass

1: I don't know when or how to return, the function ends while the timer is still running, so I can't determine when I can return, and how would I wait for the return value?

2: It feels like a waste of resources to do all that to cancell the cancell texttag, is there a better way?

Besides that, this whole thing has my head wanting to commit suicide (It always does that when I'm trying to overwrite new ideas, it keep saying "SetHandle" and I keep going "GlobalGlobalGlobal".) I'm probably doing this very poorly, and probably fairly illogicaly, but in my defense, I haven't done this before ;p.

Thank you for any help on the matter, Blackroot.
10-01-2007, 08:59 AM#2
Anitarf
How do you even manage to compile this thing?
Collapse JASS:
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

// (I'd like to return a value to my original callfunction here) You can't return a value, because your function returns nothing. You can only return, by typing return.

I'm not sure what you're trying to do with your functions, what you do with cs.time, cs.spd and cs.s_spd is incomprehensible to me. If you gave a better explanation of what you want to do, perhaps we could help you better.

Also, your loops through the arrays will often miss an index. I'll let you think about that.
10-01-2007, 09:12 AM#3
PitzerMike
You can't rely on GetTriggerUnit and GetTriggeringTrigger in BC_CancellCast since when called from the timer callback these will most likely be erased.
The obvious solution is making the unit part of the struct.

Oh, btw there are probably other errors too, I didn't really look closely.
10-01-2007, 09:53 AM#4
Blackroot
@Pitzer
I don't understand why GetTriggeringTrigger() and GetTriggerUnit() would be erased, a local trigger is created, actions are added, it should be returning the unit that was ordered & the trigger itself (Actually I'm not totaly sure that's true, the GetTriggeringTrigger() might be returning the trigger itself that created the local trigger, I'm not sure) Unless there's some other reason it would be being erased?

There's probably a few other errors, I'm really new to this global concept, I always thought of handles as pointers, but it's really hard to conceptualize globals as pointers. Or even psuedo-pointers.

@Antiarf
Honestly I don't know how it compiled O_o. That's a decent problem, I'll correct that at once.

Let me try and explain what I'm trying better:

With cs.time this is the total amount of time I want, say I have passed 1.00

cs.time = 1

and cs.spd is the amount of time (divisible by .05, otherwise it's inaccurate) to wait before removing a * from the string. cs.s_spd is the static spd, it saves spd so that cs.spd can be reset once it is <= 0.

So when I do
set cs.spd = cs.spd -.05

I want it to indicate that .05 seconds has passed, then checking if spd is <= 0, if it is I want to reset it to the value of cs.s_spd and remove a * from the string, then update my text tag. Finnaly remove the value equal to the static spd (s_spd) from time (time - s_spd) and check if the value is equal to or below zero, if it is the spell cast if finished. This is where I want to return something, and it doesn't matter if it's a literal return, or some psuedo-callback, I just need any way to return a value to whatever function called BeginCast2, even if it isin't a true 'return' call.

I hope that clarified, my mind is really bogged and I'm drinking some coffee to clear my head ;P.

Thank you again, blackroot.
10-01-2007, 10:35 AM#5
Anitarf
Quote:
I just need any way to return a value to whatever function called BeginCast2, even if it isin't a true 'return' call.
You're not making much sense here. What value?

Also, what exactly isn't working again? Have you tried putting in some debug messages?
10-01-2007, 11:14 AM#6
Blackroot
I'm not exactly sure what's not working, that's the problem. It's not waiting the correct period of time, that's all I know. And the cancell function is blatently bugged. (Although, what could be hapenning is that my timer is generating more then 1 cancell call, which might be.)

I don't need any particular value, i just need my function to wait until the duartion of the particular cast is over.

Let me iterate, say I call BeginCast2:
call BeginCast2(stuff)

Now in an ideal world, I'd be able to do this
if(BeginCast2 == done)then
stuff
endif

However, it's not an ideal world, and at this point, I cannot tell when my timer is done rolling through the values i passed to begin cast.

So say I passed:
call BeginCast(aunit, 1.00, .05)

Now I want this to tell my function that called it, that the duration I passed to it (1 second) has expired, and the cast has been successful. I, of course, could wait 1 second, but if my cast was cancelled, I woulden't know. Hope that cleared that up.

Thanks again for the help, sorry for the vague explination, it's kind of a messy system and it's rather hard to explain it all in one go.
10-01-2007, 11:34 AM#7
PitzerMike
Quote:
Originally Posted by Blackroot
@Pitzer
I don't understand why GetTriggeringTrigger() and GetTriggerUnit() would be erased, a local trigger is created, actions are added, it should be returning the unit that was ordered & the trigger itself (Actually I'm not totaly sure that's true, the GetTriggeringTrigger() might be returning the trigger itself that created the local trigger, I'm not sure) Unless there's some other reason it would be being erased?

Nevermind, I misread BC_CancelledCast as BC_CancellCast
10-01-2007, 11:53 AM#8
Blackroot
Not hard to do, I changed my naming methods and it's not very helpful to be honest x-x.

I went a little off course and tried converting a few of my older spells to use globals, it's decent practice. Jopefully i'll get a little better at this - it certainly doesn't help that I hardly understand the usages for pure globals.
10-01-2007, 12:23 PM#9
Anitarf
I think you'll find this an interesting read, should make your cancel floating texts easier to make.
10-01-2007, 12:28 PM#10
Blackroot
I'm probably not very good at textags, but the texttag doesn't ever expire even if I set a lifespan.
10-01-2007, 01:27 PM#11
Vexorian
Quote:
Originally Posted by Blackroot
I'm probably not very good at textags, but the texttag doesn't ever expire even if I set a lifespan.
that's because you also need to set it to non-permanent

Do you have a global variable called i ?
10-01-2007, 10:39 PM#12
Blackroot
Quote:
that's because you also need to set it to non-permanent
Does it default to true? I'll try and set it to false with a lifespan.

Quote:
Do you have a global variable called i ?
Nope, that's me trying to make a new naming method for myself and failing at it -,-. I'll update the code in a minute.
10-01-2007, 10:54 PM#13
Blackroot
Well now with a bit more understanding of what I'm doing;

Code:
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
 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)
   call cs.destroy()
  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
    call BJDebugMsg("Tick")

    if(cs.time <= cs.s_spd)then
     //********************************************FINISHED IF THIS IS TRUE
     set cs.this_tick = true
    else
     call SetTextTagText(cs.tag, CastString(cs.time), 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 BeginCast2 takes unit u, real time, real spd returns integer
 local Casting_Struct cs
 local trigger t
 if(time < 1)then
  return -1
 endif

 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.tag = CreateTextTag()
 call SetTextTagPos(cs.tag, cs.x, cs.y, BASE_TEXTTAG_SIZE)
 call SetTextTagPermanent(cs.tag, true)
 call SetTextTagText(cs.tag, CastString(time), 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 BJDebugMsg("Timer Started, BC_Casting_Timer")
  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 0
endfunction

Now the only issues are a way to wait for my function to mock-return. And, the 'cancelled' texttag does not display at all :/ (Doesn't make alot of sence why it doesn't though).

Thank you for all your help, once again.

[edit]
I was hoping to use PauseTrigger() to stop my trigger thread, wait for my timer to use ResumeTrigger() and that would be the pause time, then I realized there's no such thing as PauseTrigger() or ResumeTrigger() >.<. Back to the drawing board *whining*.