Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select & show preferred skill level when making a game #598

Merged
merged 14 commits into from
Jan 3, 2025
2 changes: 2 additions & 0 deletions ClientCore/ClientConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,8 @@ private List<TranslationGameFile> ParseTranslationGameFiles()

public string AllowedCustomGameModes => clientDefinitionsIni.GetStringValue(SETTINGS, "AllowedCustomGameModes", "Standard,Custom Map");

public string SkillLevelOptions => clientDefinitionsIni.GetStringValue(SETTINGS, "SkillLevelOptions", "Any,Beginner,Intermediate,Pro");

public string GetGameExecutableName()
{
string[] exeNames = clientDefinitionsIni.GetStringValue(SETTINGS, "GameExecutableNames", "Game.exe").Split(',');
Expand Down
2 changes: 1 addition & 1 deletion ClientCore/ProgramConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public static class ProgramConstants

public const string QRES_EXECUTABLE = "qres.dat";

public const string CNCNET_PROTOCOL_REVISION = "R11";
public const string CNCNET_PROTOCOL_REVISION = "R12";
public const string LAN_PROTOCOL_REVISION = "RL7";
public const int LAN_PORT = 1234;
public const int LAN_INGAME_PORT = 1234;
Expand Down
10 changes: 7 additions & 3 deletions DXMainClient/DXGUI/Multiplayer/CnCNet/CnCNetLobby.cs
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,7 @@ private void _JoinGame(HostedCnCNetGame hg, string password)
}
else
{
gameLobby.SetUp(gameChannel, false, hg.MaxPlayers, hg.TunnelServer, hg.HostName, hg.Passworded);
gameLobby.SetUp(gameChannel, false, hg.MaxPlayers, hg.TunnelServer, hg.HostName, hg.Passworded, hg.SkillLevel);
gameChannel.UserAdded += GameChannel_UserAdded;
gameChannel.InvalidPasswordEntered += GameChannel_InvalidPasswordEntered_NewGame;
gameChannel.InviteOnlyErrorOnJoin += GameChannel_InviteOnlyErrorOnJoin;
Expand Down Expand Up @@ -1037,7 +1037,7 @@ private void Gcw_GameCreated(object sender, GameCreationEventArgs e)

Channel gameChannel = connectionManager.CreateChannel(e.GameRoomName, channelName, false, true, password);
connectionManager.AddChannel(gameChannel);
gameLobby.SetUp(gameChannel, true, e.MaxPlayers, e.Tunnel, ProgramConstants.PLAYERNAME, isCustomPassword);
gameLobby.SetUp(gameChannel, true, e.MaxPlayers, e.Tunnel, ProgramConstants.PLAYERNAME, isCustomPassword, e.GameDifficulty);
gameChannel.UserAdded += GameChannel_UserAdded;
//gameChannel.MessageAdded += GameChannel_MessageAdded;
connectionManager.SendCustomMessage(new QueuedMessage("JOIN " + channelName + " " + password,
Expand Down Expand Up @@ -1484,7 +1484,7 @@ private void GameBroadcastChannel_CTCPReceived(object sender, ChannelCTCPEventAr
string msg = e.Message.Substring(5); // Cut out GAME part
string[] splitMessage = msg.Split(new char[] { ';' });

if (splitMessage.Length != 11)
if (splitMessage.Length != 12)
{
Logger.Log("Ignoring CTCP game message because of an invalid amount of parameters.");
return;
Expand Down Expand Up @@ -1514,6 +1514,9 @@ private void GameBroadcastChannel_CTCPReceived(object sender, ChannelCTCPEventAr
int tunnelPort = int.Parse(tunnelAddressAndPort[1]);

string loadedGameId = splitMessage[10];
int gameDifficulty = int.Parse(splitMessage[11]);

Logger.Log("GameDifficulty ** Received game difficulty in ctcp: " + gameDifficulty);

CnCNetGame cncnetGame = gameCollection.GameList.Find(g => g.GameBroadcastChannel == channel.ChannelName);

Expand All @@ -1536,6 +1539,7 @@ private void GameBroadcastChannel_CTCPReceived(object sender, ChannelCTCPEventAr
game.Locked = locked || (game.IsLoadedGame && !game.Players.Contains(ProgramConstants.PLAYERNAME));
game.Incompatible = cncnetGame == localGame && game.GameVersion != ProgramConstants.GAME_VERSION;
game.TunnelServer = tunnel;
game.SkillLevel = gameDifficulty;

if (isClosed)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ namespace DTAClient.DXGUI.Multiplayer.CnCNet
class GameCreationEventArgs : EventArgs
{
public GameCreationEventArgs(string roomName, int maxPlayers,
string password, CnCNetTunnel tunnel)
string password, CnCNetTunnel tunnel, int gameDifficulty)
{
GameRoomName = roomName;
MaxPlayers = maxPlayers;
Password = password;
Tunnel = tunnel;
GameDifficulty = gameDifficulty;
}

public string GameRoomName { get; private set; }
public int MaxPlayers { get; private set; }
public string Password { get; private set; }
public CnCNetTunnel Tunnel { get; private set; }
public int GameDifficulty { get; private set; }
}
}
41 changes: 36 additions & 5 deletions DXMainClient/DXGUI/Multiplayer/CnCNet/GameCreationWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ public GameCreationWindow(WindowManager windowManager, TunnelHandler tunnelHandl

private XNATextBox tbGameName;
private XNAClientDropDown ddMaxPlayers;
private XNAClientDropDown ddSkillLevel;
private XNATextBox tbPassword;

private XNALabel lblRoomName;
private XNALabel lblMaxPlayers;
private XNALabel lblSkillLevel;
private XNALabel lblPassword;

private XNALabel lblTunnelServer;
Expand All @@ -44,11 +46,15 @@ public GameCreationWindow(WindowManager windowManager, TunnelHandler tunnelHandl

private TunnelHandler tunnelHandler;

private string[] SkillLevelOptions;

public override void Initialize()
{
lbTunnelList = new TunnelListBox(WindowManager, tunnelHandler);
lbTunnelList.Name = nameof(lbTunnelList);

SkillLevelOptions = ClientConfiguration.Instance.SkillLevelOptions.Split(',');

Name = "GameCreationWindow";
Width = lbTunnelList.Width + UIDesignConstants.EMPTY_SPACE_SIDES * 2 +
UIDesignConstants.CONTROL_HORIZONTAL_MARGIN * 2;
Expand Down Expand Up @@ -82,10 +88,31 @@ public override void Initialize()
UIDesignConstants.CONTROL_HORIZONTAL_MARGIN, ddMaxPlayers.Y + 1, 0, 0);
lblMaxPlayers.Text = "Maximum number of players:".L10N("Client:Main:GameMaxPlayerCount");

// Skill Level selector
ddSkillLevel = new XNAClientDropDown(WindowManager);
ddSkillLevel.Name = nameof(ddSkillLevel);
ddSkillLevel.ClientRectangle = new Rectangle(tbGameName.X, ddMaxPlayers.Bottom + 20,
tbGameName.Width, 21);

for (int i = 0; i < SkillLevelOptions.Length; i++)
{
string skillLevel = SkillLevelOptions[i];
string localizedSkillLevel = skillLevel.L10N($"INI:ClientDefinitions:SkillLevel:{i}");
ddSkillLevel.AddItem(localizedSkillLevel);
}

ddSkillLevel.SelectedIndex = 0;

lblSkillLevel = new XNALabel(WindowManager);
lblSkillLevel.Name = nameof(lblSkillLevel);
lblSkillLevel.ClientRectangle = new Rectangle(UIDesignConstants.EMPTY_SPACE_SIDES +
UIDesignConstants.CONTROL_HORIZONTAL_MARGIN, ddSkillLevel.Y + 1, 0, 0);
lblSkillLevel.Text = "Select preferred skill level of players:".L10N("Client:Main:SelectSkillLevel");

tbPassword = new XNATextBox(WindowManager);
tbPassword.Name = nameof(tbPassword);
tbPassword.MaximumTextLength = 20;
tbPassword.ClientRectangle = new Rectangle(tbGameName.X, ddMaxPlayers.Bottom + 20,
tbPassword.ClientRectangle = new Rectangle(tbGameName.X, ddSkillLevel.Bottom + 20,
tbGameName.Width, 21);

lblPassword = new XNALabel(WindowManager);
Expand Down Expand Up @@ -142,6 +169,8 @@ public override void Initialize()
AddChild(lblRoomName);
AddChild(ddMaxPlayers);
AddChild(lblMaxPlayers);
AddChild(ddSkillLevel);
AddChild(lblSkillLevel);
AddChild(tbPassword);
AddChild(lblPassword);
AddChild(btnDisplayAdvancedOptions);
Expand Down Expand Up @@ -203,7 +232,7 @@ private void BtnLoadMPGame_LeftClick(object sender, EventArgs e)

GameCreationEventArgs ea = new GameCreationEventArgs(gameName,
spawnSGIni.GetIntValue("Settings", "PlayerCount", 2), password,
tunnelHandler.Tunnels[lbTunnelList.SelectedIndex]);
tunnelHandler.Tunnels[lbTunnelList.SelectedIndex], ddSkillLevel.SelectedIndex);

LoadedGameCreated?.Invoke(this, ea);
}
Expand All @@ -229,9 +258,11 @@ private void BtnCreateGame_LeftClick(object sender, EventArgs e)
return;
}

GameCreated?.Invoke(this, new GameCreationEventArgs(gameName,
int.Parse(ddMaxPlayers.SelectedItem.Text), tbPassword.Text,
tunnelHandler.Tunnels[lbTunnelList.SelectedIndex]));
GameCreated?.Invoke(this,
new GameCreationEventArgs(gameName,int.Parse(ddMaxPlayers.SelectedItem.Text),
tbPassword.Text,tunnelHandler.Tunnels[lbTunnelList.SelectedIndex],
ddSkillLevel.SelectedIndex)
);
}

private void BtnDisplayAdvancedOptions_LeftClick(object sender, EventArgs e)
Expand Down
20 changes: 17 additions & 3 deletions DXMainClient/DXGUI/Multiplayer/GameInformationPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.Xna.Framework;
using DTAClient.Domain.Multiplayer;
using ClientCore.Extensions;
using ClientCore;

namespace DTAClient.DXGUI.Multiplayer
{
Expand All @@ -29,8 +30,11 @@ public GameInformationPanel(WindowManager windowManager, MapLoader mapLoader)
private XNALabel lblHost;
private XNALabel lblPing;
private XNALabel lblPlayers;
private XNALabel lblSkillLevel;
private XNALabel[] lblPlayerNames;

private string[] SkillLevelOptions;

public override void Initialize()
{
ClientRectangle = new Rectangle(0, 0, 235, 264);
Expand All @@ -56,8 +60,11 @@ public override void Initialize()
lblPing = new XNALabel(WindowManager);
lblPing.ClientRectangle = new Rectangle(6, 126, 0, 0);

lblSkillLevel = new XNALabel(WindowManager);
lblSkillLevel.ClientRectangle = new Rectangle(6, 150, 0, 0);

lblPlayers = new XNALabel(WindowManager);
lblPlayers.ClientRectangle = new Rectangle(6, 150, 0, 0);
lblPlayers.ClientRectangle = new Rectangle(6, 178, 0, 0);

lblPlayerNames = new XNALabel[MAX_PLAYERS];
for (int i = 0; i < lblPlayerNames.Length / 2; i++)
Expand All @@ -84,22 +91,25 @@ public override void Initialize()
AddChild(lblPing);
AddChild(lblPlayers);
AddChild(lblGameInformation);
AddChild(lblSkillLevel);

lblGameInformation.CenterOnParent();
lblGameInformation.ClientRectangle = new Rectangle(lblGameInformation.X, 6,
lblGameInformation.Width, lblGameInformation.Height);

SkillLevelOptions = ClientConfiguration.Instance.SkillLevelOptions.Split(',');

base.Initialize();
}

public void SetInfo(GenericHostedGame game)
{
// we don't have the ID of a map here
string translatedMapName = string.IsNullOrEmpty(game.Map)
string translatedMapName = string.IsNullOrEmpty(game.Map)
? "Unknown".L10N("Client:Main:Unknown") : mapLoader.TranslatedMapNames.ContainsKey(game.Map)
? mapLoader.TranslatedMapNames[game.Map] : game.Map;

string translatedGameModeName = string.IsNullOrEmpty(game.GameMode)
string translatedGameModeName = string.IsNullOrEmpty(game.GameMode)
? "Unknown".L10N("Client:Main:Unknown") : game.GameMode.L10N($"INI:GameModes:{game.GameMode}:UIName", notify: false);

lblGameMode.Text = Renderer.GetStringWithLimitedWidth("Game mode:".L10N("Client:Main:GameInfoGameMode") + " " + Renderer.GetSafeString(translatedGameModeName, lblGameMode.FontIndex),
Expand Down Expand Up @@ -132,6 +142,10 @@ public void SetInfo(GenericHostedGame game)
{
lblPlayerNames[i].Visible = false;
}

string skillLevel = SkillLevelOptions[game.SkillLevel];
string localizedSkillLevel = skillLevel.L10N($"INI:ClientDefinitions:SkillLevel:{game.SkillLevel}");
lblSkillLevel.Text = "Preferred Skill Level:".L10N("Client:Main:GameInfoSkillLevel") + " " + localizedSkillLevel;
}

public void ClearInfo()
Expand Down
32 changes: 32 additions & 0 deletions DXMainClient/DXGUI/Multiplayer/GameListBox.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

using ClientCore;
using ClientCore.Enums;
using ClientCore.Extensions;
using DTAClient.Domain.Multiplayer;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using Rampastring.Tools;
using Rampastring.XNAUI;
using Rampastring.XNAUI.XNAControls;

Expand All @@ -21,6 +25,7 @@ public class GameListBox : XNAListBox
private const int ICON_MARGIN = 2;
private const int FONT_INDEX = 0;
private static string LOADED_GAME_TEXT => " (" + "Loaded Game".L10N("Client:Main:LoadedGame") + ")";
private string[] SkillLevelIcons;

public GameListBox(WindowManager windowManager, MapLoader mapLoader,
string localGameIdentifier, Predicate<GenericHostedGame> gameMatchesFilter = null)
Expand All @@ -29,8 +34,12 @@ public GameListBox(WindowManager windowManager, MapLoader mapLoader,
this.mapLoader = mapLoader;
this.localGameIdentifier = localGameIdentifier;
GameMatchesFilter = gameMatchesFilter;

SkillLevelIcons = ClientConfiguration.Instance.SkillLevelOptions.Split(',');
}

private List<Texture2D> txSkillLevelIcons = new List<Texture2D>();

private int loadedGameTextWidth;

public List<GenericHostedGame> HostedGames = new();
Expand Down Expand Up @@ -185,6 +194,18 @@ public override void Initialize()
ClientConfiguration.Instance.HoverOnGameColor);

loadedGameTextWidth = (int)Renderer.GetTextDimensions(LOADED_GAME_TEXT, FontIndex).X;

InitSkillLevelIcons();
}

private void InitSkillLevelIcons()
{
for (int i = 0; i < SkillLevelIcons.Length; i++)
{
Texture2D gd = AssetLoader.LoadTexture($"skillLevel{i}.png");
if (gd != null)
txSkillLevelIcons.Add(gd);
}
}

private bool IsValidGameIndex(int index)
Expand Down Expand Up @@ -332,6 +353,17 @@ public override void Draw(GameTime gameTime)
height, txPasswordedGame.Width, txPasswordedGame.Height),
Color.White);
}
else
{
Texture2D txSkillLevelIcon = txSkillLevelIcons[hostedGame.SkillLevel];
if (txSkillLevelIcon != null && hostedGame.SkillLevel != 0)
{
DrawTexture(txSkillLevelIcon,
new Rectangle(Width - txSkillLevelIcon.Width - TextBorderDistance - (scrollBarDrawn ? ScrollBar.Width : 0),
height, txSkillLevelIcon.Width, txSkillLevelIcon.Height),
Color.White);
}
}

var text = lbItem.Text;
if (hostedGame.IsLoadedGame)
Expand Down
8 changes: 7 additions & 1 deletion DXMainClient/DXGUI/Multiplayer/GameLobby/CnCNetGameLobby.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ PrivateMessagingWindow pmWindow

private bool closed = false;

private int gameDifficulty = 0;

private bool isCustomPassword = false;

private string gameFilesHash;
Expand Down Expand Up @@ -215,7 +217,8 @@ private void MultiplayerName_RightClick(object sender, MultiplayerNameRightClick
private void GameBroadcastTimer_TimeElapsed(object sender, EventArgs e) => BroadcastGame();

public void SetUp(Channel channel, bool isHost, int playerLimit,
CnCNetTunnel tunnel, string hostName, bool isCustomPassword)
CnCNetTunnel tunnel, string hostName, bool isCustomPassword,
int gameDifficulty)
{
this.channel = channel;
channel.MessageAdded += Channel_MessageAdded;
Expand All @@ -230,6 +233,7 @@ public void SetUp(Channel channel, bool isHost, int playerLimit,
this.hostName = hostName;
this.playerLimit = playerLimit;
this.isCustomPassword = isCustomPassword;
this.gameDifficulty = gameDifficulty;

if (isHost)
{
Expand Down Expand Up @@ -1929,6 +1933,8 @@ private void BroadcastGame()
sb.Append(tunnelHandler.CurrentTunnel.Address + ":" + tunnelHandler.CurrentTunnel.Port);
sb.Append(";");
sb.Append(0); // LoadedGameId
sb.Append(";");
sb.Append(gameDifficulty); // SkillLevel

broadcastChannel.SendCTCPMessage(sb.ToString(), QueuedMessageType.SYSTEM_MESSAGE, 20);
}
Expand Down
2 changes: 2 additions & 0 deletions DXMainClient/Domain/Multiplayer/GenericHostedGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public abstract class GenericHostedGame: IEquatable<GenericHostedGame>

public DateTime LastRefreshTime { get; set; }

public int SkillLevel { get; set; }

public virtual bool Equals(GenericHostedGame other)
=> string.Equals(RoomName, other?.RoomName, StringComparison.InvariantCultureIgnoreCase);
}
Expand Down
Binary file added DXMainClient/Resources/DTA/skillLevel1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added DXMainClient/Resources/DTA/skillLevel2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added DXMainClient/Resources/DTA/skillLevel3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading