some changes & additions

This commit is contained in:
Gurge44 committed 2025-06-21 18:36:50 +02:00
1 parent 03ab4127b7
commit a39aa85fb8
27 files changed
+283 -69

No files matched your search

+1 -1
View File
@@ -198,7 +198,7 @@ public enum CustomRoles
Lighter,
Lookout,
Luckey,
Lyncher,
Decryptor,
Markseeker,
Marshall,
Mathematician,
+1 -1
View File
@@ -263,7 +263,7 @@ public static class NaturalDisasters
{
"BuildingCollapse" => roomKvp.Value,
"Thunderstorm" => Pelican.GetBlackRoomPS(),
_ => IRandom.Instance.Next(2) == 0
_ => IRandom.Instance.Next(2) == 0 && Options.CurrentGameMode == CustomGameMode.NaturalDisasters
? Main.AllAlivePlayerControls.RandomElement().Pos()
: new(Random.Range(MapBounds.X.Left, MapBounds.X.Right), Random.Range(MapBounds.Y.Top, MapBounds.Y.Bottom))
};
+6 -4
View File
@@ -223,7 +223,7 @@ public static class RoomRush
Map = RandomSpawn.SpawnMap.GetSpawnMap();
yield return new WaitForSeconds(Main.CurrentMap == MapNames.Airship ? 4f : 0.2f);
yield return new WaitForSeconds(Main.CurrentMap == MapNames.Airship ? 8f : 4f);
PlayerControl[] aapc = Main.AllAlivePlayerControls;
aapc.Do(x => x.RpcSetCustomRole(CustomRoles.RRPlayer));
@@ -234,7 +234,7 @@ public static class RoomRush
if (showTutorial)
{
var readingTime = 2;
var readingTime = 0;
StringBuilder sb = new(Translator.GetString("RR_Tutorial_Basics"));
sb.AppendLine();
@@ -464,6 +464,7 @@ public static class RoomRush
switch (reader.ReadPackedInt32())
{
case 1:
PointsToWinValue = PointsToWin.GetInt() * Main.AllAlivePlayerControls.Length;
int ventLimit = VentTimes.GetInt();
VentLimit = Main.AllPlayerControls.ToDictionary(x => x.PlayerId, _ => ventLimit);
if (WinByPointsInsteadOfDeaths.GetBool()) Points = Main.AllPlayerControls.ToDictionary(x => x.PlayerId, _ => 0);
@@ -603,7 +604,8 @@ public class RRPlayer : RoleBase
public override void OnExitVent(PlayerControl pc, Vent vent)
{
RoomRush.VentLimit[pc.PlayerId]--;
Utils.SendRPC(CustomRPC.RoomRushDataSync, 2, RoomRush.VentLimit[pc.PlayerId], pc.PlayerId);
if (RoomRush.VentLimit[pc.PlayerId] <= 0) pc.RpcChangeRoleBasis(CustomRoles.RRPlayer);
int newLimit = RoomRush.VentLimit[pc.PlayerId];
Utils.SendRPC(CustomRPC.RoomRushDataSync, 2, newLimit, pc.PlayerId);
if (newLimit <= 0) pc.RpcChangeRoleBasis(CustomRoles.RRPlayer);
}
}
+1 -1
View File
@@ -402,7 +402,7 @@ public class Main : BasePlugin
{ CustomRoles.Oxyman, "#ffa58c" },
{ CustomRoles.Rhapsode, "#f5ad42" },
{ CustomRoles.Chef, "#d6d6ff" },
{ CustomRoles.Lyncher, "#14ba7d" },
{ CustomRoles.Decryptor, "#14ba7d" },
{ CustomRoles.Socialite, "#32a8a8" },
{ CustomRoles.Adrenaline, "#ffff00" },
{ CustomRoles.Safeguard, "#4949e3" },
+2 -1
View File
@@ -76,7 +76,7 @@ public static class Achievements
Speedrun, // Have a game end in under 1 minute
Carried, // Win as a madmate while the other impostors are dead
SorryToBurstYourBubble, // Explode 5 people with 1 encased player as the Bubble
GetLynched, // Successfully guess 3 roles as lyncher
GetDecrypted, // Successfully guess 3 roles as Decryptor
FlagMaster, // Carry the flag the longest in CTF
Tag, // Tag the most players in CTF
Vectory, // Vent 50 times in one game
@@ -230,6 +230,7 @@ public static class Achievements
IEnumerator FetchAchievementsFromApiAsync()
{
while (PlayerControl.LocalPlayer == null) yield return null;
yield return new WaitForSeconds(3f);
string userId = PlayerControl.LocalPlayer.GetClient().GetHashedPuid();
var url = $"{ApiLoadEndpoint}?userId={userId}";
+3 -3
View File
@@ -237,7 +237,7 @@ internal static class CustomRolesHelper
CustomRoles.President => CustomRoles.Crewmate,
CustomRoles.Oxyman => CustomRoles.Engineer,
CustomRoles.Chef => CustomRoles.Crewmate,
CustomRoles.Lyncher => CustomRoles.Crewmate,
CustomRoles.Decryptor => CustomRoles.Crewmate,
CustomRoles.Adrenaline => CustomRoles.Crewmate,
CustomRoles.Safeguard => CustomRoles.Crewmate,
CustomRoles.Clairvoyant => UsePets ? CustomRoles.Crewmate : CustomRoles.Engineer,
@@ -907,7 +907,7 @@ internal static class CustomRolesHelper
CustomRoles.Merchant or
CustomRoles.Mayor or
CustomRoles.Insight or
CustomRoles.Lyncher or
CustomRoles.Decryptor or
CustomRoles.Transporter;
}
@@ -1730,7 +1730,7 @@ internal static class CustomRolesHelper
CustomRoles.Detour => RoleOptionType.Crewmate_Power,
CustomRoles.Dictator => RoleOptionType.Crewmate_Power,
CustomRoles.Guardian => RoleOptionType.Crewmate_Power,
CustomRoles.Lyncher => RoleOptionType.Crewmate_Power,
CustomRoles.Decryptor => RoleOptionType.Crewmate_Power,
CustomRoles.Marshall => RoleOptionType.Crewmate_Power,
CustomRoles.Mayor => RoleOptionType.Crewmate_Power,
CustomRoles.NiceEraser => RoleOptionType.Crewmate_Power,
+154
View File
@@ -0,0 +1,154 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AmongUs.GameOptions;
using UnityEngine;
namespace EHR.Modules;
public abstract class CustomSabotage
{
public static readonly List<CustomSabotage> Instances = [];
public virtual void Deteriorate()
{
Instances.Add(this);
}
protected virtual void Update() { }
protected virtual void Fix()
{
Instances.Remove(this);
}
protected virtual string GetSuffix(PlayerControl seer, PlayerControl target, bool hud, bool meeting)
{
return string.Empty;
}
protected static int GetDefaultSabotageTimeLimit(MapNames map)
{
return map switch
{
MapNames.Skeld or MapNames.Dleks => 30,
MapNames.MiraHQ => 45,
MapNames.Polus => 60,
MapNames.Airship => 90,
MapNames.Fungle => 60,
_ => 75
};
}
protected static void AdjustTimeLimitBasedOnPlayerSpeed(ref int timeLimit)
{
float speed = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod);
timeLimit = (int)Math.Ceiling(timeLimit / speed);
}
public static string GetAllSuffix(PlayerControl seer, PlayerControl target, bool hud, bool meeting)
{
StringBuilder suffix = new();
foreach (CustomSabotage sabotage in Instances)
{
string tempSuffix = sabotage.GetSuffix(seer, target, hud, meeting).Trim();
if (!string.IsNullOrEmpty(tempSuffix))
suffix.Append($"{tempSuffix}\n");
}
return suffix.ToString().Trim();
}
public static void UpdateAll()
{
foreach (CustomSabotage sabotage in Instances.ToArray())
{
try { sabotage.Update(); }
catch (Exception e) { Utils.ThrowException(e); }
}
}
public static void Reset()
{
Instances.Clear();
}
}
public class GrabOxygenMaskSabotage : CustomSabotage
{
private long LastNotify;
private long LastReactorFlash;
private long DeteriorateTS;
private HashSet<byte> HasMask;
private SystemTypes TargetRoom;
private int TimeLimit;
private Vector2 RoomPosition;
public override void Deteriorate()
{
base.Deteriorate();
DeteriorateTS = Utils.TimeStamp;
HasMask = [];
MapNames map = Main.CurrentMap;
TargetRoom = map switch
{
MapNames.Skeld or MapNames.Dleks => SystemTypes.MedBay,
MapNames.MiraHQ => SystemTypes.Balcony,
MapNames.Polus => SystemTypes.Specimens,
MapNames.Airship => SystemTypes.Medical,
MapNames.Fungle => SystemTypes.Kitchen,
_ => SystemTypes.Outside
};
TimeLimit = GetDefaultSabotageTimeLimit(map);
AdjustTimeLimitBasedOnPlayerSpeed(ref TimeLimit);
RoomPosition = RandomSpawn.SpawnMap.GetSpawnMap().Positions.GetValueOrDefault(TargetRoom, TargetRoom.GetRoomClass().transform.position);
Main.AllAlivePlayerControls.Do(x => LocateArrow.Add(x.PlayerId, RoomPosition));
}
protected override void Update()
{
PlayerControl[] aapc = Main.AllAlivePlayerControls;
byte[] playersInRoom = aapc.Select(x => (id: x.PlayerId, room: x.GetPlainShipRoom())).Where(x => x.room != null && x.room.RoomId == TargetRoom).Select(x => x.id).ToArray();
playersInRoom.Except(HasMask).ToValidPlayers().NotifyPlayers(Translator.GetString("CustomSabotage.GrabOxygenMask.Done"));
playersInRoom.Except(HasMask).Do(x => LocateArrow.Remove(x, RoomPosition));
HasMask.UnionWith(playersInRoom);
long now = Utils.TimeStamp;
if (DeteriorateTS + TimeLimit <= now)
{
Main.AllPlayerControls.Do(x => LocateArrow.Remove(x.PlayerId, RoomPosition));
aapc.ExceptBy(HasMask, x => x.PlayerId).Do(x => x.Suicide(PlayerState.DeathReason.OutOfOxygen));
Fix();
return;
}
if (LastReactorFlash + 2 <= now)
{
LastReactorFlash = now;
aapc.ExceptBy(HasMask, x => x.PlayerId).Do(x => x.ReactorFlash(flashDuration: 0.1f));
}
if (LastNotify != now)
{
LastNotify = now;
Utils.NotifyRoles();
}
}
protected override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud, bool meeting)
{
if (seer.PlayerId != target.PlayerId || hud || meeting || HasMask.Contains(seer.PlayerId)) return string.Empty;
long now = Utils.TimeStamp;
return Utils.ColorString(now % 2 == 0 ? Color.yellow : Color.red, $"[{Translator.GetString(TargetRoom.ToString())}] {Translator.GetString("CustomSabotage.GrabOxygenMask")} {TimeLimit - (now - DeteriorateTS)} {LocateArrow.GetArrow(seer, RoomPosition)}");
}
}
-3
View File
@@ -6,15 +6,12 @@ namespace EHR;
internal static class DoubleTrigger
{
public static List<byte> PlayerIdList = [];
public static Dictionary<byte, float> FirstTriggerTimer = [];
public static Dictionary<byte, byte> FirstTriggerTarget = [];
public static Dictionary<byte, Action> FirstTriggerAction = [];
public static void Init()
{
PlayerIdList = [];
FirstTriggerTimer = [];
FirstTriggerAction = [];
}
+14
View File
@@ -1081,6 +1081,20 @@ internal static class ExtendedPlayerControl
_ => SystemTypes.Reactor
};
if (IsActive(systemtypes))
{
Main.PlayerStates[pc.PlayerId].IsBlackOut = true;
pc.MarkDirtySettings();
LateTask.New(() =>
{
Main.PlayerStates[pc.PlayerId].IsBlackOut = false;
pc.MarkDirtySettings();
}, (float.IsNaN(flashDuration) ? Options.KillFlashDuration.GetFloat() : flashDuration) + delay, "Fix BlackOut Reactor Flash");
return;
}
pc.RpcDesyncRepairSystem(systemtypes, 128);
LateTask.New(() =>
+5 -3
View File
@@ -80,12 +80,14 @@ public static class FixedUpdateCaller
{
NonLowLoadPlayerIndex++;
if (NonLowLoadPlayerIndex >= PlayerControl.AllPlayerControls.Count)
NonLowLoadPlayerIndex = Math.Min(0, -(30 - PlayerControl.AllPlayerControls.Count));
int count = PlayerControl.AllPlayerControls.Count;
if (NonLowLoadPlayerIndex >= count)
NonLowLoadPlayerIndex = Math.Min(0, -(30 - count));
CustomGameMode currentGameMode = Options.CurrentGameMode;
for (var index = 0; index < PlayerControl.AllPlayerControls.Count; index++)
for (var index = 0; index < count; index++)
{
try
{
@@ -170,7 +170,7 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
SetMaxVision();
NaturalDisasters.ApplyGameOptions(opt, player.PlayerId);
break;
case CustomGameMode.RoomRush when RoomRush.VentLimit[player.PlayerId] > 0:
case CustomGameMode.RoomRush when RoomRush.VentLimit.TryGetValue(player.PlayerId, out int vl) && vl > 0:
AURoleOptions.EngineerCooldown = 0.01f;
AURoleOptions.EngineerInVentMaxTime = 0f;
goto case CustomGameMode.RoomRush;
+3 -2
View File
@@ -66,6 +66,7 @@ public class PlayerState(byte playerId)
Dragged,
Mauled,
WipedOut,
OutOfOxygen,
// Natural Disasters
Meteor,
@@ -100,7 +101,7 @@ public class PlayerState(byte playerId)
public DeathReason deathReason { get; set; } = DeathReason.etc;
public bool IsBlackOut { get; set; }
public bool IsSuicide => deathReason == DeathReason.Suicide;
public bool IsSuicide => deathReason is DeathReason.Suicide or DeathReason.Fall;
public TaskState TaskState { get; set; } = new();
public void SetMainRole(CustomRoles role, bool failsafe = false)
@@ -166,7 +167,7 @@ public class PlayerState(byte playerId)
RemoveDisableDevicesPatch.UpdateDisableDevices();
}
if (Lyncher.On) Lyncher.Instances.ForEach(x => x.OnRoleChange(PlayerId));
if (Decryptor.On) Decryptor.Instances.ForEach(x => x.OnRoleChange(PlayerId));
if (!role.Is(Team.Impostor) && !(role == CustomRoles.Traitor && Traitor.CanGetImpostorOnlyAddons.GetBool()))
SubRoles.ToArray().DoIf(x => x.IsImpOnlyAddon(), RemoveSubRole);
+4 -4
View File
@@ -93,14 +93,14 @@ public static class GuessManager
return true;
}
if (pc.Is(CustomRoles.Lyncher) && Lyncher.GuessMode.GetValue() == 2) goto SkipCheck;
if (pc.Is(CustomRoles.Decryptor) && Decryptor.GuessMode.GetValue() == 2) goto SkipCheck;
if ((pc.IsCrewmate() && !Options.CrewmatesCanGuess.GetBool()) ||
(pc.IsImpostor() && !Options.ImpostorsCanGuess.GetBool()) ||
(pc.Is(CustomRoleTypes.Coven) && !Options.CovenCanGuess.GetBool()) ||
(pc.IsNeutralKiller() && !Options.NeutralKillersCanGuess.GetBool()) ||
(pc.GetCustomRole().IsNonNK() && !Options.PassiveNeutralsCanGuess.GetBool()) ||
(pc.Is(CustomRoles.Lyncher) && Lyncher.GuessMode.GetValue() == 0) ||
(pc.Is(CustomRoles.Decryptor) && Decryptor.GuessMode.GetValue() == 0) ||
(Options.GuesserNumRestrictions.GetBool() && !Guessers.Contains(pc.PlayerId)))
{
if (pc.Is(CustomRoles.Guesser)) goto SkipCheck;
@@ -113,7 +113,7 @@ public static class GuessManager
SkipCheck:
if (pc.GetCustomRole() is CustomRoles.Lyncher or CustomRoles.NecroGuesser ||
if (pc.GetCustomRole() is CustomRoles.Decryptor or CustomRoles.NecroGuesser ||
(pc.Is(CustomRoles.NiceGuesser) && Options.GGTryHideMsg.GetBool()) ||
(pc.Is(CustomRoles.EvilGuesser) && Options.EGTryHideMsg.GetBool()) ||
(pc.Is(CustomRoles.Doomsayer) && Doomsayer.DoomsayerTryHideMsg.GetBool()) ||
@@ -1082,7 +1082,7 @@ public static class GuessManager
CustomRoles.NecroGuesser => true,
CustomRoles.Augur => true,
CustomRoles.Doomsayer when !Doomsayer.CantGuess => true,
CustomRoles.Lyncher when Lyncher.GuessMode.GetValue() == 2 => true,
CustomRoles.Decryptor when Decryptor.GuessMode.GetValue() == 2 => true,
_ when Options.GuesserMode.GetBool() => lp.GetTeam() switch
{
Team.Impostor => Options.ImpostorsCanGuess.GetBool(),
+12
View File
@@ -101,6 +101,18 @@ internal static class LocateArrow
return LocateArrows.Keys.Where(ai => ai.From == seer.PlayerId).Aggregate(string.Empty, (current, arrowInfo) => current + LocateArrows[arrowInfo]);
}
/// <summary>
/// Get a specific visible target arrow
/// </summary>
/// <param name="seer"></param>
/// <param name="position"></param>
/// <returns></returns>
public static string GetArrow(PlayerControl seer, Vector3 position)
{
ArrowInfo arrowInfo = new(seer.PlayerId, position);
return LocateArrows.FirstOrDefault(a => a.Key.Equals(arrowInfo)).Value ?? string.Empty;
}
/// <summary>
/// Check target arrow every FixedUpdate
/// Issue NotifyRoles when there are updates
+2 -2
View File
@@ -243,8 +243,8 @@ public static class Statistics
if (exiled && exiledPlayer.PlayerId == lp.PlayerId && Main.PlayerStates.Values.Any(x => x.SubRoles.Contains(CustomRoles.Bait) && x.GetRealKiller() == lp.PlayerId))
Achievements.Type.Gotcha.Complete();
if (lp.Is(CustomRoles.Lyncher) && Main.PlayerStates.Values.Count(x => x.deathReason == PlayerState.DeathReason.Gambled && x.GetRealKiller() == lp.PlayerId) >= 3)
Achievements.Type.GetLynched.Complete();
if (lp.Is(CustomRoles.Decryptor) && Main.PlayerStates.Values.Count(x => x.deathReason == PlayerState.DeathReason.Gambled && x.GetRealKiller() == lp.PlayerId) >= 3)
Achievements.Type.GetDecrypted.Complete();
LateTask.New(() =>
{
+5 -3
View File
@@ -2268,17 +2268,19 @@ public static class Utils
public static string BuildSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false)
{
string suffix = string.Empty;
StringBuilder suffix = new();
foreach (PlayerState state in Main.PlayerStates.Values)
{
string tempSuffix = state.Role.GetSuffix(seer, target, hud, meeting).Trim();
if (!string.IsNullOrEmpty(tempSuffix))
suffix += $"{tempSuffix}\n";
suffix.Append($"{tempSuffix}\n");
}
return suffix.Trim();
suffix.Append(CustomSabotage.GetAllSuffix(seer, target, hud, meeting));
return suffix.ToString().Trim();
}
public static IEnumerator NotifyEveryoneAsync(int speed = 2, bool noCache = true)
+2
View File
@@ -76,6 +76,8 @@ internal static class GameEndChecker
NameNotifyManager.Reset();
NotifyRoles(ForceLoop: true);
CustomSabotage.Reset();
int saboWinner = Options.WhoWinsBySabotageIfNoImpAlive.GetValue();
if (reason == GameOverReason.ImpostorsBySabotage && saboWinner != 0 && !Main.AllAlivePlayerControls.Any(x => x.Is(Team.Impostor)))
+2 -2
View File
@@ -680,7 +680,7 @@ public static class StringOptionPatch
if (role.IsExperimental()) name += $"<size=2>{Translator.GetString("ExperimentalRoleIndicator")}</size>";
if (role.IsGhostRole()) name += GetGhostRoleTeam(role);
if (role.IsDevFavoriteRole()) name += "<size=2><#00ffff>★</color></size>";
if (role.IsDevFavoriteRole()) name += " <size=2><#00ffff>★</color></size>";
__instance.TitleText.fontWeight = FontWeight.Black;
__instance.TitleText.outlineColor = new(255, 255, 255, 255);
@@ -822,7 +822,7 @@ public static class StringOptionPatch
if (role.IsExperimental()) name += $"<size=2>{Translator.GetString("ExperimentalRoleIndicator")}</size>";
if (role.IsGhostRole()) name += GetGhostRoleTeam(role);
if (role.IsDevFavoriteRole()) name += "<size=2><#00ffff>★</color></size>";
if (role.IsDevFavoriteRole()) name += " <size=2><#00ffff>★</color></size>";
__instance.TitleText.fontWeight = FontWeight.Black;
__instance.TitleText.outlineColor = new(255, 255, 255, 255);
+10 -6
View File
@@ -1050,9 +1050,7 @@ internal static class IntroCutsceneDestroyPatch
if (Options.UsePets.GetBool() && Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.HideAndSeek or CustomGameMode.CaptureTheFlag)
{
Main.ProcessShapeshifts = false;
LateTask.New(() =>
void GrantPetForEveryone()
{
foreach (PlayerControl pc in aapc)
{
@@ -1063,7 +1061,13 @@ internal static class IntroCutsceneDestroyPatch
PetsHelper.SetPet(pc, petId);
Logger.Info($"{pc.GetNameWithRole()} => {GetString(petId)} Pet", "PetAssign");
}
}, 0.3f, "Grant Pet For Everyone");
}
Main.ProcessShapeshifts = false;
LateTask.New(GrantPetForEveryone, 0.3f, "Grant Pet For Everyone");
LateTask.New(GrantPetForEveryone, 0.7f, "Grant Pet For Everyone");
LateTask.New(GrantPetForEveryone, 1.1f, "Grant Pet For Everyone");
LateTask.New(() =>
{
@@ -1091,9 +1095,9 @@ internal static class IntroCutsceneDestroyPatch
}
catch (Exception ex) { Logger.Fatal(ex.ToString(), "IntroPatch.RpcShapeshift"); }
}
}, 0.4f, "Show Pet For Everyone");
}, 1.4f, "Show Pet For Everyone");
LateTask.New(() => Main.ProcessShapeshifts = true, 1f, "Enable SS Processing");
LateTask.New(() => Main.ProcessShapeshifts = true, 2f, "Enable SS Processing");
}
try
+7 -3
View File
@@ -360,6 +360,7 @@ internal static class ChangeRoleSettings
}
FallFromLadder.Reset();
CustomSabotage.Reset();
try
{
@@ -920,18 +921,21 @@ internal static class StartGameHostPatch
{
case CustomGameMode.HideAndSeek:
CustomHnS.StartSeekerBlindTime();
break;
goto default;
case CustomGameMode.CaptureTheFlag:
CaptureTheFlag.Init();
break;
goto default;
case CustomGameMode.NaturalDisasters:
NaturalDisasters.OnGameStart();
break;
case CustomGameMode.KingOfTheZones:
KingOfTheZones.Init();
break;
goto default;
case CustomGameMode.Quiz:
Quiz.Init();
goto default;
default:
if (Options.IntegrateNaturalDisasters.GetBool()) goto case CustomGameMode.NaturalDisasters;
break;
}
+9
View File
@@ -957,6 +957,12 @@ internal static class ReportDeadBodyPatch
if (target == null)
{
if (CustomSabotage.Instances.Count > 0)
{
Notify("CannotCallEmergencyMeetingWhileSabotage");
return false;
}
if (__instance.Is(CustomRoles.Jester) && !Jester.JesterCanUseButton.GetBool())
{
Notify("JesterCannotCallEmergencyMeeting");
@@ -1213,6 +1219,8 @@ internal static class ReportDeadBodyPatch
PhantomRolePatch.OnReportDeadBody(pc);
}
CustomSabotage.Reset();
MeetingTimeManager.OnReportDeadBody();
NameNotifyManager.Reset();
@@ -1344,6 +1352,7 @@ internal static class FixedUpdatePatch
if (localPlayer)
{
CustomSabotage.UpdateAll();
Zoom.OnFixedUpdate();
TextBoxPatch.CheckChatOpen();
+1 -1
View File
@@ -316,7 +316,7 @@ public static class TextBoxPatch
public static bool IsCharAllowedPatch(TextBoxTMP __instance, [HarmonyArgument(0)] char i, ref bool __result)
{
if (!__instance.gameObject.HasParentInHierarchy("ChatScreenRoot/ChatScreenContainer")) return true;
__result = i != '\b';
__result = i is not '\b' and not '\n' and not '\r';
return false;
}
+4
View File
@@ -98,6 +98,10 @@ afootauto#1216,026ad9f54,你妈阴道有蛆
rubykop#0410,a1de8a400,习主席近平
netgaff#6739,01b5992f0,李克强
fuckdaters#7129
pucecoast#8105,d1134e5e5
shoesilky#8411,c85846f8a
apemv#5959,77c89daa8
beadyloaf#3586,9037e9c8f
## 冒充开发者
polkaoval#0453,自作Modな橋本環奈
+11 -7
View File
@@ -1813,6 +1813,7 @@
"DoppelgangerWarning": "<#ffff00>The Doppelganger swapped skins with you!</color>",
"TriedToKillLastGameFirstKill": "Your target was the first to die in the last game.\\nLet them play!",
"CheckReportFail": "<#ff0000>This meeting call was canceled due to the following reason:\\n</color>",
"CannotCallEmergencyMeetingWhileSabotage": "Emergency meetings cannot be called during crisis",
"JesterCannotCallEmergencyMeeting": "As the <#ec62a5>Jester</color>, according to the host's settings, you cannot call emergency meetings",
"NiceSwapperCannotCallEmergencyMeeting": "As the <#922348>Nice Swapper</color>, according to the host's settings, you cannot call emergency meetings",
"AdrenalineCannotCallEmergencyMeeting": "As the <#ffff00>Adrenaline</color>, you cannot call emergency meetings currently",
@@ -2074,6 +2075,9 @@
"StressedExtraTimeAfterFixingSabotage": "Time Gained For Fixing a Sabotage",
"StressedExtraTimeAfterReporting": "Time Gained For Reporting a Dead Body",
"StressedTimePenaltyAfterCrewmateEjected": "Time Penalty When a Crewmate Gets Ejected",
"CustomSabotageActivated": "<#ffff00>Custom Sabotage Activated!</color>",
"CustomSabotage.GrabOxygenMask": "Grab Oxygen Mask",
"CustomSabotage.GrabOxygenMask.Done": "<#00ff00>Oxygen Mask Grabbed! You are safe.</color>",
"SabotageCooldownControl": "Modify Sabotage Cooldown",
"SabotageCooldown": "Sabotage Cooldown",
"SabotageTimeControl": "Modify Sabotage Time Limit",
@@ -2813,7 +2817,7 @@
"Achievement.Speedrun.Description": "Have a game end in under 1 minute",
"Achievement.Carried.Description": "Win as a Madmate while all other Impostors are dead",
"Achievement.SorryToBurstYourBubble.Description": "Explode 5 people with 1 encased player as the Bubble",
"Achievement.GetLynched.Description": "Successfully guess 3 roles as Lyncher",
"Achievement.GetDecrypted.Description": "Successfully guess 3 roles as Decryptor",
"Achievement.FlagMaster.Description": "Carry the flag the longest in Capture The Flag",
"Achievement.Tag.Description": "Tag the most players in Capture The Flag",
"Achievement.Vectory.Description": "Vent 50 times in one game",
@@ -8959,12 +8963,12 @@
"SleepInfo": "You Sleep During Lights Out",
"SleepInfoLong": "(Add-ons):\\nYou sleep during lights out. You can't see anything, and you cannot move. You can only wake up when the lights are back on. If someone with the Glow add-on comes near you, you fully wake up and lose this add-on.",
"Prefix.Sleep": "Sleeping",
"Lyncher": "Lyncher",
"LyncherInfo": "Get Letters From Everyone's Roles",
"LyncherInfoLong": "(Crewmates):\\nAs the Lyncher, each X tasks you complete (X is set by the host), you get to know one more letter from everyone's roles. You can see these characters below players' names. The letters are not in order and each letter only appears once for every occurance in the role name. Settings determine whether you can guess.",
"Lyncher.TaskNum": "Number of Tasks to Complete for Each Letter",
"Lyncher.GuessMode": "Can Guess",
"Lyncher.Suffix": "<size=70%><#00ffa5>Complete</color> <b>{0}</b> <#00ffa5>tasks for the next letters</color></size>",
"Decryptor": "Decryptor",
"DecryptorInfo": "Get Letters From Everyone's Roles",
"DecryptorInfoLong": "(Crewmates):\\nAs the Decryptor, each X tasks you complete (X is set by the host), you get to know one more letter from everyone's roles. You can see these characters below players' names. The letters are not in order and each letter only appears once for every occurance in the role name. Settings determine whether you can guess.",
"Decryptor.TaskNum": "Number of Tasks to Complete for Each Letter",
"Decryptor.GuessMode": "Can Guess",
"Decryptor.Suffix": "<size=70%><#00ffa5>Complete</color> <b>{0}</b> <#00ffa5>tasks for the next letters</color></size>",
"ParityCopTryHideMsg": "Hide <color=#0D57AF>Inspector</color>'s commands",
"MaxParityCheckLimit": "Max inspections per game",
"ParityCheckLimitPerMeeting": "Max inspections per meeting",
+18 -18
View File
@@ -6,10 +6,10 @@ using Hazel;
namespace EHR.Crewmate;
public class Lyncher : RoleBase
public class Decryptor : RoleBase
{
public static bool On;
public static List<Lyncher> Instances = [];
public static List<Decryptor> Instances = [];
private static OptionItem TaskNum;
public static OptionItem GuessMode;
@@ -25,7 +25,7 @@ public class Lyncher : RoleBase
private static Dictionary<byte, List<char>> AllRoleNames = [];
private Dictionary<byte, List<char>> KnownCharacters = [];
private byte LyncherId;
private byte DecryptorId;
private int TasksCompleted;
public override bool IsEnable => On;
@@ -33,19 +33,19 @@ public class Lyncher : RoleBase
public override void SetupCustomOption()
{
var id = 648550;
Options.SetupRoleOptions(id++, TabGroup.CrewmateRoles, CustomRoles.Lyncher);
Options.SetupRoleOptions(id++, TabGroup.CrewmateRoles, CustomRoles.Decryptor);
TaskNum = new IntegerOptionItem(++id, "Lyncher.TaskNum", new(1, 10, 1), 3, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Lyncher]);
TaskNum = new IntegerOptionItem(++id, "Decryptor.TaskNum", new(1, 10, 1), 3, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Decryptor]);
GuessMode = new StringOptionItem(++id, "Lyncher.GuessMode", GuessModes, 1, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Lyncher]);
GuessMode = new StringOptionItem(++id, "Decryptor.GuessMode", GuessModes, 1, TabGroup.CrewmateRoles)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Decryptor]);
Vision = new FloatOptionItem(++id, "Vision", new(0f, 1.5f, 0.05f), 0.5f, TabGroup.CrewmateRoles)
.SetValueFormat(OptionFormat.Multiplier)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Lyncher]);
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Decryptor]);
Options.OverrideTasksData.Create(++id, TabGroup.CrewmateRoles, CustomRoles.Lyncher);
Options.OverrideTasksData.Create(++id, TabGroup.CrewmateRoles, CustomRoles.Decryptor);
}
public override void Init()
@@ -61,9 +61,9 @@ public class Lyncher : RoleBase
{
On = true;
Instances.Add(this);
LyncherId = playerId;
DecryptorId = playerId;
TasksCompleted = 0;
Utils.SendRPC(CustomRPC.SyncRoleData, LyncherId, 1, TasksCompleted);
Utils.SendRPC(CustomRPC.SyncRoleData, DecryptorId, 1, TasksCompleted);
if (Main.HasJustStarted)
LateTask.New(Action, 12f, log: false);
@@ -102,7 +102,7 @@ public class Lyncher : RoleBase
else
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
Utils.SendRPC(CustomRPC.SyncRoleData, LyncherId, 1, TasksCompleted);
Utils.SendRPC(CustomRPC.SyncRoleData, DecryptorId, 1, TasksCompleted);
}
private void RevealLetter()
@@ -112,18 +112,18 @@ public class Lyncher : RoleBase
KnownCharacters.Do(x =>
{
x.Value.Add(nextLetters[x.Key]);
Utils.SendRPC(CustomRPC.SyncRoleData, LyncherId, 2, x.Key, nextLetters[x.Key]);
Utils.SendRPC(CustomRPC.SyncRoleData, DecryptorId, 2, x.Key, nextLetters[x.Key]);
});
}
public void OnRoleChange(byte id)
{
Utils.SendRPC(CustomRPC.SyncRoleData, LyncherId, 3, id);
Utils.SendRPC(CustomRPC.SyncRoleData, DecryptorId, 3, id);
CustomRoles newRole = Main.PlayerStates[id].MainRole;
AllRoleNames[id] = Translator.GetString($"{newRole}").ToUpper().Where(c => c is not '-' and not ' ').Shuffle();
int count = KnownCharacters[id].Count;
KnownCharacters[id] = AllRoleNames[id].Take(count).ToList();
KnownCharacters[id].ForEach(x => Utils.SendRPC(CustomRPC.SyncRoleData, LyncherId, 2, id, x));
KnownCharacters[id].ForEach(x => Utils.SendRPC(CustomRPC.SyncRoleData, DecryptorId, 2, id, x));
}
public void ReceiveRPC(MessageReader reader)
@@ -144,12 +144,12 @@ public class Lyncher : RoleBase
public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false)
{
if (seer.PlayerId != LyncherId) return string.Empty;
if (seer.PlayerId != DecryptorId) return string.Empty;
return (seer.PlayerId == target.PlayerId) switch
{
false when KnownCharacters.TryGetValue(target.PlayerId, out List<char> chars) && chars.Count > 0 => string.Join(' ', chars),
true when !seer.IsModdedClient() || hud => string.Format(Translator.GetString("Lyncher.Suffix"), TaskNum.GetInt() - TasksCompleted),
true when !seer.IsModdedClient() || hud => string.Format(Translator.GetString("Decryptor.Suffix"), TaskNum.GetInt() - TasksCompleted),
_ => string.Empty
};
}
+1 -1
View File
@@ -94,7 +94,7 @@ public class Monarch : RoleBase
sender.SendMessage(!hasValue);
Logger.Info("SetRole:" + target.Data?.PlayerName + " = " + target.GetCustomRole() + " + " + CustomRoles.Knighted, "Assign " + CustomRoles.Knighted);
Logger.Info($"Set Role: {target.Data?.PlayerName} = {target.GetCustomRole()} + {CustomRoles.Knighted}", $"Assign {CustomRoles.Knighted}");
return false;
}
+4 -2
View File
@@ -175,7 +175,7 @@ public class Gaslighter : RoleBase
string role = IRandom.Instance.Next(2) == 0 ? CustomRoles.HexMaster.ToColoredString() : CustomRoles.Witch.ToColoredString();
string text = string.Format(Translator.GetString("WitchCursedPlayersMessage"), cursed, role);
Utils.SendMessage(text, title: Translator.GetString("MessageTitle.Attention"));
}, 10f, "Witch Cursed Players Notify");
}, 10f, "Gaslighter Cursed Players Notify");
}
}
@@ -187,8 +187,10 @@ public class Gaslighter : RoleBase
return true;
case Round.Knight when killer.GetAbilityUseLimit() > 0 && !target.Is(CustomRoles.Knighted):
target.RpcSetCustomRole(CustomRoles.Knighted);
target.RpcGuardAndKill(killer);
target.RpcGuardAndKill(target);
target.Notify(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Monarch), Translator.GetString("KnightedByMonarch")));
Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target);
Utils.NotifyRoles(SpecifySeer: target, SpecifyTarget: target);
killer.RpcRemoveAbilityUse();
killer.SetKillCooldown();
break;