• 🏆 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] Random Teams

RandomTeams is a function, teaming up all Players into random Teams each having an equal amount of players.

JASS:
// Allies Players of a force (playergroup) into random teams each team having teamSize number of players.
// The last team will have less players, if there are not enough players.
// Won't ally players, if all players would be placed into 1 Team.
// playerPool   - the players from which the teams are formed. (use null or bj_FORCE_ALL_PLAYERS to include all Players)
// teamSize    - the amount of players in each team.
//   returns the last player of the last team, if it has not the wanted amount of players.
//           in other cases returns null
function RandomTeams takes force playerPool, integer teamSize returns player
   local integer LoopA = bj_MAX_PLAYER_SLOTS
   local player array unteamedPlayer
   local integer unteamedPlayerSize = 0
   local integer currentTeamMemberCount = 0
   local integer random
   local force currentTeam
   local player lastAddedPlayer

   if playerPool == null then //For lacy people
       set playerPool = bj_FORCE_ALL_PLAYERS
   endif
   call SetForceAllianceStateBJ( playerPool, playerPool, bj_ALLIANCE_UNALLIED )
   // Load All Players into an Array
   loop
       if IsPlayerInForce(Player(LoopA), playerPool) and IsPlayerInForce(Player(LoopA), bj_FORCE_ALL_PLAYERS) then   //Pick only playing players
           set unteamedPlayerSize = unteamedPlayerSize + 1
           set unteamedPlayer[unteamedPlayerSize] = Player(LoopA)
       endif      
       exitwhen LoopA == 0
       set LoopA = LoopA - 1
   endloop
  
   // skip remaining actions if all players would be placed in one team.
   if unteamedPlayerSize <= teamSize or teamSize < 2 then
        return null
   endif
  
   set currentTeam = CreateForce()
   // Add 1 Random Player to current Team
   // If current Team has enough members switch to next team
   loop
       set random = GetRandomInt(1, unteamedPlayerSize)
       call ForceAddPlayer(currentTeam, unteamedPlayer[random])
       set lastAddedPlayer = unteamedPlayer[random]
       set currentTeamMemberCount = currentTeamMemberCount + 1
       set unteamedPlayer[random] = unteamedPlayer[unteamedPlayerSize]
       set unteamedPlayerSize = unteamedPlayerSize - 1
       if currentTeamMemberCount == teamSize or unteamedPlayerSize == 0 then
           call SetForceAllianceStateBJ( currentTeam, currentTeam, bj_ALLIANCE_ALLIED_VISION )    // bj_ALLIANCE_ALLIED  bj_ALLIANCE_ALLIED_VISION  bj_ALLIANCE_ALLIED_UNITS bj_ALLIANCE_ALLIED_ADVUNITS  
           call ForceClear(currentTeam)
           if unteamedPlayerSize != 0 then   //if there are further players reset currentTeamMemberCount
               set currentTeamMemberCount = 0
           endif
       endif
       exitwhen unteamedPlayerSize == 0
   endloop
  
   call DestroyForce(currentTeam)
   set currentTeam = null
   if currentTeamMemberCount != teamSize then   //last Team has not teamSize amount of members?
       return lastAddedPlayer
   else
       return null
   endif
endfunction

ChangeLog:
Added a Force argument, teams are formed out of players from that force.
unteamedPlayer integer -> player
returns now a player: the last added Player, if the last team does not have the wanted amount of members. In other cases null.​
 
Last edited:
Maybe a boolean param with allowing CPUs would be useful.

If for example there are reserved slots for a special enemy, or neutral position, one might want to exlcude certain players from being teamed.
With user giving a force as param, this could work, and if really all players should be teamed, then he can make just use bj_FORCE_ALL_PLAYERS.

player array would be slightly more straight forward > integer array ^^ (also nulling player would not be required)
 
Not sure what you mean with CPU? Should that be an argument to dis/allow teams mixed of users and bots?
My bad, I thought if "false", then all comp players will be completly ignored and not put in any team. This would be a lazy way to ban comps from whitelist in case "ALL_PLAYERS" is given as param

But also your idea, possibly trying to avoid comps in a human-team sounds good.
 
Updated the code inside the first post. It now uses an force argument, only players in this force are considered for teaming.
If one wants bot only teams one should consider the function from blizzard.j: "GetPlayersByMapControl(MAP_CONTROL_COMPUTER)" or "GetPlayersByMapControl(MAP_CONTROL_USER)" for user only teams.
 

Jampion

Code Reviewer
Level 15
Joined
Mar 25, 2016
Messages
1,327
Looks good to me.
I am not really familiar with local arrays. Do you have to null them like normal variables?

I was thinking if it would be a good idea to return the last team, if it is smaller than the other teams. Since there is no return value right now you could add something.
If you have access to the smaller team you could give them some kind of advantage in your map for example.

It would be best, if the user had access to all teams after using this functions, but I think that is not easily possible in JASS.
 
It would be best, if the user had access to all teams after using this functions, but I think that is not easily possible in JASS.
That would reqiuer a global variable, cause one can't return an array. Actually the first verison saved the teams in a global force array, but somehow wanted to make that simple copy paste and decided for the current version.

I was thinking if it would be a good idea to return the last team, if it is smaller than the other teams. Since there is no return value right now you could add something.
If you have access to the smaller team you could give them some kind of advantage in your map for example.
Done by returning the last added Player, if the last team has not the wanted amount of members. In other cases return null.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
For best results, I would recommend automating this and waiting until 0 seconds of game time, then you can check who is actually a player and who is playing, then automatically split the results based on a constant integer specifying the number of teams. Then, when a player leaves, there could be an option that this system could automatically re-shuffle the players, which would lead to some very awkward results.

Of course, the user could just call this function. But I'd recommend that you incorporate at least a zero second timer and some minor automation.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
I'm surprised that this isn't built into WarCraft 3. It seems essential. How does it factor in with earlier discussion about start locations? Creating Random Teams

I saw some funny attempts here: How do I make random even teams?

Alas, as this is a JASS function, you'll want to wrap it in a library or write the code in GUI.
 
Top