521 lines
20 KiB
C#

using Microsoft.AspNetCore.SignalR.Client;
using qtc_net_client_2.Forms;
using qtc_net_client_2.Services;
using QtCNETAPI.Enums;
using QtCNETAPI.Models;
using QtCNETAPI.Schema;
using QtCNETAPI.Services.ApiService;
using System.Threading.Tasks;
using qtc_net_client_2.ClientModel;
namespace qtc_net_client_2
{
public partial class TicTacToeGame : Form
{
private HubConnection? GameHubConnection { get; set; }
private GameRoom? CurrentRoom { get; set; }
private IApiService _apiService;
private Config _config;
private AudioService _audioService = new();
private int WinCount { get; set; }
private bool JackpotWon { get; set; } = false;
public TicTacToeGame(IApiService apiService, Config config)
{
_apiService = apiService;
_config = config;
InitializeComponent();
}
private async void Main_Load(object sender, EventArgs e)
{
// first, connect to the game hub
GameHubConnection = new HubConnectionBuilder()
.WithUrl($"{_config.ServerUrl}/tttgame", options =>
{
options.AccessTokenProvider = () => Task.FromResult(_apiService.SessionToken)!;
})
.WithAutomaticReconnect()
.Build();
pLoading.Visible = true;
lblLoadStatus.Text = "Connecting\nTo\nHub...";
GameHubConnection.On<GameRoom>("WaitingForPlayer", (room) =>
{
CurrentRoom = room;
BeginInvoke(delegate ()
{
if (room.Player1 != null)
{
lblP1Username.Text = room.Player1.Username;
lvUserlist.Items.Add(room.Player1.Id, room.Player1.Username, room.Player1.Status);
}
lblLoadStatus.Text = "Waiting\nFor\nPlayer...";
});
});
GameHubConnection.On<GameRoom>("GameStart", (room) =>
{
CurrentRoom = room;
BeginInvoke(delegate ()
{
pLoading.Visible = false;
pSymbolSelection.Visible = false;
});
});
GameHubConnection.On<GameRoom, string?>("GameEnd", (room, usernameDisconnected) =>
{
CurrentRoom = room;
BeginInvoke(delegate ()
{
if (room.Player1 == null) lblP1Username.Text = "Username";
if (room.Player2 == null) lblP2Username.Text = "Username";
ToggleBoardControl(false);
switch (room.Status)
{
case GameStatus.P1Win:
{
if (_apiService.CurrentUser.Id == room.Player1?.Id)
{
lblLoadStatus.Text = "You Won!";
WinCount++;
if (WinCount >= 3)
{
JackpotWon = true;
lblJackpotWon.Text = "You Won A Spin!";
}
}
else lblLoadStatus.Text = "You Lost!";
lblPlayAgain.Visible = true;
btnPlayAgain.Visible = true;
break;
}
case GameStatus.P2Win:
{
if (_apiService.CurrentUser.Id == room.Player2?.Id)
{
lblLoadStatus.Text = "You Won!";
WinCount++;
if (WinCount >= 3)
{
JackpotWon = true;
lblJackpotWon.Text = "You Won A Spin!";
}
}
else lblLoadStatus.Text = "You Lost!";
lblPlayAgain.Visible = true;
btnPlayAgain.Visible = true;
break;
}
case GameStatus.PlayerDisconnected:
{
if (!string.IsNullOrEmpty(usernameDisconnected))
lblLoadStatus.Text = $"Game Ended.\nUser {usernameDisconnected}\nDisconnected.";
lblPlayAgain.Visible = false;
btnPlayAgain.Visible = false;
break;
}
case GameStatus.NoWin:
lblLoadStatus.Text = "It's a draw!";
lblPlayAgain.Visible = true;
btnPlayAgain.Visible = true;
break;
}
pLoading.Visible = true;
});
});
GameHubConnection.On<GameRoom>("RestartGame", (room) =>
{
CurrentRoom = room;
BeginInvoke(delegate ()
{
if (pLoading.Visible) pLoading.Visible = false;
});
ClearBoard();
ToggleBoardControl(true);
BeginInvoke(delegate ()
{
List<Button> buttons = [btnSquare1, btnSquare2, btnSquare3, btnSquare4, btnSquare5, btnSquare6, btnSquare7, btnSquare8, btnSquare9];
foreach (Button button in buttons)
{
if (button.BackgroundImage == null)
button.Enabled = true;
}
});
});
GameHubConnection.On<GameRoom>("SelectSymbol", (room) =>
{
CurrentRoom = room;
BeginInvoke(delegate ()
{
if (room.Player1 != null)
{
lblP1Username.Text = room.Player1.Username;
if (!lvUserlist.Items.ContainsKey(room.Player1.Id)) lvUserlist.Items.Add(room.Player1.Id, room.Player1.Username, room.Player1.Status);
}
if (room.Player2 != null)
{
lblP2Username.Text = room.Player2.Username;
if (!lvUserlist.Items.ContainsKey(room.Player2.Id)) lvUserlist.Items.Add(room.Player2.Id, room.Player2.Username, room.Player2.Status);
}
if (pLoading.Visible) pLoading.Visible = false;
pSymbolSelection.Visible = true;
pBoard.Enabled = true;
ToggleAllSquareButtons(false);
});
});
GameHubConnection.On<GameRoom>("SelectingSymbol", (room) =>
{
CurrentRoom = room;
BeginInvoke(delegate ()
{
if (pSymbolSelection.Visible) return;
if (room.Player1 != null)
{
lblP1Username.Text = room.Player1.Username;
if (!lvUserlist.Items.ContainsKey(room.Player1.Id)) lvUserlist.Items.Add(room.Player1.Id, room.Player1.Username, room.Player1.Status);
}
if (room.Player2 != null)
{
lblP2Username.Text = room.Player2.Username;
if (!lvUserlist.Items.ContainsKey(room.Player2.Id)) lvUserlist.Items.Add(room.Player2.Id, room.Player2.Username, room.Player2.Status);
}
pLoading.Visible = true;
lblLoadStatus.Text = $"Player 1\nIs Selecting\nSymbol...";
});
});
GameHubConnection.On<GameRoom, TicTacToeMove>("UpdateBoard", (room, move) =>
{
CurrentRoom = room;
UpdateBoardUI(move);
});
GameHubConnection.On<GameRoom>("StartTurn", (room) =>
{
CurrentRoom = room;
ToggleBoardControl(true);
AddChatMessage("[SERVER] Your Turn!");
});
GameHubConnection.On<GameRoom>("EndTurn", (room) =>
{
CurrentRoom = room;
ToggleBoardControl(false);
AddChatMessage("[SERVER] Other Players Turn");
});
GameHubConnection.On<string>("ReceiveMessage", (msg) =>
{
AddChatMessage(msg);
if (msg.Split('[')[1] != _apiService.CurrentUser.Username)
_audioService.PlaySoundEffect("sndMessage");
});
try { await GameHubConnection.StartAsync(); }
catch (HttpRequestException ex)
{
MessageBox.Show($"Sorry, We Couldn't Connect To The Game Server Due To An Error. Please Try Again Later.\n\n{ex.Message}", "Oops.", MessageBoxButtons.OK, MessageBoxIcon.Error);
Environment.Exit(0);
}
lblLoadStatus.Text = "Finding\nRoom...";
await GameHubConnection.SendAsync("FindRoom");
}
private async void TicTacToeGame_FormClosed(object sender, FormClosedEventArgs e)
{
if (GameHubConnection != null && GameHubConnection.State == HubConnectionState.Connected)
{
if(JackpotWon)
{
// start a jackpot spin
CurrencyJackpotSpinner currencyJackpotSpinner = new CurrencyJackpotSpinner();
var dialogResult = currencyJackpotSpinner.ShowDialog();
if (dialogResult == DialogResult.OK)
{
await _apiService.AddCurrencyToCurrentUser(currencyJackpotSpinner.TokensWon, false);
_apiService.CurrentUser.CurrencyAmount += currencyJackpotSpinner.TokensWon;
}
}
// stop and dispose connection
await GameHubConnection.StopAsync();
await GameHubConnection.DisposeAsync();
GameHubConnection = null;
}
}
private async void btnXSelect_Click(object sender, EventArgs e) => await SelectSymbol(TicTacToeSymbol.X);
private async void btnOSelect_Click(object sender, EventArgs e) => await SelectSymbol(TicTacToeSymbol.O);
private async void btnPlayAgain_Click(object sender, EventArgs e)
{
if (GameHubConnection != null && GameHubConnection.State == HubConnectionState.Connected && CurrentRoom != null)
{
await GameHubConnection.SendAsync("RestartGame", CurrentRoom.Id);
}
}
private async void btnSquareX_Click(object sender, EventArgs e)
{
// create move
TicTacToeMove move = new TicTacToeMove
{
User = _apiService.CurrentUser
};
if (sender is Button btn)
{
switch (btn.Name)
{
case "btnSquare1":
move.Point = 1;
break;
case "btnSquare2":
move.Point = 2;
break;
case "btnSquare3":
move.Point = 3;
break;
case "btnSquare4":
move.Point = 4;
break;
case "btnSquare5":
move.Point = 5;
break;
case "btnSquare6":
move.Point = 6;
break;
case "btnSquare7":
move.Point = 7;
break;
case "btnSquare8":
move.Point = 8;
break;
case "btnSquare9":
move.Point = 9;
break;
}
}
// send move
if (GameHubConnection != null && GameHubConnection.State == HubConnectionState.Connected && CurrentRoom != null)
await GameHubConnection.SendAsync("MakeMove", CurrentRoom.Id, move);
}
private async void btnSend_Click(object sender, EventArgs e)
{
if ((GameHubConnection != null && GameHubConnection.State == HubConnectionState.Connected && CurrentRoom != null) &&
!string.IsNullOrWhiteSpace(rtxtChatbox.Text))
{
await GameHubConnection.SendAsync("SendRoomMessage", CurrentRoom.Id, $"[{_apiService.CurrentUser.Username}] {rtxtChatbox.Text}");
_audioService.PlaySoundEffect("sndSendClick");
rtxtChatbox.Clear();
}
}
private void rtxtChatbox_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.Enter)
btnSend_Click(sender, e);
}
private void ToggleBoardControl(bool toggle)
{
if (IsHandleCreated && !IsDisposed)
{
Invoke(delegate ()
{
pBoard.Enabled = toggle;
});
}
}
private void ToggleAllSquareButtons(bool toggle)
{
if (IsHandleCreated && !IsDisposed)
{
Invoke(delegate ()
{
List<Button> buttons = [btnSquare1, btnSquare2, btnSquare3, btnSquare4, btnSquare5, btnSquare6, btnSquare7, btnSquare8, btnSquare9];
foreach (Button button in buttons)
button.Enabled = toggle;
});
}
}
private async Task SelectSymbol(TicTacToeSymbol symbol)
{
if (GameHubConnection != null && GameHubConnection.State == HubConnectionState.Connected && CurrentRoom != null)
{
await GameHubConnection.SendAsync("SetSymbol", CurrentRoom.Id, symbol);
ToggleAllSquareButtons(true);
}
}
private void UpdateBoardUI(TicTacToeMove move)
{
if (IsHandleCreated && !IsDisposed && CurrentRoom != null)
{
// play move made sound
_audioService.PlaySoundEffect("sndTTTMoveMade");
Invoke(delegate ()
{
switch (CurrentRoom.Board.Square1)
{
case TicTacToeSymbol.X:
btnSquare1.BackgroundImage = Properties.Resources.X;
btnSquare1.Enabled = false;
break;
case TicTacToeSymbol.O:
btnSquare1.BackgroundImage = Properties.Resources.O;
btnSquare1.Enabled = false;
break;
}
switch (CurrentRoom.Board.Square2)
{
case TicTacToeSymbol.X:
btnSquare2.BackgroundImage = Properties.Resources.X;
btnSquare2.Enabled = false;
break;
case TicTacToeSymbol.O:
btnSquare2.BackgroundImage = Properties.Resources.O;
btnSquare2.Enabled = false;
break;
}
switch (CurrentRoom.Board.Square3)
{
case TicTacToeSymbol.X:
btnSquare3.BackgroundImage = Properties.Resources.X;
btnSquare3.Enabled = false;
break;
case TicTacToeSymbol.O:
btnSquare3.BackgroundImage = Properties.Resources.O;
btnSquare3.Enabled = false;
break;
}
switch (CurrentRoom.Board.Square4)
{
case TicTacToeSymbol.X:
btnSquare4.BackgroundImage = Properties.Resources.X;
btnSquare4.Enabled = false;
break;
case TicTacToeSymbol.O:
btnSquare4.BackgroundImage = Properties.Resources.O;
btnSquare4.Enabled = false;
break;
}
switch (CurrentRoom.Board.Square5)
{
case TicTacToeSymbol.X:
btnSquare5.BackgroundImage = Properties.Resources.X;
btnSquare5.Enabled = false;
break;
case TicTacToeSymbol.O:
btnSquare5.BackgroundImage = Properties.Resources.O;
btnSquare5.Enabled = false;
break;
}
switch (CurrentRoom.Board.Square6)
{
case TicTacToeSymbol.X:
btnSquare6.BackgroundImage = Properties.Resources.X;
btnSquare6.Enabled = false;
break;
case TicTacToeSymbol.O:
btnSquare6.BackgroundImage = Properties.Resources.O;
btnSquare6.Enabled = false;
break;
}
switch (CurrentRoom.Board.Square7)
{
case TicTacToeSymbol.X:
btnSquare7.BackgroundImage = Properties.Resources.X;
btnSquare7.Enabled = false;
break;
case TicTacToeSymbol.O:
btnSquare7.BackgroundImage = Properties.Resources.O;
btnSquare7.Enabled = false;
break;
}
switch (CurrentRoom.Board.Square8)
{
case TicTacToeSymbol.X:
btnSquare8.BackgroundImage = Properties.Resources.X;
btnSquare8.Enabled = false;
break;
case TicTacToeSymbol.O:
btnSquare8.BackgroundImage = Properties.Resources.O;
btnSquare8.Enabled = false;
break;
}
switch (CurrentRoom.Board.Square9)
{
case TicTacToeSymbol.X:
btnSquare9.BackgroundImage = Properties.Resources.X;
btnSquare9.Enabled = false;
break;
case TicTacToeSymbol.O:
btnSquare9.BackgroundImage = Properties.Resources.O;
btnSquare9.Enabled = false;
break;
}
});
}
}
private void AddChatMessage(string msg)
{
if (IsHandleCreated && !IsDisposed)
{
Invoke(delegate ()
{
rtxtChat.AppendText($"{msg}\n");
});
}
}
private void ClearBoard()
{
if (IsHandleCreated && !IsDisposed)
{
Invoke(delegate ()
{
List<Button> buttons = [btnSquare1, btnSquare2, btnSquare3, btnSquare4, btnSquare5, btnSquare6, btnSquare7, btnSquare8, btnSquare9];
foreach (Button button in buttons)
button.BackgroundImage = null;
});
}
}
}
}