• 🏆 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] JASS Trigger Setup

Status
Not open for further replies.
Level 12
Joined
Aug 20, 2007
Messages
866
I have been really curious about how a proper JASS map (not just a system) should be coded, I understand that in the script there is a main function, and when you create a trigger, then convert it, it tells it to call it (in vJASS I believe you can edit any specific part of the script)

I have heard about 1000x times how GUI creates triggers inefficiently, but I have not seen any examples, here is how I did my map, but I would really like somebody to let me know if I'm doing something wrong (or right)

Btw, I don't feel like getting a NewGen upgrade, so all of my globals have the "udg_" tacked on, sorry

Heres the Init trigger (not the main, but is called by the main)

JASS:
function Trig_GameStart_Actions takes nothing returns nothing
    local integer i = -1

    //Starting Game Settings
    call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, 2000, 0)
    call FogEnable(false)
    call FogMaskEnable(false)
    set udg_SpawnTimer = CreateTimer()
    call TimerStart(udg_SpawnTimer, 10.00, true, null)
    set udg_EntireMap = GetWorldBounds()
    set udg_SpawnRegions[0] = gg_rct_RedSpawn
    set udg_SpawnRegions[1] = gg_rct_BlueSpawn
    set udg_SpawnRegions[2] = gg_rct_TealSpawn
    set udg_SpawnRegions[3] = gg_rct_PurpleSpawn
    set udg_SpawnRegions[4] = gg_rct_YellowSpawn
    set udg_SpawnRegions[5] = gg_rct_OrangeSpawn
    set udg_SpawnRegions[6] = gg_rct_GreenSpawn
    set udg_SpawnRegions[7] = gg_rct_PinkSpawn
    set udg_SpawnRegions[8] = gg_rct_GraySpawn
    set udg_SpawnRegions[9] = gg_rct_LightBlueSpawn
    set udg_SpawnRegions[10] = gg_rct_DarkGreenSpawn
    set udg_SpawnRegions[11] = gg_rct_BrownSpawn
    call SetPlayerFlagBJ( PLAYER_STATE_GIVES_BOUNTY, true, Player(12) )
    call SetPlayerFlagBJ( PLAYER_STATE_GIVES_BOUNTY, true, Player(13) )
    call SetPlayerFlagBJ( PLAYER_STATE_GIVES_BOUNTY, true, Player(14) )
    call SetPlayerFlagBJ( PLAYER_STATE_GIVES_BOUNTY, true, Player(15) )

    //Create Triggers
    set udg_trgSpawnTimer = CreateTrigger()
    set udg_trgChangeD = CreateTrigger()
    set udg_trgChangeRo = CreateTrigger()
    set udg_trgBuildatBase = CreateTrigger()
    set udg_trgSetBase = CreateTrigger()
    set udg_trgKillATrollTent = CreateTrigger()


    //Add Trigger Actions
    call TriggerAddAction( udg_trgSpawnTimer, function SpawnTimer )
    call TriggerAddAction( udg_trgChangeD, function ChangeDistance )
    call TriggerAddAction( udg_trgChangeRo, function ChangeRotation )
    call TriggerAddAction( udg_trgBuildatBase, function BuildatBase )
    call TriggerAddAction( udg_trgSetBase, function SetBase )
    call TriggerAddAction( udg_trgKillATrollTent, function KillTrollTents )

    //Add Trigger Events
    call TriggerRegisterTimerExpireEvent(udg_trgSpawnTimer, udg_SpawnTimer)

    //Add Trigger Conditions
    call TriggerAddCondition(udg_trgBuildatBase,Condition( function IsUnitABuilder))
    call TriggerAddCondition(udg_trgSetBase,Condition( function CheckAncient))
    call TriggerAddCondition(udg_trgKillATrollTent,Condition( function CheckTrollTent))


    //Loops
    loop
      set i=i+1
      exitwhen i==12

      //Add Trigger Events (Looped)
      call TriggerRegisterPlayerChatEvent(udg_trgChangeD,Player(i),"-d ",false)
      call TriggerRegisterPlayerChatEvent(udg_trgChangeRo,Player(i),"-Ro ",false)
      call TriggerRegisterLeaveRectSimple(udg_trgBuildatBase, udg_SpawnRegions[i])
      call TriggerRegisterPlayerUnitEvent(udg_trgSetBase, Player(i),EVENT_PLAYER_UNIT_CONSTRUCT_START, null)
      call TriggerRegisterPlayerUnitEvent(udg_trgKillATrollTent, Player(i),EVENT_PLAYER_UNIT_DEATH, null)

      //Setup (Looped)
      call SetPlayerFlagBJ( PLAYER_STATE_GIVES_BOUNTY, true, Player(i) )
        //Create Starters
      if i < 3 then
        call CreateUnit(Player(i),'e001', GetRectCenterX(udg_SpawnRegions[i]), GetRectCenterY(udg_SpawnRegions[i]), bj_RADTODEG * AngleBetweenCoordsRad(GetRectCenterX(udg_SpawnRegions[i]),GetRectCenterY(udg_SpawnRegions[i]),GetRectCenterX(udg_EntireMap),GetRectCenterY(udg_EntireMap)))                
      elseif i > 2 then
        call CreateUnit(Player(i),'e002', GetRectCenterX(udg_SpawnRegions[i]), GetRectCenterY(udg_SpawnRegions[i]), bj_RADTODEG * AngleBetweenCoordsRad(GetRectCenterX(udg_SpawnRegions[i]),GetRectCenterY(udg_SpawnRegions[i]),GetRectCenterX(udg_EntireMap),GetRectCenterY(udg_EntireMap)))
      elseif i > 5 then
        call CreateUnit(Player(i),'e003', GetRectCenterX(udg_SpawnRegions[i]), GetRectCenterY(udg_SpawnRegions[i]), bj_RADTODEG * AngleBetweenCoordsRad(GetRectCenterX(udg_SpawnRegions[i]),GetRectCenterY(udg_SpawnRegions[i]),GetRectCenterX(udg_EntireMap),GetRectCenterY(udg_EntireMap)))
      elseif i > 8 then
        call CreateUnit(Player(i),'e000', GetRectCenterX(udg_SpawnRegions[i]), GetRectCenterY(udg_SpawnRegions[i]), bj_RADTODEG * AngleBetweenCoordsRad(GetRectCenterX(udg_SpawnRegions[i]),GetRectCenterY(udg_SpawnRegions[i]),GetRectCenterX(udg_EntireMap),GetRectCenterY(udg_EntireMap)))
      endif

    endloop
endfunction

//===========================================================================
function InitTrig_GameStart takes nothing returns nothing
    set gg_trg_GameStart = CreateTrigger()
    call TriggerAddAction( gg_trg_GameStart, function Trig_GameStart_Actions )
endfunction


And then here is the script that contains the actions, conditions, and just functions used by the map

JASS:
//[Useful Functions]=======================================================

function cGroupAddGroupEnum takes nothing returns nothing
    call GroupAddUnit(udg_DestGroup, GetEnumUnit())
endfunction

function cGroupAddGroup takes group sourceGroup, group destGroup returns nothing
    call ForGroup(sourceGroup, function cGroupAddGroupEnum)
    set udg_DestGroup = destGroup
endfunction

function GetPolarCoordX takes real x, real dist, real angle returns real
    set x = x + dist * Cos(angle * bj_DEGTORAD)
    return x
endfunction

function GetPolarCoordY takes real y, real dist, real angle returns real
    set y = y + dist * Sin(angle * bj_DEGTORAD)
    return y
endfunction

function AngleBetweenCoordsRad takes real x1, real y1, real x2, real y2 returns real
    return Atan2(y2 - y1, x2 - x1)
endfunction

function DistBetweenCoords takes real x1, real y1, real x2, real y2 returns real
    return SquareRoot((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))
endfunction

//[Boolean Checks]=========================================================

function IsUnitABuilder takes nothing returns boolean
    if GetUnitTypeId(GetTriggerUnit()) == 'e000' then
        return true
    endif
    if GetUnitTypeId(GetTriggerUnit()) == 'e001' then
        return true
    endif
    if GetUnitTypeId(GetTriggerUnit()) == 'e002' then
        return true
    endif
    if GetUnitTypeId(GetTriggerUnit()) == 'e003' then
        return true
    endif
    return false
endfunction

function CheckAncient takes nothing returns boolean
    if IsUnitType(GetConstructingStructure(),UNIT_TYPE_ANCIENT) then
      return true
    endif
    return false
endfunction

function CheckTrollTent takes nothing returns boolean
    if GetUnitTypeId(GetDyingUnit()) == 'o001' and FirstOfGroup(udg_Tents) != null then
      return true
    endif
    return false
endfunction

//[Trigger Actions]========================================================

function SpawnTimer takes nothing returns nothing
    local integer i = -1
    local real X
    local real Y
    local real X2 = GetRectCenterX(udg_EntireMap)
    local real Y2 = GetRectCenterY(udg_EntireMap)
    loop
      set i=i+1
      exitwhen i == 12
      set X = GetUnitX(udg_Bases[i])
      set Y = GetUnitY(udg_Bases[i])
      if udg_Bases[i] != null and GetUnitState(udg_Bases[i],UNIT_STATE_LIFE) > 0.0 then
        call CreateUnit( Player(i), 'hfoo', X,Y,bj_RADTODEG * AngleBetweenCoordsRad(X,Y,X2,Y2))
      endif
    endloop
endfunction

function ChangeDistance takes nothing returns nothing
    local real distance = S2R(SubString(GetEventPlayerChatString(), 3, StringLength(GetEventPlayerChatString()) ))
    call SetCameraFieldForPlayer(GetTriggerPlayer(),CAMERA_FIELD_TARGET_DISTANCE, distance, 0)
endfunction

function ChangeRotation takes nothing returns nothing
    local real degrees = S2R(SubString(GetEventPlayerChatString(), 4, StringLength(GetEventPlayerChatString()) ))
    call SetCameraFieldForPlayer(GetTriggerPlayer(),CAMERA_FIELD_ROTATION, degrees, 0)
endfunction

function BuildatBase takes nothing returns nothing
    local real X =  GetRectCenterX(udg_SpawnRegions[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))])
    local real Y =  GetRectCenterY(udg_SpawnRegions[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))])
    call SetUnitPosition(GetTriggerUnit(),X,Y)
endfunction

function SetBase takes nothing returns nothing
    local unit u = GetConstructingStructure()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local integer unitid = GetUnitTypeId(u)
    local player owner = GetOwningPlayer(u)
    local integer i = 0
    call KillUnit(u)
    set udg_Bases[GetPlayerId(owner)] = CreateUnit(owner, unitid, x,y,270)
    if GetUnitTypeId(u) == 'n002' or GetUnitTypeId(u) == 'n002'  then
      call UnitAddAbility(udg_Bases[GetPlayerId(owner)],'Aro1')
      call IssuePointOrder( udg_Bases[GetPlayerId(owner)], "root",GetUnitX(udg_Bases[GetPlayerId(owner)]),GetUnitY(udg_Bases[GetPlayerId(owner)]))
      call UnitRemoveAbility(udg_Bases[GetPlayerId(owner)],'Aro1')
    endif
    if GetUnitTypeId(u) == 'o001' then
        loop
          exitwhen i==4
          set i = i+1
          call GroupAddUnit(udg_Tents,CreateUnit(owner, 'n001', GetPolarCoordX(x,300.0, i*90.0 + 45.0), GetPolarCoordY(y,300.0, i*90.0 + 45.0), 270.0))
        endloop
    endif
    set u = null
    set owner = null
endfunction

function TentDistance takes nothing returns nothing
    if (GetUnitX(GetEnumUnit()) - udg_BaseX) * (GetUnitX(GetEnumUnit()) - udg_BaseX) + (GetUnitY(GetEnumUnit()) - udg_BaseY) * (GetUnitY(GetEnumUnit()) - udg_BaseY) <= 160000 then
      call KillUnit(GetEnumUnit())
      call GroupRemoveUnit(udg_Tents,GetEnumUnit())
    endif
endfunction

function KillTrollTents takes nothing returns nothing
    local unit u = GetDyingUnit()
    set udg_BaseX = GetUnitX(u)
    set udg_BaseY = GetUnitY(u)
    call ForGroup(udg_Tents, function TentDistance)
    set u = null
endfunction

Ugh, the jass tags condensed it, I had a really stylistic system going that made it easy to find certain code (I'm kinda new to JASS, so I gotta constantly re-check names + order of parameters and what else)
 
Level 9
Joined
Mar 25, 2005
Messages
252
I recoded a few functions for you
JASS:
function cGroupAddGroup takes group sourceGroup, group destGroup returns nothing
	set udg_DestGroup = destGroup
    call ForGroup(sourceGroup, function cGroupAddGroupEnum)    
endfunction 

function IsUnitABuilder takes nothing returns boolean
	local integer id = GetUnitTypeId(GetTriggerUnit())
    return 'e000' <= id and id <= 'e003'
endfunction 

function GetPolarCoordX takes real x, real dist, real angle returns real
    return x + dist * Cos(angle * bj_DEGTORAD)
endfunction

function GetPolarCoordY takes real y, real dist, real angle returns real
    return y + dist * Sin(angle * bj_DEGTORAD)
endfunction 

function CheckAncient takes nothing returns boolean
	return IsUnitType(GetConstructingStructure(),UNIT_TYPE_ANCIENT) == true
endfunction 

function CheckTrollTent takes nothing returns boolean
	return GetUnitTypeId(GetDyingUnit()) == 'o001' and FirstOfGroup(udg_Tents) != null
endfunction

In the cGroupAddGroup function I just swapped the order of the two lines because I don't have a clue why you would want to have them the other way around (if you had a reason for that then ignore my version).

If you want to improve your code further the next step would be to inline the functions you can, meaning for example the DistBetweenCoords and others like it. Altough I doubt you really need to make your code more efficient, since you aren't doing anything too often.

Btw I think you should feel like getting the JNPG.
 
Level 12
Joined
Aug 20, 2007
Messages
866
Whoops

I messed up the cGroupAddGroup(), supposed to be a better version of the one provided by Blizzard (or at least the one registered in my JassCraft)

JASS:
function cGroupAddGroupEnum takes nothing returns nothing
    call GroupAddUnit(udg_DestGroup, GetEnumUnit())
endfunction
//
function cGroupAddGroup takes group sourceGroup, group destGroup returns group
    call ForGroup(sourceGroup, function cGroupAddGroupEnum) //Enums all units from the source
    call ForGroup(destGroup, function cGroupAddGroupEnum)   //Enums all the units from the destgroup (just incase)
    set destgroup = udg_DestGroup       //sets the original destgroup to the global
    return destgroup             //returns the new group
endfunction


I think this is how should be done, now that I put some thought into it

Also, for the boolean checks, for some reason, they just don't work properly, like the checkancient thing, I used it almost exactly the same way you showed it, cept it came out like I put "null" instead of condition()

I think it might be because I didn't add the == just the function ( it returns a boolean already, but I suppose the "==" is necessary)

For the local triggers, I think I'm gonna start doing that instead of constanly creating globals for them


Btw, the re-coding is much appreciated :D
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Using the local triggers doesn't really have an advantage (the memory used by globals is almost nothing (you won't notice it), and unless you optimize with certain tweaks in Vex they are there anyways...) and has some disadvantages, so I'd suggest not using them. (And local triggers make your script longer once you optimize :p)

However you like it, though, I guess.

And just out of curiosity, why do you want to recode GroupAddGroup? Basically, there's no point to not either make it 100% inlined, or just use the original (bj_wantDestroyGroup is handy sometimes, anyways).
 
Level 12
Joined
Aug 20, 2007
Messages
866
I'm a bit new

Just started really JASSing a few days ago, but basically I have read that the bj_ functions are very inefficient. I saw all the stuff in the regular addgroup function, and thought, "Gee that's a little unnecessary". Also, I wanted to get a stronger understanding of the groupings in JASS, because I used them soooo much for GUI
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
BJ != bad.

There are BJ functions that are like a cover to the real functions, for example
JASS:
function AddItemToStockBJ takes integer itemId, unit whichUnit, integer currentStock, integer stockMax returns nothing
    call AddItemToStock(whichUnit, itemId, currentStock, stockMax)
endfunction

As you can see, the BJ just calls the real function with the values it takes.
Thats stupid and inefficient.

It doesn't mean, however, that every BJ is bad lol.
BJ = Blizzard Jass.

Thats why use a function list and check if it calls something stupid like the AddItemToStock.

Another example is the bj_DEGTORAD, which is actualy a constant, which is faster then making the math for radians (pi/180 or whatever it is).
 
Level 12
Joined
Aug 20, 2007
Messages
866
Yeah

The more I worked with stuff, I noticed that

The first was the bj_RADTODEG , and it's reverse
Much easier to write, and I suppose easier for the computer to use too

There were a couple others that I'm glad Blizzard put in, but I don't remember them


//=============================================================
I put some more thought into it, what the hell is the function supposed to look like?, because I don't think the

JASS:
set destgroup = udg_DestGroup

will enumerate the units into the destgroup, or will it because the variable is now pointing at the udg_DestGroup???

JASS:
function cGroupAddGroupEnum takes nothing returns nothing
    call GroupAddUnit(udg_DestGroup, GetEnumUnit())
endfunction

function cGroupAddGroup takes group sourceGroup, group destGroup returns group
    call DestroyGroup(udg_DestGroup)
    set udg_DestGroup = CreateGroup()
    call ForGroup(sourceGroup, function cGroupAddGroupEnum) //Enums all units from the source
    call ForGroup(destGroup, function cGroupAddGroupEnum)
   //Enums all the units from the destgroup (just incase)
    set destgroup = udg_DestGroup       //sets the original destgroup to the global
    return destgroup             //returns the new group
endfunction

Please help me :cry:
 
Status
Not open for further replies.
Top