diff --git a/DiscordMafia/Activity/BooleanVoteActivity.cs b/DiscordMafia/Activity/BooleanVoteActivity.cs
index 2095bd7..51db9fd 100644
--- a/DiscordMafia/Activity/BooleanVoteActivity.cs
+++ b/DiscordMafia/Activity/BooleanVoteActivity.cs
@@ -7,12 +7,16 @@ public class BooleanVoteActivity : BaseActivity
{
public BooleanVote Vote { get; protected set; }
public bool Value { get; protected set; }
+ public int Weight { get; protected set; }
+ public EWeightType WeightType { get; protected set; }
- public BooleanVoteActivity(InGamePlayerInfo player, BooleanVote vote, bool value)
+ public BooleanVoteActivity(InGamePlayerInfo player, BooleanVote vote, bool value, int weight, EWeightType weightType)
: base(player)
{
Vote = vote;
Value = value;
+ Weight = weight;
+ WeightType = weightType;
Player.EveningVoteActivity = this;
}
@@ -29,4 +33,13 @@ protected override void OnCancel(InGamePlayerInfo onlyAgainstTarget)
}
}
}
+
+ [Flags]
+ public enum EWeightType
+ {
+ None = 0,
+ Positive = 1,
+ Negative = 2,
+ Both = 3
+ }
}
diff --git a/DiscordMafia/Config/GameSettings.cs b/DiscordMafia/Config/GameSettings.cs
index 5228b1d..0bcaf2d 100644
--- a/DiscordMafia/Config/GameSettings.cs
+++ b/DiscordMafia/Config/GameSettings.cs
@@ -32,6 +32,7 @@ public class GameSettings : IXmlSerializable
public int DayTime { get; protected set; }
public int EveningTime { get; protected set; }
public int NightTime { get; protected set; }
+ public int MaxInactiveDays { get; protected set; }
public byte MaxUsersToNotify { get; protected set; }
public int MinNotificationInterval { get; protected set; }
@@ -65,6 +66,7 @@ public GameSettings(MainSettings mainSettings, string gametype)
EveningTime = 30000;
NightTime = 90000;
InfectionChancePercent = 33;
+ MaxInactiveDays = 3;
MaxUsersToNotify = 50;
MinNotificationInterval = 7200;
ShowNightActions = true;
@@ -184,6 +186,9 @@ public void ReadXml(XmlReader reader)
case "MaxUsersToNotify":
MaxUsersToNotify = byte.Parse(reader.ReadElementContentAsString());
break;
+ case "MaxInactiveDays":
+ MaxInactiveDays = int.Parse(reader.ReadElementContentAsString());
+ break;
case "InfectionChancePercent":
InfectionChancePercent = short.Parse(reader.ReadElementContentAsString());
break;
diff --git a/DiscordMafia/Config/Gametypes/yakuza-only/roles.xml b/DiscordMafia/Config/Gametypes/yakuza-only/roles.xml
index 04c52b8..f25d139 100644
--- a/DiscordMafia/Config/Gametypes/yakuza-only/roles.xml
+++ b/DiscordMafia/Config/Gametypes/yakuza-only/roles.xml
@@ -50,6 +50,11 @@
true
10
+
+ true
+ false
+ 12
+
true
false
@@ -70,6 +75,11 @@
true
10
+
+ true
+ false
+ 12
+
true
true
@@ -85,6 +95,11 @@
true
8
+
+ true
+ true
+ 8
+
true
true
diff --git a/DiscordMafia/Config/Gametypes/yakuza/roles.xml b/DiscordMafia/Config/Gametypes/yakuza/roles.xml
index 32d4a42..663634f 100644
--- a/DiscordMafia/Config/Gametypes/yakuza/roles.xml
+++ b/DiscordMafia/Config/Gametypes/yakuza/roles.xml
@@ -50,6 +50,11 @@
true
10
+
+ true
+ false
+ 15
+
true
false
@@ -75,6 +80,11 @@
true
10
+
+ true
+ false
+ 15
+
true
true
@@ -85,6 +95,11 @@
true
10
+
+ true
+ false
+ 15
+
true
true
@@ -100,6 +115,11 @@
true
8
+
+ true
+ true
+ 8
+
true
true
diff --git a/DiscordMafia/Config/Lang/en/messages.xml b/DiscordMafia/Config/Lang/en/messages.xml
index eabba50..2719a02 100644
--- a/DiscordMafia/Config/Lang/en/messages.xml
+++ b/DiscordMafia/Config/Lang/en/messages.xml
@@ -42,6 +42,18 @@
Not enough players ({count}/{minCount})
+ -
+ ChargesRemainingInfo
+
+ Charges: {count}
+
+
+ -
+ CooldownInfo
+
+ Cooldown: {current}/{total}
+
+
-
MafiaWelcome
@@ -137,10 +149,24 @@ Remaining Players:
{nameSimple} votes for the murder of {toKill} ({count})!
+ -
+ DayRepeated
+
+
+ Rabble-rouser talks, you listen? OK, let's skip this night.]]>
+
+
+
+ -
+ InactivePlayersKilled
+
+ Some players were inactive more than {limit} days and removed from game: {players}.
+
+
-
CheckStatus
- {name}'s status — {role}.
+ {name}'s (`{nameSimple}'s`) status — {role}.
-
@@ -235,6 +261,12 @@ Remaining Players:
You are a fan of sunbeams, so peaceful that no one dares to raise his hand on you at night and applies his action to himself.
+ -
+ RoleHelp_RabbleRouser
+
+ You are a Rabble Rouser. Citizens can send victims to jail twice a day.
+
+
-
RoleHelp_Mafioso
@@ -259,6 +291,12 @@ Remaining Players:
On New Year's Eve you loved to blow firecrackers. Over time, this hobby turned into work.
+ -
+ RoleHelp_Hammerer
+
+ Your vote have double weight on **evening** **positive** (yes) voting.
+
+
-
RoleHelp_Yakuza
@@ -277,6 +315,12 @@ Remaining Players:
You are a horror, creeping on tiptoe of the night. Against you nothing can be done at night. And in the rest you are the same participant in the Japanese mafia, shoot innocents and mafia one by one.
+ -
+ RoleHelp_Kamikaze
+
+ You are so loyal to the yakuza that you are ready to sacrifice your life for its sake. Life is one, so once per game, of course.
+
+
-
RoleHelp_Maniac
@@ -301,6 +345,12 @@ Remaining Players:
You are a master of keyboard and mouse. Hack into the computers of players and tell everyone their statuses.
+ -
+ RoleHelp_Poisoner
+
+ You are a maniac chemist. Every day you can poison the water in the well of one of the citizens. Next day he will die.
+
+
-
GameStart_Role_Default
@@ -451,6 +501,15 @@ Remaining Players:
+ -
+ NightInfo_Kamikaze
+
+
+ /kill X, where X — number of the player. You can skip by /skip.]]>
+
+
+
-
NightInfo_Maniac
@@ -504,6 +563,23 @@ Remaining Players:
+ -
+ DayInfo_RabbleRouser
+
+
+ /talk.]]>
+
+
+
+ -
+ DayInfo_Poisoner
+
+
+ /kill X, where X — number of the player.]]>
+
+
+
-
EndNight
@@ -668,6 +744,18 @@ Remaining Players:
🛡 Yakuza wanted to make a sieve from a citizen, but he was the {role} and survived.
+ -
+ KamikazeKill
+
+ ☠ Kamikaze killed {name}, who was the {role}.
+
+
+ -
+ KamikazeKillHimself
+
+ ☠ {name} ({role}) has killed {gender:himself|herself}.
+
+
-
ComNoActive
@@ -853,6 +941,18 @@ Remaining Players:
👠 {name} ({role}) was dead from a deadly infection. Greetings from the Wench :)
+ -
+ PoisonerPoison
+
+ 🤢 {role} was poisoned by the Poisoner.
+
+
+ -
+ PoisonerKill
+
+ 🤢 {name} ({role}) died of poison.
+
+
-
ComKilled_ToSergeant
diff --git a/DiscordMafia/Config/Lang/en/modules.xml b/DiscordMafia/Config/Lang/en/modules.xml
index 4382520..45c7df5 100644
--- a/DiscordMafia/Config/Lang/en/modules.xml
+++ b/DiscordMafia/Config/Lang/en/modules.xml
@@ -74,6 +74,12 @@
Assist in killing a player.
+ -
+ talk
+
+ Talk with players.
+
+
-
curse
diff --git a/DiscordMafia/Config/Lang/en/roles.xml b/DiscordMafia/Config/Lang/en/roles.xml
index 816bd4e..1415ef5 100644
--- a/DiscordMafia/Config/Lang/en/roles.xml
+++ b/DiscordMafia/Config/Lang/en/roles.xml
@@ -60,6 +60,16 @@
+ -
+ Hammerer
+
+ Hammerer
+
+ hammerer
+ hammerer's
+
+
+
-
Highlander
@@ -100,6 +110,16 @@
+ -
+ Kamikaze
+
+ Kamikaze
+
+ kamikaze
+ kamikaze's
+
+
+
-
Killer
@@ -160,6 +180,16 @@
+ -
+ Poisoner
+
+ Poisoner
+
+ poisoner
+ poisoner's
+
+
+
-
Prosecutor
@@ -170,6 +200,16 @@
+ -
+ RabbleRouser
+
+ Rabble-Rouser
+
+ rabble-rouser
+ rabble-rouser's
+
+
+
-
RobinHood
diff --git a/DiscordMafia/Config/Lang/ru/messages.xml b/DiscordMafia/Config/Lang/ru/messages.xml
index 09e6dcf..cb287a6 100644
--- a/DiscordMafia/Config/Lang/ru/messages.xml
+++ b/DiscordMafia/Config/Lang/ru/messages.xml
@@ -42,6 +42,18 @@
Недостаточно игроков ({count}/{minCount})
+ -
+ ChargesRemainingInfo
+
+ Осталось зарядов: {count}
+
+
+ -
+ CooldownInfo
+
+ Осталось до отката способности: {current}/{total}
+
+
-
MafiaWelcome
@@ -137,10 +149,27 @@
{nameSimple} голосует за убийство {toKill} ({count})!
+ -
+ DayRepeated
+
+
+ Демагог заболтал всех настолько, что ночь уже прошла! Снова наступило время кого-то посадить.]]>
+
+
+ демагогом?]]>
+
+
+
+ -
+ InactivePlayersKilled
+
+ Голосовать надо днем! За отстуствие активности более {limit} дней были удалены из игры: {players}
+
+
-
CheckStatus
- Статус {name} — {role}.
+ Статус {name} (`{nameSimple}`) — {role}.
-
@@ -235,6 +264,12 @@
Вы — любитель солнечных зайчиков. При этом настолько миролюбивы, что никто не смеет поднять на Вас ночью руку и применяет своё действие на себя.
+ -
+ RoleHelp_RabbleRouser
+
+ Вы — неприятный демагог. Настолько завлекаете жителей города своей болтовнёй, что они рады могут быть днем посадить кого-нибудь еще раз.
+
+
-
RoleHelp_Mafioso
@@ -259,6 +294,12 @@
На Новый Год Вы любили взрывать петарды. Со временем это хобби переросло в работу.
+ -
+ RoleHelp_Hammerer
+
+ Никто не знает о Ваших связях с мафией. Но мнение уважают, поэтому при **вечерней** посадке голос **за повешение** будет считаться за два.
+
+
-
RoleHelp_Yakuza
@@ -277,6 +318,12 @@
Вы – Ужас, крадущийся на цыпочках ночи. Против вас ничего нельзя сделать ночью. Вы как бы есть, но Вас как бы нет. А в остальном вы такой же участник японской мафии, отстреливаете граждан и мафов по одному.
+ -
+ RoleHelp_Kamikaze
+
+ Вы настолько верны якудзе, что готовы пожертвовать жизнью ради неё. Жизнь - одна, так что один раз за игру, разумеется.
+
+
-
RoleHelp_Maniac
@@ -298,7 +345,13 @@
-
RoleHelp_Hacker
- Вы — мастер клавиатуры и мыши. Взламывайте компьютеры игроков и сообщайте всем их статусы.
+ Вы — мастер клавиатуры и мыши. Взламывайте компьютеры игроков и сообщайте всем их статусы.
+
+
+ -
+ RoleHelp_Poisoner
+
+ Вы — маньяк-отравитель. Более изощрённый способ убийства, но в сухом остатке — смерти.
-
@@ -314,6 +367,12 @@
Ваш статус {role}.
+ -
+ GameStart_Role_Hammerer
+
+ Вы — {role0}, продавшийся мафии. Но мирные этого не знают и считают ваш голос на вечернем голосовании за два (в случае, если это голос **за** повешение).
+
+
-
NightInfo_Commissioner
@@ -451,6 +510,15 @@
+ -
+ NightInfo_Kamikaze
+
+
+ /убить X, где X — номер игрока. Не забудьте, после подготовки действие уже не отменить. Ход можно пропустить /скип.]]>
+
+
+
-
NightInfo_Maniac
@@ -504,6 +572,23 @@
+ -
+ DayInfo_Poisoner
+
+
+ /убить X, где X — номер игрока.]]>
+
+
+
+ -
+ DayInfo_RabbleRouser
+
+
+ /уболтать.]]>
+
+
+
-
EndNight
@@ -669,6 +754,18 @@
🛡 Японская мафия хотела сделать решето из жителя, но тот оказался {role4} и выжил.
+ -
+ KamikazeKill
+
+ ☠ Камикадзе подорвал {name}, {gender:который оказался|которая оказалась} {role4}.
+
+
+ -
+ KamikazeKillHimself
+
+ ☠ {name} ({role}) {gender:самоуничтожился|самоуничтожилась}.
+
+
-
ComNoActive
@@ -855,6 +952,19 @@
👠 {name} ({role}) {gender:умер|умерла} от смертельной инфекции. Привет от путаны :)
+ -
+ PoisonerPoison
+
+ 🤢 {role} был отравлен отравителем.
+ 🤢 Вода в колодце {role3} была отравлена.
+
+
+ -
+ PoisonerKill
+
+ 🤢 {name} ({role}) {gender:умер|умерла} от инфекции. Отравитель в восторге.
+
+
-
ComKilled_ToSergeant
diff --git a/DiscordMafia/Config/Lang/ru/modules.xml b/DiscordMafia/Config/Lang/ru/modules.xml
index c58464b..5fae067 100644
--- a/DiscordMafia/Config/Lang/ru/modules.xml
+++ b/DiscordMafia/Config/Lang/ru/modules.xml
@@ -107,6 +107,17 @@
Посодействовать в убийстве игрока.
+ -
+ talk
+
+
+ заболтать
+ уболтать
+ болтать
+
+ Заболтать игроков.
+
+
-
curse
diff --git a/DiscordMafia/Config/Lang/ru/roles.xml b/DiscordMafia/Config/Lang/ru/roles.xml
index 3fe8c50..53939ba 100644
--- a/DiscordMafia/Config/Lang/ru/roles.xml
+++ b/DiscordMafia/Config/Lang/ru/roles.xml
@@ -84,6 +84,20 @@
+ -
+ Hammerer
+
+ Палач
+
+ палач
+ палача
+ палачу
+ палача
+ палачом
+ палаче
+
+
+
-
Highlander
@@ -140,6 +154,20 @@
+ -
+ Kamikaze
+
+ Камикадзе
+
+ камикадзе
+ камикадзе
+ камикадзе
+ камикадзе
+ камикадзе
+ камикадзе
+
+
+
-
Killer
@@ -224,6 +252,20 @@
+ -
+ Poisoner
+
+ Отравитель
+
+ отравитель
+ отравителя
+ отравителю
+ отравителя
+ отравителем
+ отравителе
+
+
+
-
Prosecutor
@@ -238,6 +280,20 @@
+ -
+ RabbleRouser
+
+ Демагог
+
+ демагог
+ демагога
+ демагогу
+ демагога
+ демагогом
+ демагоге
+
+
+
-
RobinHood
diff --git a/DiscordMafia/Config/roles.xml b/DiscordMafia/Config/roles.xml
index d966a26..322b835 100644
--- a/DiscordMafia/Config/roles.xml
+++ b/DiscordMafia/Config/roles.xml
@@ -50,6 +50,11 @@
true
10
+
+ true
+ false
+ 12
+
true
false
@@ -75,6 +80,11 @@
true
9
+
+ true
+ false
+ 12
+
true
true
@@ -90,6 +100,11 @@
true
8
+
+ true
+ true
+ 8
+
true
true
diff --git a/DiscordMafia/Game.cs b/DiscordMafia/Game.cs
index c4f151b..f3b8671 100644
--- a/DiscordMafia/Game.cs
+++ b/DiscordMafia/Game.cs
@@ -15,6 +15,7 @@
using Microsoft.EntityFrameworkCore;
using static DiscordMafia.Config.MessageBuilder;
using DiscordMafia.Extensions;
+using DiscordMafia.Activity;
namespace DiscordMafia
{
@@ -153,7 +154,7 @@ internal void EveningVote(InGamePlayerInfo player, bool voteValue)
var leader = CurrentPlayers[result.Leader.Value];
if (leader != player)
{
- CurrentEveningVote.Add(player, voteValue);
+ CurrentEveningVote.Add(player, voteValue, player.Role.EveningVoteWeight, player.Role.EveningVoteWeightType);
MessageBuilder
.PrepareTextReplacePlayer(
voteValue ? "EveningVote_Yes" : "EveningVote_No",
@@ -378,7 +379,7 @@ internal void CheckNextCheckpoint()
isAllReady = player.IsReady(CurrentState);
if (player.Role is Demoman && CurrentState == GameState.Night)
{
- if ((player.Role as Demoman).Counter == 0)
+ if (!(player.Role as Demoman).IsOnCooldown())
{
isAllReady = false;
}
@@ -525,7 +526,7 @@ private void StartDay()
{
if (player.IsAlive)
{
- player.Role.DayInfo(this, player);
+ player.Role.OnDayStart(this, player);
}
}
@@ -568,7 +569,7 @@ private void StartNight()
{
if (player.IsAlive)
{
- player.Role.NightInfo(this, player);
+ player.Role.OnNightStart(this, player);
}
}
@@ -585,7 +586,8 @@ private void EndEvening()
Console.WriteLine("EndEvening");
_notifier.ResetTimeOfDay();
var result = CurrentDayVote?.GetResult();
- var eveningResult = CurrentEveningVote?.GetResult();
+ var eveningResult = CurrentEveningVote?.GetResult(true);
+ bool willDayBeRepeated = false;
foreach (var player in PlayerSorter.SortForActivityCheck(PlayersList, GameState.Day))
{
@@ -654,6 +656,61 @@ private void EndEvening()
}
}
#endregion
+
+ #region Kamikaze
+ if (player.Role is Kamikaze)
+ {
+ var role = player.Role as Kamikaze;
+ if (role.PlayerToInteract != null)
+ {
+ if (role.PlayerToInteract.IsAlive)
+ {
+ string pointsStrategy = null;
+ if (role.PlayerToInteract.Role is Commissioner)
+ {
+ pointsStrategy = "MafKillCom";
+ }
+ else if (role.PlayerToInteract.Role.Team == Team.Mafia)
+ {
+ pointsStrategy = "MafKillOpposite";
+ }
+
+ // Double points
+ if (pointsStrategy != null)
+ {
+ player.AddPoints(pointsStrategy);
+ player.AddPoints(pointsStrategy);
+ }
+ player.AddPoints("MafKill");
+ player.AddPoints("MafKill");
+
+ KillManager.Kill(role.PlayerToInteract);
+ MessageBuilder.PrepareTextReplacePlayer("KamikazeKill", role.PlayerToInteract).SendPublic(GameChannel);
+ Pause();
+ }
+ KillManager.Kill(player);
+ MessageBuilder.PrepareTextReplacePlayer("KamikazeKillHimself", player).SendPublic(GameChannel);
+ Pause();
+ }
+ }
+ #endregion
+
+ #region Poisoner
+ if (player.Role is Poisoner)
+ {
+ var role = player.Role as Poisoner;
+ if (role.PlayerToInteract != null)
+ {
+ if (role.PlayerToInteract.DelayedDeath == null)
+ {
+ role.PlayerToInteract.DelayedDeath = 1;
+ role.PlayerToInteract.DelayedDeathReason = role;
+ }
+ MessageBuilder.PrepareTextReplacePlayer("PoisonerPoison", role.PlayerToInteract).SendPublic(GameChannel);
+ Pause();
+ }
+ }
+ #endregion
}
if (result != null && !result.IsEmpty)
@@ -740,6 +797,7 @@ private void EndEvening()
MessageBuilder.PrepareText("DayKillNoActive").SendPublic(GameChannel);
}
+ var inactivePlayers = new List();
foreach (var player in PlayerSorter.SortForActivityCheck(PlayersList, GameState.Day))
{
@@ -768,6 +826,54 @@ private void EndEvening()
}
}
#endregion
+
+ if (player.IsAlive && player.DelayedDeath != null && player.DelayedDeathReason is Poisoner)
+ {
+ if (player.DelayedDeath-- == 0)
+ {
+ player.DelayedDeath = null;
+ MessageBuilder.PrepareTextReplacePlayer("PoisonerKill", player).SendPublic(GameChannel);
+ player.DelayedDeathReason.Player.AddPoints("NeutralKill");
+ KillManager.Kill(player);
+ }
+ }
+
+ #region RabbleRouser
+ if (player.Role is RabbleRouser)
+ {
+ var role = player.Role as RabbleRouser;
+ if (role.IsCharged)
+ {
+ role.PutOnCooldown();
+ willDayBeRepeated = true;
+ }
+ }
+ #endregion
+
+ #region Inactive Players
+ if (result.GetTarget(player) == null && !eveningResult.IsVoted(player))
+ {
+ player.InactiveDays++;
+ if (player.InactiveDays > Settings.MaxInactiveDays)
+ {
+ inactivePlayers.Add(player);
+ KillManager.Kill(player);
+ }
+ }
+ else
+ {
+ player.InactiveDays = 0;
+ }
+ #endregion
+ }
+
+ if (inactivePlayers.Count > 0)
+ {
+ MessageBuilder.PrepareText("InactivePlayersKilled", new Dictionary
+ {
+ ["limit"] = Settings.MaxInactiveDays,
+ ["players"] = string.Join(", ", inactivePlayers.Select(p => $"{MessageBuilder.FormatName(p)} ({MessageBuilder.FormatRole(p.StartRole.GetName(MainSettings.Language))})")),
+ }).SendPublic(GameChannel);
}
KillManager.Apply();
@@ -775,7 +881,15 @@ private void EndEvening()
if (!CheckWinConditions())
{
Pause();
- StartNight();
+ if (willDayBeRepeated)
+ {
+ MessageBuilder.PrepareText("DayRepeated").SendPublic(GameChannel);
+ StartMorning();
+ }
+ else
+ {
+ StartNight();
+ }
}
}
@@ -941,6 +1055,7 @@ private void EndNight()
if (randomGenerator.Next(0, 100) < Settings.InfectionChancePercent && role.PlayerToInteract.DelayedDeath == null)
{
role.PlayerToInteract.DelayedDeath = 1;
+ role.PlayerToInteract.DelayedDeathReason = role;
}
MessageBuilder.PrepareTextReplacePlayer("WenchBlock", role.PlayerToInteract).SendPublic(GameChannel);
Pause();
@@ -1200,8 +1315,9 @@ private void EndNight()
if (player.Role is Demoman)
{
var role = player.Role as Demoman;
- if (role.Counter == 0 && role.PlaceToDestroy != null)
+ if (!role.IsOnCooldown() && role.PlaceToDestroy != null)
{
+ role.PutOnCooldown();
var killedPlayersMessage = "";
var killedPlayers = new List();
foreach (var target in PlayersList)
@@ -1554,7 +1670,7 @@ private void EndNight()
}
#endregion
- if (player.IsAlive && player.DelayedDeath != null)
+ if (player.IsAlive && player.DelayedDeath != null && player.DelayedDeathReason is Wench)
{
if (player.DelayedDeath-- == 0)
{
diff --git a/DiscordMafia/InGamePlayerInfo.cs b/DiscordMafia/InGamePlayerInfo.cs
index c91d2c9..ae6d519 100644
--- a/DiscordMafia/InGamePlayerInfo.cs
+++ b/DiscordMafia/InGamePlayerInfo.cs
@@ -18,6 +18,7 @@ public class InGamePlayerInfo
public bool IsBot { get; set; }
public long CurrentGamePoints { get; set; }
public int? DelayedDeath { get; set; }
+ public BaseRole DelayedDeathReason { get; set; }
public Game Game { get; protected set; }
protected List ActivityList { get; set; }
public VoteActivity VoteFor { get; set; }
@@ -27,18 +28,20 @@ public class InGamePlayerInfo
public Place PlaceToGo { get; set; }
public List OwnedItems { get; set; }
protected bool IsTurnSkipped { get; set; }
+ public int InactiveDays { get; set; }
public InGamePlayerInfo(UserWrapper user, Game game)
{
- this.User = user;
- this.IsBot = false;
- this.IsAlive = true;
- this.CurrentGamePoints = 0;
- this.Game = game;
- this.ActivityList = new List();
+ User = user;
+ IsBot = false;
+ IsAlive = true;
+ CurrentGamePoints = 0;
+ Game = game;
+ ActivityList = new List();
DbUser = DB.User.FindById(user.Id);
PlaceToGo = Place.AvailablePlaces[0];
OwnedItems = new List();
+ InactiveDays = 0;
}
public void AddPoints(string strategy)
diff --git a/DiscordMafia/Messages/MessageBuilder.cs b/DiscordMafia/Messages/MessageBuilder.cs
index 8495032..b652402 100644
--- a/DiscordMafia/Messages/MessageBuilder.cs
+++ b/DiscordMafia/Messages/MessageBuilder.cs
@@ -63,6 +63,12 @@ public MessageBuilder Text(string message, bool encode = true)
return this;
}
+ public MessageBuilder AddText(string message, bool encode = true)
+ {
+ BuiltMessage += encode ? Encode(message) : message;
+ return this;
+ }
+
public string GetTextReplacePlayer(string key, InGamePlayerInfo player, IDictionary additionalReplaceDictionary = null)
{
return FormatTextReplacePlayer(GetText(key), player, additionalReplaceDictionary);
diff --git a/DiscordMafia/Modules/GameActionsModule.cs b/DiscordMafia/Modules/GameActionsModule.cs
index 6f17086..ce60942 100644
--- a/DiscordMafia/Modules/GameActionsModule.cs
+++ b/DiscordMafia/Modules/GameActionsModule.cs
@@ -329,6 +329,11 @@ public async Task Kill([Summary("номер игрока")] InGamePlayerInfo pla
(currentPlayer.Role as Prosecutor).PerformNightAction(player);
return;
}
+ if (currentPlayer.Role is Kamikaze)
+ {
+ (currentPlayer.Role as Kamikaze).PerformNightAction(player);
+ return;
+ }
if (currentPlayer.Role is Killer)
{
var killer = (currentPlayer.Role as Killer);
@@ -354,6 +359,17 @@ public async Task Kill([Summary("номер игрока")] InGamePlayerInfo pla
await Task.CompletedTask;
}
+ [Command("kill"), RequireContext(ContextType.DM), RequirePlayer(typeof(Poisoner)), RequireGameState(GameState.Day)]
+ public async Task KillPoisoner([Summary("номер игрока")] InGamePlayerInfo player, [Remainder] string ignored = null)
+ {
+ if (_game.CurrentPlayers.TryGetValue(Context.User.Id, out InGamePlayerInfo currentPlayer))
+ {
+ (currentPlayer.Role as Poisoner).PerformNightAction(player);
+ _game.CheckNextCheckpoint();
+ }
+ await Task.CompletedTask;
+ }
+
[Command("curse"), Summary("Проклясть игрока."), Alias("проклясть"), RequireContext(ContextType.DM), RequirePlayer(typeof(Warlock)), RequireGameState(GameState.Night)]
public async Task CursePlayer([Summary("номер игрока")] InGamePlayerInfo player, [Remainder] string ignored = null)
{
@@ -448,6 +464,26 @@ public async Task JustifyPlayer([Summary("номер игрока")] InGamePlaye
await Task.CompletedTask;
}
+ [Command("talk"), RequireContext(ContextType.DM), RequirePlayer(typeof(RabbleRouser)), RequireGameState(GameState.Day, GameState.Evening)]
+ public async Task RepeatDay([Remainder] string ignored = null)
+ {
+ if (_game.CurrentPlayers.TryGetValue(Context.User.Id, out InGamePlayerInfo currentPlayer))
+ {
+ var rabbleRouser = (currentPlayer.Role as RabbleRouser);
+ try
+ {
+ rabbleRouser.IsCharged = true;
+ _game.CheckNextCheckpoint();
+ await ReplyAsync("OK");
+ }
+ catch (Exception ex)
+ {
+ _game.MessageBuilder.Text(ex.Message).SendPrivate(currentPlayer);
+ }
+ }
+ await Task.CompletedTask;
+ }
+
[Command("destroy"), Summary("Взорвать локацию."), Alias("подорвать", "kaboom"), RequireContext(ContextType.DM), RequirePlayer(typeof(Demoman)), RequireGameState(GameState.Night)]
public async Task Kaboom([Summary("номер локации")] int place, [Remainder] string ignored = null)
{
diff --git a/DiscordMafia/PlayerSorter.cs b/DiscordMafia/PlayerSorter.cs
index 289b739..ab6a015 100644
--- a/DiscordMafia/PlayerSorter.cs
+++ b/DiscordMafia/PlayerSorter.cs
@@ -36,6 +36,9 @@ static PlayerSorter()
typeof(Judge).Name,
typeof(Elder).Name,
typeof(Prosecutor).Name,
+ typeof(Kamikaze).Name,
+ typeof(Poisoner).Name,
+ typeof(RabbleRouser).Name,
};
}
diff --git a/DiscordMafia/Roles/BaseRole.cs b/DiscordMafia/Roles/BaseRole.cs
index bb3cef8..e2a0478 100644
--- a/DiscordMafia/Roles/BaseRole.cs
+++ b/DiscordMafia/Roles/BaseRole.cs
@@ -1,4 +1,5 @@
-using System;
+using DiscordMafia.Activity;
+using System;
using System.ComponentModel;
namespace DiscordMafia.Roles
@@ -9,6 +10,10 @@ public abstract class BaseRole
public InGamePlayerInfo Player { get; internal set; }
+ public virtual int EveningVoteWeight { get; } = 1;
+
+ public virtual EWeightType EveningVoteWeightType { get; } = EWeightType.None;
+
public BaseRole()
{
}
@@ -18,12 +23,12 @@ public virtual void ClearActivity(bool cancel = false, InGamePlayerInfo onlyAgai
}
- public virtual void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public virtual void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
game.MessageBuilder.PrepareText("NightInfo_" + this.GetType().Name).SendPrivate(currentPlayer);
}
- public virtual void DayInfo(Game game, InGamePlayerInfo currentPlayer)
+ public virtual void OnDayStart(Game game, InGamePlayerInfo currentPlayer)
{
game.MessageBuilder.PrepareText("DayInfo_" + this.GetType().Name).SendPrivate(currentPlayer);
}
diff --git a/DiscordMafia/Roles/Commissioner.cs b/DiscordMafia/Roles/Commissioner.cs
index 545a6d1..ea3c32d 100644
--- a/DiscordMafia/Roles/Commissioner.cs
+++ b/DiscordMafia/Roles/Commissioner.cs
@@ -21,9 +21,9 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/Demoman.cs b/DiscordMafia/Roles/Demoman.cs
index 5ee2447..a5c41c6 100644
--- a/DiscordMafia/Roles/Demoman.cs
+++ b/DiscordMafia/Roles/Demoman.cs
@@ -2,7 +2,7 @@
namespace DiscordMafia.Roles
{
- public class Demoman : UniqueRole
+ public class Demoman : UniqueRole, IRoleWithCooldown
{
public override Team Team
{
@@ -31,6 +31,15 @@ public Place PlaceToDestroy {
public int TotalVictims { get; set; } = 0;
+ public int Cooldown => 2;
+
+ public int CurrentCooldown { get; set; }
+
+ public Demoman()
+ {
+ CurrentCooldown = Cooldown;
+ }
+
public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarget = null)
{
if (onlyAgainstTarget == null)
@@ -40,12 +49,12 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- Counter = (Counter + 1) % 2;
- if (Counter == 0)
+ this.DecreaseCooldown();
+ if (!this.IsOnCooldown())
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
foreach (var player in game.PlayersList)
{
if (player.IsAlive && player.Role.Team != Team.Mafia)
@@ -61,7 +70,7 @@ public override bool IsReady(GameState currentState)
switch (currentState)
{
case GameState.Night:
- if (PlaceToDestroy == null && Counter == 0)
+ if (PlaceToDestroy == null && !this.IsOnCooldown())
{
return false;
}
diff --git a/DiscordMafia/Roles/Doctor.cs b/DiscordMafia/Roles/Doctor.cs
index 3916394..606654c 100644
--- a/DiscordMafia/Roles/Doctor.cs
+++ b/DiscordMafia/Roles/Doctor.cs
@@ -57,9 +57,9 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/Elder.cs b/DiscordMafia/Roles/Elder.cs
index 46e496f..f8792d1 100644
--- a/DiscordMafia/Roles/Elder.cs
+++ b/DiscordMafia/Roles/Elder.cs
@@ -35,9 +35,9 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void DayInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnDayStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.DayInfo(game, currentPlayer);
+ base.OnDayStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/Hacker.cs b/DiscordMafia/Roles/Hacker.cs
index 69a6a72..e680797 100644
--- a/DiscordMafia/Roles/Hacker.cs
+++ b/DiscordMafia/Roles/Hacker.cs
@@ -24,9 +24,9 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/Hammerer.cs b/DiscordMafia/Roles/Hammerer.cs
new file mode 100644
index 0000000..32316f4
--- /dev/null
+++ b/DiscordMafia/Roles/Hammerer.cs
@@ -0,0 +1,18 @@
+using DiscordMafia.Activity;
+
+namespace DiscordMafia.Roles
+{
+ public class Hammerer : UniqueRole
+ {
+ public override Team Team
+ {
+ get
+ {
+ return Team.Mafia;
+ }
+ }
+
+ public override int EveningVoteWeight => 2;
+ public override EWeightType EveningVoteWeightType => EWeightType.Positive;
+ }
+}
diff --git a/DiscordMafia/Roles/Highlander.cs b/DiscordMafia/Roles/Highlander.cs
index 69198d1..0a8ad4f 100644
--- a/DiscordMafia/Roles/Highlander.cs
+++ b/DiscordMafia/Roles/Highlander.cs
@@ -35,9 +35,9 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/Homeless.cs b/DiscordMafia/Roles/Homeless.cs
index 2d87733..d1b1196 100644
--- a/DiscordMafia/Roles/Homeless.cs
+++ b/DiscordMafia/Roles/Homeless.cs
@@ -21,9 +21,9 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/Hoodlum.cs b/DiscordMafia/Roles/Hoodlum.cs
index bfd70ed..fa6049a 100644
--- a/DiscordMafia/Roles/Hoodlum.cs
+++ b/DiscordMafia/Roles/Hoodlum.cs
@@ -37,9 +37,9 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/IRoleWithCooldown.cs b/DiscordMafia/Roles/IRoleWithCooldown.cs
new file mode 100644
index 0000000..516d222
--- /dev/null
+++ b/DiscordMafia/Roles/IRoleWithCooldown.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace DiscordMafia.Roles
+{
+ public interface IRoleWithCooldown
+ {
+ int Cooldown { get; }
+ int CurrentCooldown { get; set; }
+ }
+
+ public static class IRoleWithCooldownExtensions
+ {
+ public static void PutOnCooldown(this T role) where T : IRoleWithCooldown
+ {
+ role.CurrentCooldown = role.Cooldown;
+ }
+
+ public static void DecreaseCooldown(this T role) where T : IRoleWithCooldown
+ {
+ role.CurrentCooldown = Math.Max(role.CurrentCooldown - 1, 0);
+ }
+
+ public static bool IsOnCooldown(this T role) where T : IRoleWithCooldown
+ {
+ return role.CurrentCooldown != 0;
+ }
+
+ public static string GetCooldownText(this T role, Game game) where T : IRoleWithCooldown
+ {
+ return game.MessageBuilder.GetText("CooldownInfo", new Dictionary { ["current"] = role.CurrentCooldown, ["total"] = role.Cooldown });
+ }
+ }
+}
diff --git a/DiscordMafia/Roles/Judge.cs b/DiscordMafia/Roles/Judge.cs
index aac5c25..776cf12 100644
--- a/DiscordMafia/Roles/Judge.cs
+++ b/DiscordMafia/Roles/Judge.cs
@@ -46,9 +46,9 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void DayInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnDayStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.DayInfo(game, currentPlayer);
+ base.OnDayStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/Kamikaze.cs b/DiscordMafia/Roles/Kamikaze.cs
new file mode 100644
index 0000000..3df5d67
--- /dev/null
+++ b/DiscordMafia/Roles/Kamikaze.cs
@@ -0,0 +1,46 @@
+namespace DiscordMafia.Roles
+{
+ public class Kamikaze : UniqueRole, ITargetedRole
+ {
+ public override Team Team
+ {
+ get
+ {
+ return Team.Yakuza;
+ }
+ }
+
+ public InGamePlayerInfo PlayerToInteract { get; set; }
+
+ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarget = null)
+ {
+ var nightCancel = cancel && Player.Game.CurrentState == GameState.Night && (onlyAgainstTarget == null || PlayerToInteract == onlyAgainstTarget);
+ var eveningClear = !cancel && Player.Game.CurrentState == GameState.Evening && (onlyAgainstTarget == null || PlayerToInteract == onlyAgainstTarget);
+ if (nightCancel || eveningClear)
+ {
+ PlayerToInteract = null;
+ }
+ base.ClearActivity(cancel, onlyAgainstTarget);
+ }
+
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
+ {
+ base.OnNightStart(game, currentPlayer);
+ game.SendAlivePlayersMesssage(currentPlayer);
+ }
+
+ public override bool IsReady(GameState currentState)
+ {
+ switch (currentState)
+ {
+ case GameState.Night:
+ if (PlayerToInteract == null)
+ {
+ return false;
+ }
+ break;
+ }
+ return base.IsReady(currentState);
+ }
+ }
+}
diff --git a/DiscordMafia/Roles/Killer.cs b/DiscordMafia/Roles/Killer.cs
index 9f26b63..ecf73ab 100644
--- a/DiscordMafia/Roles/Killer.cs
+++ b/DiscordMafia/Roles/Killer.cs
@@ -21,9 +21,9 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/Lawyer.cs b/DiscordMafia/Roles/Lawyer.cs
index ac27888..7e4b8cb 100644
--- a/DiscordMafia/Roles/Lawyer.cs
+++ b/DiscordMafia/Roles/Lawyer.cs
@@ -21,9 +21,9 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/Mafioso.cs b/DiscordMafia/Roles/Mafioso.cs
index 9cc5394..01dd56e 100644
--- a/DiscordMafia/Roles/Mafioso.cs
+++ b/DiscordMafia/Roles/Mafioso.cs
@@ -10,9 +10,9 @@ public override Team Team
}
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/NeutralKiller.cs b/DiscordMafia/Roles/NeutralKiller.cs
index 6a02543..f58cccc 100644
--- a/DiscordMafia/Roles/NeutralKiller.cs
+++ b/DiscordMafia/Roles/NeutralKiller.cs
@@ -21,9 +21,9 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/Poisoner.cs b/DiscordMafia/Roles/Poisoner.cs
new file mode 100644
index 0000000..020585f
--- /dev/null
+++ b/DiscordMafia/Roles/Poisoner.cs
@@ -0,0 +1,44 @@
+namespace DiscordMafia.Roles
+{
+ public class Poisoner : UniqueRole, ITargetedRole
+ {
+ public override Team Team
+ {
+ get
+ {
+ return Team.Neutral;
+ }
+ }
+
+ public InGamePlayerInfo PlayerToInteract { get; set; }
+
+ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarget = null)
+ {
+ if (onlyAgainstTarget == null || PlayerToInteract == onlyAgainstTarget)
+ {
+ PlayerToInteract = null;
+ }
+ base.ClearActivity(cancel, onlyAgainstTarget);
+ }
+
+ public override void OnDayStart(Game game, InGamePlayerInfo currentPlayer)
+ {
+ base.OnDayStart(game, currentPlayer);
+ game.SendAlivePlayersMesssage(currentPlayer);
+ }
+
+ public override bool IsReady(GameState currentState)
+ {
+ switch (currentState)
+ {
+ case GameState.Day:
+ if (PlayerToInteract == null)
+ {
+ return false;
+ }
+ break;
+ }
+ return base.IsReady(currentState);
+ }
+ }
+}
diff --git a/DiscordMafia/Roles/Prosecutor.cs b/DiscordMafia/Roles/Prosecutor.cs
index e09de63..5ad6b3f 100644
--- a/DiscordMafia/Roles/Prosecutor.cs
+++ b/DiscordMafia/Roles/Prosecutor.cs
@@ -23,9 +23,9 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/RabbleRouser.cs b/DiscordMafia/Roles/RabbleRouser.cs
new file mode 100644
index 0000000..37a750c
--- /dev/null
+++ b/DiscordMafia/Roles/RabbleRouser.cs
@@ -0,0 +1,70 @@
+using System.Collections.Generic;
+
+namespace DiscordMafia.Roles
+{
+ public class RabbleRouser : UniqueRole, IRoleWithCooldown
+ {
+ public override Team Team
+ {
+ get
+ {
+ return Team.Civil;
+ }
+ }
+
+ private bool isCharged = false;
+ public bool IsCharged
+ {
+ get
+ {
+ return isCharged;
+ }
+ set
+ {
+ if (this.IsOnCooldown() && value)
+ {
+ throw new System.Exception(this.GetCooldownText(Player.Game));
+ }
+ isCharged = value;
+ }
+ }
+
+ public int Cooldown => 4;
+
+ public int CurrentCooldown { get; set; }
+
+ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarget = null)
+ {
+ if (onlyAgainstTarget == null)
+ {
+ IsCharged = false;
+ }
+ base.ClearActivity(cancel, onlyAgainstTarget);
+ }
+
+ public override void OnDayStart(Game game, InGamePlayerInfo currentPlayer)
+ {
+ this.DecreaseCooldown();
+ if (!this.IsOnCooldown())
+ {
+ base.OnDayStart(game, currentPlayer);
+ game.MessageBuilder.Text(this.GetCooldownText(game), false).SendPrivate(currentPlayer);
+ }
+ }
+
+ public override bool IsReady(GameState currentState)
+ {
+ switch (currentState)
+ {
+ case GameState.Day:
+ case GameState.Evening:
+ if (!IsCharged && !this.IsOnCooldown())
+ {
+ return false;
+ }
+ break;
+ }
+ return base.IsReady(currentState);
+ }
+ }
+}
diff --git a/DiscordMafia/Roles/Sheriff.cs b/DiscordMafia/Roles/Sheriff.cs
index fc6d49f..2e6f420 100644
--- a/DiscordMafia/Roles/Sheriff.cs
+++ b/DiscordMafia/Roles/Sheriff.cs
@@ -21,9 +21,9 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/Spy.cs b/DiscordMafia/Roles/Spy.cs
index ba22916..55b91ea 100644
--- a/DiscordMafia/Roles/Spy.cs
+++ b/DiscordMafia/Roles/Spy.cs
@@ -21,9 +21,9 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/Warlock.cs b/DiscordMafia/Roles/Warlock.cs
index 0a8d21e..8af8a51 100644
--- a/DiscordMafia/Roles/Warlock.cs
+++ b/DiscordMafia/Roles/Warlock.cs
@@ -1,4 +1,6 @@
-namespace DiscordMafia.Roles
+using System.Collections.Generic;
+
+namespace DiscordMafia.Roles
{
public class Warlock : UniqueRole, ITargetedRole
{
@@ -38,13 +40,13 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
if (AvailableCursesCount > 0)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
- game.MessageBuilder.Text($"Осталось проклятий: {AvailableCursesCount}").SendPrivate(currentPlayer);
+ game.MessageBuilder.PrepareText("ChargesRemaining", new Dictionary { ["count"] = AvailableCursesCount }).SendPrivate(currentPlayer);
}
}
diff --git a/DiscordMafia/Roles/Wench.cs b/DiscordMafia/Roles/Wench.cs
index 4888185..55131c1 100644
--- a/DiscordMafia/Roles/Wench.cs
+++ b/DiscordMafia/Roles/Wench.cs
@@ -37,9 +37,9 @@ public override void ClearActivity(bool cancel, InGamePlayerInfo onlyAgainstTarg
base.ClearActivity(cancel, onlyAgainstTarget);
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Roles/Yakuza.cs b/DiscordMafia/Roles/Yakuza.cs
index b3015ec..94da5db 100644
--- a/DiscordMafia/Roles/Yakuza.cs
+++ b/DiscordMafia/Roles/Yakuza.cs
@@ -10,9 +10,9 @@ public override Team Team
}
}
- public override void NightInfo(Game game, InGamePlayerInfo currentPlayer)
+ public override void OnNightStart(Game game, InGamePlayerInfo currentPlayer)
{
- base.NightInfo(game, currentPlayer);
+ base.OnNightStart(game, currentPlayer);
game.SendAlivePlayersMesssage(currentPlayer);
}
diff --git a/DiscordMafia/Voting/BooleanVote.cs b/DiscordMafia/Voting/BooleanVote.cs
index 45444a4..87ccb54 100644
--- a/DiscordMafia/Voting/BooleanVote.cs
+++ b/DiscordMafia/Voting/BooleanVote.cs
@@ -18,9 +18,9 @@ public BooleanVote()
HasVotes = false;
}
- public BooleanVoteResult GetResult()
+ public BooleanVoteResult GetResult(bool useWeght = false)
{
- return new BooleanVoteResult(Votes);
+ return new BooleanVoteResult(Votes, useWeght);
}
///
@@ -28,11 +28,13 @@ public BooleanVoteResult GetResult()
///
///
///
+ ///
+ ///
/// Если голосовавший уже голосовал
- public void Add(InGamePlayerInfo voter, bool value)
+ public void Add(InGamePlayerInfo voter, bool value, int weight, EWeightType weightType)
{
HasVotes = true;
- var activity = new BooleanVoteActivity(voter, this, value);
+ var activity = new BooleanVoteActivity(voter, this, value, weight, weightType);
Votes.Add(voter.User.Id, activity);
voter.AddActivity(activity);
}
diff --git a/DiscordMafia/Voting/BooleanVoteResult.cs b/DiscordMafia/Voting/BooleanVoteResult.cs
index d638456..8ddeacc 100644
--- a/DiscordMafia/Voting/BooleanVoteResult.cs
+++ b/DiscordMafia/Voting/BooleanVoteResult.cs
@@ -40,24 +40,24 @@ public bool? Result
}
}
- public BooleanVoteResult(IDictionary detailedInfo)
+ public BooleanVoteResult(IDictionary detailedInfo, bool useWeght = false)
{
- this.DetailedInfo = detailedInfo;
+ DetailedInfo = detailedInfo;
YesCount = NoCount = 0;
- fillResult();
+ FillResult(useWeght);
}
- private void fillResult()
+ private void FillResult(bool useWeght)
{
foreach (var vote in DetailedInfo.Values)
{
if (vote.Value)
{
- YesCount++;
+ YesCount += vote.WeightType.HasFlag(EWeightType.Positive) && useWeght ? vote.Weight : 1;
}
else
{
- NoCount++;
+ NoCount += vote.WeightType.HasFlag(EWeightType.Negative) && useWeght ? vote.Weight : 1;
}
}
}
@@ -70,5 +70,10 @@ public bool IsVotedYes(InGamePlayerInfo voter)
}
return false;
}
+
+ public bool IsVoted(InGamePlayerInfo voter)
+ {
+ return DetailedInfo.ContainsKey(voter.User.Id);
+ }
}
}