baseline: OpenMU upstream b5a0961 (fresh source)
This commit is contained in:
121
src/GameLogic/MiniGames/DevilSquareContext.cs
Normal file
121
src/GameLogic/MiniGames/DevilSquareContext.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
// <copyright file="DevilSquareContext.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.GameLogic.MiniGames;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using Nito.Disposables.Internals;
|
||||
|
||||
/// <summary>
|
||||
/// The context of a devil square game.
|
||||
/// </summary>
|
||||
public sealed class DevilSquareContext : MiniGameContext
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, PlayerGameState> _gameStates = new();
|
||||
|
||||
private IReadOnlyCollection<(string Name, int Score, int BonusMoney, int BonusExp)>? _highScoreTable;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DevilSquareContext"/> class.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of this context.</param>
|
||||
/// <param name="definition">The definition of the mini game.</param>
|
||||
/// <param name="gameContext">The game context, to which this game belongs.</param>
|
||||
/// <param name="mapInitializer">The map initializer, which is used when the event starts.</param>
|
||||
public DevilSquareContext(MiniGameMapKey key, MiniGameDefinition definition, IGameContext gameContext, IMapInitializer mapInitializer)
|
||||
: base(key, definition, gameContext, mapInitializer)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnMonsterDied(object? sender, DeathInformation e)
|
||||
{
|
||||
base.OnMonsterDied(sender, e);
|
||||
|
||||
if (this._gameStates.TryGetValue(e.KillerName, out var state))
|
||||
{
|
||||
state.AddScore(this.Definition.GameLevel);
|
||||
|
||||
// todo add money? -> in the original servers, in DS drops no money!
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async ValueTask OnGameStartAsync(ICollection<Player> players)
|
||||
{
|
||||
foreach (var player in players)
|
||||
{
|
||||
this._gameStates.TryAdd(player.Name, new PlayerGameState(player));
|
||||
}
|
||||
|
||||
await base.OnGameStartAsync(players).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async ValueTask GameEndedAsync(ICollection<Player> finishers)
|
||||
{
|
||||
var sortedFinishers = finishers
|
||||
.Select(f => this._gameStates[f.Name])
|
||||
.WhereNotNull()
|
||||
.OrderBy(state => state.Score)
|
||||
.ToList();
|
||||
|
||||
var scoreList = new List<(string Name, int Score, int BonusMoney, int BonusExp)>();
|
||||
int rank = 0;
|
||||
foreach (var state in sortedFinishers)
|
||||
{
|
||||
rank++;
|
||||
state.Rank = rank;
|
||||
var (bonusScore, givenMoney) = await this.GiveRewardsAndGetBonusScoreAsync(state.Player, rank).ConfigureAwait(false);
|
||||
state.AddScore(bonusScore);
|
||||
scoreList.Add((
|
||||
state.Player.Name,
|
||||
state.Score,
|
||||
givenMoney,
|
||||
this.Definition.Rewards.FirstOrDefault(r => r.RewardType == MiniGameRewardType.Experience && (r.Rank is null || r.Rank == rank))?.RewardAmount ?? 0));
|
||||
}
|
||||
|
||||
this._highScoreTable = scoreList.AsReadOnly();
|
||||
|
||||
await this.SaveRankingAsync(sortedFinishers.Select(state => (state.Rank, state.Player.SelectedCharacter!, state.Score))).ConfigureAwait(false);
|
||||
await base.GameEndedAsync(finishers).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async ValueTask ShowScoreAsync(Player player)
|
||||
{
|
||||
if (this._highScoreTable is { } table
|
||||
&& this._gameStates.TryGetValue(player.Name, out var state))
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IMiniGameScoreTableViewPlugin>(p => p.ShowScoreTableAsync((byte)state.Rank, table)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class PlayerGameState
|
||||
{
|
||||
private int _score;
|
||||
|
||||
public PlayerGameState(Player player)
|
||||
{
|
||||
if (player.SelectedCharacter?.CharacterClass is null)
|
||||
{
|
||||
throw new InvalidOperationException($"The player '{player}' is in the wrong state");
|
||||
}
|
||||
|
||||
this.Player = player;
|
||||
}
|
||||
|
||||
public Player Player { get; }
|
||||
|
||||
public int Score => this._score;
|
||||
|
||||
public int Rank { get; set; }
|
||||
|
||||
public void AddScore(int value)
|
||||
{
|
||||
Interlocked.Add(ref this._score, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user