Add bot play, replay creation, and move phrases
Create replay games when a match ends (win or draw) and include ReplayGameCode in the GameEnded payload; adjust deletion timing to keep the replay longer and clean up original games sooner. Update game deletion logic to only destroy non-running games and schedule immediate deletion for quick timeouts. Add optional local bot support (botPlayer2 flag) with automated random-delayed moves and a UI switch in the game creation menu; expose botPlayer2 in GameSettings and LocalMode defaults. Introduce RandomPlaceMessage utility to generate varied turn descriptions and integrate it into LocalGame and OnlineGame. Also include a minor whitespace fix in Game.cs.
This commit is contained in:
@@ -100,27 +100,34 @@ public class GameManager(IGameRepository gameRepository, IHubContext<GameHubSock
|
||||
var winResult = game.Field.CheckForWin();
|
||||
if (winResult != 0)
|
||||
{
|
||||
var newGame = gameRepository.Create(game.Field.GFs);
|
||||
|
||||
var winPlayer = game.GetPlayerByTag(winResult);
|
||||
game.EndGame();
|
||||
await hubContext.Clients.Group(game.Id).SendAsync("GameEnded", new
|
||||
{
|
||||
Method = "Win",
|
||||
Player = winPlayer
|
||||
Player = winPlayer,
|
||||
ReplayGameCode = newGame.GameCode
|
||||
});
|
||||
|
||||
ScheduleGameDeletion(game.Id, TimeSpan.FromSeconds(5));
|
||||
ScheduleGameDeletion(newGame.Id, TimeSpan.FromSeconds(20));
|
||||
ScheduleGameDeletion(game.Id, TimeSpan.FromSeconds(10));
|
||||
}
|
||||
|
||||
if (game.Field.IsFull())
|
||||
{
|
||||
var newGame = gameRepository.Create(game.Field.GFs);
|
||||
game.EndGame();
|
||||
|
||||
await hubContext.Clients.Group(game.Id).SendAsync("GameEnded", new
|
||||
{
|
||||
Method = "Draw"
|
||||
Method = "Draw",
|
||||
ReplayGameCode = newGame.GameCode
|
||||
});
|
||||
|
||||
ScheduleGameDeletion(game.Id, TimeSpan.FromSeconds(5));
|
||||
ScheduleGameDeletion(newGame.Id, TimeSpan.FromSeconds(15));
|
||||
ScheduleGameDeletion(game.Id, TimeSpan.FromSeconds(10));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +149,7 @@ public class GameManager(IGameRepository gameRepository, IHubContext<GameHubSock
|
||||
Player = player
|
||||
});
|
||||
|
||||
ScheduleGameDeletion(game.Id, TimeSpan.FromSeconds(5));
|
||||
ScheduleGameDeletion(game.Id, TimeSpan.FromSeconds(0));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@@ -176,7 +183,7 @@ public class GameManager(IGameRepository gameRepository, IHubContext<GameHubSock
|
||||
await Task.Delay(delay);
|
||||
|
||||
var g = gameRepository.GetOne(gameId);
|
||||
if (g != null && g.State == GameState.Ended)
|
||||
if (g != null && g.State != GameState.Running)
|
||||
{
|
||||
gameRepository.Destroy(gameId);
|
||||
|
||||
|
||||
@@ -33,6 +33,11 @@ function gameFieldPreset(x: number, y: number) {
|
||||
label="Name vom Spieler 2"
|
||||
required
|
||||
></v-text-field>
|
||||
<v-switch
|
||||
v-model="settingsProp.botPlayer2"
|
||||
:label="`${settingsProp.playerName2} ist ein Bot`"
|
||||
color="primary"
|
||||
></v-switch>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<h2 class="settingsCat">Spielfeld</h2>
|
||||
|
||||
@@ -17,6 +17,7 @@ enum CurrentState {
|
||||
let settings = ref<GameSettings>({
|
||||
playerName1: 'Spieler 1',
|
||||
playerName2: 'Spieler 2',
|
||||
botPlayer2: false,
|
||||
fieldSize: { x: 7, y: 6 },
|
||||
});
|
||||
|
||||
|
||||
@@ -4,6 +4,6 @@ export interface GameSettings {
|
||||
fieldSize: FieldSize;
|
||||
playerName1: string;
|
||||
playerName2?: string | null;
|
||||
aiLevel?: number | null;
|
||||
botPlayer2?: boolean | null;
|
||||
message?: string | null;
|
||||
}
|
||||
|
||||
@@ -4,12 +4,14 @@ import GameConnection, {
|
||||
type GameInformationDto,
|
||||
type GameEnded,
|
||||
} from '../signalR/GameConnection';
|
||||
import { getRandomMovePhrase } from '@/scripts/utils/RandomPlaceMessage';
|
||||
|
||||
class LocalGame {
|
||||
public player1: GameConnection;
|
||||
public player2: GameConnection;
|
||||
public currentDescription: string = 'Warte auf Spielaufbau ...';
|
||||
private gameId: string = '';
|
||||
private botGame = false;
|
||||
|
||||
public gameState: GameInformationDto | undefined;
|
||||
public onGameStateChanged?: (gameState: GameInformationDto | undefined) => void;
|
||||
@@ -50,6 +52,8 @@ class LocalGame {
|
||||
await this.player1.connect(settings.playerName1);
|
||||
await this.player2.connect(settings.playerName2 ?? 'Spieler 2');
|
||||
|
||||
this.botGame = settings.botPlayer2 ?? false;
|
||||
|
||||
await this.player1.createGame(settings.fieldSize);
|
||||
}
|
||||
|
||||
@@ -63,7 +67,15 @@ class LocalGame {
|
||||
async drop(index: number) {
|
||||
if (this.gameState?.currentTurn == 1) {
|
||||
this.player1.drop(this.gameId, index);
|
||||
} else {
|
||||
|
||||
if (this.botGame) {
|
||||
const randomDelay = Math.random() * 2000 + 1000;
|
||||
setTimeout(() => {
|
||||
const botIndex = Math.floor(Math.random() * this.gameState!.currentField.length);
|
||||
this.player2.drop(this.gameId, botIndex);
|
||||
}, randomDelay);
|
||||
}
|
||||
} else if(!this.botGame) {
|
||||
this.player2.drop(this.gameId, index);
|
||||
}
|
||||
}
|
||||
@@ -71,7 +83,7 @@ class LocalGame {
|
||||
changePlaceDescription() {
|
||||
const playerName =
|
||||
this.gameState?.currentTurn == 1 ? this.player1.playerName : this.player2.playerName;
|
||||
this.currentDescription = `${playerName} ist dran mit setzen!`;
|
||||
this.currentDescription = getRandomMovePhrase(playerName);
|
||||
}
|
||||
|
||||
async disconnectAll() {
|
||||
|
||||
@@ -5,6 +5,7 @@ import GameConnection, {
|
||||
type GameInformationDto,
|
||||
} from '../signalR/GameConnection';
|
||||
import type JoinGameObject from '@/scripts/interfaces/JoinGameObject';
|
||||
import { getRandomMovePhrase } from '@/scripts/utils/RandomPlaceMessage';
|
||||
|
||||
class OnlineGame {
|
||||
public player: GameConnection;
|
||||
@@ -89,7 +90,7 @@ class OnlineGame {
|
||||
changePlaceDescription() {
|
||||
const playerName =
|
||||
this.gameState?.currentTurn == 1 ? this.gameState.players[0]?.name : this.gameState?.players[1]?.name;
|
||||
this.currentDescription = `${playerName} ist dran mit setzen!`;
|
||||
this.currentDescription = getRandomMovePhrase(playerName ?? "Spieler");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
const movePhrases: string[] = [
|
||||
"Jetzt ist {playerName} dran.",
|
||||
"Die Bühne gehört jetzt {playerName}.",
|
||||
"Ein Stein fliegt gleich – gesetzt von {playerName}.",
|
||||
"Die nächste Spalte wartet auf {playerName}.",
|
||||
"Alle schauen gespannt zu, während {playerName} überlegt.",
|
||||
"Mit großer Verantwortung: {playerName}.",
|
||||
"Ein taktischer Moment für {playerName}.",
|
||||
"Die Entscheidung liegt jetzt bei {playerName}.",
|
||||
"Wer rettet die Situation? {playerName}.",
|
||||
"Ein neuer Stein rollt – gesteuert von {playerName}.",
|
||||
"Jetzt darf {playerName} zeigen, was Strategie bedeutet.",
|
||||
"Der nächste Zug gehört {playerName}.",
|
||||
"Spannung im Raum – {playerName} ist dran.",
|
||||
"Die nächste Spalte gehört heute {playerName}.",
|
||||
"Alle warten auf den genialen Zug von {playerName}.",
|
||||
"Ein mutiger Schritt von {playerName} steht an.",
|
||||
"Jetzt kommt der Moment von {playerName}.",
|
||||
"Das Brett wartet geduldig auf {playerName}.",
|
||||
"Ein Stein fällt gleich – dank {playerName}.",
|
||||
"Strategiezeit für {playerName}.",
|
||||
"Ein kleiner Stein, gesetzt von {playerName}.",
|
||||
"Jetzt wird’s ernst für {playerName}.",
|
||||
"Ein neuer Zug steht an – ausgeführt von {playerName}.",
|
||||
"Jetzt entscheidet {playerName} über das Schicksal der Spalte.",
|
||||
"Der nächste Stein gehört {playerName}.",
|
||||
"Jetzt wird das Spielfeld von {playerName} erweitert.",
|
||||
"Ein kluger Zug könnte gleich von {playerName} kommen.",
|
||||
"Jetzt darf {playerName} das Spiel voranbringen.",
|
||||
"Alle Augen auf {playerName}.",
|
||||
"Der nächste Spielzug gehört eindeutig {playerName}.",
|
||||
"Die nächste Spalte hat Besuch von {playerName}.",
|
||||
"Jetzt ist Zeit für eine Entscheidung von {playerName}.",
|
||||
"Ein Stein macht sich bereit – {playerName} ist schuld.",
|
||||
"Jetzt bringt {playerName} Bewegung ins Spiel.",
|
||||
"Der nächste Schritt kommt von {playerName}.",
|
||||
"Ein strategischer Moment für {playerName}.",
|
||||
"Das Brett wartet gespannt auf {playerName}.",
|
||||
"Jetzt liegt alles in den Händen von {playerName}.",
|
||||
"Eine Spalte wird gleich von {playerName} erobert.",
|
||||
"Jetzt darf {playerName} zeigen, was geplant war.",
|
||||
"Ein neuer Stein gehört {playerName}.",
|
||||
"Die Spannung steigt – {playerName} ist dran.",
|
||||
"Ein weiterer Spielzug kommt von {playerName}.",
|
||||
"Das Spielfeld ruft nach {playerName}.",
|
||||
"Jetzt kommt ein Zug von {playerName}.",
|
||||
"Eine Spalte wird gleich von {playerName} gefüllt.",
|
||||
"Der nächste Moment gehört {playerName}.",
|
||||
"Jetzt wird’s strategisch – dank {playerName}.",
|
||||
"Ein kluger Stein könnte gleich von {playerName} kommen.",
|
||||
"Alle warten auf den Zug von {playerName}.",
|
||||
"Jetzt entscheidet {playerName}.",
|
||||
"Ein Zug voller Hoffnung von {playerName}.",
|
||||
"Jetzt wird das Brett von {playerName} beeinflusst.",
|
||||
"Eine neue Position entsteht durch {playerName}.",
|
||||
"Jetzt darf {playerName} glänzen.",
|
||||
"Ein Stein nimmt Fahrt auf – gesteuert von {playerName}.",
|
||||
"Jetzt kommt der nächste Schritt von {playerName}.",
|
||||
"Das Spiel bewegt sich weiter – dank {playerName}.",
|
||||
"Ein entscheidender Moment für {playerName}.",
|
||||
"Jetzt darf {playerName} kreativ werden.",
|
||||
"Ein weiterer Stein gehört {playerName}.",
|
||||
"Die Entscheidung fällt bei {playerName}.",
|
||||
"Jetzt darf {playerName} das Brett verändern.",
|
||||
"Ein Spielzug kündigt sich an – von {playerName}.",
|
||||
"Jetzt rollt der nächste Stein für {playerName}.",
|
||||
"Ein taktischer Augenblick für {playerName}.",
|
||||
"Jetzt ist der Zug von {playerName} gefragt.",
|
||||
"Die nächste Spalte wartet geduldig auf {playerName}.",
|
||||
"Jetzt darf {playerName} das Spiel formen.",
|
||||
"Ein neuer Zug entsteht durch {playerName}.",
|
||||
"Jetzt bringt {playerName} Bewegung ins Brett.",
|
||||
"Ein Stein fällt gleich – geworfen von {playerName}.",
|
||||
"Jetzt ist {playerName} wieder am Steuer.",
|
||||
"Ein neuer Spielzug wird von {playerName} gestartet.",
|
||||
"Jetzt darf {playerName} das Spiel drehen.",
|
||||
"Ein Moment voller Strategie für {playerName}.",
|
||||
"Jetzt kommt ein Stein von {playerName}.",
|
||||
"Eine Spalte wird gleich von {playerName} gewählt.",
|
||||
"Jetzt darf {playerName} die nächste Lücke füllen.",
|
||||
"Ein weiterer Zug gehört {playerName}.",
|
||||
"Jetzt entscheidet die Idee von {playerName}.",
|
||||
"Ein Stein fällt – {playerName} hat entschieden.",
|
||||
"Jetzt bringt {playerName} den nächsten Zug.",
|
||||
"Eine neue Möglichkeit entsteht durch {playerName}.",
|
||||
"Jetzt steht der Zug von {playerName} an.",
|
||||
"Ein weiteres Kapitel im Spiel – geschrieben von {playerName}.",
|
||||
"Jetzt darf {playerName} die nächste Spalte wählen.",
|
||||
"Ein kluger Moment für {playerName}.",
|
||||
"Jetzt wird das Brett von {playerName} erweitert.",
|
||||
"Ein weiterer Spielzug gehört {playerName}.",
|
||||
"Jetzt kommt die Entscheidung von {playerName}.",
|
||||
"Ein Stein landet gleich – gesetzt von {playerName}.",
|
||||
"Jetzt darf {playerName} den nächsten Plan umsetzen.",
|
||||
"Ein weiterer Moment für {playerName}.",
|
||||
"Jetzt führt {playerName} das Spiel weiter.",
|
||||
"Ein Zug mit Wirkung – von {playerName}.",
|
||||
"Jetzt darf {playerName} die Strategie zeigen.",
|
||||
"Ein weiterer Stein gehört eindeutig {playerName}.",
|
||||
"Jetzt ist der Moment von {playerName} gekommen.",
|
||||
"Ein neuer Zug entsteht durch die Entscheidung von {playerName}.",
|
||||
"Jetzt darf {playerName} die nächste Lücke schließen.",
|
||||
"Ein Stein macht sich bereit – für {playerName}.",
|
||||
"Jetzt setzt {playerName} den nächsten Impuls.",
|
||||
"Ein weiterer Schritt im Spiel kommt von {playerName}.",
|
||||
"Jetzt darf {playerName} das Brett verändern.",
|
||||
"Ein neuer Spielzug wartet auf {playerName}."
|
||||
];
|
||||
|
||||
export function getRandomMovePhrase(playerName: string): string {
|
||||
const phrase = movePhrases[Math.floor(Math.random() * movePhrases.length)];
|
||||
return phrase?.replace("{playerName}", playerName) ?? "Spieler";
|
||||
}
|
||||
Reference in New Issue
Block a user