/// <summary> /// Primary method - processes commands from server /// </summary> /// <param name="command">command name</param> /// <param name="args">command arguments</param> private void DispatchServerCommand(string command, string[] args) { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; try { switch (command) { case "TASServer": // happens after connecting to server serverVersion = args[0]; int.TryParse(args[2], out serverUdpHolePunchingPort); isConnected = true; if (Connected != null) Connected(this, new TasEventArgs()); break; case "ACCEPTED": // Login accepted username = args[0]; isLoggedIn = true; if (LoginAccepted != null) LoginAccepted(this, new TasEventArgs()); break; case "DENIED": // login denied isLoggedIn = false; if (LoginDenied != null) LoginDenied(this, new TasEventArgs(Utils.Glue(args))); break; case "JOIN": // channel joined if (!joinedChannels.ContainsKey(args[0])) joinedChannels.Add(args[0], Channel.Create(args[0])); if (ChannelJoined != null) ChannelJoined(this, new TasEventArgs(args)); break; case "JOINFAILED": // channel join failed if (ChannelJoinFailed != null) ChannelJoinFailed(this, new TasEventArgs(Utils.Glue(args))); break; case "CHANNEL": // iterating channels { var c = new ExistingChannel(); c.name = args[0]; int.TryParse(args[1], out c.userCount); if (args.Length >= 3) c.topic = Utils.Glue(args, 2); existingChannels.Add(c.name, c); } break; case "ENDOFCHANNELS": // end of channel list iteration isChanScanning = false; if (ChannelListDone != null) ChannelListDone(this, new TasEventArgs()); break; case "ADDUSER": // new user joined ta server { var u = User.Create(args[0]); u.country = args[1]; int.TryParse(args[2], out u.cpu); //IPAddress.TryParse(args[3], out u.ip); existingUsers.Add(u.name, u); if (UserAdded != null) UserAdded(this, new TasEventArgs(args)); } break; case "REMOVEUSER": // user left ta server existingUsers.Remove(args[0]); if (UserRemoved != null) UserRemoved(this, new TasEventArgs(args)); break; case "MOTD": // server motd if (Said != null && args.Length > 0) Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Server, TasSayEventArgs.Places.Motd, "", "", Utils.Glue(args, 0), false)); break; case "SERVERMSG": // server message if (Said != null) Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Server, TasSayEventArgs.Places.Normal, "", "", Utils.Glue(args, 0), false)); break; case "SERVERMSGBOX": // server messagebox if (Said != null) Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Server, TasSayEventArgs.Places.MessageBox, "", "", Utils.Glue(args, 0), false)); break; case "CHANNELMESSAGE": // server broadcast to channel if (Said != null) Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Server, TasSayEventArgs.Places.Channel, args[0], "", Utils.Glue(args, 1), false)); break; case "SAID": // someone said something in channel if (Said != null) Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Player, TasSayEventArgs.Places.Channel, args[0], args[1], Utils.Glue(args, 2), false)); break; case "SAIDEX": // someone said something with emote in channel if (Said != null) Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Player, TasSayEventArgs.Places.Channel, args[0], args[1], Utils.Glue(args, 2), true)); break; case "SAYPRIVATE": // sent back from sever when user sends private message if (Said != null) Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Player, TasSayEventArgs.Places.Normal, args[0], username, Utils.Glue(args, 1), false)); // channel = char partner name break; case "SAIDPRIVATE": // someone said something to me if (Said != null) Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Player, TasSayEventArgs.Places.Normal, args[0], args[0], Utils.Glue(args, 1), false)); break; case "SAIDBATTLE": // someone said something in battle if (Said != null) Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Player, TasSayEventArgs.Places.Battle, "", args[0], Utils.Glue(args, 1), false)); break; case "SAIDBATTLEEX": // someone said in battle with emote if (Said != null) Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Player, TasSayEventArgs.Places.Battle, "", args[0], Utils.Glue(args, 1), true)); break; case "BROADCAST": // server sends urgent broadcast if (Said != null) Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Server, TasSayEventArgs.Places.Broadcast, "", "", Utils.Glue(args, 0), false)); break; case "REDIRECT": // server sends backup IP // removed due to bugs break; case "CLIENTSTATUS": // client's status changed { int status = 0; int.TryParse(args[1], out status); var u = existingUsers[args[0]]; u.FromInt(status); if (u.name == UserName && (u.isInGame && existingUsers[args[0]].isInGame == false)) { existingUsers[args[0]] = u; if (MyStatusChangedToInGame != null) MyStatusChangedToInGame(this, new TasEventArgs()); } existingUsers[args[0]] = u; if (UserStatusChanged != null) UserStatusChanged(this, new TasEventArgs(args)); } break; case "CLIENTS": // client list sent after channel join var usrs = Utils.Glue(args, 1).Split(' '); foreach (var s in usrs) joinedChannels[args[0]].channelUsers.Add(s); if (ChannelUserAdded != null) ChannelUserAdded(this, new TasEventArgs(args[0])); break; case "JOINED": // user joined one of my channels joinedChannels[args[0]].channelUsers.Add(args[1]); if (ChannelUserAdded != null) ChannelUserAdded(this, new TasEventArgs(args[0])); break; case "LEFT": // user left one of my channels joinedChannels[args[0]].channelUsers.Remove(args[1]); if (ChannelUserRemoved != null) ChannelUserRemoved(this, new TasEventArgs(args[0], args[1], Utils.Glue(args, 2))); break; case "CHANNELTOPIC": // channel topic update (after joining a channel) { var c = joinedChannels[args[0]]; c.topicSetBy = args[1]; c.topicSetDate = ConvertMilisecondTime(args[2]); c.topic = Utils.Glue(args, 3); if (ChannelTopicChanged != null) ChannelTopicChanged(this, new TasEventArgs(args[0])); } break; case "OPENBATTLEFAILED": // opening new battle has failed if (BattleOpenFailed != null) BattleOpenFailed(this, new TasEventArgs(Utils.Glue(args))); break; case "OPENBATTLE": // openbattle ok { battleID = int.Parse(args[0]); var self = new UserBattleStatus(username); self.IsSpectator = true; battle.Users.Add(self); // add self UpdateBattleDetails(battle.Details); if (BattleOpened != null) BattleOpened(this, new TasEventArgs(args[0])); } break; case "REQUESTBATTLESTATUS": // server asks us to update our status con.SendCommand(0, "MYBATTLESTATUS", 1 << 22, 0); // tell server that we are synchronized spectators break; case "JOINEDBATTLE": // user joined the battle if (battle != null && int.Parse(args[0]) == battleID) { battle.Users.Add(new UserBattleStatus(args[1])); if (BattleUserJoined != null) BattleUserJoined(this, new TasEventArgs(args[1])); } break; case "ADDBOT": // bot added to battle if (battle != null && int.Parse(args[0]) == battleID) { var bs = new BotBattleStatus(args[1], args[2], Utils.Glue(args, 5)); bs.SetFrom(int.Parse(args[3]), int.Parse(args[4])); battle.Bots.Add(bs); } break; case "REMOVEBOT": // bot removed from battle if (battle != null && int.Parse(args[0]) == battleID) battle.Bots.RemoveAll(delegate(BotBattleStatus bot) { return bot.name == args[1]; }); break; case "UPDATEBOT": // bot data changed if (battle != null && int.Parse(args[0]) == battleID) { var st = battle.Bots.Find(delegate(BotBattleStatus bot) { return bot.name == args[1]; }); if (st != null) st.SetFrom(int.Parse(args[2]), int.Parse(args[3])); } break; case "LEFTBATTLE": // user left the battle if (battle != null && int.Parse(args[0]) == battleID) { battle.RemoveUser(args[1]); UpdateSpectators(); if (BattleUserLeft != null) BattleUserLeft(this, new TasEventArgs(args[1])); if (args[1] == username) { battle = null; battleID = 0; if (BattleClosed != null) BattleClosed(this, new TasEventArgs()); } } break; case "CLIENTBATTLESTATUS": // player battle status has changed if (battle != null) { int uindex = battle.GetUserIndex(args[0]); if (uindex != -1) { var bs = battle.Users[uindex]; bs.SetFrom(int.Parse(args[1]), int.Parse(args[2])); battle.Users[uindex] = bs; UpdateSpectators(); if (BattleUserStatusChanged != null) BattleUserStatusChanged(this, new TasEventArgs(args[0])); } } break; case "UPDATEBATTLEINFO": // update external battle info (lock and map) if (battle != null && int.Parse(args[0]) == battleID) { string mapname = Utils.Glue(args, 4); if (battle.Map.Name != mapname) { if (mapToChangeTo != null && mapToChangeTo.Name == mapname) { // if we changed to known requested map, use it battle.Map = mapToChangeTo; } else battle.Map = Program.main.Spring.UnitSync.MapList[mapname]; //otherwise find this map using unitsync if (BattleMapChanged != null) BattleMapChanged(this, new TasEventArgs(mapname)); } if (battle.IsLocked != int.Parse(args[2]) > 0) { battle.IsLocked = int.Parse(args[2]) > 0; if (BattleLockChanged != null) BattleLockChanged(this, new TasEventArgs(args[2])); } } break; case "BATTLEOPENED": { if (BattleFound != null) BattleFound(this, new TasEventArgs(args)); break; } case "CLIENTIPPORT": if (battle != null) { int idx = battle.GetUserIndex(args[0]); if (idx != -1) { var bs = battle.Users[idx]; bs.ip = IPAddress.Parse(args[1]); bs.port = int.Parse(args[2]); battle.Users[idx] = bs; if (BattleUserIpRecieved != null) BattleUserIpRecieved(this, new TasEventArgs(args)); } } break; case "SETSCRIPTTAGS": // updates internal battle details if (battle != null) { var bd = new BattleDetails(); bd.Parse(Utils.Glue(args), battle.ModOptions); battle.Details = bd; if (BattleDetailsChanged != null) BattleDetailsChanged(this, new TasEventArgs(args)); } break; case "UDPSOURCEPORT": udpPunchingTimer.Stop(); if (startingAfterUdpPunch) { startingAfterUdpPunch = false; if (battle != null) { // send UDP packets to client (2x to be sure) foreach (var ubs in battle.Users) if (ubs.ip != IPAddress.None && ubs.port != 0) SendUdpPacket(lastUdpSourcePort, ubs.ip, ubs.port); foreach (var ubs in battle.Users) if (ubs.ip != IPAddress.None && ubs.port != 0) SendUdpPacket(lastUdpSourcePort, ubs.ip, ubs.port); battle.HostPort = lastUdpSourcePort; // update source port for hosting and start it ChangeMyStatus(false, true); } } break; } } catch (Exception e) { if (!ErrorHandling.HandleException(e, "Exception while dispatching " + command + " " + Utils.Glue(args))) throw e; } ; }
public GrTeam(int leader) { bot = null; this.leader = leader; }
/// <summary> /// Primary method - processes commands from server /// </summary> /// <param name="command">command name</param> /// <param name="args">command arguments</param> private void DispatchServerCommand(string command, string[] args) { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; try { switch (command) { case "TASServer": // happens after connecting to server serverVersion = args[0]; int.TryParse(args[2], out serverUdpHolePunchingPort); isConnected = true; if (Connected != null) { Connected(this, new TasEventArgs()); } break; case "ACCEPTED": // Login accepted username = args[0]; isLoggedIn = true; if (LoginAccepted != null) { LoginAccepted(this, new TasEventArgs()); } break; case "DENIED": // login denied isLoggedIn = false; if (LoginDenied != null) { LoginDenied(this, new TasEventArgs(Utils.Glue(args))); } break; case "JOIN": // channel joined if (!joinedChannels.ContainsKey(args[0])) { joinedChannels.Add(args[0], Channel.Create(args[0])); } if (ChannelJoined != null) { ChannelJoined(this, new TasEventArgs(args)); } break; case "JOINFAILED": // channel join failed if (ChannelJoinFailed != null) { ChannelJoinFailed(this, new TasEventArgs(Utils.Glue(args))); } break; case "CHANNEL": // iterating channels { var c = new ExistingChannel(); c.name = args[0]; int.TryParse(args[1], out c.userCount); if (args.Length >= 3) { c.topic = Utils.Glue(args, 2); } existingChannels.Add(c.name, c); } break; case "ENDOFCHANNELS": // end of channel list iteration isChanScanning = false; if (ChannelListDone != null) { ChannelListDone(this, new TasEventArgs()); } break; case "ADDUSER": // new user joined ta server { var u = User.Create(args[0]); u.country = args[1]; int.TryParse(args[2], out u.cpu); //IPAddress.TryParse(args[3], out u.ip); existingUsers.Add(u.name, u); if (UserAdded != null) { UserAdded(this, new TasEventArgs(args)); } } break; case "REMOVEUSER": // user left ta server existingUsers.Remove(args[0]); if (UserRemoved != null) { UserRemoved(this, new TasEventArgs(args)); } break; case "MOTD": // server motd if (Said != null && args.Length > 0) { Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Server, TasSayEventArgs.Places.Motd, "", "", Utils.Glue(args, 0), false)); } break; case "SERVERMSG": // server message if (Said != null) { Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Server, TasSayEventArgs.Places.Normal, "", "", Utils.Glue(args, 0), false)); } break; case "SERVERMSGBOX": // server messagebox if (Said != null) { Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Server, TasSayEventArgs.Places.MessageBox, "", "", Utils.Glue(args, 0), false)); } break; case "CHANNELMESSAGE": // server broadcast to channel if (Said != null) { Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Server, TasSayEventArgs.Places.Channel, args[0], "", Utils.Glue(args, 1), false)); } break; case "SAID": // someone said something in channel if (Said != null) { Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Player, TasSayEventArgs.Places.Channel, args[0], args[1], Utils.Glue(args, 2), false)); } break; case "SAIDEX": // someone said something with emote in channel if (Said != null) { Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Player, TasSayEventArgs.Places.Channel, args[0], args[1], Utils.Glue(args, 2), true)); } break; case "SAYPRIVATE": // sent back from sever when user sends private message if (Said != null) { Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Player, TasSayEventArgs.Places.Normal, args[0], username, Utils.Glue(args, 1), false)); // channel = char partner name } break; case "SAIDPRIVATE": // someone said something to me if (Said != null) { Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Player, TasSayEventArgs.Places.Normal, args[0], args[0], Utils.Glue(args, 1), false)); } break; case "SAIDBATTLE": // someone said something in battle if (Said != null) { Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Player, TasSayEventArgs.Places.Battle, "", args[0], Utils.Glue(args, 1), false)); } break; case "SAIDBATTLEEX": // someone said in battle with emote if (Said != null) { Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Player, TasSayEventArgs.Places.Battle, "", args[0], Utils.Glue(args, 1), true)); } break; case "BROADCAST": // server sends urgent broadcast if (Said != null) { Said(this, new TasSayEventArgs(TasSayEventArgs.Origins.Server, TasSayEventArgs.Places.Broadcast, "", "", Utils.Glue(args, 0), false)); } break; case "REDIRECT": // server sends backup IP // removed due to bugs break; case "CLIENTSTATUS": // client's status changed { int status = 0; int.TryParse(args[1], out status); var u = existingUsers[args[0]]; u.FromInt(status); if (u.name == UserName && (u.isInGame && existingUsers[args[0]].isInGame == false)) { existingUsers[args[0]] = u; if (MyStatusChangedToInGame != null) { MyStatusChangedToInGame(this, new TasEventArgs()); } } existingUsers[args[0]] = u; if (UserStatusChanged != null) { UserStatusChanged(this, new TasEventArgs(args)); } } break; case "CLIENTS": // client list sent after channel join var usrs = Utils.Glue(args, 1).Split(' '); foreach (var s in usrs) { joinedChannels[args[0]].channelUsers.Add(s); } if (ChannelUserAdded != null) { ChannelUserAdded(this, new TasEventArgs(args[0])); } break; case "JOINED": // user joined one of my channels joinedChannels[args[0]].channelUsers.Add(args[1]); if (ChannelUserAdded != null) { ChannelUserAdded(this, new TasEventArgs(args[0])); } break; case "LEFT": // user left one of my channels joinedChannels[args[0]].channelUsers.Remove(args[1]); if (ChannelUserRemoved != null) { ChannelUserRemoved(this, new TasEventArgs(args[0], args[1], Utils.Glue(args, 2))); } break; case "CHANNELTOPIC": // channel topic update (after joining a channel) { var c = joinedChannels[args[0]]; c.topicSetBy = args[1]; c.topicSetDate = ConvertMilisecondTime(args[2]); c.topic = Utils.Glue(args, 3); if (ChannelTopicChanged != null) { ChannelTopicChanged(this, new TasEventArgs(args[0])); } } break; case "OPENBATTLEFAILED": // opening new battle has failed if (BattleOpenFailed != null) { BattleOpenFailed(this, new TasEventArgs(Utils.Glue(args))); } break; case "OPENBATTLE": // openbattle ok { battleID = int.Parse(args[0]); var self = new UserBattleStatus(username); self.IsSpectator = true; battle.Users.Add(self); // add self UpdateBattleDetails(battle.Details); if (BattleOpened != null) { BattleOpened(this, new TasEventArgs(args[0])); } } break; case "REQUESTBATTLESTATUS": // server asks us to update our status con.SendCommand(0, "MYBATTLESTATUS", 1 << 22, 0); // tell server that we are synchronized spectators break; case "JOINEDBATTLE": // user joined the battle if (battle != null && int.Parse(args[0]) == battleID) { battle.Users.Add(new UserBattleStatus(args[1])); if (BattleUserJoined != null) { BattleUserJoined(this, new TasEventArgs(args[1])); } } break; case "ADDBOT": // bot added to battle if (battle != null && int.Parse(args[0]) == battleID) { var bs = new BotBattleStatus(args[1], args[2], Utils.Glue(args, 5)); bs.SetFrom(int.Parse(args[3]), int.Parse(args[4])); battle.Bots.Add(bs); } break; case "REMOVEBOT": // bot removed from battle if (battle != null && int.Parse(args[0]) == battleID) { battle.Bots.RemoveAll(delegate(BotBattleStatus bot) { return(bot.name == args[1]); }); } break; case "UPDATEBOT": // bot data changed if (battle != null && int.Parse(args[0]) == battleID) { var st = battle.Bots.Find(delegate(BotBattleStatus bot) { return(bot.name == args[1]); }); if (st != null) { st.SetFrom(int.Parse(args[2]), int.Parse(args[3])); } } break; case "LEFTBATTLE": // user left the battle if (battle != null && int.Parse(args[0]) == battleID) { battle.RemoveUser(args[1]); UpdateSpectators(); if (BattleUserLeft != null) { BattleUserLeft(this, new TasEventArgs(args[1])); } if (args[1] == username) { battle = null; battleID = 0; if (BattleClosed != null) { BattleClosed(this, new TasEventArgs()); } } } break; case "CLIENTBATTLESTATUS": // player battle status has changed if (battle != null) { int uindex = battle.GetUserIndex(args[0]); if (uindex != -1) { var bs = battle.Users[uindex]; bs.SetFrom(int.Parse(args[1]), int.Parse(args[2])); battle.Users[uindex] = bs; UpdateSpectators(); if (BattleUserStatusChanged != null) { BattleUserStatusChanged(this, new TasEventArgs(args[0])); } } } break; case "UPDATEBATTLEINFO": // update external battle info (lock and map) if (battle != null && int.Parse(args[0]) == battleID) { string mapname = Utils.Glue(args, 4); if (battle.Map.Name != mapname) { if (mapToChangeTo != null && mapToChangeTo.Name == mapname) { // if we changed to known requested map, use it battle.Map = mapToChangeTo; } else { battle.Map = Program.main.Spring.UnitSync.MapList[mapname]; //otherwise find this map using unitsync } if (BattleMapChanged != null) { BattleMapChanged(this, new TasEventArgs(mapname)); } } if (battle.IsLocked != int.Parse(args[2]) > 0) { battle.IsLocked = int.Parse(args[2]) > 0; if (BattleLockChanged != null) { BattleLockChanged(this, new TasEventArgs(args[2])); } } } break; case "BATTLEOPENED": { if (BattleFound != null) { BattleFound(this, new TasEventArgs(args)); } break; } case "CLIENTIPPORT": if (battle != null) { int idx = battle.GetUserIndex(args[0]); if (idx != -1) { var bs = battle.Users[idx]; bs.ip = IPAddress.Parse(args[1]); bs.port = int.Parse(args[2]); battle.Users[idx] = bs; if (BattleUserIpRecieved != null) { BattleUserIpRecieved(this, new TasEventArgs(args)); } } } break; case "SETSCRIPTTAGS": // updates internal battle details if (battle != null) { var bd = new BattleDetails(); bd.Parse(Utils.Glue(args), battle.ModOptions); battle.Details = bd; if (BattleDetailsChanged != null) { BattleDetailsChanged(this, new TasEventArgs(args)); } } break; case "UDPSOURCEPORT": udpPunchingTimer.Stop(); if (startingAfterUdpPunch) { startingAfterUdpPunch = false; if (battle != null) { // send UDP packets to client (2x to be sure) foreach (var ubs in battle.Users) { if (ubs.ip != IPAddress.None && ubs.port != 0) { SendUdpPacket(lastUdpSourcePort, ubs.ip, ubs.port); } } foreach (var ubs in battle.Users) { if (ubs.ip != IPAddress.None && ubs.port != 0) { SendUdpPacket(lastUdpSourcePort, ubs.ip, ubs.port); } } battle.HostPort = lastUdpSourcePort; // update source port for hosting and start it ChangeMyStatus(false, true); } } break; } } catch (Exception e) { if (!ErrorHandling.HandleException(e, "Exception while dispatching " + command + " " + Utils.Glue(args))) { throw e; } } ; }
/// <summary> /// Groups tam and ally numbers, so that they both start from 0 /// </summary> public void GroupData(out List <GrPlayer> players, out List <GrTeam> teams, out List <GrAlly> alliances) { Dictionary <int, int> teamNums = new Dictionary <int, int>(); Dictionary <int, int> allyNums = new Dictionary <int, int>(); players = new List <GrPlayer>(); teams = new List <GrTeam>(); alliances = new List <GrAlly>(); foreach (UserBattleStatus p in Users) { UserBattleStatus u = (UserBattleStatus)p.Clone(); if (!u.IsSpectator) { if (!teamNums.ContainsKey(u.TeamNumber)) { teamNums.Add(u.TeamNumber, teams.Count); // add transformation of team teams.Add(new GrTeam(players.Count)); } u.TeamNumber = teamNums[u.TeamNumber]; if (!allyNums.ContainsKey(u.AllyNumber)) { allyNums.Add(u.AllyNumber, alliances.Count); // add transformation of ally alliances.Add(new GrAlly()); } u.AllyNumber = allyNums[u.AllyNumber]; } players.Add(new GrPlayer(u)); } foreach (BotBattleStatus p in Bots) { BotBattleStatus u = (BotBattleStatus)p.Clone(); if (!teamNums.ContainsKey(u.TeamNumber)) { teamNums.Add(u.TeamNumber, teams.Count); // add transformation of team int leader = 0; for (leader = 0; leader < players.Count; ++leader) { if (players[leader].user.name == u.owner) { break; } } GrTeam gr = new GrTeam(leader); gr.bot = u; teams.Add(gr); } u.TeamNumber = teamNums[u.TeamNumber]; if (!allyNums.ContainsKey(u.AllyNumber)) { allyNums.Add(u.AllyNumber, alliances.Count); // add transformation of ally alliances.Add(new GrAlly()); } u.AllyNumber = allyNums[u.AllyNumber]; } // now assign rectangles and skip unused foreach (KeyValuePair <int, BattleRect> r in Rectangles) { if (allyNums.ContainsKey(r.Key)) { alliances[allyNums[r.Key]] = new GrAlly(r.Value); } } }