• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[JASS] Creating a Circle of Heros

Status
Not open for further replies.
Level 2
Joined
Jun 20, 2007
Messages
8
Hello!

I can't seem to get this to work. I think the problem lies in the unitid string to integer conversion while calling the creation of.

Please, help! :thumbs_up:

JASS:
function UnitSelectionIni takes nothing returns nothing
    local real iDegree = 60
    local string array sUnit
    local integer i = 0
    set sUnit[0] = "N001"
    set sUnit[1] = "N003"
    set sUnit[2] = "N004"
    set sUnit[3] = "N005"
    set sUnit[4] = "N006"
    set sUnit[5] = "N007"
    loop
        exitwhen i == 6
    call CreateNUnitsAtLocFacingLocBJ( 1, String2UnitIdBJ(sUnit[i]), Player(PLAYER_NEUTRAL_PASSIVE), PolarProjectionBJ(GetRectCenter(GetEntireMapRect()), 512.00, iDegree), GetRectCenter(GetEntireMapRect()) )
    set iDegree = iDegree + 60
    set i = i + 1
    endloop
endfunction

Hope you can help! Thanks,
Satsuki :grin:
 
JASS:
function UserSelectionIni takes nothing returns nothing
    local real iDegree = 60
    local integer array sUnit
    local integer i = 0
    local location loc
    set sUnit[0] = 'N001'  
    set sUnit[1] = 'N002'  
    set sUnit[2] = 'N003'  
    set sUnit[3] = 'N004'  
    set sUnit[4] = 'N005'  
    set sUnit[5] = 'N006'
    loop
        exitwhen i == 6
           set loc = PolarProjectionBJ( GetRectCenter( GetEntireMapRect() ), 512.00, iDegree )
           call CreateNUnitsAtLoc( 1, sUnit[i], Player(PLAYER_NEUTRAL_PASSIVE), loc, ( iDegree + 180 ) )
           set iDegree = iDegree + 60
           set i = i + 1
           call RemoveLocation( loc )
    endloop
endfunction

You have to make the sUnit variable a integer, so it can be used for UnitID.
I fixed leak too.
 
Level 2
Joined
Jun 20, 2007
Messages
8
Hey, thanks you for your feedback!

I found it myself, actually. But thanks for the memory leak fix.

I'm now trying to make the units spin around the edge of the circle. I'm having trouble though. WE keeps telling me it's expecting a function name on line 16!

Hope you can help:
JASS:
function UnitSelectionIni takes nothing returns nothing
    local real iDegree = 60
    local integer array sUnit
    local integer i = 0
    local location loc
    set sUnit[0] = 'N001'
    set sUnit[1] = 'N003'
    set sUnit[2] = 'N004'
    set sUnit[3] = 'N005'
    set sUnit[4] = 'N006'
    set sUnit[5] = 'N007'
    loop
        exitwhen i == 6
            set loc = PolarProjectionBJ(GetRectCenter(GetEntireMapRect()), 512.00, iDegree)
            call CreateNUnitsAtLoc( 1, sUnit[i], Player(PLAYER_NEUTRAL_PASSIVE), loc, 270 )
            call UnitSelectionSpin(GetLastCreatedUnit(), iDegree)
            set iDegree = iDegree + 60
            set i = i + 1
            call RemoveLocation( loc )
    endloop
endfunction

function UnitSelectionSpin takes unit implUnit, real Degree returns nothing
    //Spin Units, each unit needs its own loop due to low RPMs. 
    local location loc
    loop
        exitwhen udg_IsSelecting == false
            set loc = PolarProjectionBJ(Location(0, 0), 512.00, Degree)
            call SetUnitPositionLoc( implUnit, loc )
            set Degree = Degree + .2
            if Degree > 360 then
                set Degree = 0
            endif
            call TriggerSleepAction( 0.01 )
            call RemoveLocation( loc )
    endloop
endfunction

Thanks again. :grin:
 
Level 11
Joined
Oct 13, 2005
Messages
233
JASS:
function UnitSelectionIni takes nothing returns nothing
    local real iDegree = 60
    local integer array sUnit
    local integer i = 0
    local location loc
    set sUnit[0] = 'N001'
    set sUnit[1] = 'N003'
    set sUnit[2] = 'N004'
    set sUnit[3] = 'N005'
    set sUnit[4] = 'N006'
    set sUnit[5] = 'N007'
    loop
        exitwhen i == 6
            set loc = PolarProjectionBJ(GetRectCenter(GetEntireMapRect()), 512.00, iDegree)
            call CreateNUnitsAtLoc( 1, sUnit[i], Player(PLAYER_NEUTRAL_PASSIVE), loc, 270 )
            call UnitSelectionSpin(GetLastCreatedUnit(), iDegree)
            set iDegree = iDegree + 60
            set i = i + 1
            call RemoveLocation( loc )
    endloop
endfunction

function UnitSelectionSpin takes unit implUnit, real Degree returns nothing
    //Spin Units, each unit needs its own loop due to low RPMs. 
    local location loc
    loop
        exitwhen udg_IsSelecting == false
            set loc = PolarProjectionBJ(Location(0, 0), 512.00, Degree)
            call SetUnitPositionLoc( implUnit, loc )
            set Degree = Degree + .2
            if Degree > 360 then
                set Degree = 0
            endif
            call TriggerSleepAction( 0.01 )
            call RemoveLocation( loc )
    endloop
endfunction

Dragoon's suggestion would make your code work, though currently the code you're using still has some memory leaks. In addition, there's some BJ functions in there that are rather pointless to be using. Here's some fixes to the code:
JASS:
function UnitSelectionSpin takes unit implUnit, real Degree returns nothing
 //My added locals
 local real targetX
 local real targetY


    loop
        exitwhen udg_IsSelecting == false
        //
        // Check the other function below for an explanation on what I'm doing right here
        //
        set targetX = 512 * Cos(Degree * bj_DEGTORAD)
        set targetY = 512 * Sin(Degree * bj_DEGTORAD)
        //
        // We'll use the SetUnitPosition function since we are no longer using locations
        //
        call SetUnitPosition(implUnit, targetX, targetY)

        set Degree = Degree + .2
        if Degree > 360 then
            set Degree = 360 - Degree
        endif
            //
            // Uh oh, what's this? We can't have a TriggerSleepAction call in this function.
            // The reason is that it's not in its own thread, so it will just end the function
            // right here. Also, the minimum interval TriggerSleepAction will use is .1 and not .01
            // so in addition to that, you're losing accuracy
            //
            call TriggerSleepAction( 0.01 )
    endloop
endfunction

function UnitSelectionIni takes nothing returns nothing
    // My added locals
    local real targetX
    local real targetY
    local unit temp
    
    
    local real iDegree = 60
    local integer array sUnit
    local integer i = 0
    set sUnit[0] = 'N001'
    set sUnit[1] = 'N003'
    set sUnit[2] = 'N004'
    set sUnit[3] = 'N005'
    set sUnit[4] = 'N006'
    set sUnit[5] = 'N007'
    loop
        exitwhen i == 6
        
            // You're leaking a location and rect with the GetRectCenter and GetEntireMapRect function calls
            // CreateNUnitsAtLoc can easily be replaced with CreateUnitAtLoc with just changing the order of a few things
            // GetLastCreatedUnit is something we will now be avoiding; it is unnecessary
            //
            // Instead, I'm going further with additional improvements on efficiency
            // We will do the polar projection right here in the loop instead so we can use X/Y coords
            // We will then have to use CreateUnit to create the unit now that we're using X/Y instead of a loction
            //
            set targetX = 512.00 * Cos(iDegree * bj_DEGTORAD)
            set targetY = 512.00 * Sin(iDegree * bj_DEGTORAD)
        
            set temp = CreateUnit(Player(15), sUnit[i], targetX, targetY, 270)
            //
            // Right here is where I'm worried about what you're doing
            // The called function will not return until it is finished, and how I see you've coded it
            // I'm fairly sure you want it to keep going awhile.
            // Instead, I'd put all the heroes in a group and then pass that group to the other function
            // after creating all the units
            //
            call UnitSelectionSpin(temp, iDegree)
            
            
            set iDegree = iDegree + 60
            set i = i + 1
    endloop
endfunction
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
By the way, I suggest you use X/Y instead of locations, since they don't leak and are faster.

Eg.

JASS:
function UnitSelectionSpin takes unit implUnit, real Degree returns nothing
    loop
        exitwhen udg_IsSelecting == false
            call SetUnitPosition( implUnit, 512 * Cos( Degree*bj_DEGTORAD ), 512 * Sin( Degree*bj_DEGTORAD ) )
            set Degree = Degree + .2
            if Degree > 360 then
                set Degree = 0
            endif
            call TriggerSleepAction( .01 )
    endloop
endfunction
function UnitSelectionIni takes nothing returns nothing
    local real iDegree = 60
    local integer array sUnit
    local integer i = 0
    local rect wb = GetWorldBounds()
    set sUnit[0] = 'N001'
    set sUnit[1] = 'N003'
    set sUnit[2] = 'N004'
    set sUnit[3] = 'N005'
    set sUnit[4] = 'N006'
    set sUnit[5] = 'N007'
    loop
        exitwhen i > 5
            call UnitSelectionSpin(CreateUnit( Player(15), sUnit[i], GetRectCenterX(wb) + 512 * Cos(iDegree*bj_DEGTORAD), GetRectCenterY(wb) + 512 * Sin(iDegree*bj_DEGTORAD), 270 ), iDegree)
            set iDegree = iDegree + 60
            set i = i + 1
    endloop
    call RemoveRect( wb )
    set wb = null
endfunction

By the way, TriggerSleepAction(.01) will sleep for a number between .27 and infinite, depending on the game latency, and also pause every function that is in the same call stack as the function calling TSA.

EDIT: Wyrmie posted while I did >_>
 
Level 2
Joined
Jun 20, 2007
Messages
8
Hello!

Thanks for all the help! I had to do some research inorder to understand some of your code. I think I've got it down.

There's a problem though: only one hero is made and spins. Also, what would you suggest using instead of a sleepaction?

Most recent code:
JASS:
function UnitSelectionSpin takes unit implUnit, real Degree returns nothing
 local real targetX
 local real targetY
    loop
        exitwhen udg_IsSelecting == false
        set targetX = 512 * Cos(Degree * bj_DEGTORAD)
        set targetY = 512 * Sin(Degree * bj_DEGTORAD)
        call SetUnitPosition(implUnit, targetX, targetY)
        set Degree = Degree + .2
        if Degree > 360 then
            set Degree = 360 - Degree
        endif
        //call TriggerSleepAction( 0.01 )
    endloop
endfunction
function UnitSelectionIni takes nothing returns nothing
    local real targetX
    local real targetY
    local unit temp
    local real iDegree = 60
    local integer array sUnit
    local integer i = 0
    set sUnit[0] = 'N001'
    set sUnit[1] = 'N003'
    set sUnit[2] = 'N004'
    set sUnit[3] = 'N005'
    set sUnit[4] = 'N006'
    set sUnit[5] = 'N007'
    loop
        exitwhen i == 6
            set targetX = 512.00 * Cos(iDegree * bj_DEGTORAD)
            set targetY = 512.00 * Sin(iDegree * bj_DEGTORAD)
            set temp = CreateUnit(Player(15), sUnit[i], targetX, targetY, 270)
            call UnitSelectionSpin(temp, iDegree)
            set iDegree = iDegree + 60
            set i = i + 1
    endloop
endfunction
 
Level 11
Joined
Oct 13, 2005
Messages
233
Only 1 hero will be created and will rotate because function calls are not run in separate threads. If you read my suggestion in the code I wrote, I suggested you add all the heroes to a group and then after the loop, call that function. The function would then loop through the group and rotate all the heroes accordingly.

Another solution would be to call ExecuteFunc on your separate function and pass the unit and angle as temporary global variables. Because ExecuteFunc starts the specified function in a new thread, it should work properly.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
JASS:
function UnitSelectionSpin takes nothing returns nothing
 local unit implUnit = bj_ghoul[100]
 local real iDegree = bj_lastTransmissionDuration
 local real targetX
 local real targetY
    loop
        exitwhen udg_IsSelecting == false
        set targetX = 512 * Cos(Degree * bj_DEGTORAD)
        set targetY = 512 * Sin(Degree * bj_DEGTORAD)
        call SetUnitPosition(implUnit, targetX, targetY)
        set Degree = Degree + .2
        if Degree > 360 then
            set Degree = 360 - Degree
        endif
        call TriggerSleepAction( .01 )
    endloop
endfunction
function UnitSelectionIni takes nothing returns nothing
    local real targetX
    local real targetY
    local unit temp
    local real iDegree = 60
    local integer array sUnit
    local integer i = 0
    set sUnit[0] = 'N001'
    set sUnit[1] = 'N003'
    set sUnit[2] = 'N004'
    set sUnit[3] = 'N005'
    set sUnit[4] = 'N006'
    set sUnit[5] = 'N007'
    loop
        exitwhen i == 6
            set targetX = 512 * Cos(iDegree * bj_DEGTORAD)
            set targetY = 512 * Sin(iDegree * bj_DEGTORAD)
            set bj_ghoul[100] = CreateUnit(Player(15), sUnit[i], targetX, targetY, 270)
            set bj_lastTransmissionDuration = iDegree
            call ExecuteFunc("UnitSelectionSpin")
            set iDegree = iDegree + 60
            set i = i + 1
    endloop
endfunction

Here's the ExecFunc method wyrm's talking about.
 
Level 2
Joined
Jun 20, 2007
Messages
8
Thanks!!

Do you think you could explain to me how these three lines work exactly?

JASS:
set bj_ghoul[100] = CreateUnit(Player(15), sUnit[i], targetX, targetY, 270)  
set bj_lastTransmissionDuration = iDegree 
call ExecuteFunc("UnitSelectionSpin")

I've never heard of bj_ghoul[] or bj_lastTransmissionDuration.

Also, is there any way I could increase the speed of them circulating?
:thumbs_up:
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
bj_ghoul is a unit array hardcoded into warcraft
bj_lastTransmissionDuration is a real hardcoded into warcraft.

They're normally only used for blizzard's functions.

I use them since ExecuteFunc doesn't allow you to pass parameters to the function

To increase the speed of the rotation, do something like

JASS:
function UnitSpin_Child takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit u = GetAttachedUnit( t, "u" )
    //do more stuff
endfunction

function UnitSpin takes unit which, (more params) returns nothing
    local timer t = CreateTimer()
    call AttachUnit( t, "u", which )
    call TimerStart( t, interval, true, function UnitSpin_Child )
    set t = null
endfunction

Interval will work as low as .035 accurately.
 
Level 2
Joined
Jun 20, 2007
Messages
8
Thank you for all your help!

Could you help me with this?

  • Unit Manipulate
    • Events
      • Unit - A unit Finishes casting an ability
    • Conditions
    • Actions
      • Game - Display to (All players) the text: Finished Casting
      • For each (Integer A) from 1 to nBalls, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Target unit of ability being cast) Equal to Ball[(Integer A)]
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • UnitHoldingBallN[(Integer A)] Equal to No unit
                  • (Ability being cast) Equal to Grab Ball
                • Then - Actions
                  • Game - Display to (All players) the text: Assigning Ball To P...
                  • Set UnitHoldingBallN[(Integer A)] = (Casting unit)
                • Else - Actions
            • Else - Actions
The problem seems to lie in the below section:
  • If - Conditions
    • (Target unit of ability being cast) Equal to Ball[(Integer A)]
Ball[1] and Ball[2] are both assigned to units before this trigger is ran.
Do you have any idea what's wrong?
 
Last edited:
Level 2
Joined
Jun 20, 2007
Messages
8
Hey!

Could you proof this?


JASS:
function CheckSelectionStatus takes nothing returns nothing
    local boolean HasSelected = true
    local  integer i = 1
    
    loop
        exitwhen i == 12
            if  GetPlayerSlotState(ConvertedPlayer(i)) == PLAYER_SLOT_STATE_PLAYING  then
                if udg_PlayerUnit[i] == null then
                    set HasSelected = false                
                endif
            endif
    set i = i + 1 
    endloop
    
    if HasSelected == true then
        set i = 0
        set udg_IsSelecting = false
        call CinematicFadeBJ( bj_CINEFADETYPE_FADEOUT, 0.00, "ReplaceableTextures\\CameraMasks\\White_mask.blp", 100.00, 100.00, 100.00, 0 )
        call PlaySoundBJ( gg_snd_LightningBolt1 )
        loop
            exitwhen i == 12
                call PanCameraToTimedLocForPlayer( ConvertedPlayer(i), GetPlayerStartLocationLoc(ConvertedPlayer(i)), 0 )
                call ShowUnitShow( udg_PlayerUnit[i] )
                call SetCameraFieldForPlayer( ConvertedPlayer(i), CAMERA_FIELD_ROTATION, 90.00, 0.50 )
                call SetCameraFieldForPlayer( ConvertedPlayer(i), CAMERA_FIELD_ANGLE_OF_ATTACK, 295.00, 0.50 )
                call SetCameraFieldForPlayer( ConvertedPlayer(i), CAMERA_FIELD_TARGET_DISTANCE, 3000.00, 0.50 )
                call SetCameraFieldForPlayer( ConvertedPlayer(i), CAMERA_FIELD_FIELD_OF_VIEW, 75.00, 0.50 )
                set i = i + 1
            endloop  
    call CinematicFadeBJ( bj_CINEFADETYPE_FADEIN, 1.00, "ReplaceableTextures\\CameraMasks\\White_mask.blp", 100.00, 100.00, 100.00, 0 )  
    endif
endfunction

LOL Thanks :coolgrunt:
 
Level 2
Joined
Jun 20, 2007
Messages
8
So:

JASS:
function CheckSelectionStatus takes nothing returns nothing
    local boolean HasSelected = true
    local integer i = 0
    
    loop
        exitwhen i == 12
            if  GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING  then
                if udg_PlayerUnit[i + 1] == null then
                    set HasSelected = false                
                endif
            endif
    set i = i + 1 
    endloop
    
    if HasSelected == true then
        set i = 0
        set udg_IsSelecting = false
        call CinematicFadeBJ( bj_CINEFADETYPE_FADEOUT, 0.00, "ReplaceableTextures\\CameraMasks\\White_mask.blp", 100.00, 100.00, 100.00, 0 )
        call PlaySoundBJ( gg_snd_LightningBolt1 )
        loop
            exitwhen i == 12
                call PanCameraToTimedLocForPlayer( ConvertedPlayer(i), GetPlayerStartLocationLoc(ConvertedPlayer(i)), 0 )
                call ShowUnitShow( udg_PlayerUnit[i] )
                call SetCameraFieldForPlayer( Player(i), CAMERA_FIELD_ROTATION, 90.00, 0.50 )
                call SetCameraFieldForPlayer( Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, 295.00, 0.50 )
                call SetCameraFieldForPlayer( Player(i), CAMERA_FIELD_TARGET_DISTANCE, 3000.00, 0.50 )
                call SetCameraFieldForPlayer( Player(i), CAMERA_FIELD_FIELD_OF_VIEW, 75.00, 0.50 )
                set i = i + 1
            endloop  
    call CinematicFadeBJ( bj_CINEFADETYPE_FADEIN, 1.00, "ReplaceableTextures\\CameraMasks\\White_mask.blp", 100.00, 100.00, 100.00, 0 )  
    endif
endfunction

There's a fatal error when this function is ran. Hahah! I don't know what the hell is wrong. Any suggestions? (Could it be another function interfering?)
 
Last edited:
Level 4
Joined
Jun 21, 2007
Messages
116
try doing debugging by // commenting everything, then uncommenting line-by-line. I think its either the fade filter or PanCamera what causes the crash
 
Status
Not open for further replies.
Top