Animal Racing added ($race, $joinrace). Need to add betting to it.

This commit is contained in:
Kwoth 2016-07-25 04:21:37 +02:00
parent fce0da50f1
commit a7618b1ee4
7 changed files with 282 additions and 3 deletions

View File

@ -138,7 +138,7 @@ namespace NadekoBot.Extensions
/// </summary> /// </summary>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <param name="list"></param> /// <param name="list"></param>
public static void Shuffle<T>(this IList<T> list) public static IList<T> Shuffle<T>(this IList<T> list)
{ {
// Thanks to @Joe4Evr for finding a bug in the old version of the shuffle // Thanks to @Joe4Evr for finding a bug in the old version of the shuffle
@ -160,6 +160,7 @@ namespace NadekoBot.Extensions
list[k] = list[n]; list[k] = list[n];
list[n] = value; list[n] = value;
} }
return list;
} }
/// <summary> /// <summary>

View File

@ -41,8 +41,9 @@ namespace NadekoBot
var commandService = NadekoBot.Client.GetService<CommandService>(); var commandService = NadekoBot.Client.GetService<CommandService>();
statsStopwatch.Start(); statsStopwatch.Start();
#if !NADEKO_RELEASE
commandService.CommandExecuted += StatsCollector_RanCommand; commandService.CommandExecuted += StatsCollector_RanCommand;
#endif
Task.Run(StartCollecting); Task.Run(StartCollecting);
commandLogTimer.Start(); commandLogTimer.Start();

View File

@ -0,0 +1,253 @@
using NadekoBot.Classes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
using System.Collections.Concurrent;
using Discord;
using NadekoBot.Extensions;
using System.Threading;
namespace NadekoBot.Modules.Gambling.Commands
{
class AnimalRacing : DiscordCommand
{
public static ConcurrentDictionary<ulong, AnimalRace> AnimalRaces = new ConcurrentDictionary<ulong, AnimalRace>();
public AnimalRacing(DiscordModule module) : base(module)
{
}
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Prefix + "race")
.Description("Starts a new animal race.")
.Do(e => {
var ar = new AnimalRace(e.Server.Id, e.Channel);
if (ar.Fail)
{
return;
}
});
cgb.CreateCommand(Prefix + "joinrace")
.Alias(Prefix + "jr")
.Description("Joins a new race")
.Do(async e => {
AnimalRace ar;
if (!AnimalRaces.TryGetValue(e.Server.Id, out ar)) {
await e.Channel.SendMessage("No race exists on this server");
}
await ar.JoinRace(e.User);
});
}
public class AnimalRace
{
private ConcurrentQueue<string> animals = new ConcurrentQueue<string>(NadekoBot.Config.RaceAnimals.Shuffle());
public bool Fail { get; internal set; }
public List<Participant> participants = new List<Participant>();
private ulong serverId;
private int messagesSinceGameStarted = 0;
public Channel raceChannel { get; set; }
public bool Started { get; private set; } = false;
public AnimalRace(ulong serverId, Channel ch)
{
this.serverId = serverId;
this.raceChannel = ch;
if (!AnimalRaces.TryAdd(serverId, this))
{
Fail = true;
return;
}
var cancelSource = new CancellationTokenSource();
var token = cancelSource.Token;
var fullgame = CheckForFullGameAsync(token);
Task.Run(async () =>
{
await raceChannel.SendMessage($"🏁`Race is starting in 20 seconds or when the room is full. Type $jr to join the race.`");
var t = await Task.WhenAny(Task.Delay(20000, token), fullgame);
Started = true;
cancelSource.Cancel();
if (t == fullgame)
{
await raceChannel.SendMessage("🏁`Race full, starting right now!`");
}
else if (participants.Count > 1) {
await raceChannel.SendMessage("🏁`Game starting with " + participants.Count + " praticipants.`");
}
else {
await raceChannel.SendMessage("🏁`Race failed to start since there was not enough participants.`");
End();
return;
}
await Task.Run(StartRace);
End();
});
}
private void End()
{
AnimalRace throwaway;
AnimalRaces.TryRemove(serverId, out throwaway);
}
private async Task StartRace() {
var rng = new Random();
Participant winner = null;
Message msg = null;
int place = 1;
try
{
NadekoBot.Client.MessageReceived += Client_MessageReceived;
while (!participants.All(p => p.Total >= 60))
{
//update the state
participants.ForEach(p =>
{
p.Total += 1 + rng.Next(0, 10);
if (p.Total > 60)
{
p.Total = 60;
if (winner == null)
{
winner = p;
}
if (p.Place == 0)
p.Place = place++;
}
});
//draw the state
var text = $@"|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|
{String.Join("\n", participants.Select(p => $"{(int)(p.Total / 60f * 100),-2}%|{p.ToString()}"))}
|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|";
if (msg == null || messagesSinceGameStarted >= 10) // also resend the message if channel was spammed
{
if(msg != null)
try { await msg.Delete(); } catch { }
msg = await raceChannel.SendMessage(text);
messagesSinceGameStarted = 0;
}
else
await msg.Edit(text);
await Task.Delay(2500);
}
}
finally
{
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
}
await raceChannel.SendMessage($"🏁 {winner.User.Mention} as {winner.Animal} `Won the race!`");
}
private void Client_MessageReceived(object sender, MessageEventArgs e)
{
if (e.Message.IsAuthor)
return;
Console.WriteLine("Message received " + messagesSinceGameStarted);
messagesSinceGameStarted++;
}
private async Task CheckForFullGameAsync(CancellationToken cancelToken) {
while (animals.Count > 0)
{
await Task.Delay(100,cancelToken);
}
}
public async Task<bool> JoinRace(User u)
{
var animal = "";
if (!animals.TryDequeue(out animal))
{
await raceChannel.SendMessage($"{u.Mention} `There is no running race on this server.`");
return false;
}
var p = new Participant(u, animal);
if (participants.Contains(p))
{
await raceChannel.SendMessage($"{u.Mention} `You already joined this race.`");
return false;
}
if (Started)
{
await raceChannel.SendMessage($"{u.Mention} `Race is already started`");
return false;
}
participants.Add(p);
await raceChannel.SendMessage($"{u.Mention} **joined the race as a {p.Animal}**");
return true;
}
}
public class Participant
{
public User User { get; set; }
public string Animal { get; set; }
public float Coeff { get; set; }
public int Total { get; set; }
public int Place { get; set; } = 0;
public Participant(User u, string a)
{
this.User = u;
this.Animal = a;
}
public override int GetHashCode()
{
return User.GetHashCode();
}
public override bool Equals(object obj)
{
var p = obj as Participant;
return p == null?
false:
p.User == User;
}
public override string ToString()
{
var str = new string('‣', Total) + Animal;
if (Place == 0)
return str;
if (Place == 1)
{
return str + "🏆";
}
else if (Place == 2)
{
return str + "`2nd`";
}
else if (Place == 3)
{
return str + "`3rd`";
}
else {
return str + $"`{Place}th`";
}
}
}
}
}

View File

@ -4,6 +4,7 @@ using Discord.Modules;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.DataModels; using NadekoBot.DataModels;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using NadekoBot.Modules.Gambling.Commands;
using NadekoBot.Modules.Permissions.Classes; using NadekoBot.Modules.Permissions.Classes;
using System; using System;
using System.Linq; using System.Linq;
@ -18,6 +19,7 @@ namespace NadekoBot.Modules.Gambling
commands.Add(new DrawCommand(this)); commands.Add(new DrawCommand(this));
commands.Add(new FlipCoinCommand(this)); commands.Add(new FlipCoinCommand(this));
commands.Add(new DiceRollCommand(this)); commands.Add(new DiceRollCommand(this));
commands.Add(new AnimalRacing(this));
} }
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Gambling; public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Gambling;

View File

@ -56,6 +56,7 @@
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'PRIVATE|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'PRIVATE|AnyCPU'">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -189,6 +190,7 @@
<Compile Include="Classes\FlowersHandler.cs" /> <Compile Include="Classes\FlowersHandler.cs" />
<Compile Include="Modules\Conversations\Commands\RipCommand.cs" /> <Compile Include="Modules\Conversations\Commands\RipCommand.cs" />
<Compile Include="Modules\CustomReactions\CustomReactions.cs" /> <Compile Include="Modules\CustomReactions\CustomReactions.cs" />
<Compile Include="Modules\Gambling\Commands\AnimalRacing.cs" />
<Compile Include="Modules\Music\Classes\PlaylistFullException.cs" /> <Compile Include="Modules\Music\Classes\PlaylistFullException.cs" />
<Compile Include="Modules\Programming\Commands\HaskellRepl.cs" /> <Compile Include="Modules\Programming\Commands\HaskellRepl.cs" />
<Compile Include="Modules\Programming\ProgrammingModule.cs" /> <Compile Include="Modules\Programming\ProgrammingModule.cs" />

View File

@ -90,6 +90,17 @@ namespace NadekoBot.Classes.JSONModels
public bool IsRotatingStatus { get; set; } = false; public bool IsRotatingStatus { get; set; } = false;
public int BufferSize { get; set; } = 4.MiB(); public int BufferSize { get; set; } = 4.MiB();
public string[] RaceAnimals { get; internal set; } = {
"🐼",
"🐻",
"🐧",
"🐨",
"🐬",
"🐞",
"🦀",
"🦄" };
[JsonIgnore]
public List<Quote> Quotes { get; set; } = new List<Quote>(); public List<Quote> Quotes { get; set; } = new List<Quote>();
[JsonIgnore] [JsonIgnore]

View File

@ -4,7 +4,16 @@
"ForwardToAllOwners": false, "ForwardToAllOwners": false,
"IsRotatingStatus": false, "IsRotatingStatus": false,
"BufferSize": 4194304, "BufferSize": 4194304,
"Quotes": [], "RaceAnimals": [
"🐼",
"🐻",
"🐧",
"🐨",
"🐬",
"🐞",
"🦀",
"🦄"
],
"RemindMessageFormat": "❗⏰**I've been told to remind you to '%message%' now by %user%.**⏰❗", "RemindMessageFormat": "❗⏰**I've been told to remind you to '%message%' now by %user%.**⏰❗",
"CustomReactions": { "CustomReactions": {
"\\o\\": [ "\\o\\": [