About Units formation.

merlinds

Member
Reaction score
15
HI every one! now im making a hero defence and i have a question.

I want to create a group of units and order them to go to the players base like all the defense maps. but i would like the units to go in a formation.
Since they are romans i would like the formation to be the turtle formation:
300px-Testudo_formation.jpg


Has some one an idea of how to do it?.

Thanks in advance
 

GFreak45

I didnt slap you, i high 5'd your face.
Reaction score
130
you would need to use a formula for placement and how to direct them to move, essentially, you create 1 at center of region offset by 90 in the x direction 315 in the y direction, then that -90 in the y direction 8 times, then do this again -90 in the x direction 2 more times, then order them all to attack a point in front of them x range
 

merlinds

Member
Reaction score
15
Holy Sh*t!
To complicated and the units don go in a straight path, XD
Im going to try it but the corners of my path will be a heache XD
 

GFreak45

I didnt slap you, i high 5'd your face.
Reaction score
130
ill write a system to do it tonight in jass, it will be easy to use tho if you are willing to try

EDIT:
How many units in the group?
How many rows?
Did you want 3 units to lead them like in the picture?
how many points did you want to use?
 

merlinds

Member
Reaction score
15
I have just 1 corner, there are 20 units per group, and would be great to have the 3 leading kinghts.
The formation will be 4*5, the idea is to make a rectangle in this case.

Thank you so much your awesome!
 

GFreak45

I didnt slap you, i high 5'd your face.
Reaction score
130
ok im still working on it, got a lot done but not all of it, right now, you do this action:
Trigger:
  • Actions
    • Set Spawn_Point (or whatever variable you want) = the place you want them to spawn
    • Set Target_Point = where they are going to head to
    • Custom Script: call RomanFormationSpawn(udg_Spawn_Point, udg_Target_Point)

and it will create them with that formation facing that point tell them to move to that point relative to their place in line
then when they all get there it will do this:
Trigger:
  • Actions
    • Set Point_Reached = (their target point)
    • Set Formation_Event = 0.0
    • Set Formation_Event = 1.0


and you can do this to react to it:
Trigger:
  • New Points
    • Events
      • Game - Formation_Event becomes equal to 0.0
    • Conditions
    • Actions
      • For each Integer A from 1 to max points
        • Loop Actions
          • If Then Else
            • If
              • Reached_Point = Target_Points[Absolute Value of (Integer A - (max points + 2))] (this checks every points in reverse order to see if the reached point is equal to a target point then sets it to the next one, it does this in that order so that it can set the point to the next one and that point will already have been checked, so it doesnt just automatically set it to the last point)
            • Then
              • Set Target_Point = Target_Points[Integer A + 1]
              • Custom Script: call NewTarget(udg_Target_Point)


does that make sense to you?
 

GFreak45

I didnt slap you, i high 5'd your face.
Reaction score
130
the only issue with it is that when they turn around a corner, they just turn and face that direction rather than turning so that the leaders are still in front, the stay in formation but look the wrong way, if you set the first point equal to a point thats relative to their position when they will be running in to attack it will look right

oh and you would need AIDS, do you have it already?
 

GFreak45

I didnt slap you, i high 5'd your face.
Reaction score
130
ok... so how to impliment: follow the instructions above and create variables EXPLICITLY NAMED BasicUnit(default value of whatever you want the basic unit-type to be), LeaderUnit (Same but for the leader), EnemyPlayerNumber (this is the player that spawns the units), RomanSpawnDistance (This is the distance between every unit when they spawn, set this default value to 135 or whatever you want, the units pathing is off when they are placed and while walking so it doesnt matter how close they are, it could be 0 if you want, but the pathing does turn back on when an enemy of the unit comes within 800 range

after you do that, create a trigger named: Roman Formation
convert it to custom text, select everything inside
delete all that junk, and past this in it:

JASS:
library RomanFormation requires AIDS initializer OnInit
    struct Romans extends array
        location RomanTarget
        integer RomanGroupNumber
        trigger RomanTrigger
        trigger RomanRangeTrigger
        //! runtextmacro AIDS()
    endstruct
    
    struct RomanGroups
        group RomanGroup
        location RomanGroupTarget
        integer RomanStopCount
    endstruct
    
    globals
        integer array RecycleList
        integer NewGroupIndex = 0
        integer LastRecycled = 0
        integer ArrivalGroup = 0
    endglobals
    
    function GroupRecycler takes nothing returns integer
        local integer i
        if (RecycleList[0] != 0) then
            set i = RecycleList[0]
            set RecycleList[0] = RecycleList<i>
            set RecycleList<i> = 0
            if (RecycleList[0] = 0) then
                set LastRecycled = 0
            endif
        else
            set i = NewGroupIndex
            set NewGroupIndex = NewGroupIndex + 1
        endif
        if (i &lt; 8190) then
            return i
        else
            BJDebugMsg(&quot;You have too god damn many groups, just hit 8190 unit groups&quot;)
        endif
        return null
    endfunction
    
    private function Conditions takes nothing returns boolean
        if (GetIssuedOrderId() = 851972) then
            set (GetUnitID(GetTriggerUnit()).RomanGroupNumber).RomanStopCount = (GetUnitID(GetTriggerUnit()).RomanGroupNumber).RomanStopCount + 1
            if ((GetUnitID(GetTriggerUnit()).RomanGroupNumber).RomanStopCount = 23) then
                set (GetUnitID(GetTriggerUnit()).RomanGroupNumber).RomanStopCount = 0
                set ArrivalGroup = GetUnitID(GetTriggerUnit()).RomanGroupNumber
                set udg_Arival_Point = (GetUnitID(GetTriggerUnit()).RomanGroupNumber).RomanGroupTarget
                set udg_Arival_Event = 0.0
                set udg_Arival_Event = 1.0
            endif
        endif
    endfunction
    
    private function OnInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterPlayerUnitEvent(t, Player(udg_EnemyPlayerNumber), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
        call TriggerAddCondition(t, Filter(function Conditions))
        call TriggerAddAction(t, function Actions)
        set t = null
    endfunction
    
//this next function (NewTarget) orders all the units that just arrived at their target
//point to attack their next supplied point, this is not mui if waits are used, you must
//make it an instant trigger.  Use this custom script to call this function:
//Custom Script: call NewTarget(udg_NewTargetLocationVariable)
    function NewTarget takes location a returns nothing
        local group b = ArrivalGroup.RomanGroup
        local location c
        local unit d
        local real e
        local real f
        loop
            exitwhen (FirstOfGroup(b) == null)
            call ForGroup(b, function GroupPickRandomUnitEnum)
            set d = FirstOfGroup(b)
            set c = GetUnitLoc(d)
            set e = SquareRoot((GetLocationX(ArrivalGroup.RomanGroupTarget)-GetLocationX(a))*(GetLocationY(ArrivalGroup.RomanGroupTarget)-GetLocationY(a)))
            set f = bj_RADTODEG * Atan2(GetLocationY(a) - GetLocationY(ArrivalGroup.RomanGroupTarget), GetLocationX(a) - GetLocationX(ArrivalGroup.RomanGroupTarget))) * bj_DEGTORAD
            call IssuePointOrder(d, &quot;attack&quot;, GetLocationX(c) + (e * Cos(f)), GetLocationY(c) + (e * Sin(f)))
            call GroupRemoveUnit(b,d)
        endloop
        set ArrivalGroup.RomanGroupTarget = a
        call DestroyGroup(b)
        set b = null
        set c = null
        set d = null
    endfunction
    
    function DeathActions takes nothing returns nothing
        if (GetPlayerId(GetOwningPlayer(GetTriggerUnit())) == (udg_EnemyPlayerNumber - 1)) then
            call GroupRemoveUnit((GetUnitID(GetTriggerUnit()).RomanGroupNumber).RomanGroup, GetTriggerUnit())
            if (FirstOfGroup((GetUnitID(GetTriggerUnit()).RomanGroupNumber).RomanGroup == null) then
                call RomanGroups.destroy(GetUnitID(GetTriggerUnit()).RomanGroupNumber)
                set RecycleList[LastRecycled] = GetUnitID(GetTriggerUnit()).RomanGroupNumber
                set LastRecycled = GetUnitID(GetTriggerUnit()).RomanGroupNumber
            endif
            call DestroyTrigger(GetUnitID(u).RomanTrigger)
        endif
    endfunction
        
    function RangeActions takes unit u returns nothing
        call SetUnitPathing(u, true)
        call DestroyTrigger(GetUnitID(u).RomanRangeTrigger)
    endfunction

//this function creates the romans at a location then orders them to attack to their
//relative target location, you can use it with:
//Custom Script: call SpawnRomans(startlocation,targetlocation)
    function SpawnRomans takes location a, location b returns nothing
        local real r = bj_RADTODEG * Atan2(GetLocationY(b) - GetLocationY(a), GetLocationX(b) - GetLocationX(a)
        local location array rows[5]
        local integer i = 1
        local integer i2
        local integer Group_Number = RomanGroups.Create(GroupRecycler())
        local location L
        local unit u
        loop
            exitwhen i &gt; 5
            if (i == 1) then
                set rows[0] = Location(GetLocationX(a) + (((3.5 x udg_RomanSpawnDistance) - (udg_RomanSpawnDistance x I2R(i))) * Cos((r) * bj_DEGTORAD), GetLocationY(a) + (((3.5 x udg_RomanSpawnDistance) - (udg_RomanSpawnDistance x I2R(i))) * Sin((r) * bj_DEGTORAD))
            else
                set rows[i-1] = Location(GetLocationX(a) + (((3.0 x udg_RomanSpawnDistance) - (udg_RomanSpawnDistance x I2R(i))) * Cos((r) * bj_DEGTORAD), GetLocationY(a) + (((3.0 x udg_RomanSpawnDistance) - (udg_RomanSpawnDistance x I2R(i))) * Sin((r) * bj_DEGTORAD))
            endif
            set i2 = 1
            if (i == 1) then
                loop
                    exitwhen i2 &gt; 3
                    set L = Location(GetLocationX(rows[i-1]) + (udg_RomanSpawnDistance * Cos((r + 90.0) * bj_DEGTORAD), GetLocationY(rows[i-1]) + (udg_RomanSpawnDistance * Sin((r + 90.0) * bj_DEGTORAD))
                    set u = CreateUnit((udg_EnemyPlayerNumber - 1), udg_LeaderUnit, GetLocationX(L), GetLocationY(L), r)
                    call SetUnitPathing(u, false)
                    set GetUnitID(u).RomanTarget = Location(GetLocationX(L) + (SquareRoot((GetLocationX(a)-GetLocationX(b))*(GetLocationY(a)-GetLocationY(b))) * Cos((r) * bj_DEGTORAD), GetLocationY(L) + (SquareRoot((GetLocationX(a)-GetLocationX(b))*(GetLocationY(a)-GetLocationY(b))) * Sin((r) * bj_DEGTORAD))
                    set GetUnitID(u).RomanGroupNumber = Group_Number
                    set GetUnitID(u).RomanTrigger = CreateTrigger()
                    set GetUnitID(u).RomanRangeTrigger = CreateTrigger()
                    call GroupAddUnit(Group_Number.RomanGroup, u)
                    call IssuePointOrder(u, &quot;attack&quot;, GetLocationX(GetUnitID(u).RomanTarget), GetLocationY(GetUnitID(u).RomanTarget)
                    call TriggerRegisterPlayerUnitEvent(GetUnitID(u).RomanTrigger, Player(udg_EnemyPlayerNumber), EVENT_PLAYER_UNIT_DEATH, null)
                    call TriggerRegisterUnitInRange(GetUnitID(u).RomanRangeTrigger, u, 800, null)
                    call TriggerAddAction(GetUnitID(u).RomanTrigger, function Actions)
                    call TriggerAddAction(GetUnitID(u).RomanRangeTrigger, function Actions2(u))
                    set i2 = i2 + 1
                endloop
            else
                loop
                    exitwhen i2 &gt; 5
                    set L = Location(GetLocationX(rows[i-1]) + (udg_RomanSpawnDistance * Cos((r + 90.0) * bj_DEGTORAD), GetLocationY(rows[i-1]) + (udg_RomanSpawnDistance * Sin((r + 90.0) * bj_DEGTORAD))
                    set u = CreateUnit((udg_EnemyPlayerNumber - 1), udg_BasicUnit, GetLocationX(L), GetLocationY(L), r)
                    call SetUnitPathing(u, false)
                    set GetUnitID(u).RomanTarget = Location(GetLocationX(L) + (SquareRoot((GetLocationX(a)-GetLocationX(b))*(GetLocationY(a)-GetLocationY(b))) * Cos((r) * bj_DEGTORAD), GetLocationY(L) + (SquareRoot((GetLocationX(a)-GetLocationX(b))*(GetLocationY(a)-GetLocationY(b))) * Sin((r) * bj_DEGTORAD))
                    set GetUnitID(u).RomanGroupNumber = Group_Number
                    set GetUnitID(u).RomanTrigger = CreateTrigger()
                    set GetUnitID(u).RomanRangeTrigger = CreateTrigger()
                    call GroupAddUnit(Group_Number.RomanGroup, u)
                    call IssuePointOrder(u, &quot;attack&quot;, GetLocationX(GetUnitID(u).RomanTarget), GetLocationY(GetUnitID(u).RomanTarget)
                    call TriggerRegisterPlayerUnitEvent(GetUnitID(u).RomanTrigger, Player(udg_EnemyPlayerNumber), EVENT_PLAYER_UNIT_DEATH, null)
                    call TriggerRegisterUnitInRange(GetUnitID(u).RomanRangeTrigger, u, 800, null)
                    call TriggerAddAction(GetUnitID(u).RomanTrigger, function DeathActions)
                    call TriggerAddAction(GetUnitID(u).RomanRangeTrigger, function RangeActions(u))
                    set i2 = i2 + 1
                endloop
            endif
            set rows[i-1] = null
            set i = i + 1
        endloop
        set L = null
        set u = null
        set Group_Number.RomanGroupTarget = b
    endfunction
endlibrary</i></i>
 

Dirac

22710180
Reaction score
147
G your library is extermely broken.

Stuff like [ljass]private function OnInit takes nothing returns nothing[/ljass] don't need to run on initialization, you have to declare it in the scope: [ljass]scope TargetReachedTrigger initializer OnInit[/ljass] also on the thread at the JASS section i made a comment on how broken your current group recycler is.
You're also using many scopes for a single library when you shouldn't even use one.
Also, have you tested it?
 

GFreak45

I didnt slap you, i high 5'd your face.
Reaction score
130
do you think about the way you say things before you say them?
ill fix that, no1 brought it up in my thread, im using 2 scopes simply to organize 2 trigger sets, for nothing more, i cant test it AIDS wont work on my computer, every single time regardless of what newgen i use i get syntax errors for it, and yes i have the most recent one, and i fixed the recycler, maybe i made this post before i did so, i was about to say nice catch in the other thread but damn dude
 

Dirac

22710180
Reaction score
147
I keep reading my post and i see nothing wrong with it.
You're providing a broken resource and it's your job to fix it before posting it.
If i point out that something is broken about it take a keen look into it.

Delete the scope names, put all the functions inside the same library.
You don't have to declare array sizes in JASS.
No one said anything about your code in the JASS section because no one took a deep look into it, they just pointed out errors in your way to write the code, and i'm surprised that the scope thing didn't came up.
You also forgot to explain how does your system works or how to use it, you can't expect a GUI user to get anything from what's written there without a good documentation or at least the API posted at the top.
In the thread they also said this but i repeat it: don't use locations, use reals.
 

GFreak45

I didnt slap you, i high 5'd your face.
Reaction score
130
G your library is extermely broken.

this. its a plainly dickish comment and you have one in almost every single post, i mean come on dude i see people get irritated at you all the time for shit like that, including TooltipError
you might as well say, your work is shit delete it and start over

I was never told scopes shouldnt be inside libraries, why should they not, and how do you create triggers that are needed from init when the function is never called? btw i did delete the scope at the bottom of the library and fixed the other one around the middle so now its: [ljass]scope whatever initializer OnInit[/ljass]
i know i need to fix it and i have been, if its broken that is
the system was explained perfectly above if you read the whole thread and he understood how to use it before i posted it
i will next time but changing all of this to reals from locations will take too long and im just plain out of time for the weekend and during the week i get almost no time to do anything but browse the internet at work while i work (no editor) and school right after so ill change that next weekend and update it

so how should i initialize functions that create triggers needed from the start if they arent in scopes?
 

Dirac

22710180
Reaction score
147
you might as well say, your work is shit delete it and start over
You're right, i might as well just said that, but i was being polite, and it was indeed, very broken as it didn't work properly

libraries can also be initialized
JASS:
library TEST initializer onInit


structs have a default initialization method name
JASS:
struct TEST
    static method onInit takes nothing returns nothing
    endmethod
endstruct


It amazes me that scopes inside libraries would even compile.
 

GFreak45

I didnt slap you, i high 5'd your face.
Reaction score
130
and you wonder why you have trouble getting your resources approved eventhough they actually are pretty well written as far as i can tell

i removed the scopes completely
fixed the recycler
removed all BJs
anything else i should do to it before it is acceptable? other than changing the locations to reals which ill do this weekend
 

merlinds

Member
Reaction score
15
Dear lord! i better let my soldiers go the way they want! i never though it was so complicated guys.
But thank you both any way!!
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top