• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] simple pereodic trigger

Status
Not open for further replies.
Level 6
Joined
Jan 7, 2007
Messages
247
Hello. I tried to create some simple spell in JASS and faced some weird problem.
Spell summons invisible ghost in target location, ghost becomes visible over 3 seconds and kills everyone around after it becomes 0% transparent. I think i made this MUI, but sometimes if someone uses this skill before last summoned ghost becomes visible it bugs a little. Like becomes invisible two times or does not become visible at all. Here's the code:

Trigger, registers spell use, creates a unit and makes it 100% transparent:

JASS:
function Trig_Spell_Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityId() == 'A009' ) ) then
        return false
    endif
    return true
endfunction

function Trig_Spell_Actions takes nothing returns nothing
    local location l 
    set l = GetSpellTargetLoc()
    set udg_num = ( udg_num + 1 )
    call CreateNUnitsAtLoc( 1, 'n001', GetOwningPlayer(GetTriggerUnit()), l, bj_UNIT_FACING )
    set udg_u[udg_num] = bj_lastCreatedUnit
    set udg_WoBl[udg_num] = l
    call SetUnitVertexColorBJ( udg_u[udg_num], 100, 100, 100, 100 )
    call RemoveLocation(l)
 endfunction

Then *pereodic* trigger:

  • Events
    • Time - Every 0.15 seconds of game time
  • Conditions
  • Actions
    • For each (Integer i) from 1 to num, do (Actions)
      • Loop - Actions
        • Custom script: call ghost(udg_i)
Script that checks how transparent is ghost and makes it less transparent or kills everyone around with stomp from dummy unit if ghost is fully visible.

JASS:
function ghost takes integer i returns nothing
    local unit z
if ( udg_WoBt[i] > 0 ) then
   set udg_WoBt[i] = udg_WoBt[i] - 5
   call SetUnitVertexColorBJ( udg_u[i], 100, 100, 100, udg_WoBt[i] )
else
    call SetUnitAnimation( udg_u[i], "spell" )
    call CreateNUnitsAtLoc( 1, 'n000', Player(0), udg_WoBl[i], bj_UNIT_FACING )
    set z = bj_lastCreatedUnit
    call UnitAddAbility(z, 'A00A')
    call IssueImmediateOrder( z, "stomp" )
    set udg_WoBl[i] = null
    set udg_WoBt[i] = 100
    set udg_u[i]= null
endif

endfunction

I know last trigger leaks and does not remove dummy, ill fix that, but now im really curious why transparency bugs sometimes =p
P.S.
WoBt is real
WoBl is location
i and num are integers
u is unit
 
Level 9
Joined
May 28, 2007
Messages
365
This is a bad way to do things. Use a timer instead. Give me a second to cleanup your code.

JASS:
function Trig_Spell_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A009' 
endfunction

function Ghost takes nothing returns nothing
  local timer t = GetExpiredTimer()
  local integer id = GetHandleId(t)
  local unit dummy
  call SetUnitVertexColorBJ( udg_u[id], 100, 100, 100, 100-udg_WoBt[id] )
  set udg_WoBt[id] = udg_WoBt[id] + 5
  if udg_WoBt[id] >= 100 then
    // Do your dummy stuff here
    set dummy = CreateUnit( Player(0), 'n000', GetUnitX(udg_u[id]), GetUnitY(udg_u[id]), 270 )
    call UnitAddAbility(... stuff)
    call IssueImmediatorOrder(...stuff)
    call PauseTimer(t)
    call DestroyTimer(t)
  endif

endfunction

function Trig_Spell_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    local location l = GetSpellTargetLoc()    
    call CreateNUnitsAtLoc( 1, 'n001', GetOwningPlayer(GetTriggerUnit()), l, bj_UNIT_FACING )
    set udg_num = GetHandleId(t)
    set udg_u[udg_num] = bj_lastCreatedUnit
    call SetUnitVertexColorBJ( udg_u[udg_num], 100, 100, 100, 100 )
    call RemoveLocation(l)
    call TimerStart(t, 0.15, true, function Ghost)
 endfunction

Honestly, just use a hashtable. It'll make your life easier. Check the tutorial section for a hashtable tutorial.
 
Level 6
Joined
Jan 7, 2007
Messages
247
Aww, i actually encountered a problem. Unit that is created by
JASS:
function Trig_Spell_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    local location l = GetSpellTargetLoc()    
    call CreateNUnitsAtLoc( 1, 'n001', GetOwningPlayer(GetTriggerUnit()), l, bj_UNIT_FACING )
    set udg_num = GetHandleId(t)
    set udg_u[udg_num] = bj_lastCreatedUnit
    call SetUnitVertexColorBJ( udg_u[udg_num], 100, 100, 100, 100 )
    call RemoveLocation(l)
    call TimerStart(t, 0.15, true, function Ghost)
 endfunction
doesn't become transparent (and doesnt chage transparency over time if i force it to become transparent (like with another trigger)) It's really strange, because
JASS:
set udg_u[udg_num] = bj_lastCreatedUnit
call SetUnitVertexColorBJ( udg_u[udg_num], 100, 100, 100, 100 )
looks correct and logical to me. *sigh*
But if i change it to
JASS:
call SetUnitVertexColorBJ( bj_lastCreatedUnit, 100, 100, 100, 100 )
it becomes invisible, but it doesn't change visibility over time. Looks like there's something wrong with udg_u[udg_num]
 
When you enter a number into an array higher than 8192 (?) it will just treat the variable as null. I tested it with this:
JASS:
scope Tests initializer Init
globals
    unit array u 
endglobals

private function Act takes nothing returns nothing
    local timer t = CreateTimer()
    local integer i = GetHandleId(t)
    set u[i] = CreateUnit(Player(0),'opeo',1000,1000,270)
    call BJDebugMsg(I2S(i))
    if u[i] == null then
        call BJDebugMsg("u["+I2S(i)+"] is null")
    else
        call BJDebugMsg("u["+I2S(i)+"] is not null")
    endif
    set u[0] = CreateUnit(Player(0),'hfoo',1030,1030,270)
    call IssuePointOrder(u[i],"patrol",2000,2000)
    call IssuePointOrder(u[0],"patrol",2000,2000)
    if u[0] == null then
        call BJDebugMsg("u[0] is null")
    else
        call BJDebugMsg("u[0] is not null")
    endif
endfunction
private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterTimerEvent(t,2,false)
    call TriggerAddAction(t,function Act)
endfunction
endscope

And it ended up saying:
u[1048694] is null.
u[0] is not null.

The footman u[0] patrolled, but the peon u[1048694] didn't.

So, don't use handle id's as indexes to arrays since it won't really work other than for things such as texttags. (99 initially and 1 less for every non-destroyed texttag) You could probably just use a global integer if you really just want a unique index.
 
It doesn't matter to declare them as globals if you're going to use them locally. You don't need to declare a variable as a global unless you are going to use it as a global/constant. It could be a global variable, but there is no need for it. =) Anyway, that was just a test code. I am aware that it leaks and might not be the most efficient. =P

Basically, as long as you are using them locally in the function (and that function only) you should declare them as a local.
 
Level 6
Joined
Jan 7, 2007
Messages
247
Well, i think i still need help with this code. I tried to fix that as you told me, but now it's not MUI. Transparency\Dummy stuff works perfect, but it totally bugs out if you try to cast same spell while first one is not finished yet.

Problem is in this:
JASS:
set udg_num = GetHandleId(t)

In debug mode, it shows ID like 295375982 (big number), so PurgeandFire111 was right, this does not work =|
 
Last edited:
Try this:
JASS:
function Trig_Spell_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A009' 
endfunction

function Ghost takes nothing returns nothing
  local timer t = GetExpiredTimer()
  local integer id = GetHandleId(t)-1048694
  local unit dummy
  call SetUnitVertexColor(udg_u[id],255,255,255,PercentToInt(100-udg_WoBt[id],255))
  set udg_WoBt[id] = udg_WoBt[id] + 5
  if udg_WoBt[id] >= 100 then
    set dummy = CreateUnit( Player(0), 'n000', GetUnitX(udg_u[id]), GetUnitY(udg_u[id]), 270 )
    call UnitAddAbility(... stuff)
    call IssueImmediatorOrder(...stuff)
    call PauseTimer(t)
    call DestroyTimer(t)
  endif
endfunction

function Trig_Spell_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    local real x = GetSpellTargetX()
    local real y = GetSpellTargetY()
    set udg_num = GetHandleId(t)-1048694
    set udg_u[udg_num] = CreateUnit(GetOwningPlayer(GetTriggerUnit()),'n001',x,y,270)  
    call SetUnitVertexColor(udg_u[udg_num],255,255,255,255)
    call TimerStart(t, 0.15, true, function Ghost)
 endfunction

Timers start out allocated with a handle id of 1048694 as far as I know. Based on how many timers you have created, this will modify the array value to an appropriate amount. 1st timer will result in an array index of 0, 2nd will result in an array index of 1, and 3rd will result in an array index of 2, and so on...

Timers are normally allocated with a handle ID of 1048694 as far as I know (just tested it, and yeah it came out as that number), so it will do it appropriately. The thing about their id's is that they don't depend on how many active timers there are, it depends on how many timers were created total. This means that if you destroy a timer, it will still jump to the next array index.

This is only a problem if you somehow happen to create more than 8192 timers in the map. Which seems unlikely unless you have some sort of infinite loop. =D
 
Level 6
Joined
Jan 7, 2007
Messages
247
Thanks you! It was little bugged, in SetUnitVertexColorBJ 100 is invisibility and 0 is full visibility, and in SetUnitVertexColor it's reverse. This map is like mini-game, so i doubt i'll have so many timers. :thumbs_up:
 
Status
Not open for further replies.
Top