New game mode: Capture The Flag

This commit is contained in:
Gurge44 committed 2024-08-05 18:51:36 +02:00
1 parent 7f740afa0d
commit f4bca467c1
30 files changed
+573 -42

No files matched your search

+3
View File
@@ -363,6 +363,9 @@ public enum CustomRoles
// Speedrun
Runner,
// Capture The Flag
CTFPlayer,
// GM
GM,
+3
View File
@@ -363,6 +363,9 @@ public enum CustomRoles
// Speedrun
Runner,
// Capture The Flag
CTFPlayer,
// GM
GM,
+1
View File
@@ -7,6 +7,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AU/@EntryIndexedValue">AU</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CD/@EntryIndexedValue">CD</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CK/@EntryIndexedValue">CK</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CTF/@EntryIndexedValue">CTF</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DLL/@EntryIndexedValue">DLL</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DY/@EntryIndexedValue">DY</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EHR/@EntryIndexedValue">EHR</s:String>
+356
View File
@@ -0,0 +1,356 @@
using System;
using System.Collections.Generic;
using System.Linq;
using HarmonyLib;
using UnityEngine;
namespace EHR
{
public static class CTFManager
{
private static OptionItem AlertTeamMembersOfFlagTaken;
private static OptionItem TaggedPlayersGet;
private static OptionItem WhenFlagCarrierGetsTagged;
private static readonly string[] TaggedPlayersGetOptions =
[
"CTF_TaggedPlayersGet.SentBackToBase",
"CTF_TaggedPlayersGet.Killed"
];
private static readonly string[] WhenFlagCarrierGetsTaggedOptions =
[
"CTF_WhenFlagCarrierGetsTagged.FlagIsDropped",
"CTF_WhenFlagCarrierGetsTagged.FlagIsReturned"
];
public static (Color Color, string Team) WinnerData = (Color.white, "No one wins");
private static Dictionary<byte, CTFTeam> PlayerTeams = [];
private static Dictionary<CTFTeam, CTFTeamData> TeamData = [];
private static Dictionary<byte, CTFPlayerData> PlayerData = [];
private static bool ValidTag;
private static NetworkedPlayerInfo.PlayerOutfit YellowOutfit => new NetworkedPlayerInfo.PlayerOutfit().Set("", 5, "", "", "", "pet_coaltonpet", "");
private static NetworkedPlayerInfo.PlayerOutfit BlueOutfit => new NetworkedPlayerInfo.PlayerOutfit().Set("", 1, "", "", "", "pet_coaltonpet", "");
private static (Vector2 Position, string RoomName) BlueFlagBase => Main.CurrentMap switch
{
MapNames.Skeld => (new(16.5f, -4.8f), Translator.GetString(SystemTypes.Nav.ToString())),
MapNames.Mira => (new(-4.5f, 2.0f), Translator.GetString(SystemTypes.Launchpad.ToString())),
MapNames.Dleks => (new(-16.5f, -4.8f), Translator.GetString(SystemTypes.Nav.ToString())),
MapNames.Polus => (new(9.5f, -12.5f), Translator.GetString(SystemTypes.Electrical.ToString())),
MapNames.Airship => (new(-23.5f, -1.6f), Translator.GetString(SystemTypes.Cockpit.ToString())),
MapNames.Fungle => (new(-15.5f, -7.5f), Translator.GetString(SystemTypes.Kitchen.ToString())),
_ => (Vector2.zero, string.Empty)
};
private static (Vector2 Position, string RoomName) YellowFlagBase => Main.CurrentMap switch
{
MapNames.Skeld => (new(-20.5f, -5.5f), Translator.GetString(SystemTypes.Reactor.ToString())),
MapNames.Mira => (new(17.8f, 23.0f), Translator.GetString(SystemTypes.Greenhouse.ToString())),
MapNames.Dleks => (new(20.5f, -5.5f), Translator.GetString(SystemTypes.Reactor.ToString())),
MapNames.Polus => (new(36.5f, -7.5f), Translator.GetString(SystemTypes.Laboratory.ToString())),
MapNames.Airship => (new(33.5f, -1.5f), Translator.GetString(SystemTypes.CargoBay.ToString())),
MapNames.Fungle => (new(22.2f, 13.7f), Translator.GetString(SystemTypes.Comms.ToString())),
_ => (Vector2.zero, string.Empty)
};
public static void SetupCustomOption()
{
const int id = 69_215_001;
Color color = Utils.GetRoleColor(CustomRoles.CTFPlayer);
AlertTeamMembersOfFlagTaken = new BooleanOptionItem(id, "CTF_AlertTeamMembersOfFlagTaken", true, TabGroup.GameSettings)
.SetGameMode(CustomGameMode.CaptureTheFlag)
.SetColor(color);
TaggedPlayersGet = new StringOptionItem(id + 1, "CTF_TaggedPlayersGet", TaggedPlayersGetOptions, 0, TabGroup.GameSettings)
.SetGameMode(CustomGameMode.CaptureTheFlag)
.SetColor(color);
WhenFlagCarrierGetsTagged = new StringOptionItem(id + 2, "CTF_WhenFlagCarrierGetsTagged", WhenFlagCarrierGetsTaggedOptions, 0, TabGroup.GameSettings)
.SetGameMode(CustomGameMode.CaptureTheFlag)
.SetColor(color);
}
public static bool KnowTargetRoleColor(PlayerControl seer, PlayerControl target, ref string color)
{
Color32 teamColor = PlayerTeams[target.PlayerId].GetTeamColor();
color = $"#{teamColor.r:x2}{teamColor.g:x2}{teamColor.b:x2}{teamColor.a:x2}";
return true;
}
public static string GetSuffixText(PlayerControl seer, PlayerControl target)
{
if (seer.PlayerId != target.PlayerId) return string.Empty;
return $"<size=1.4>{GetStatistics(target.PlayerId).Replace(" - ", "\n")}</size>";
}
public static string GetStatistics(byte id)
{
if (!PlayerData.TryGetValue(id, out var stats)) return string.Empty;
return string.Format(Translator.GetString("CTF_PlayerStats"), Math.Round(stats.FlagTime, 1), stats.TagCount);
}
public static int GetFlagTime(byte id)
{
return (int)Math.Round(PlayerData[id].FlagTime);
}
public static int GetTagCount(byte id)
{
return PlayerData[id].TagCount;
}
public static bool CheckForGameEnd(out GameOverReason reason)
{
reason = GameOverReason.ImpostorByKill;
var aapc = Main.AllAlivePlayerControls;
switch (aapc.Length)
{
case 0:
CustomWinnerHolder.ResetAndSetWinner(CustomWinner.Draw);
CustomWinnerHolder.WinnerIds = Main.PlayerStates.Keys.ToHashSet();
reason = GameOverReason.HumansDisconnect;
return true;
case 1:
TeamData[PlayerTeams[aapc[0].PlayerId]].SetAsWinner();
return true;
default:
// If WinnerData is already set, end the game
if (WinnerData.Team != "No one wins") return true;
// If all players are on the same team, end the game
if (aapc.All(x => PlayerTeams[x.PlayerId] == CTFTeam.Blue) || aapc.All(x => PlayerTeams[x.PlayerId] == CTFTeam.Yellow))
{
TeamData[PlayerTeams[aapc[0].PlayerId]].SetAsWinner();
return true;
}
return false;
}
}
public static void OnGameStart()
{
// Reset all data
PlayerTeams = [];
TeamData = [];
WinnerData = (Color.white, "No one wins");
PlayerData = Main.PlayerStates.Keys.ToDictionary(x => x, _ => new CTFPlayerData());
ValidTag = false;
// Check if the current game mode is Capture The Flag
if (Options.CurrentGameMode != CustomGameMode.CaptureTheFlag) return;
// Assign players to teams
List<PlayerControl> players = Main.AllAlivePlayerControls.ToList();
int blueCount = players.Count / 2;
int yellowCount = players.Count - blueCount;
HashSet<byte> bluePlayers = [];
HashSet<byte> yellowPlayers = [];
for (int i = 0; i < blueCount; i++)
{
PlayerControl player = players.RandomElement();
players.Remove(player);
PlayerTeams[player.PlayerId] = CTFTeam.Blue;
bluePlayers.Add(player.PlayerId);
Utils.RpcChangeSkin(player, BlueOutfit);
}
foreach (PlayerControl player in players)
{
PlayerTeams[player.PlayerId] = CTFTeam.Yellow;
yellowPlayers.Add(player.PlayerId);
Utils.RpcChangeSkin(player, YellowOutfit);
}
// Create flags
var blueFlagBase = BlueFlagBase;
var yellowFlagBase = YellowFlagBase;
CustomNetObject blueFlag = new BlueFlag(blueFlagBase.Position);
CustomNetObject yellowFlag = new YellowFlag(yellowFlagBase.Position);
// Create team data
TeamData[CTFTeam.Blue] = new(CTFTeam.Blue, blueFlag, bluePlayers, byte.MaxValue);
TeamData[CTFTeam.Yellow] = new(CTFTeam.Yellow, yellowFlag, yellowPlayers, byte.MaxValue);
// Teleport players to their respective bases
LateTask.New(() =>
{
foreach (var pc in Main.AllAlivePlayerControls)
{
if (PlayerTeams.TryGetValue(pc.PlayerId, out var team))
{
switch (team)
{
case CTFTeam.Blue:
pc.TP(blueFlagBase.Position);
pc.Notify(string.Format(Translator.GetString("CTF_Notify_EnemyTeamRoom"), yellowFlagBase.RoomName));
break;
case CTFTeam.Yellow:
pc.TP(yellowFlagBase.Position);
pc.Notify(string.Format(Translator.GetString("CTF_Notify_EnemyTeamRoom"), blueFlagBase.RoomName));
break;
}
}
}
ValidTag = true;
}, 10f, "CTFManager.OnGameStart");
}
public static void OnCheckMurder(PlayerControl killer, PlayerControl target)
{
if (!ValidTag) return;
if (TeamData.FindFirst(x => x.Value.FlagCarrier == target.PlayerId, out var kvp))
{
kvp.Value.DropFlag();
if (WhenFlagCarrierGetsTagged.GetValue() == 1)
{
kvp.Value.Flag.TP(kvp.Key.GetOppositeTeam().GetFlagBase().Position);
}
}
switch (TaggedPlayersGet.GetValue())
{
case 0:
target.TP(PlayerTeams[target.PlayerId].GetFlagBase().Position);
break;
case 1:
target.Suicide();
break;
}
PlayerData[killer.PlayerId].TagCount++;
Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: killer);
}
public static void OnPet(PlayerControl pc)
{
Logger.Info($"{pc.GetRealName()} petted their pet", "CTF.OnPet");
// If the player is near the enemy's flag, pick it up
var pos = pc.Pos();
var enemy = TeamData[PlayerTeams[pc.PlayerId].GetOppositeTeam()];
if (enemy.IsNearFlag(pos)) enemy.PickUpFlag(pc.PlayerId);
}
static Color GetTeamColor(this CTFTeam team)
{
return team switch
{
CTFTeam.Blue => Color.blue,
CTFTeam.Yellow => Color.yellow,
_ => Color.white
};
}
static string GetTeamName(this CTFTeam team)
{
return team switch
{
CTFTeam.Blue => Translator.GetString("CTF_BlueTeamWins"),
CTFTeam.Yellow => Translator.GetString("CTF_YellowTeamWins"),
_ => string.Empty
};
}
static CTFTeam GetOppositeTeam(this CTFTeam team)
{
return team switch
{
CTFTeam.Blue => CTFTeam.Yellow,
CTFTeam.Yellow => CTFTeam.Blue,
_ => CTFTeam.Blue
};
}
static (Vector2 Position, string RoomName) GetFlagBase(this CTFTeam team)
{
return team switch
{
CTFTeam.Blue => BlueFlagBase,
CTFTeam.Yellow => YellowFlagBase,
_ => (Vector2.zero, string.Empty)
};
}
enum CTFTeam
{
Blue,
Yellow
}
class CTFTeamData(CTFTeam team, CustomNetObject flag, HashSet<byte> players, byte flagCarrier)
{
public CustomNetObject Flag { get; } = flag;
private HashSet<byte> Players { get; } = players;
public byte FlagCarrier { get; private set; } = flagCarrier;
public void SetAsWinner()
{
WinnerData = (team.GetTeamColor(), team.GetTeamName());
CustomWinnerHolder.WinnerIds = Players;
}
public void Update()
{
if (FlagCarrier == byte.MaxValue) return;
var flagCarrierPc = FlagCarrier.GetPlayer();
if (flagCarrierPc == null || !flagCarrierPc.IsAlive())
{
DropFlag();
return;
}
Flag.TP(flagCarrierPc.Pos());
PlayerData[FlagCarrier].FlagTime += Time.fixedDeltaTime;
Utils.NotifyRoles(SpecifySeer: flagCarrierPc, SpecifyTarget: flagCarrierPc);
CTFTeam enemy = team.GetOppositeTeam();
if (Translator.GetString(Flag.playerControl.GetPlainShipRoom().RoomId.ToString()) == enemy.GetFlagBase().RoomName)
TeamData[enemy].SetAsWinner();
}
public void PickUpFlag(byte id)
{
if (FlagCarrier == id) return;
FlagCarrier = id;
Update();
if (AlertTeamMembersOfFlagTaken.GetBool())
{
var enemyPlayers = TeamData[team.GetOppositeTeam()].Players;
enemyPlayers.Select(x => x.GetPlayer()).DoIf(x => x != null, x => x.Notify("CTF_FlagTaken"));
}
}
public void DropFlag() => FlagCarrier = byte.MaxValue;
public bool IsNearFlag(Vector2 pos) => Vector2.Distance(Flag.Position, pos) < 1f;
}
class CTFPlayerData
{
public int TagCount { get; set; }
public float FlagTime { get; set; }
}
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.FixedUpdate))]
class FixedUpdatePatch
{
public static void Postfix(PlayerControl __instance)
{
if (!AmongUsClient.Instance.AmHost || !GameStates.IsInTask || Options.CurrentGameMode != CustomGameMode.Speedrun || Main.HasJustStarted || !__instance.IsHost()) return;
TeamData.Values.Do(x => x.Update());
}
}
}
}
+22 -3
View File
@@ -17,9 +17,9 @@ namespace EHR
public static readonly List<CustomNetObject> AllObjects = [];
private static int MaxId = -1;
protected int Id;
private PlayerControl playerControl;
public PlayerControl playerControl;
private float PlayerControlTimer;
private Vector2 Position;
public Vector2 Position;
private string Sprite;
protected void RpcChangeSprite(string sprite)
@@ -219,7 +219,7 @@ namespace EHR
{
foreach (var pc in PlayerControl.AllPlayerControls)
{
if (!trapArea.VisibleList.Contains(pc.PlayerId))
if (trapArea.VisibleList.Contains(pc.PlayerId))
Show(pc);
}
}
@@ -312,6 +312,7 @@ namespace EHR
Sprite = sprite;
++MaxId;
Id = MaxId;
if (MaxId > 10000) MaxId = 0;
AllObjects.Add(this);
foreach (var pc in PlayerControl.AllPlayerControls)
{
@@ -548,4 +549,22 @@ namespace EHR
Show(catcher);
}
}
internal sealed class YellowFlag : CustomNetObject
{
public YellowFlag(Vector2 position)
{
CreateNetObject("<size=100%><font=\"VCR SDF\"><line-height=72%><#000000>\u2588<#ffff00>\u2588<#ffff00>\u2588<#ffff00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><#000000>\u2588<#ffff00>\u2588<#ffff00>\u2588<#ffff00>\u2588<#ffff00>\u2588<#ffff00>\u2588<br><#000000>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#ffff00>\u2588<#ffff00>\u2588<#ffff00>\u2588<br><#000000>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><#000000>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><#000000>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br></line-height></size>", position);
Main.AllPlayerControls.Do(Show);
}
}
internal sealed class BlueFlag : CustomNetObject
{
public BlueFlag(Vector2 position)
{
CreateNetObject("<size=100%><font=\"VCR SDF\"><line-height=72%><#000000>\u2588<#0000ff>\u2588<#0000ff>\u2588<#0000ff>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><#000000>\u2588<#0000ff>\u2588<#0000ff>\u2588<#0000ff>\u2588<#0000ff>\u2588<#0000ff>\u2588<br><#000000>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#0000ff>\u2588<#0000ff>\u2588<#0000ff>\u2588<br><#000000>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><#000000>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><#000000>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br></line-height></size>", position);
Main.AllPlayerControls.Do(Show);
}
}
}
+3
View File
@@ -59,6 +59,9 @@ internal static class CustomRoleSelector
case CustomGameMode.Speedrun:
AssignRoleToEveryone(CustomRoles.Runner);
return;
case CustomGameMode.CaptureTheFlag:
AssignRoleToEveryone(CustomRoles.CTFPlayer);
return;
case CustomGameMode.HideAndSeek:
HnSManager.AssignRoles();
RoleResult = HnSManager.PlayerRoles.ToDictionary(x => Utils.GetPlayerById(x.Key), x => x.Value.Role);
+7 -2
View File
@@ -53,7 +53,8 @@ internal static class CustomRolesHelper
CustomRoles.Killer or
CustomRoles.Tasker or
CustomRoles.Potato or
CustomRoles.Runner;
CustomRoles.Runner or
CustomRoles.CTFPlayer;
public static RoleBase GetRoleClass(this CustomRoles role)
{
@@ -366,6 +367,8 @@ internal static class CustomRolesHelper
CustomRoles.Potato => RoleTypes.Crewmate,
// Speedrun
CustomRoles.Runner => RoleTypes.Crewmate,
// Capture The Flag
CustomRoles.CTFPlayer => RoleTypes.Impostor,
// Standard
CustomRoles.Executioner => Executioner.CRoleChangeRoles[Executioner.ChangeRolesAfterTargetKilled.GetValue()].GetDYRole(),
CustomRoles.Sheriff => UsePets && Sheriff.UsePet.GetBool() ? RoleTypes.GuardianAngel : RoleTypes.Impostor,
@@ -659,6 +662,7 @@ internal static class CustomRolesHelper
public static bool PetActivatedAbility(this CustomRoles role)
{
if (Options.CurrentGameMode == CustomGameMode.CaptureTheFlag) return true;
if (!Options.UsePets.GetBool()) return false;
if (role.UsesPetInsteadOfKill()) return true;
@@ -1037,7 +1041,8 @@ internal static class CustomRolesHelper
public static CountTypes GetCountTypes(this CustomRoles role) => role switch
{
CustomRoles.GM => CountTypes.OutOfGame,
CustomRoles.Sidekick => CountTypes.Jackal,
CustomRoles.Sidekick when Jackal.SidekickCountMode.GetValue() == 0 => CountTypes.Jackal,
CustomRoles.Sidekick when Jackal.SidekickCountMode.GetValue() == 1 => CountTypes.OutOfGame,
CustomRoles.Deathknight => CountTypes.Necromancer,
CustomRoles.Parasite => CountTypes.Impostor,
CustomRoles.Crewpostor => CountTypes.Impostor,
+7 -3
View File
@@ -546,7 +546,7 @@ static class ExtendedPlayerControl
public static string GetNameWithRole(this PlayerControl player, bool forUser = false)
{
return $"{player?.Data?.PlayerName}" + (GameStates.IsInGame && Options.CurrentGameMode is not CustomGameMode.FFA and not CustomGameMode.MoveAndStop and not CustomGameMode.HotPotato and not CustomGameMode.Speedrun ? $" ({player?.GetAllRoleName(forUser).RemoveHtmlTags().Replace('\n', ' ')})" : string.Empty);
return $"{player?.Data?.PlayerName}" + (GameStates.IsInGame && Options.CurrentGameMode is not CustomGameMode.FFA and not CustomGameMode.MoveAndStop and not CustomGameMode.HotPotato and not CustomGameMode.Speedrun and not CustomGameMode.CaptureTheFlag ? $" ({player?.GetAllRoleName(forUser).RemoveHtmlTags().Replace('\n', ' ')})" : string.Empty);
}
public static string GetRoleColorCode(this PlayerControl player)
@@ -656,16 +656,18 @@ static class ExtendedPlayerControl
public static bool CanUseKillButton(this PlayerControl pc)
{
if (!pc.IsAlive()) return false;
if (Mastermind.ManipulatedPlayers.ContainsKey(pc.PlayerId)) return true;
if (Penguin.IsVictim(pc)) return false;
switch (Options.CurrentGameMode)
{
case CustomGameMode.HotPotato or CustomGameMode.MoveAndStop:
case CustomGameMode.Speedrun when !SpeedrunManager.CanKill.Contains(pc.PlayerId):
return false;
case CustomGameMode.CaptureTheFlag:
return true;
}
if (Mastermind.ManipulatedPlayers.ContainsKey(pc.PlayerId)) return true;
if (Penguin.IsVictim(pc)) return false;
if (Pelican.IsEaten(pc.PlayerId)) return false;
if (pc.Data.Role.Role == RoleTypes.GuardianAngel) return false;
if (pc.Is(CustomRoles.Bloodlust)) return true;
@@ -721,6 +723,8 @@ static class ExtendedPlayerControl
CustomRoles.Potato => false,
// Speedrun
CustomRoles.Runner => false,
// Capture The Flag
CustomRoles.CTFPlayer => false,
_ => Main.PlayerStates.TryGetValue(pc.PlayerId, out var state) && state.Role.CanUseImpostorVentButton(pc)
};
@@ -167,6 +167,7 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
}
break;
case CustomGameMode.CaptureTheFlag:
case CustomGameMode.Speedrun:
case CustomGameMode.HotPotato:
case CustomGameMode.MoveAndStop:
+1
View File
@@ -124,6 +124,7 @@ public class PlayerState(byte playerId)
}
if (!role.Is(Team.Impostor)) SubRoles.ToArray().DoIf(x => x.IsImpOnlyAddon(), RemoveSubRole);
if (role is CustomRoles.Sidekick or CustomRoles.Necromancer or CustomRoles.Deathknight) RemoveSubRole(CustomRoles.Nimble);
}
CheckMurderPatch.TimeSinceLastKill.Remove(PlayerId);
+14 -5
View File
@@ -376,6 +376,13 @@ public static class GuessManager
return true;
}
if (Markseeker.PlayerIdList.Any(x => Main.PlayerStates[x].Role is Markseeker { TargetRevealed: true } ms && ms.MarkedId == target.PlayerId))
{
if (!isUI) Utils.SendMessage(GetString("GuessMarkseekerTarget"), pc.PlayerId);
else pc.ShowPopUp(GetString("GuessMarkseekerTarget"));
return true;
}
// Check whether add-on guessing is allowed
if (!forceAllowGuess)
{
@@ -447,15 +454,17 @@ public static class GuessManager
{
if (DoubleShot.CheckGuess(pc, isUI)) return true;
guesserSuicide = true;
Logger.Msg($"{guesserSuicide}", "guesserSuicide1");
if (!isUI) Utils.SendMessage(GetString("GuessCrewRole"), pc.PlayerId, Utils.ColorString(Color.cyan, GetString("MessageFromGurge44")));
else pc.ShowPopUp(Utils.ColorString(Color.cyan, GetString("MessageFromGurge44")) + "\n" + GetString("GuessCrewRole"));
return true;
}
else if (pc.Is(CustomRoles.EvilGuesser) && target.Is(CustomRoleTypes.Impostor) && !Options.EGCanGuessImp.GetBool())
{
if (DoubleShot.CheckGuess(pc, isUI)) return true;
guesserSuicide = true;
Logger.Msg($"{guesserSuicide}", "guesserSuicide2");
if (!isUI) Utils.SendMessage(GetString("GuessImpRole"), pc.PlayerId, Utils.ColorString(Color.cyan, GetString("MessageFromGurge44")));
else pc.ShowPopUp(Utils.ColorString(Color.cyan, GetString("MessageFromGurge44")) + "\n" + GetString("GuessImpRole"));
return true;
}
else if (!target.Is(role))
{
@@ -465,7 +474,7 @@ public static class GuessManager
Logger.Msg($"{guesserSuicide}", "guesserSuicide3");
}
if (Options.GuesserDoesntDieOnMisguess.GetBool())
if (guesserSuicide && Options.GuesserDoesntDieOnMisguess.GetBool())
{
if (!isUI) Utils.SendMessage(GetString("MisguessButNoSuicide"), pc.PlayerId, Utils.ColorString(Color.yellow, GetString("MessageFromGurge44")));
else pc.ShowPopUp(Utils.ColorString(Color.yellow, GetString("MessageFromGurge44")) + "\n" + GetString("MisguessButNoSuicide"));
+2
View File
@@ -56,6 +56,8 @@ public static class NameColorManager
case CustomGameMode.Speedrun when SpeedrunManager.CanKill.Contains(target.PlayerId):
color = Main.ImpostorColor;
return true;
case CustomGameMode.CaptureTheFlag:
return CTFManager.KnowTargetRoleColor(seer, target, ref color);
}
var seerRoleClass = Main.PlayerStates[seer.PlayerId].Role;
+9 -4
View File
@@ -23,6 +23,7 @@ public enum CustomGameMode
HotPotato = 0x05,
HideAndSeek = 0x06,
Speedrun = 0x07,
CaptureTheFlag = 0x08,
All = int.MaxValue
}
@@ -55,7 +56,8 @@ public static class Options
"MoveAndStop",
"HotPotato",
"HideAndSeek",
"Speedrun"
"Speedrun",
"CaptureTheFlag"
];
private static Dictionary<CustomRoles, int> roleCounts;
@@ -773,6 +775,7 @@ public static class Options
4 => CustomGameMode.HotPotato,
5 => CustomGameMode.HideAndSeek,
6 => CustomGameMode.Speedrun,
7 => CustomGameMode.CaptureTheFlag,
_ => CustomGameMode.Standard
};
@@ -802,7 +805,7 @@ public static class Options
var sb = new System.Text.StringBuilder();
var grouped = Enum.GetValues<CustomRoles>().GroupBy(x =>
{
if (x is CustomRoles.GM or CustomRoles.Philantropist or CustomRoles.Konan or CustomRoles.NotAssigned or CustomRoles.LovingCrewmate or CustomRoles.LovingImpostor or CustomRoles.Convict || x.IsForOtherGameMode() || x.IsVanilla() || x.ToString().Contains("EHR")) return 4;
if (x is CustomRoles.GM or CustomRoles.Philantropist or CustomRoles.Konan or CustomRoles.NotAssigned or CustomRoles.LovingCrewmate or CustomRoles.LovingImpostor or CustomRoles.Convict || x.IsForOtherGameMode() || x.IsVanilla() || x.ToString().Contains("EHR") || HnSManager.AllHnSRoles.Contains(x)) return 4;
if (x.IsAdditionRole()) return 3;
if (x.IsImpostor() || x.IsMadmate()) return 0;
if (x.IsNeutral()) return 1;
@@ -827,8 +830,8 @@ public static class Options
}
const string path = "./roles.txt";
if (!File.Exists(path)) File.Create(path).Close();
File.WriteAllText(path, sb.ToString());
if (!System.IO.File.Exists(path)) System.IO.File.Create(path).Close();
System.IO.File.WriteAllText(path, sb.ToString());
}
catch (Exception e)
{
@@ -1259,6 +1262,8 @@ public static class Options
SpeedrunManager.SetupCustomOption();
// Hide And Seek
HnSManager.SetupCustomOption();
// Capture The Flag
CTFManager.SetupCustomOption();
yield return null;
+17 -2
View File
@@ -26,7 +26,6 @@ using Newtonsoft.Json;
using UnityEngine;
using static EHR.Translator;
namespace EHR;
/*
@@ -638,6 +637,7 @@ public static class Utils
case CustomGameMode.MoveAndStop: return true;
case CustomGameMode.HotPotato: return false;
case CustomGameMode.Speedrun: return true;
case CustomGameMode.CaptureTheFlag: return false;
case CustomGameMode.HideAndSeek: return HnSManager.HasTasks(p);
}
@@ -828,6 +828,7 @@ public static class Utils
public static bool IsRoleTextEnabled(PlayerControl __instance)
{
if (Options.CurrentGameMode == CustomGameMode.CaptureTheFlag) return false;
if (__instance.PlayerId == PlayerControl.LocalPlayer.PlayerId || Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.SoloKombat or CustomGameMode.MoveAndStop or CustomGameMode.HotPotato or CustomGameMode.Speedrun || (Options.CurrentGameMode == CustomGameMode.HideAndSeek && HnSManager.IsRoleTextEnabled(PlayerControl.LocalPlayer, __instance)) || Main.VisibleTasksCount && PlayerControl.LocalPlayer.Data.IsDead && Options.GhostCanSeeOtherRoles.GetBool() || PlayerControl.LocalPlayer.Is(CustomRoles.Mimic) && Main.VisibleTasksCount && __instance.Data.IsDead && Options.MimicCanSeeDeadRoles.GetBool()) return true;
switch (__instance.GetCustomRole())
@@ -1328,6 +1329,7 @@ public static class Utils
}
break;
case CustomGameMode.CaptureTheFlag:
case CustomGameMode.Speedrun:
case CustomGameMode.HotPotato:
case CustomGameMode.HideAndSeek:
@@ -1668,6 +1670,7 @@ public static class Utils
CustomGameMode.MoveAndStop => $"<color=#00ffa5><size=1.7>{modeText}</size></color>\r\n{name}",
CustomGameMode.HotPotato => $"<color=#e8cd46><size=1.7>{modeText}</size></color>\r\n{name}",
CustomGameMode.HideAndSeek => $"<color=#345eeb><size=1.7>{modeText}</size></color>\r\n{name}",
CustomGameMode.CaptureTheFlag => $"<color=#1313c2><size=1.7>{modeText}</size></color>\r\n{name}",
CustomGameMode.Speedrun => ColorString(GetRoleColor(CustomRoles.Speedrunner), $"<size=1.7>{modeText}</size>\r\n") + name,
_ => name
};
@@ -1932,6 +1935,9 @@ public static class Utils
case CustomGameMode.HideAndSeek:
SelfSuffix.Append(HnSManager.GetSuffixText(seer, seer));
break;
case CustomGameMode.CaptureTheFlag:
SelfSuffix.Append(CTFManager.GetSuffixText(seer, seer));
break;
}
}
@@ -1942,7 +1948,7 @@ public static class Utils
if (Options.CurrentGameMode == CustomGameMode.FFA && FFAManager.FFATeamMode.GetBool())
SeerRealName = SeerRealName.ApplyNameColorData(seer, seer, isForMeeting);
if (!isForMeeting && MeetingStates.FirstMeeting && Options.ChangeNameToRoleInfo.GetBool() && Options.CurrentGameMode is not CustomGameMode.FFA and not CustomGameMode.MoveAndStop and not CustomGameMode.HotPotato and not CustomGameMode.Speedrun)
if (!isForMeeting && MeetingStates.FirstMeeting && Options.ChangeNameToRoleInfo.GetBool() && Options.CurrentGameMode is not CustomGameMode.FFA and not CustomGameMode.MoveAndStop and not CustomGameMode.HotPotato and not CustomGameMode.Speedrun and not CustomGameMode.CaptureTheFlag)
{
var team = CustomTeamManager.GetCustomTeam(seer.PlayerId);
if (team != null)
@@ -2164,6 +2170,8 @@ public static class Utils
? $"<size={fontSize}>{target.GetDisplayRoleName(seer.PlayerId != target.PlayerId && !seer.Data.IsDead)}{GetProgressText(target)}</size>\r\n"
: string.Empty;
if (Options.CurrentGameMode == CustomGameMode.CaptureTheFlag) TargetRoleText = string.Empty;
if (!GameStates.IsLobby)
{
if (!seer.Data.IsDead && seer.IsRevealedPlayer(target) && target.Is(CustomRoles.Trickster))
@@ -2248,6 +2256,9 @@ public static class Utils
case CustomGameMode.HideAndSeek:
TargetSuffix.Append(HnSManager.GetSuffixText(seer, target));
break;
case CustomGameMode.CaptureTheFlag:
TargetSuffix.Append(CTFManager.GetSuffixText(seer, target));
break;
}
Main.PlayerStates.Values.Do(x => TargetSuffix.Append(x.Role.GetSuffix(seer, target, isMeeting: isForMeeting)));
@@ -2448,6 +2459,7 @@ public static class Utils
CustomRoles.QuickShooter => QuickShooter.ShapeshiftCooldown.GetInt(),
CustomRoles.Disperser => Disperser.DisperserShapeshiftCooldown.GetInt(),
CustomRoles.Twister => Twister.ShapeshiftCooldown.GetInt(),
CustomRoles.Abyssbringer => Abyssbringer.BlackHolePlaceCooldown.GetInt(),
CustomRoles.Warlock => Warlock.IsCursed ? -1 : Warlock.ShapeshiftCooldown.GetInt(),
CustomRoles.Swiftclaw => Swiftclaw.DashCD.GetInt() + (includeDuration ? Swiftclaw.DashDuration.GetInt() : 0),
CustomRoles.Parasite => (int)Parasite.SSCD + (includeDuration ? (int)Parasite.SSDur : 0),
@@ -2846,6 +2858,9 @@ public static class Utils
int time = HotPotatoManager.GetSurvivalTime(id);
summary = $"{ColorString(Main.PlayerColors[id], name)} - <#e8cd46>Survived: <#ffffff>{(time == 0 ? "Until The End</color>" : $"{time}</color>s")}</color> ({GetVitalText(id, true)})";
break;
case CustomGameMode.CaptureTheFlag:
summary = $"{ColorString(Main.PlayerColors[id], name)} - {CTFManager.GetStatistics(id)} ({GetVitalText(id, true)})";
break;
}
return check && GetDisplayRoleName(id, true).RemoveHtmlTags().Contains("INVALID:NotAssigned")
+15
View File
@@ -368,6 +368,7 @@ class GameEndChecker
public static void SetPredicateToHotPotato() => Predicate = new HotPotatoGameEndPredicate();
public static void SetPredicateToSpeedrun() => Predicate = new SpeedrunGameEndPredicate();
public static void SetPredicateToHideAndSeek() => Predicate = new HideAndSeekGameEndPredicate();
public static void SetPredicateToCaptureTheFlag() => Predicate = new CaptureTheFlagGameEndPredicate();
class NormalGameEndPredicate : GameEndPredicate
{
@@ -713,6 +714,20 @@ class GameEndChecker
}
}
class CaptureTheFlagGameEndPredicate : GameEndPredicate
{
public override bool CheckForEndGame(out GameOverReason reason)
{
reason = GameOverReason.ImpostorByKill;
return WinnerIds.Count <= 0 && CheckGameEndByLivingPlayers(out reason);
}
private static bool CheckGameEndByLivingPlayers(out GameOverReason reason)
{
return CTFManager.CheckForGameEnd(out reason);
}
}
public abstract class GameEndPredicate
{
/// <summary>Checks the game ending condition and stores the value in CustomWinnerHolder. </summary>
+4 -4
View File
@@ -20,6 +20,9 @@ public static class OptionsMenuBehaviourStartPatch
private static ClientOptionItem LongMode;
private static ClientOptionItem ShowPlayerInfoInLobby;
private static ClientOptionItem LobbyMusic;
#if DEBUG
private static ClientOptionItem GodMode;
#endif
public static void Postfix(OptionsMenuBehaviour __instance)
{
@@ -44,7 +47,7 @@ public static class OptionsMenuBehaviourStartPatch
static void UnlockFPSButtonToggle()
{
Application.targetFrameRate = Main.UnlockFps.Value ? 165 : 60;
Application.targetFrameRate = Main.UnlockFps.Value ? 120 : 60;
Logger.SendInGame(string.Format(Translator.GetString("FPSSetTo"), Application.targetFrameRate));
}
}
@@ -170,9 +173,6 @@ public static class OptionsMenuBehaviourStartPatch
}
#endif
}
#if DEBUG
private static ClientOptionItem GodMode;
#endif
}
[HarmonyPatch(typeof(OptionsMenuBehaviour), nameof(OptionsMenuBehaviour.Close))]
+4 -2
View File
@@ -932,11 +932,13 @@ public class GameSettingMenuPatch
var GameSettingsLabel = __instance.GameSettingsButton.transform.parent.parent.FindChild("GameSettingsLabel").GetComponent<TextMeshPro>();
GameSettingsLabel.DestroyTranslator();
GameSettingsLabel.text = Translator.GetString($"Mode{Options.CurrentGameMode}").Split(':').Last().TrimStart(' ');
var gameModeText = Translator.GetString($"Mode{Options.CurrentGameMode}").Split(':').Last().TrimStart(' ');
if (gameModeText.Length >= 15) gameModeText = $"<size=70%>{gameModeText}</size>";
GameSettingsLabel.text = gameModeText;
if (IsRussian)
{
GameSettingsLabel.transform.localScale = new(0.7f, 0.7f, 1f);
GameSettingsLabel.transform.localPosition = new Vector3(-3.77f, 1.62f, -4);
GameSettingsLabel.transform.localPosition = new(-3.77f, 1.62f, -4);
}
var GameSettingsLabelPos = GameSettingsLabel.transform.localPosition;
+2
View File
@@ -58,6 +58,7 @@ class SetRecommendationsPatch
case CustomGameMode.SoloKombat:
case CustomGameMode.FFA:
case CustomGameMode.HotPotato:
case CustomGameMode.CaptureTheFlag:
__instance.CrewLightMod = __instance.ImpostorLightMod = 1.25f;
__instance.NumImpostors = 3;
__instance.NumCommonTasks = 0;
@@ -65,6 +66,7 @@ class SetRecommendationsPatch
__instance.NumShortTasks = 0;
__instance.KillCooldown = 0f;
__instance.NumEmergencyMeetings = 0;
__instance.KillDistance = 0;
break;
case CustomGameMode.Speedrun:
case CustomGameMode.MoveAndStop:
+1
View File
@@ -422,6 +422,7 @@ class SetHudActivePatch
__instance.ImpostorVentButton?.ToggleVisible(false);
__instance.AbilityButton?.ToggleVisible(false);
return;
case CustomGameMode.CaptureTheFlag:
case CustomGameMode.FFA:
__instance.ReportButton?.ToggleVisible(false);
__instance.SabotageButton?.ToggleVisible(false);
+24 -4
View File
@@ -77,6 +77,16 @@ class SetUpRoleTextPatch
__instance.RoleBlurbText.text = GetString("RunnerInfo");
break;
}
case CustomGameMode.CaptureTheFlag:
{
var color = ColorUtility.TryParseHtmlString("#1313c2", out var c) ? c : new(255, 255, 255, 255);
__instance.YouAreText.transform.gameObject.SetActive(false);
__instance.RoleText.text = GetString("CTFPlayer");
__instance.RoleText.color = color;
__instance.RoleBlurbText.color = color;
__instance.RoleBlurbText.text = GetString("CTFPlayerInfo");
break;
}
default:
{
CustomRoles role = lp.GetCustomRole();
@@ -181,7 +191,8 @@ class BeginCrewmatePatch
{
public static bool Prefix(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List<PlayerControl> teamToDisplay)
{
if (PlayerControl.LocalPlayer.Is(CustomRoleTypes.Neutral) && !PlayerControl.LocalPlayer.GetCustomRole().IsMadmate())
CustomRoles role = PlayerControl.LocalPlayer.GetCustomRole();
if (PlayerControl.LocalPlayer.Is(CustomRoleTypes.Neutral) && !role.IsMadmate())
{
teamToDisplay = new();
teamToDisplay.Add(PlayerControl.LocalPlayer);
@@ -197,7 +208,7 @@ class BeginCrewmatePatch
break;
}
}
else if (PlayerControl.LocalPlayer.Is(CustomRoles.Madmate) || PlayerControl.LocalPlayer.GetCustomRole().IsMadmate())
else if (PlayerControl.LocalPlayer.Is(CustomRoles.Madmate) || role.IsMadmate())
{
teamToDisplay = new();
teamToDisplay.Add(PlayerControl.LocalPlayer);
@@ -206,13 +217,13 @@ class BeginCrewmatePatch
return false;
}
if (PlayerControl.LocalPlayer.GetCustomRole() == CustomRoles.LovingCrewmate)
if (role == CustomRoles.LovingCrewmate || PlayerControl.LocalPlayer.Is(CustomRoles.Lovers))
{
teamToDisplay = new();
teamToDisplay.Add(PlayerControl.LocalPlayer);
teamToDisplay.Add(Main.LoversPlayers.FirstOrDefault(x => x.PlayerId != PlayerControl.LocalPlayer.PlayerId));
}
else if (PlayerControl.LocalPlayer.GetCustomRole() == CustomRoles.LovingImpostor)
else if (role == CustomRoles.LovingImpostor)
{
teamToDisplay.Add(Main.LoversPlayers.FirstOrDefault(x => x.PlayerId != PlayerControl.LocalPlayer.PlayerId));
}
@@ -555,6 +566,15 @@ class BeginCrewmatePatch
__instance.ImpostorText.text = GetString("SubText.HideAndSeek");
break;
}
case CustomGameMode.CaptureTheFlag:
{
__instance.TeamTitle.text = $"<size=70%>{GetString("CTFPlayer")}</size>";
__instance.TeamTitle.color = __instance.BackgroundBar.material.color = new Color32(19, 19, 194, byte.MaxValue);
PlayerControl.LocalPlayer.Data.Role.IntroSound = GetIntroSound(RoleTypes.Engineer);
__instance.ImpostorText.gameObject.SetActive(true);
__instance.ImpostorText.text = GetString("CTFPlayerInfo");
break;
}
}
// if (Input.GetKey(KeyCode.RightShift))
+2 -2
View File
@@ -70,7 +70,7 @@ public static class MainMenuManagerPatch
UpdateButton.gameObject.SetActive(ModUpdater.HasUpdate);
Application.targetFrameRate = Main.UnlockFps.Value ? 9999 : 60;
Application.targetFrameRate = Main.UnlockFps.Value ? 120 : 60;
}
[HarmonyPatch(typeof(MainMenuManager), nameof(MainMenuManager.LateUpdate)), HarmonyPostfix]
@@ -152,7 +152,7 @@ public static class MainMenuManagerPatch
WebsiteButton.gameObject.SetActive(true);
Application.targetFrameRate = Main.UnlockFps.Value ? 9999 : 60;
Application.targetFrameRate = Main.UnlockFps.Value ? 120 : 60;
}
private static PassiveButton CreateButton(string name, Vector3 localPosition, Color32 normalColor, Color32 hoverColor, Action action, string label, Vector2? scale = null)
+6
View File
@@ -815,6 +815,9 @@ internal class SelectRolesPatch
case CustomGameMode.HideAndSeek:
HnSManager.StartSeekerBlindTime();
break;
case CustomGameMode.CaptureTheFlag:
CTFManager.OnGameStart();
break;
}
HudManager.Instance.SetHudActive(true);
@@ -856,6 +859,9 @@ internal class SelectRolesPatch
case CustomGameMode.HideAndSeek:
GameEndChecker.SetPredicateToHideAndSeek();
break;
case CustomGameMode.CaptureTheFlag:
GameEndChecker.SetPredicateToCaptureTheFlag();
break;
}
GameOptionsSender.AllSenders.Clear();
+16 -1
View File
@@ -62,7 +62,7 @@ class EndGamePatch
if (date == DateTime.MinValue) continue;
var killerId = value.GetRealKiller();
var gmIsFM = Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.MoveAndStop;
var gmIsFMHH = gmIsFM || Options.CurrentGameMode is CustomGameMode.HotPotato or CustomGameMode.HideAndSeek or CustomGameMode.Speedrun;
var gmIsFMHH = gmIsFM || Options.CurrentGameMode is CustomGameMode.HotPotato or CustomGameMode.HideAndSeek or CustomGameMode.Speedrun or CustomGameMode.CaptureTheFlag;
sb.Append($"\n{date:T} {Main.AllPlayerNames[key]} ({(gmIsFMHH ? string.Empty : Utils.GetDisplayRoleName(key, true))}{(gmIsFM ? string.Empty : Utils.GetSubRolesText(key, summary: true))}) [{Utils.GetVitalText(key)}]");
if (killerId != byte.MaxValue && killerId != key)
sb.Append($"\n\t⇐ {Main.AllPlayerNames[killerId]} ({(gmIsFMHH ? string.Empty : Utils.GetDisplayRoleName(killerId, true))}{(gmIsFM ? string.Empty : Utils.GetSubRolesText(killerId, summary: true))})");
@@ -261,6 +261,14 @@ class SetEverythingUpPatch
WinnerText.color = Main.PlayerColors[winnerId];
goto EndOfText;
}
case CustomGameMode.CaptureTheFlag:
{
var winnerData = CTFManager.WinnerData;
__instance.BackgroundBar.material.color = winnerData.Color;
WinnerText.text = winnerData.Team;
WinnerText.color = winnerData.Color;
goto EndOfText;
}
}
if (CustomWinnerHolder.WinnerTeam == CustomWinner.CustomTeam)
@@ -426,6 +434,13 @@ class SetEverythingUpPatch
sb.Append("\n\u3000 ").Append(EndGamePatch.SummaryText[id]);
break;
}
case CustomGameMode.CaptureTheFlag:
{
var list = cloneRoles.OrderByDescending(CTFManager.GetFlagTime);
foreach (var id in list.Where(EndGamePatch.SummaryText.ContainsKey))
sb.Append("\n\u3000 ").Append(EndGamePatch.SummaryText[id]);
break;
}
default:
{
sb.Append("</b>\n");
+12 -2
View File
@@ -19,16 +19,20 @@ class LocalPetPatch
public static bool Prefix(PlayerControl __instance)
{
if (!Options.UsePets.GetBool()) return true;
if (!Options.UsePets.GetBool() && Options.CurrentGameMode != CustomGameMode.CaptureTheFlag) return true;
if (!(AmongUsClient.Instance.AmHost && AmongUsClient.Instance.AmClient)) return true;
if (GameStates.IsLobby || !__instance.IsAlive()) return true;
if (__instance.petting) return true;
__instance.petting = true;
if (Options.CurrentGameMode == CustomGameMode.CaptureTheFlag) goto Skip;
if (!LastProcess.ContainsKey(__instance.PlayerId)) LastProcess.TryAdd(__instance.PlayerId, Utils.TimeStamp - 2);
if (LastProcess[__instance.PlayerId] + 1 >= Utils.TimeStamp) return true;
Skip:
ExternalRpcPetPatch.Prefix(__instance.MyPhysics, (byte)RpcCalls.Pet);
LastProcess[__instance.PlayerId] = Utils.TimeStamp;
@@ -50,7 +54,7 @@ class ExternalRpcPetPatch
public static void Prefix(PlayerPhysics __instance, [HarmonyArgument(0)] byte callID)
{
if (GameStates.IsLobby || !Options.UsePets.GetBool() || !AmongUsClient.Instance.AmHost || (RpcCalls)callID != RpcCalls.Pet) return;
if (GameStates.IsLobby || (!Options.UsePets.GetBool() && Options.CurrentGameMode != CustomGameMode.CaptureTheFlag) || !AmongUsClient.Instance.AmHost || (RpcCalls)callID != RpcCalls.Pet) return;
var pc = __instance.myPlayer;
var physics = __instance;
@@ -69,6 +73,12 @@ class ExternalRpcPetPatch
&& pc.GetCustomRole().PetActivatedAbility())
physics.CancelPet();
if (Options.CurrentGameMode == CustomGameMode.CaptureTheFlag)
{
CTFManager.OnPet(pc);
return;
}
if (!LastProcess.ContainsKey(pc.PlayerId)) LastProcess.TryAdd(pc.PlayerId, Utils.TimeStamp - 2);
if (LastProcess[pc.PlayerId] + 1 >= Utils.TimeStamp) return;
LastProcess[pc.PlayerId] = Utils.TimeStamp;
+14 -4
View File
@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AmongUs.GameOptions;
using EHR.AddOns.Common;
using EHR.AddOns.Crewmate;
@@ -225,6 +224,9 @@ class CheckMurderPatch
case CustomGameMode.HideAndSeek:
HnSManager.OnCheckMurder(killer, target);
return false;
case CustomGameMode.CaptureTheFlag:
CTFManager.OnCheckMurder(killer, target);
return false;
}
if (ToiletMaster.OnAnyoneCheckMurderStart(killer, target)) return false;
@@ -1218,7 +1220,7 @@ class FixedUpdatePatch
}
}
public static Task DoPostfix(PlayerControl __instance)
public static void DoPostfix(PlayerControl __instance)
{
var player = __instance;
var playerId = player.PlayerId;
@@ -1471,6 +1473,13 @@ class FixedUpdatePatch
var seer = PlayerControl.LocalPlayer;
var target = __instance;
if (target.Is(CustomRoles.Car))
{
target.cosmetics.nameText.text = Car.Name;
RoleText.enabled = false;
return;
}
bool self = seer.PlayerId == target.PlayerId;
Mark.Clear();
@@ -1675,6 +1684,9 @@ class FixedUpdatePatch
case CustomGameMode.HideAndSeek:
Suffix.Append(HnSManager.GetSuffixText(seer, target));
break;
case CustomGameMode.CaptureTheFlag:
Suffix.Append(CTFManager.GetSuffixText(seer, target));
break;
}
if (Options.CurrentGameMode == CustomGameMode.SoloKombat)
@@ -1732,8 +1744,6 @@ class FixedUpdatePatch
RoleText.transform.SetLocalY(0.2f);
}
}
return Task.CompletedTask;
}
public static void AddExtraAbilityUsesOnFinishedTasks(PlayerControl player)
+21 -2
View File
@@ -1906,6 +1906,7 @@
"GuessAdtRole": "Unfortunately, the Host's settings do not allow you to guess add-ons",
"GuessImpRole": "Unfortunately, the Host's settings do not allow Impostors to guess Impostor roles.",
"GuessCrewRole": "Unfortunately, the Host's settings do not allow crewmates to guess crewmate roles.",
"GuessMarkseekerTarget": "You can't guess the target of the Markseeker",
"GuessKill": "<b>{0}</b> was guessed",
"GuessNull": "Please select an ID of a living player to guess their role",
"GuessHelp": "Instructions: /bt [Player ID] [Role Name] \\nExample: /bt 3 Bait \\nYou can see the player IDs before everyone's names \\n or use the /id command to list the player IDs",
@@ -3914,6 +3915,24 @@
"Runner": "Speedrunner",
"RunnerInfo": "COMPLETE TASKS AND KILL EVERYONE FIRST TO WIN",
"RunnerInfoLong": "COMPLETE TASKS AND KILL EVERYONE FIRST TO WIN",
"CaptureTheFlag": "CAPTURE THE FLAG",
"ModeCaptureTheFlag": "Gamemode: Capture The Flag",
"ModeDescribe.CaptureTheFlag": "In the Capture The Flag gamemode, there are two teams: Yellow and Blue. Each team has a flag in their base. The goal is to capture the enemy's flag and bring it back to your base. The first team to capture the enemy's flag wins!\\n\\nYou can grab the flag by petting your pet near it.\\n\\nPlayers can be tagged by the enemy team, which will send them back to their base or kill them, depending on the settings. Players who are carrying a flag cannot tag other players.",
"CTF_AlertTeamMembersOfFlagTaken": "Alert Team Members When their Flag is Taken",
"CTF_TaggedPlayersGet": "Tagged Players get",
"CTF_TaggedPlayersGet.SentBackToBase": "Sent Back to Base",
"CTF_TaggedPlayersGet.Killed": "Killed",
"CTF_WhenFlagCarrierGetsTagged": "When the Flag Carrier Gets Tagged, the Flag is",
"CTF_WhenFlagCarrierGetsTagged.FlagIsDropped": "Dropped",
"CTF_WhenFlagCarrierGetsTagged.FlagIsReturned": "Returned",
"CTFPlayer": "Capture The Flag",
"CTFPlayerInfo": "CAPTURE THE ENEMY'S FLAG TO WIN",
"CTFPlayerInfoLong": "CAPTURE THE ENEMY'S FLAG TO WIN",
"CTF_FlagTaken": "The enemy took your flag!",
"CTF_BlueTeamWins": "The Blue Team wins!",
"CTF_YellowTeamWins": "The Yellow Team wins!",
"CTF_PlayerStats": "<#00ffa5>Total Flag Carrying Time: <#ffffff>{0}s</color> - Total Tags: <#ffffff>{1}</color></color>",
"CTF_Notify_EnemyTeamRoom": "The enemy team is in <#00ffa5>{0}</color>",
"HideAndSeek": "HIDE AND SEEK",
"ModeHideAndSeek": "Gamemode: Hide And Seek",
"ModeDescribe.HideAndSeek": "In the Hide And Seek gamemode, seekers have to kill all hiders, while hiders have to complete all tasks without being killed in order to win.\\nIf the time limit reaches 0, hiders win.\\n\\nRoles: Hider, Seeker, Fox, Troll, Jumper, Detector, Jet, Dasher, Locator, Venter, Agent, Taskinator",
@@ -4344,8 +4363,8 @@
"BlackHolePlaceCooldown": "Black Hole Place Cooldown",
"BlackHoleDespawnMode": "Black Hole Despawn Mode",
"BlackHoleDespawnTime": "Time After Black Hole Despawns",
"Abyssbringer.Suffix": "<size=80%><#00ffa5>Number of players consumed by</color> {0} <#00ffa5>active black holes:</color></size><size=70%>\\n",
"Abyssbringer.Suffix.BlackHole": "<#00ffa5>{0}:</color> {1}</size>",
"Abyssbringer.Suffix": "<size=80%><#00ffa5>Number of players consumed by</color> {0} <#00ffa5>active black holes:</color></size><size=70%>\\n{1}",
"Abyssbringer.Suffix.BlackHole": "<#00ffa5>{0}:</color> {1}",
"After1PlayerEaten": "After 1 Player Was Eaten",
"BlackHoleMovesTowardsNearestPlayer": "Black Hole Moves Towards Nearest Player",
"BlackHoleMoveSpeed": "Black Hole Moving Speed",
+2 -1
View File
@@ -93,8 +93,9 @@ namespace EHR.Crewmate
var distance = PropelDistance.GetFloat();
var collider = target.Collider;
for (var newPos = target.Pos(); Vector2.Distance(pos, newPos) < distance && !PhysicsHelpers.AnythingBetween(collider, collider.bounds.center, newPos, Constants.ShipOnlyMask, false) && GameStates.IsInTask; newPos += addVector)
for (var newPos = target.Pos(); Vector2.Distance(pos, newPos) < distance && GameStates.IsInTask; newPos += addVector)
{
if (PhysicsHelpers.AnythingBetween(collider, collider.bounds.center, newPos, Constants.ShipOnlyMask, false)) break;
target.TP(newPos, log: false);
yield return new WaitForSeconds(0.05f);
}
+1
View File
@@ -69,6 +69,7 @@ namespace EHR.Crewmate
if (!OptionCanSellHarmful.GetBool()) GroupedAddons.Remove(AddonTypes.Harmful);
if (!OptionCanSellHelpful.GetBool()) GroupedAddons.Remove(AddonTypes.Helpful);
if (!OptionCanSellMixed.GetBool()) GroupedAddons.Remove(AddonTypes.Mixed);
GroupedAddons.Remove(AddonTypes.ImpOnly);
Addons = GroupedAddons.Values.Flatten().ToList();
+1 -1
View File
@@ -11,7 +11,7 @@ namespace EHR.Impostor
{
public static bool On;
private static OptionItem BlackHolePlaceCooldown;
public static OptionItem BlackHolePlaceCooldown;
private static OptionItem BlackHoleDespawnMode;
private static OptionItem BlackHoleDespawnTime;
private static OptionItem BlackHoleMovesTowardsNearestPlayer;
+2
View File
@@ -621,6 +621,8 @@ public class Main : BasePlugin
{ CustomRoles.Potato, "#e8cd46" },
// Speedrun
{ CustomRoles.Runner, "#800080" },
// Capture The Flag
{ CustomRoles.CTFPlayer, "#1313c2" },
// Hide And Seek
{ CustomRoles.Seeker, "#ff1919" },
{ CustomRoles.Hider, "#345eeb" },