• 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] Recalc Starting Positions

Status
Not open for further replies.
The reason i reclac the starting positions is, I change the teams inside a map Init Trigger, which should load after the placing. So the starting locations would be quite random and teams are complettly splited in most times.
Therefore I wrote that Jass Script changing the used starting positions for all Players, placing Teams together. Often it produces good results, but othertimes one team is placed completly unfair.

Like in this pictures:

Bad 2.png
Team Teal isn't placed together.

or in that one:

TheQueensGarden bad Random.png
Team Purple is not placed Together.

I also tested the maps with the default Blizzard Team-placement (1.30) which also produces this situtations.
The question would be how would one avoid such situation or if that would be to costly how would one detect such a situation in most cases/maps and just redo the whole starting position.​

Or does it not matter at all and that error is just who cares?


JASS:
function CalcStartingLocs takes nothing returns nothing
   local integer LoopAlly = 0
   local integer LoopPrim = 0
   local integer LoopLoc = 0
   local force isPlaced = CreateForce()
   local integer array startLocations
   local integer startLocationsLast = -1
   local integer random
   local real distance
   local real dx
   local real dy
   local real newDistance
   local integer neareastLocIndex
   loop
       exitwhen LoopPrim == GetPlayers()
       set startLocations[LoopPrim] = LoopPrim
       set startLocationsLast = startLocationsLast + 1
       set LoopPrim = LoopPrim + 1
   endloop
   set LoopPrim = 0
   loop
      exitwhen LoopPrim == GetPlayers()
      if IsPlayerInForce(Player(LoopPrim), bj_FORCE_ALL_PLAYERS) then //Valid Player
          if not IsPlayerInForce(Player(LoopPrim), isPlaced) then // not placed yet
              set random = GetRandomInt(0, startLocationsLast)
              call SetPlayerStartLocation(Player(LoopPrim), startLocations[random])
           
              set startLocations[random] = startLocations[startLocationsLast]
              set startLocationsLast = startLocationsLast - 1
              call ForceAddPlayer(isPlaced, Player(LoopPrim))
              set LoopAlly = LoopPrim + 1
              //Loop Further Players
              //Find allies and give them a nearby Location.
              loop
                  exitwhen LoopAlly == GetPlayers()
                  if IsPlayerInForce(Player(LoopPrim), bj_FORCE_ALL_PLAYERS) then //Valid Player
                      if IsPlayerAlly(Player(LoopPrim), Player(LoopAlly)) and not IsPlayerInForce(Player(LoopAlly), isPlaced) then
                          set LoopLoc = 0
                          set distance = 9999999
                          set neareastLocIndex = -1
                          loop // Find nearest
                              exitwhen LoopLoc > startLocationsLast
                              //check nearer
                              set dx = GetStartLocationX(startLocations[LoopLoc]) - GetStartLocationX(GetPlayerStartLocation(Player(LoopPrim)))
                              set dy = GetStartLocationY(startLocations[LoopLoc]) - GetStartLocationY(GetPlayerStartLocation(Player(LoopPrim)))
                              set newDistance = SquareRoot(dx * dx + dy * dy)
                              if newDistance < distance then
                                  set distance = newDistance
                                  set neareastLocIndex = LoopLoc
                              endif
                              set LoopLoc = LoopLoc + 1
                          endloop 
                          call SetPlayerStartLocation(Player(LoopAlly), startLocations[neareastLocIndex])
                          set startLocations[neareastLocIndex] = startLocations[startLocationsLast]
                          set startLocationsLast = startLocationsLast - 1
                          call ForceAddPlayer(isPlaced, Player(LoopAlly))
                      endif
                  endif
                  set LoopAlly = LoopAlly + 1
              endloop
          endif
      endif 
      set LoopPrim = LoopPrim + 1
   endloop
   call DestroyForce(isPlaced)
   set isPlaced = null
endfunction
 
Maybe placing teams in steps would help:
  1. Team_1 gets 1 random place
  2. Look for a 1 more close place for Team_1 ( =distance_1)

  3. Team_2 gets a random place
  4. Look for 1 more close place for Team 2 ( =distance_2)

    If distance_2 is too much different from distance_1 go back one step (to step 3), and try other places.
    If step 3 was repeated with all possibilitiesa, and nothing works, go back one step again (step 2), and try next locations.
This would be repeated for all teams, and always only 1 new player for a team would be placed per iteration. If 1 newly added player place for any team is too different from others, always go back and try until all possebilities are tried.
But with these heuristics you maybe also won't ever find a truely fair placing for teams, and need to be prepared for such situations what to do if .. no possiblity seems fair, 1 team is always disadvantaged.. it might be quite a good lot of work I believe to make it more ore less balanced for "all" cases.

What I did in my map, has a con, because I manually defined team positions at init after knowing teams and player amount, but this ensured me I could have always wanted forms that were acceptable for teams. For a very lot of positions it would mean more setup work, but imo maybe still fine. With manually grouping places, one could also consider taking not only "distance" into account, but can just consider every other possible aspect, too. (unless you explicitly want not to put config work in here)
 
Status
Not open for further replies.
Top