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

feat: Create the Maps module #34

Merged
merged 15 commits into from
Aug 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/Application/CTF.Application.csproj
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>

<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="SampSharp.CTF.Entities" />
<PackageReference Include="seztion-parser" />
<PackageReference Include="SmartFormat" />
</ItemGroup>

Expand All @@ -29,4 +30,8 @@
</EmbeddedResource>
</ItemGroup>

<ItemGroup>
<Content Include="Maps\Files\*.ini" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

</Project>
45 changes: 45 additions & 0 deletions src/Application/Common/Resources/Messages.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions src/Application/Common/Resources/Messages.resx
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@
<data name="EmptyWeaponPackage" xml:space="preserve">
<value>You have no items in your weapon package</value>
</data>
<data name="InvalidInterval" xml:space="preserve">
<value>The interval must be between 0 to {Max}</value>
</data>
<data name="InvalidMap" xml:space="preserve">
<value>Invalid map id has been passed</value>
</data>
<data name="InvalidNickName" xml:space="preserve">
<value>Must be 3-20 characters long and only contain valid characters (0-9, a-z, A-Z, [], (), $, @ . _ and = only)</value>
</data>
Expand All @@ -141,6 +147,12 @@
<data name="InvalidWeapon" xml:space="preserve">
<value>Invalid weapon has been passed</value>
</data>
<data name="LocationListCannotBeEmpty" xml:space="preserve">
<value>The spawn location list cannot be empty</value>
</data>
<data name="MapNotFound" xml:space="preserve">
<value>Map has not been found</value>
</data>
<data name="MemberAlreadyExists" xml:space="preserve">
<value>Player '{Name}' is a member that already exists</value>
</data>
Expand All @@ -159,6 +171,9 @@
<data name="PlayerNotFound" xml:space="preserve">
<value>Player '{Name}' is not found</value>
</data>
<data name="SpawnLocationFailure" xml:space="preserve">
<value>A spawn location can only be obtained for the alpha or beta team</value>
</data>
<data name="SubtractPoints" xml:space="preserve">
<value>Points must be between -1 to -100</value>
</data>
Expand Down
22 changes: 11 additions & 11 deletions src/Application/Common/Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,32 @@
/// <summary>
/// Represents the result of an operation that does not return a value.
/// </summary>
public readonly ref struct Result
public ref struct Result
{
public Result() { }

/// <summary>
/// Gets the description of a result.
/// </summary>
public string Message { get; init; } = string.Empty;
public string Message { get; private set; } = string.Empty;

/// <summary>
/// A value indicating that the result was successful.
/// </summary>
public bool IsSuccess { get; init; } = true;
public bool IsSuccess { get; private set; } = false;

/// <summary>
/// A value that indicates that the result was a failure.
/// </summary>
public bool IsFailed => !IsSuccess;

public static Result Success() => new();
public static Result Success(string message) => new() { Message = message };

public static Result Failure() => new() { IsSuccess = false };
public static Result Failure(string message) => new()
{
IsSuccess = false,
Message = message
public static Result Success() => new() { IsSuccess = true };
public static Result Success(string message) => new()
{
IsSuccess = true,
Message = message
};

public static Result Failure() => new();
public static Result Failure(string message) => new() { Message = message };
}
40 changes: 29 additions & 11 deletions src/Application/Common/ResultOfT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,59 @@
/// Represents the result of an operation that returns a value.
/// </summary>
/// <typeparam name="TValue">A value associated to the result.</typeparam>
public readonly ref struct Result<TValue>
public ref struct Result<TValue>
{
private TValue _value;
public Result() { }

/// <summary>
/// Gets the value associated with the result.
/// </summary>
public TValue Value { get; init; } = default;
/// <exception cref="InvalidOperationException">
/// when <see cref="Result.IsFailed"/> is true.
/// </exception>
public TValue Value
{
get
{
return IsSuccess ?
_value :
throw new InvalidOperationException("The value of a failure result can not be accessed.");
}
private set
{
_value = value;
}
}

/// <summary>
/// Gets the description of a result.
/// </summary>
public string Message { get; init; } = string.Empty;
public string Message { get; private set; } = string.Empty;

/// <summary>
/// A value indicating that the result was successful.
/// </summary>
public bool IsSuccess { get; init; } = true;
public bool IsSuccess { get; private set; } = false;

/// <summary>
/// A value that indicates that the result was a failure.
/// </summary>
public bool IsFailed => !IsSuccess;

public static Result<TValue> Success(TValue value) => new() { Value = value };
public static Result<TValue> Success(TValue value) => new()
{
IsSuccess = true,
Value = value
};

public static Result<TValue> Success(TValue value, string message) => new()
{
IsSuccess = true,
Value = value,
Message = message
};

public static Result<TValue> Failure() => new() { IsSuccess = false };
public static Result<TValue> Failure(string message) => new()
{
IsSuccess = false,
Message = message
};
public static Result<TValue> Failure() => new();
public static Result<TValue> Failure(string message) => new() { Message = message };
}
65 changes: 65 additions & 0 deletions src/Application/Maps/CurrentMap.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
namespace CTF.Application.Maps;

/// <summary>
/// Represents the current information of a map.
/// </summary>
public class CurrentMap
{
private IMap _nextMap;
private readonly Random _random = new();
public const int DefaultInterior = 0;
public const int DefaultWeather = 10;
public const int DefaultWorldTime = 12;
public int Id { get; }
public string Name { get; }
public IReadOnlyList<SpawnLocation> AlphaTeamLocations { get; }
public IReadOnlyList<SpawnLocation> BetaTeamLocations { get; }
public int Interior { get; }
public int Weather { get; }
public int WorldTime { get; }
public IMap NextMap => _nextMap;
public int IsLoading { get; set; }

public CurrentMap(
IMap map,
IReadOnlyList<SpawnLocation> alphaTeamLocations,
IReadOnlyList<SpawnLocation> betaTeamLocations,
int interior = DefaultInterior,
int weather = DefaultWeather,
int worldTime = DefaultWorldTime)
{
ArgumentNullException.ThrowIfNull(map);
ArgumentNullException.ThrowIfNull(alphaTeamLocations);
ArgumentNullException.ThrowIfNull(betaTeamLocations);

if (alphaTeamLocations.Count == 0)
throw new ArgumentException(Messages.LocationListCannotBeEmpty, nameof(alphaTeamLocations));

if (betaTeamLocations.Count == 0)
throw new ArgumentException(Messages.LocationListCannotBeEmpty, nameof(betaTeamLocations));

Id = map.Id;
Name = map.Name;
AlphaTeamLocations = alphaTeamLocations;
BetaTeamLocations = betaTeamLocations;
Interior = interior;
Weather = weather;
WorldTime = worldTime;
int nextMapId = (Id + 1) % MapCollection.Count;
_nextMap = MapCollection.GetById(nextMapId).Value;
}

public string GetMapNameAsText() => $"Map: ~w~{Name}";
public void SetNextMap(IMap nextMap)
{
ArgumentNullException.ThrowIfNull(nextMap);
_nextMap = nextMap;
}

public SpawnLocation GetRandomSpawnLocation(TeamId team) => team switch
{
TeamId.Alpha => AlphaTeamLocations[_random.Next(AlphaTeamLocations.Count)],
TeamId.Beta => BetaTeamLocations[_random.Next(BetaTeamLocations.Count)],
_ => throw new NotSupportedException(Messages.SpawnLocationFailure)
};
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
7 changes: 7 additions & 0 deletions src/Application/Maps/IMap.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace CTF.Application.Maps;

public interface IMap
{
int Id { get; }
string Name { get; }
}
58 changes: 58 additions & 0 deletions src/Application/Maps/LoadTime.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
namespace CTF.Application.Maps;

/// <summary>
/// Represents the total wait time for the new map to load.
/// </summary>
public class LoadTime
{
private readonly Action _onLoadingMap;
private readonly Action _onLoadedMap;
private int _interval = MaxLoadTime;
public const int MaxLoadTime = 6;

/// <summary>
/// Displays the load time in the game.
/// </summary>
public string GameText { get; private set; } = string.Empty;

/// <summary>
/// Represents the interval in seconds.
/// </summary>
public int Interval => _interval;

public LoadTime(Action onLoadingMap, Action onLoadedMap)
{
ArgumentNullException.ThrowIfNull(onLoadingMap);
ArgumentNullException.ThrowIfNull(onLoadedMap);
_onLoadingMap = onLoadingMap;
_onLoadedMap = onLoadedMap;
}

/// <summary>
/// Reduces the load time until it reaches zero.
/// </summary>
public void Decrease()
{
if (_interval == 0)
{
Reset();
_onLoadedMap();
return;
}

if (_interval == MaxLoadTime)
{
_onLoadingMap();
}

_interval--;
UpdateGameText();
}

private void UpdateGameText() => GameText = $"Loading map... ({_interval})";
private void Reset()
{
_interval = MaxLoadTime;
GameText = string.Empty;
}
}
Loading
Loading