Compare commits

..
9 Commits
Author SHA1 Message Date
Gurge44 d9b06aff9a fix 2024-01-07 21:46:40 +01:00
Gurge44 063b9ff964 change version 2024-01-07 21:24:15 +01:00
Gurge44 9a944d9fd3 Some fixes 2024-01-07 21:10:00 +01:00
Gurge44 b2013dc25f Last minute addition 2024-01-07 00:08:09 +01:00
Gurge44 cc8244f487 Remove unnecessary code 2024-01-06 23:30:08 +01:00
Gurge44 0dc6fc2164 Delete String.csv 2024-01-06 23:25:19 +01:00
Gurge44 1e57d4e171 /ban 2024-01-06 23:14:48 +01:00
Gurge44 9abed63369 Fix & Improve some roles & add-ons, Optimize 2024-01-06 21:44:21 +01:00
Gurge44 2713b69f86 CSV => JSON, Fix Librarian & Bubble, Sort guesser UI alphabetically 2024-01-06 19:01:05 +01:00
29 changed files with 4225 additions and 4562 deletions

No files matched your search

+1 -4
View File
@@ -88,15 +88,12 @@ internal class CustomRoleSelector
{
object cr = list[i1];
CustomRoles role = (CustomRoles)Enum.Parse(typeof(CustomRoles), cr.ToString());
if (role.IsVanilla() || role.IsAdditionRole()) continue;
if (!Main.UseVersionProtocol.Value && !role.IsAbleToHostPublic()) continue;
if (role.IsVanilla() || role.IsAdditionRole() || (CustomRolesHelper.OnlySpawnsWithPetsRoleList.Contains(role) && !Options.UsePets.GetBool()) || (!Main.UseVersionProtocol.Value && !role.IsAbleToHostPublic())) continue;
switch (role)
{
case CustomRoles.DarkHide when (MapNames)Main.NormalOptions.MapId == MapNames.Fungle:
case CustomRoles.Pelican when roleList.Contains(CustomRoles.Duellist):
case CustomRoles.Duellist when roleList.Contains(CustomRoles.Pelican):
case CustomRoles.Tunneler when !Options.UsePets.GetBool():
case CustomRoles.Tornado when !Options.UsePets.GetBool():
case CustomRoles.GM:
case CustomRoles.NotAssigned:
continue;
+1 -1
View File
@@ -15,7 +15,7 @@ public class DevUser(string code = "", string color = "null", string tag = "null
public string UpName { get; set; } = upName;
public bool HasTag() => Tag != "null";
public string GetTag() => Color == "null" ? $"<size=1>{Tag}</size>\r\n" : $"<color={Color}><size=1>{(Tag == "#Dev" ? Translator.GetString("Developer") : Tag)}</size></color>\r\n";
public string GetTag() => Color == "null" ? $"<size=1.4>{Tag}</size>\r\n" : $"<color={Color}><size=1.4>{(Tag == "#Dev" ? Translator.GetString("Developer") : Tag)}</size></color>\r\n";
}
public static class DevManager
+6 -4
View File
@@ -213,7 +213,10 @@ static class ExtendedPlayerControl
Main.PlayerStates[pc.PlayerId].deathReason = deathReason;
Main.PlayerStates[pc.PlayerId].SetDead();
if (realKiller != null) pc.SetRealKiller(realKiller);
Medic.IsDead(pc);
if (realKiller != null && realKiller.Is(CustomRoles.Damocles)) Damocles.OnMurder(realKiller.PlayerId);
pc.Kill(pc);
}
@@ -624,8 +627,8 @@ static class ExtendedPlayerControl
CustomRoles.YinYanger => pc.IsAlive(),
CustomRoles.Librarian => pc.IsAlive() && Librarian.CanUseKillButton(pc),
CustomRoles.Cantankerous => pc.IsAlive() && Cantankerous.CanUseKillButton(pc.PlayerId),
CustomRoles.Inhibitor => !Utils.IsActive(SystemTypes.Electrical) && !Utils.IsActive(SystemTypes.Comms) && !Utils.IsActive(SystemTypes.MushroomMixupSabotage) && !Utils.IsActive(SystemTypes.Laboratory) && !Utils.IsActive(SystemTypes.LifeSupp) && !Utils.IsActive(SystemTypes.Reactor) && !Utils.IsActive(SystemTypes.HeliSabotage),
CustomRoles.Saboteur => Utils.IsActive(SystemTypes.Electrical) || Utils.IsActive(SystemTypes.Comms) || Utils.IsActive(SystemTypes.MushroomMixupSabotage) || Utils.IsActive(SystemTypes.Laboratory) || Utils.IsActive(SystemTypes.LifeSupp) || Utils.IsActive(SystemTypes.Reactor) || Utils.IsActive(SystemTypes.HeliSabotage),
CustomRoles.Inhibitor => !IsActive(SystemTypes.Electrical) && !IsActive(SystemTypes.Comms) && !IsActive(SystemTypes.MushroomMixupSabotage) && !IsActive(SystemTypes.Laboratory) && !IsActive(SystemTypes.LifeSupp) && !IsActive(SystemTypes.Reactor) && !IsActive(SystemTypes.HeliSabotage),
CustomRoles.Saboteur => IsActive(SystemTypes.Electrical) || IsActive(SystemTypes.Comms) || IsActive(SystemTypes.MushroomMixupSabotage) || IsActive(SystemTypes.Laboratory) || IsActive(SystemTypes.LifeSupp) || IsActive(SystemTypes.Reactor) || IsActive(SystemTypes.HeliSabotage),
CustomRoles.Sniper => Sniper.CanUseKillButton(pc),
CustomRoles.Sheriff => Sheriff.CanUseKillButton(pc.PlayerId),
CustomRoles.Crusader => Crusader.CanUseKillButton(pc.PlayerId),
@@ -1209,7 +1212,6 @@ static class ExtendedPlayerControl
case CustomRoles.Medusa:
Medusa.SetKillCooldown(player.PlayerId);
break;
case CustomRoles.Cleaner:
Main.AllPlayerKillCooldown[player.PlayerId] = Options.CleanerKillCooldown.GetFloat();
break;
@@ -1402,7 +1404,7 @@ static class ExtendedPlayerControl
if (target.GetTeam() is Team.Impostor or Team.Neutral) Stressed.OnNonCrewmateDead();
if (killer.Is(CustomRoles.Damocles)) Damocles.OnMurder();
if (killer.Is(CustomRoles.Damocles)) Damocles.OnMurder(killer.PlayerId);
else if (killer.Is(Team.Impostor)) Damocles.OnOtherImpostorMurder();
if (target.Is(Team.Impostor)) Damocles.OnImpostorDeath();
+2 -2
View File
@@ -1124,7 +1124,7 @@ public static class Options
NameDisplayAddons = BooleanOptionItem.Create(210, "NameDisplayAddons", true, TabGroup.Addons, false)
.SetGameMode(CustomGameMode.Standard)
.SetHeader(true);
NoLimitAddonsNumMax = IntegerOptionItem.Create(211, "NoLimitAddonsNumMax", new(1, 15, 1), 1, TabGroup.Addons, false)
NoLimitAddonsNumMax = IntegerOptionItem.Create(211, "NoLimitAddonsNumMax", new(1, 90, 1), 1, TabGroup.Addons, false)
.SetGameMode(CustomGameMode.Standard);
//==================================================================================================================================//
@@ -3705,7 +3705,7 @@ public static class Options
.SetHeader(true)
.SetGameMode(customGameMode) as StringOptionItem;
var countOption = IntegerOptionItem.Create(id + 1, "Maximum", new(1, canSetNum ? 10 : 1, 1), 1, tab, false)
var countOption = IntegerOptionItem.Create(id + 1, "Maximum", new(1, canSetNum ? 15 : 1, 1), 1, tab, false)
.SetParent(spawnOption)
.SetValueFormat(OptionFormat.Players)
.SetHidden(!canSetNum)
+147 -47
View File
@@ -1,4 +1,3 @@
using Csv;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using System;
@@ -7,6 +6,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace TOHE;
@@ -17,55 +17,105 @@ public static class Translator
public const string LANGUAGE_FOLDER_NAME = "Language";
public static void Init()
{
Logger.Info("Loading language file...", "Translator");
Logger.Info("Loading Custom Translations...", "Translator");
LoadLangs();
Logger.Info("Language file loaded successfully", "Translator");
Logger.Info("Loaded Custom Translations", "Translator");
}
public static void LoadLangs()
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var stream = assembly.GetManifestResourceStream("TOHE.Resources.String.csv");
translateMaps = [];
try
{
// Get the directory containing the JSON files (e.g., TOHE.Resources.Lang)
string jsonDirectory = "TOHE.Resources.Lang";
// Get the assembly containing the resources
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
string[] jsonFileNames = GetJsonFileNames(assembly, jsonDirectory);
var options = new CsvOptions()
{
HeaderMode = HeaderMode.HeaderPresent,
AllowNewLineInEnclosedFieldValues = false,
};
foreach (var line in CsvReader.ReadFromStream(stream, options))
{
if (line.Values[0][0] == '#') continue;
try
translateMaps = [];
if (jsonFileNames.Length == 0)
{
Dictionary<int, string> dic = [];
for (int i = 1; i < line.ColumnCount; i++)
Logger.Warn("Json Translation files does not exist.", "Translator");
return;
}
foreach (string jsonFileName in jsonFileNames)
{
// Read the JSON file content
using Stream resourceStream = assembly.GetManifestResourceStream(jsonFileName);
if (resourceStream != null)
{
int id = int.Parse(line.Headers[i]);
dic[id] = line.Values[i].Replace("\\n", "\n").Replace("\\r", "\r");
using StreamReader reader = new(resourceStream);
string jsonContent = reader.ReadToEnd();
// Deserialize the JSON into a dictionary
Dictionary<string, string> jsonDictionary = JsonSerializer.Deserialize<Dictionary<string, string>>(jsonContent);
if (jsonDictionary.TryGetValue("LanguageID", out string languageIdObj) && int.TryParse(languageIdObj, out int languageId))
{
// Remove the "LanguageID" entry
jsonDictionary.Remove("LanguageID");
// Handle the rest of the data and merge it into the resulting translation map
MergeJsonIntoTranslationMap(translateMaps, languageId, jsonDictionary);
}
else
{
//Logger.Warn(jsonDictionary["HostText"], "Translator");
Logger.Warn($"Invalid JSON format in {jsonFileName}: Missing or invalid 'LanguageID' field.", "Translator");
}
}
if (!translateMaps.TryAdd(line.Values[0], dic))
Logger.Warn($"Duplicate in CSV file to be translated: line {line.Index} => \"{line.Values[0]}\"", "Translator");
}
catch (Exception ex)
// Convert the resulting translation map to JSON
string mergedJson = JsonSerializer.Serialize(translateMaps, new JsonSerializerOptions
{
Logger.Warn($"Translation file error: line {line.Index} => \"{line.Values[0]}\"", "Translator");
Logger.Warn(ex.ToString(), "Translator");
}
WriteIndented = true
});
}
catch (Exception ex)
{
Logger.Error($"Error: {ex}", "Translator");
}
// カスタム翻訳ファイルの読み込み
// Loading custom translation files
if (!Directory.Exists(LANGUAGE_FOLDER_NAME)) Directory.CreateDirectory(LANGUAGE_FOLDER_NAME);
// 翻訳テンプレートの作成
// Creating a translation template
CreateTemplateFile();
System.Collections.IList list = Enum.GetValues(typeof(SupportedLangs));
for (int i = 0; i < list.Count; i++)
foreach (var lang in EnumHelper.GetAllValues<SupportedLangs>())
{
object lang = list[i];
if (File.Exists(@$"./{LANGUAGE_FOLDER_NAME}/{lang}.dat"))
LoadCustomTranslation($"{lang}.dat", (SupportedLangs)lang);
{
UpdateCustomTranslation($"{lang}.dat", lang);
LoadCustomTranslation($"{lang}.dat", lang);
}
}
}
static void MergeJsonIntoTranslationMap(Dictionary<string, Dictionary<int, string>> translationMaps, int languageId, Dictionary<string, string> jsonDictionary)
{
foreach (var kvp in jsonDictionary)
{
string textString = kvp.Key;
if (kvp.Value is string translation)
{
// If the textString is not already in the translation map, add it
if (!translationMaps.ContainsKey(textString))
{
translationMaps[textString] = [];
}
// Add or update the translation for the current id and textString
translationMaps[textString][languageId] = translation.Replace("\\n", "\n").Replace("\\r", "\r");
}
}
}
// Function to get a list of JSON file names in a directory
static string[] GetJsonFileNames(System.Reflection.Assembly assembly, string directoryName)
{
string[] resourceNames = assembly.GetManifestResourceNames();
return resourceNames.Where(resourceName => resourceName.StartsWith(directoryName) && resourceName.EndsWith(".json")).ToArray();
}
public static string GetString(string s, Dictionary<string, string> replacementDic = null, bool console = false)
{
@@ -93,8 +143,8 @@ public static class Translator
}
if (!translateMaps.ContainsKey(str)) //translateMapsにない場合、StringNamesにあれば取得する
{
var stringNames = Enum.GetValues(typeof(StringNames)).Cast<StringNames>().Where(x => x.ToString() == str);
if (stringNames != null && stringNames.Any())
var stringNames = EnumHelper.GetAllValues<StringNames>().Where(x => x.ToString() == str).ToArray();
if (stringNames != null && stringNames.Length > 0)
res = GetString(stringNames.FirstOrDefault());
}
}
@@ -132,34 +182,84 @@ public static class Translator
return SupportedLangs.English;
}
}
static void UpdateCustomTranslation(string filename, SupportedLangs lang)
{
string path = @$"./{LANGUAGE_FOLDER_NAME}/{filename}";
if (File.Exists(path))
{
Logger.Info("Updating Custom Translations", "UpdateCustomTranslation");
try
{
List<string> textStrings = [];
using (StreamReader reader = new(path, Encoding.GetEncoding("UTF-8")))
{
string line;
while ((line = reader.ReadLine()) != null)
{
// Split the line by ':' to get the first part
string[] parts = line.Split(':');
// Check if there is at least one part before ':'
if (parts.Length >= 1)
{
// Trim any leading or trailing spaces and add it to the list
string textString = parts[0].Trim();
textStrings.Add(textString);
}
}
}
var sb = new StringBuilder();
foreach (var templateString in translateMaps.Keys)
{
if (!textStrings.Contains(templateString)) sb.Append($"{templateString}:\n");
}
using FileStream fileStream = new(path, FileMode.Append, FileAccess.Write);
using StreamWriter writer = new(fileStream);
writer.WriteLine(sb.ToString());
}
catch (Exception e)
{
Logger.Error("An error occurred: " + e.Message, "Translator");
}
}
}
public static void LoadCustomTranslation(string filename, SupportedLangs lang)
{
string path = @$"./{LANGUAGE_FOLDER_NAME}/{filename}";
if (File.Exists(path))
{
Logger.Info($"Loading custom translation file:{filename}", "LoadCustomTranslation");
using StreamReader sr = new(path, Encoding.GetEncoding("UTF-8"));
string text;
string[] tmp = [];
while ((text = sr.ReadLine()) != null)
Logger.Info($"Loading Custom Translation File:{filename}", "LoadCustomTranslation");
try
{
tmp = text.Split(":");
if (tmp.Length > 1 && tmp[1] != "")
using StreamReader sr = new(path, Encoding.GetEncoding("UTF-8"));
string text;
string[] tmp = [];
while ((text = sr.ReadLine()) != null)
{
try
tmp = text.Split(":");
if (tmp.Length > 1 && tmp[1] != "")
{
translateMaps[tmp[0]][(int)lang] = tmp.Skip(1).Join(delimiter: ":").Replace("\\n", "\n").Replace("\\r", "\r");
}
catch (KeyNotFoundException)
{
Logger.Warn($"Invalid key:{tmp[0]}", "LoadCustomTranslation");
try
{
translateMaps[tmp[0]][(int)lang] = tmp.Skip(1).Join(delimiter: ":").Replace("\\n", "\n").Replace("\\r", "\r");
}
catch (KeyNotFoundException)
{
Logger.Warn($"Invalid Key:{tmp[0]}", "LoadCustomTranslation");
}
}
}
}
catch (ObjectDisposedException) { }
catch (Exception e)
{
Logger.Error(e.ToString(), "Translator.LoadCustomTranslation");
}
}
else
{
Logger.Error($"Custom translation file not found:{filename}", "LoadCustomTranslation");
Logger.Error($"Custom Translation File Not Found:{filename}", "LoadCustomTranslation");
}
}
+12 -32
View File
@@ -383,32 +383,8 @@ public static class Utils
if (Options.NameDisplayAddons.GetBool() && !pure && self)
{
if (Options.AddBracketsToAddons.GetBool())
{
if (Options.ImpEgoistVisibalToAllies.GetBool())
{
foreach (var subRole in targetSubRoles.Where(x => x is not CustomRoles.LastImpostor and not CustomRoles.Madmate and not CustomRoles.Charmed and not CustomRoles.Recruit and not CustomRoles.Admired and not CustomRoles.Soulless and not CustomRoles.Lovers and not CustomRoles.Infected and not CustomRoles.Contagious))
RoleText = ColorString(GetRoleColor(subRole), GetString("PrefixB." + subRole.ToString())) + RoleText;
}
if (!Options.ImpEgoistVisibalToAllies.GetBool())
{
foreach (var subRole in targetSubRoles.Where(x => x is not CustomRoles.LastImpostor and not CustomRoles.Madmate and not CustomRoles.Charmed and not CustomRoles.Recruit and not CustomRoles.Admired and not CustomRoles.Soulless and not CustomRoles.Lovers and not CustomRoles.Infected and not CustomRoles.Contagious))
RoleText = ColorString(GetRoleColor(subRole), GetString("PrefixB." + subRole.ToString())) + RoleText;
}
}
else if (!Options.AddBracketsToAddons.GetBool())
{
if (Options.ImpEgoistVisibalToAllies.GetBool())
{
foreach (var subRole in targetSubRoles.Where(x => x is not CustomRoles.LastImpostor and not CustomRoles.Madmate and not CustomRoles.Charmed and not CustomRoles.Recruit and not CustomRoles.Admired and not CustomRoles.Soulless and not CustomRoles.Lovers and not CustomRoles.Infected and not CustomRoles.Contagious))
RoleText = ColorString(GetRoleColor(subRole), GetString("Prefix." + subRole.ToString())) + RoleText;
}
if (!Options.ImpEgoistVisibalToAllies.GetBool())
{
foreach (var subRole in targetSubRoles.Where(x => x is not CustomRoles.LastImpostor and not CustomRoles.Madmate and not CustomRoles.Charmed and not CustomRoles.Recruit and not CustomRoles.Admired and not CustomRoles.Soulless and not CustomRoles.Lovers and not CustomRoles.Infected and not CustomRoles.Contagious))
RoleText = ColorString(GetRoleColor(subRole), GetString("Prefix." + subRole.ToString())) + RoleText;
}
}
foreach (var subRole in targetSubRoles.Where(x => x is not CustomRoles.LastImpostor and not CustomRoles.Madmate and not CustomRoles.Charmed and not CustomRoles.Recruit and not CustomRoles.Admired and not CustomRoles.Soulless and not CustomRoles.Lovers and not CustomRoles.Infected and not CustomRoles.Contagious))
RoleText = ColorString(GetRoleColor(subRole), (Options.AddBracketsToAddons.GetBool() ? "<#ffffff>(</color>" : string.Empty) + GetString("Prefix." + subRole.ToString()) + (Options.AddBracketsToAddons.GetBool() ? "<#ffffff>)</color>" : string.Empty) + " ") + RoleText;
}
if (targetSubRoles.Contains(CustomRoles.Madmate))
@@ -1154,7 +1130,7 @@ public static class Utils
Logger.Error($"For {pc.GetNameWithRole().RemoveHtmlTags()}, failed to get progress text: " + ex.ToString(), "Utils.GetProgressText");
}
if (pc.Is(CustomRoles.Damocles)) ProgressText.Append(' ' + Damocles.GetProgressText());
if (pc.Is(CustomRoles.Damocles)) ProgressText.Append(' ' + Damocles.GetProgressText(playerId));
if (pc.Is(CustomRoles.Stressed)) ProgressText.Append(' ' + Stressed.GetProgressText(playerId));
if (ProgressText.Length != 0 && !ProgressText.ToString().StartsWith(' '))
@@ -1882,12 +1858,13 @@ public static class Utils
}
DevUser devUser = player.FriendCode.GetDevUser();
if (!name.Contains('\r') && devUser.HasTag())
bool isMod = ChatCommands.IsPlayerModerator(player.FriendCode);
if (!name.Contains('\r') && (devUser.HasTag() || isMod))
{
string tag = devUser.GetTag();
if (player.AmOwner || player.IsModClient())
name = tag + name;
else name = tag.Replace("\r\n", " - ") + name;
name = tag + (isMod ? ("<size=1.4>" + GetString("ModeratorTag") + "\r\n</size>") : string.Empty) + name;
else name = tag.Replace("\r\n", " - ") + (isMod ? ("<size=1.4>" + GetString("ModeratorTag") + " - </size>") : string.Empty) + name;
}
if (player.AmOwner)
@@ -1963,6 +1940,8 @@ public static class Utils
PlayerControl[] seerList = SpecifySeer != null ? ([SpecifySeer]) : Main.AllPlayerControls;
PlayerControl[] targetList = SpecifyTarget != null ? ([SpecifyTarget]) : Main.AllPlayerControls;
Logger.Info($" Seers: {string.Join(", ", seerList.Select(x => x.GetNameWithRole()))} Targets: {string.Join(", ", targetList.Select(x => x.GetNameWithRole()))}", "NR");
//seer: Players who can see changes made here
//target: Players subject to changes that seer can see
foreach (PlayerControl seer in seerList)
@@ -2215,7 +2194,6 @@ public static class Utils
if (target.PlayerId == seer.PlayerId) continue;
Logger.Info("NotifyRoles-Loop2-" + target.GetNameWithRole().RemoveHtmlTags() + ":START", "NotifyRoles");
if ((IsActive(SystemTypes.MushroomMixupSabotage) || MushroomMixup) && target.IsAlive() && !seer.Is(CustomRoleTypes.Impostor) && Main.ResetCamPlayerList.Contains(seer.PlayerId))
{
seer.RpcSetNamePrivate("<size=0%>", true, force: NoCache);
@@ -2491,6 +2469,7 @@ public static class Utils
TargetSuffix.Append(PlagueDoctor.GetLowerTextOthers(seer, target));
TargetSuffix.Append(Stealth.GetSuffix(seer, target));
TargetSuffix.Append(Bubble.GetEncasedPlayerSuffix(seer, target));
if (target.Is(CustomRoles.Librarian)) TargetSuffix.Append(Librarian.GetNameTextForSuffix(target.PlayerId));
@@ -2899,7 +2878,7 @@ public static class Utils
neutralnum++;
}
}
return (notify ? "<#777777>" : string.Empty) +
return (notify ? "<#777777>" : string.Empty) +
(impnum == 1 ? GetString("RemainingText.Prefix.SingleImp") : GetString("RemainingText.Prefix.PluralImp")) +
(notify ? " " : "\n") +
(notify ? "<#ffffff>" : "<b>") +
@@ -3058,4 +3037,5 @@ public static class Utils
public static int PlayersCount(CountTypes countTypes) => Main.PlayerStates.Values.Count(state => state.countTypes == countTypes);
public static int AlivePlayersCount(CountTypes countTypes) => Main.AllAlivePlayerControls.Count(pc => pc.Is(countTypes));
public static int IsOneAlive(CountTypes countTypes) => Main.AllAlivePlayerControls.Any(pc => pc.Is(countTypes)) ? 1 : 0;
public static bool IsNonHostModClient(this byte id) => id != 0 && Main.playerVersion.ContainsKey(id);
}
+10 -7
View File
@@ -20,12 +20,12 @@ namespace TOHE;
internal class ChatCommands
{
// Function to check if a player is a moderator
private static bool IsPlayerModerator(string friendCode)
public static bool IsPlayerModerator(string friendCode)
{
if (friendCode == "" || friendCode == string.Empty) return false;
if (friendCode == "" || friendCode == string.Empty || !Options.ApplyModeratorList.GetBool()) return false;
var friendCodesFilePath = @"./TOHE_DATA/Moderators.txt";
var friendCodes = File.ReadAllLines(friendCodesFilePath);
return friendCodes.Any(code => code.Contains(friendCode));
return friendCodes.Any(code => code.Contains(friendCode, StringComparison.CurrentCultureIgnoreCase));
}
public static List<string> ChatHistory = [];
@@ -322,6 +322,7 @@ internal class ChatCommands
Utils.SendMessage(args.Skip(1).Join(delimiter: " "), title: $"<color=#ff0000>{GetString("MessageFromTheHost")}</color>");
break;
case "/ban":
case "/kick":
canceled = true;
// Check if the kick command is enabled in the settings
@@ -366,7 +367,7 @@ internal class ChatCommands
}
// Kick the specified player
AmongUsClient.Instance.KickPlayer(kickedPlayer.GetClientId(), true);
AmongUsClient.Instance.KickPlayer(kickedPlayer.GetClientId(), args[0] == "/ban");
string kickedPlayerName = kickedPlayer.GetRealName();
string textToSend = $"{kickedPlayerName} {GetString("KickCommandKicked")}";
if (GameStates.IsInGame)
@@ -818,7 +819,8 @@ internal class ChatCommands
if (isUp) return;
}
var sb = new StringBuilder();
_ = sb.Append($"{devMark}<b>{roleName}</b>{Utils.GetRoleMode(rl)}{GetString($"{rl}InfoLong")}");
var title = $"{devMark}<{Main.roleColors[rl]}>{roleName}</color> {Utils.GetRoleMode(rl)}";
_ = sb.Append($"{GetString($"{rl}InfoLong")}");
var settings = new StringBuilder();
if (Options.CustomRoleSpawnChances.ContainsKey(rl))
{
@@ -829,7 +831,7 @@ internal class ChatCommands
_ = sb.Clear().Append(txt);
}
Utils.SendMessage(text: "\n", sendTo: playerId, title: settings.ToString());
Utils.SendMessage(text: sb.ToString(), sendTo: playerId);
Utils.SendMessage(text: sb.ToString(), sendTo: playerId, title: title);
return;
}
}
@@ -999,6 +1001,7 @@ internal class ChatCommands
Utils.SendMessage(msgText, player.PlayerId);
break;
case "/ban":
case "/kick":
// Check if the kick command is enabled in the settings
if (Options.ApplyModeratorList.GetValue() == 0)
@@ -1042,7 +1045,7 @@ internal class ChatCommands
}
// Kick the specified player
AmongUsClient.Instance.KickPlayer(kickedPlayer.GetClientId(), true);
AmongUsClient.Instance.KickPlayer(kickedPlayer.GetClientId(), args[0] == "/ban");
string kickedPlayerName = kickedPlayer.GetRealName();
string textToSend = $"{kickedPlayerName} {GetString("KickCommandKicked")}";
if (GameStates.IsInGame)
+20 -4
View File
@@ -594,14 +594,22 @@ class HudManagerPatch
bool CanUseVent = (player.CanUseImpostorVentButton() || player.inVent || player.MyPhysics.Animations.IsPlayingEnterVentAnimation()) && GameStates.IsInTask;
__instance.ImpostorVentButton?.ToggleVisible(CanUseVent);
player.Data.Role.CanVent = CanUseVent;
if (player.PlayerId == 0 && player.inVent && GameStates.IsInTask)
var vents = Object.FindObjectsOfType<Vent>().ToArray();
if (player.PlayerId == 0 && player.inVent && GameStates.IsInTask) SetVentButtonEnabled(TryMoveToVentPatch.HostVentTarget);
else if (CanUseVent && vents.Any(vent => Vector2.Distance(new Vector2(vent.transform.position.x, vent.transform.position.y + 0.3636f), player.Pos()) < 0.4f))
{
Vent vent = vents.FirstOrDefault(vent => Vector2.Distance(new Vector2(vent.transform.position.x, vent.transform.position.y + 0.3636f), player.Pos()) < 0.4f);
SetVentButtonEnabled(vent);
}
void SetVentButtonEnabled(Vent target)
{
__instance.ImpostorVentButton.canInteract = true;
__instance.ImpostorVentButton.enabled = true;
__instance.ImpostorVentButton.isCoolingDown = false;
__instance.ImpostorVentButton.SetEnabled();
__instance.ImpostorVentButton.currentTarget = TryMoveToVentPatch.HostVentTarget;
__instance.ImpostorVentButton.SetTarget(TryMoveToVentPatch.HostVentTarget);
__instance.ImpostorVentButton.currentTarget = target;
__instance.ImpostorVentButton.SetTarget(target);
}
}
else
@@ -788,7 +796,15 @@ class VentButtonDoClickPatch
TryMoveToVentPatch.HostVentTarget.SetButtons(false);
return true;
}
if (!pc.Is(CustomRoles.Swooper) || !pc.Is(CustomRoles.Wraith) || !pc.Is(CustomRoles.Chameleon) || pc.inVent || __instance.currentTarget == null || !pc.CanMove || !__instance.isActiveAndEnabled) return true;
if (pc.inVent || !pc.CanMove) return true;
var vents = Object.FindObjectsOfType<Vent>().ToArray();
if (vents.Any(vent => Vector2.Distance(new Vector2(vent.transform.position.x, vent.transform.position.y + 0.3636f), pc.Pos()) < 0.4f))
{
Vent vent = vents.FirstOrDefault(vent => Vector2.Distance(new Vector2(vent.transform.position.x, vent.transform.position.y + 0.3636f), pc.Pos()) < 0.4f);
pc.MyPhysics.RpcEnterVent(vent.Id);
vent.SetButtons(true);
return false;
}
pc?.MyPhysics?.RpcEnterVent(__instance.currentTarget.Id);
return false;
}
+1 -1
View File
@@ -157,7 +157,7 @@ class SetEverythingUpPatch
var color = Main.roleColors[role];
var rolename = Utils.GetRoleName(role);
poolablePlayer.cosmetics.nameText.text += $"\n<color={color}>{rolename}</color>";
poolablePlayer.cosmetics.nameText.transform.localPosition = new Vector3(defaultPos.x, !lowered || role.IsImpostor() || role.IsNK() ? defaultPos.y - 0.6f : defaultPos.y - 1.4f, -15f);
poolablePlayer.cosmetics.nameText.transform.localPosition = new Vector3(defaultPos.x, !lowered || role.IsImpostorTeamV3() || role.IsNK() ? defaultPos.y - 0.6f : defaultPos.y - 1.4f, -15f);
}
}
}
+6
View File
@@ -96,6 +96,12 @@ class ExternalRpcPetPatch
Pelican.IsEaten(pc.PlayerId))
return;
if (Mastermind.ManipulatedPlayers.ContainsKey(pc.PlayerId))
{
var killTarget = SelectKillButtonTarget(pc);
if (killTarget != null) Mastermind.ForceKillForManipulatedPlayer(pc, killTarget);
}
if (pc.HasAbilityCD()) return;
PlayerControl[] AllAlivePlayers = Main.AllAlivePlayerControls;
+26 -20
View File
@@ -214,15 +214,14 @@ class CheckMurderPatch
//非自杀场景下才会触发
switch (killer.GetCustomRole())
{
//==========内鬼阵营==========//
case CustomRoles.BountyHunter: //必须在击杀发生前处理
case CustomRoles.BountyHunter:
BountyHunter.OnCheckMurder(killer, target);
break;
case CustomRoles.Reckless:
Reckless.OnCheckMurder(killer);
break;
case CustomRoles.YinYanger:
if (YinYanger.OnCheckMurder(killer, target)) return false;
if (!YinYanger.OnCheckMurder(killer, target)) return false;
break;
case CustomRoles.Magician:
Magician.OnCheckMurder(killer);
@@ -1395,7 +1394,7 @@ class ShapeshiftPatch
isSSneeded = false;
break;
case CustomRoles.Librarian:
if (shapeshifting) isSSneeded = Librarian.OnShapeshift(shapeshifter);
isSSneeded = Librarian.OnShapeshift(shapeshifter, shapeshifting);
break;
case CustomRoles.Warlock:
if (Main.CursedPlayers[shapeshifter.PlayerId] != null)//呪われた人がいるか確認
@@ -1939,7 +1938,7 @@ class ReportDeadBodyPatch
if (player.Is(CustomRoles.Damocles))
{
Damocles.OnReport();
Damocles.OnReport(player.PlayerId);
}
Damocles.OnMeetingStart();
@@ -1947,6 +1946,7 @@ class ReportDeadBodyPatch
{
Stressed.OnReport(player);
}
Stressed.OnMeetingStart();
if (Options.InhibitorCDAfterMeetings.GetFloat() != Options.InhibitorCD.GetFloat() || Options.SaboteurCD.GetFloat() != Options.SaboteurCDAfterMeetings.GetFloat())
{
@@ -2137,9 +2137,6 @@ class FixedUpdatePatch
case CustomRoles.BountyHunter:
BountyHunter.FixedUpdate(player);
break;
case CustomRoles.Tornado when !lowLoad:
Tornado.OnFixedUpdate(player);
break;
case CustomRoles.Glitch when !lowLoad:
Glitch.UpdateHackCooldown(player);
break;
@@ -2173,9 +2170,6 @@ class FixedUpdatePatch
case CustomRoles.Bubble when !lowLoad:
Bubble.OnFixedUpdate();
break;
case CustomRoles.Sprayer when !lowLoad:
Sprayer.OnFixedUpdate();
break;
case CustomRoles.Sentinel when !lowLoad:
Sentinel.OnFixedUpdate();
break;
@@ -2218,6 +2212,15 @@ class FixedUpdatePatch
PlagueBearer.playerIdList.Remove(playerId);
}
if (GameStates.IsInTask && player != null && player.IsAlive())
{
Druid.OnCheckPlayerPosition(player);
Sentinel.OnCheckPlayerPosition(player);
Tornado.OnCheckPlayerPosition(player);
BallLightning.OnCheckPlayerPosition(player);
Sprayer.OnCheckPlayerPosition(player);
}
if (!lowLoad && Main.PlayerStates.TryGetValue(playerId, out var playerState) && GameStates.IsInTask)
{
if (playerState.SubRoles.Contains(CustomRoles.Damocles))
@@ -2532,10 +2535,6 @@ class FixedUpdatePatch
Pelican.OnFixedUpdate();
break;
case CustomRoles.BallLightning:
BallLightning.OnFixedUpdate();
break;
case CustomRoles.Sapper:
Sapper.OnFixedUpdate(player);
break;
@@ -2936,6 +2935,7 @@ class FixedUpdatePatch
if (PlagueDoctor.IsEnable) Suffix.Append(PlagueDoctor.GetLowerTextOthers(seer, target));
if (Stealth.IsEnable) Suffix.Append(Stealth.GetSuffix(seer, target));
if (Tracker.IsEnable) Suffix.Append(Tracker.GetTrackerArrow(seer, target));
if (Bubble.IsEnable) Suffix.Append(Bubble.GetEncasedPlayerSuffix(seer, target));
if (Deathpact.IsEnable)
{
@@ -3034,6 +3034,10 @@ class FixedUpdatePatch
target.cosmetics.nameText.text = changeTo;
float offset = 0.2f;
if (NameNotifyManager.Notice.TryGetValue(seer.PlayerId, out var notify) && notify.TEXT.Contains('\n'))
{
offset += 0.1f;
}
if (Suffix.ToString() != string.Empty)
{
// If the name is on two lines, the job title text needs to be moved up.
@@ -3041,6 +3045,10 @@ class FixedUpdatePatch
offset += 0.15f;
target.cosmetics.nameText.text += "\r\n" + Suffix.ToString();
}
if (!seer.IsAlive())
{
offset += 0.1f;
}
if (isProgressTextLong)
{
offset += 0.3f;
@@ -3067,14 +3075,12 @@ class FixedUpdatePatch
{
foreach (PlayerControl loversPlayer in Main.LoversPlayers.ToArray())
{
if (!loversPlayer.Data.IsDead && loversPlayer.PlayerId != deathId)
continue;
if (!loversPlayer.Data.IsDead && loversPlayer.PlayerId != deathId) continue;
Main.isLoversDead = true;
for (int i1 = 0; i1 < Main.LoversPlayers.Count; i1++)
{
PlayerControl partnerPlayer = Main.LoversPlayers[i1];
if (loversPlayer.PlayerId == partnerPlayer.PlayerId)
continue;
if (loversPlayer.PlayerId == partnerPlayer.PlayerId) continue;
if (partnerPlayer.PlayerId != deathId && !partnerPlayer.Data.IsDead)
{
if (partnerPlayer.Is(CustomRoles.Lovers))
@@ -3226,7 +3232,7 @@ class EnterVentPatch
if (pc.Is(CustomRoles.Damocles))
{
Damocles.OnEnterVent(__instance.Id);
Damocles.OnEnterVent(pc.PlayerId, __instance.Id);
}
switch (pc.GetCustomRole())
+2 -3
View File
@@ -187,10 +187,9 @@ class RepairSystemPatch
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
break;
}
if (player.Is(CustomRoles.Damocles) && Damocles.countRepairSabotage) Damocles.OnRepairSabotage();
if (player.Is(CustomRoles.Damocles) && Damocles.countRepairSabotage) Damocles.OnRepairSabotage(player.PlayerId);
if (player.Is(CustomRoles.Stressed) && Stressed.countRepairSabotage) Stressed.OnRepairSabotage(player);
}
break;
}
@@ -200,7 +199,7 @@ class RepairSystemPatch
case SystemTypes.Laboratory:
case SystemTypes.HeliSabotage:
case SystemTypes.Electrical:
if (player.Is(CustomRoles.Damocles) && Damocles.countRepairSabotage) Damocles.OnRepairSabotage();
if (player.Is(CustomRoles.Damocles) && Damocles.countRepairSabotage) Damocles.OnRepairSabotage(player.PlayerId);
if (player.Is(CustomRoles.Stressed) && Stressed.countRepairSabotage) Stressed.OnRepairSabotage(player);
break;
}
File diff suppressed because it is too large. Load diff
-3981
View File
File diff suppressed because it is too large. Load diff
+9 -4
View File
@@ -103,10 +103,10 @@ namespace TOHE.Roles.AddOns.Crewmate
public static void Update(PlayerControl pc)
{
if (!LastUpdates.TryGetValue(pc.PlayerId, out var x) || x >= GetTimeStamp() || !Timers.ContainsKey(pc.PlayerId) || !IsEnable || !GameStates.IsInTask || !pc.IsAlive() || !pc.Is(CustomRoles.Stressed)) return;
if (!LastUpdates.TryGetValue(pc.PlayerId, out var x) || x >= GetTimeStamp() || !Timers.ContainsKey(pc.PlayerId) || !IsEnable || !GameStates.IsInTask || !pc.Is(CustomRoles.Stressed)) return;
LastUpdates[pc.PlayerId] = GetTimeStamp();
if (pc.GetPlayerTaskState().IsTaskFinished)
if (pc.GetPlayerTaskState().IsTaskFinished || !pc.IsAlive())
{
Main.PlayerStates[pc.PlayerId].RemoveSubRole(CustomRoles.Stressed);
Timers.Remove(pc.PlayerId);
@@ -121,7 +121,7 @@ namespace TOHE.Roles.AddOns.Crewmate
pc.Suicide();
}
if (pc.IsModClient() && pc.PlayerId != 0) SendRPC(pc.PlayerId, Timers[pc.PlayerId], LastUpdates[pc.PlayerId]);
if (pc.IsNonHostModClient()) SendRPC(pc.PlayerId, Timers[pc.PlayerId], LastUpdates[pc.PlayerId]);
if (!pc.IsModClient()) NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
}
@@ -154,7 +154,6 @@ namespace TOHE.Roles.AddOns.Crewmate
public static void AfterMeetingTasks()
{
if (!IsEnable) return;
AdjustTime(TimeAfterMeeting + 9);
countRepairSabotage = true;
}
@@ -188,6 +187,12 @@ namespace TOHE.Roles.AddOns.Crewmate
Timers[pc.PlayerId] += TimeAfterReport;
}
public static void OnMeetingStart()
{
if (!IsEnable) return;
AdjustTime(TimeAfterMeeting + 9);
}
public static string GetProgressText(byte playerId) => Timers.TryGetValue(playerId, out var x) ? string.Format(GetString("DamoclesTimeLeft"), x) : string.Empty;
private static void AdjustTime(int change)
+61 -39
View File
@@ -1,6 +1,7 @@
using Hazel;
using System;
using System.Collections.Generic;
using System.Linq;
using static TOHE.Options;
using static TOHE.Translator;
using static TOHE.Utils;
@@ -19,16 +20,16 @@ namespace TOHE.Roles.AddOns.Impostor
private static int TimeAfterMeeting;
private static int StartingTime;
public static int Timer;
public static Dictionary<byte, int> Timer;
public static long lastUpdate;
public static List<int> PreviouslyEnteredVents;
public static Dictionary<byte, long> lastUpdate;
public static Dictionary<byte, List<int>> PreviouslyEnteredVents;
public static bool countRepairSabotage;
public static void SetupCustomOption()
{
SetupAdtRoleOptions(Id, CustomRoles.Damocles, canSetNum: false);
SetupAdtRoleOptions(Id, CustomRoles.Damocles, canSetNum: true);
DamoclesExtraTimeAfterKill = IntegerOptionItem.Create(Id + 10, "DamoclesExtraTimeAfterKill", new(0, 60, 1), 30, TabGroup.Addons, false)
.SetParent(CustomRoleSpawnChances[CustomRoles.Damocles])
.SetValueFormat(OptionFormat.Seconds);
@@ -46,109 +47,130 @@ namespace TOHE.Roles.AddOns.Impostor
TimeAfterMeeting = DamoclesExtraTimeAfterMeeting.GetInt();
StartingTime = DamoclesStartingTime.GetInt();
Timer = StartingTime;
lastUpdate = GetTimeStamp() + 10;
Timer = [];
lastUpdate = [];
PreviouslyEnteredVents = [];
countRepairSabotage = true;
}
public static void Update(PlayerControl pc)
{
if (lastUpdate >= GetTimeStamp() || !GameStates.IsInTask || pc == null) return;
byte id = pc.PlayerId;
if (lastUpdate.TryGetValue(id, out var ts) && ts >= GetTimeStamp() || !GameStates.IsInTask || pc == null) return;
if (!pc.IsAlive())
{
Main.PlayerStates[pc.PlayerId].RemoveSubRole(CustomRoles.Damocles);
Main.PlayerStates[id].RemoveSubRole(CustomRoles.Damocles);
return;
}
lastUpdate = GetTimeStamp();
lastUpdate[id] = GetTimeStamp();
if (!Timer.ContainsKey(id)) Timer[id] = StartingTime + 8;
Timer--;
Timer[id]--;
if (Timer < 0)
if (Timer[id] < 0)
{
Timer = 0;
Timer[id] = 0;
pc.Suicide();
}
if (pc.IsNonHostModClient()) SendRPC();
NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
if (pc.IsNonHostModClient()) SendRPC(id);
if (!pc.IsModClient()) NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
}
public static void SendRPC()
public static void SendRPC(byte playerId)
{
if (!DoRPC) return;
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncDamoclesTimer, SendOption.Reliable, -1);
writer.Write(Timer);
writer.Write(lastUpdate.ToString());
writer.Write(PreviouslyEnteredVents.Count);
if (PreviouslyEnteredVents.Count > 0) foreach (var vent in PreviouslyEnteredVents.ToArray()) writer.Write(vent);
writer.Write(playerId);
writer.Write(Timer[playerId]);
writer.Write(lastUpdate[playerId].ToString());
writer.Write(PreviouslyEnteredVents[playerId].Count);
if (PreviouslyEnteredVents[playerId].Count > 0) foreach (var vent in PreviouslyEnteredVents[playerId].ToArray()) writer.Write(vent);
AmongUsClient.Instance.FinishRpcImmediately(writer);
}
public static void ReceiveRPC(MessageReader reader)
{
Timer = reader.ReadInt32();
lastUpdate = long.Parse(reader.ReadString());
byte playerId = reader.ReadByte();
Timer[playerId] = reader.ReadInt32();
lastUpdate[playerId] = long.Parse(reader.ReadString());
var elements = reader.ReadInt32();
if (elements > 0) for (int i = 0; i < elements; i++) PreviouslyEnteredVents.Add(reader.ReadInt32());
if (elements > 0) for (int i = 0; i < elements; i++) PreviouslyEnteredVents[playerId].Add(reader.ReadInt32());
}
public static void OnMurder()
public static void OnMurder(byte id)
{
Timer += TimeAfterKill;
Timer[id] += TimeAfterKill;
}
public static void OnOtherImpostorMurder()
{
Timer += 10;
AdjustTime(10);
}
public static void OnEnterVent(int ventId)
public static void OnEnterVent(byte id, int ventId)
{
if (PreviouslyEnteredVents.Contains(ventId)) return;
if (!PreviouslyEnteredVents.ContainsKey(id)) PreviouslyEnteredVents[id] = [];
if (PreviouslyEnteredVents[id].Contains(ventId)) return;
PreviouslyEnteredVents.Add(ventId);
Timer += 10;
PreviouslyEnteredVents[id].Add(ventId);
Timer[id] += 10;
}
public static void AfterMeetingTasks()
{
PreviouslyEnteredVents.Clear();
Timer += TimeAfterMeeting;
AdjustTime(TimeAfterMeeting);
countRepairSabotage = true;
}
public static void OnMeetingStart()
{
Timer += 9;
AdjustTime(9);
}
public static void OnCrewmateEjected()
{
Timer = (int)Math.Round(Timer * 1.3);
AdjustTimeByPercent(1.3);
}
public static void OnRepairSabotage()
public static void OnRepairSabotage(byte id)
{
Timer -= 15;
Timer[id] -= 15;
}
public static void OnImpostorDeath()
{
Timer -= 20;
AdjustTime(-20);
}
public static void OnReport()
public static void OnReport(byte id)
{
Timer = (int)Math.Round(Timer * 0.9);
Timer[id] = (int)Math.Round(Timer[id] * 0.9);
}
public static void OnImpostorEjected()
{
Timer = (int)Math.Round(Timer * 0.8);
AdjustTimeByPercent(0.8);
}
public static string GetProgressText() => string.Format(GetString("DamoclesTimeLeft"), Timer);
private static void AdjustTime(int change)
{
foreach (var item in Timer.Keys.ToArray())
{
Timer[item] += change;
}
}
private static void AdjustTimeByPercent(double percent)
{
foreach (var item in Timer.Keys.ToArray())
{
Timer[item] = (int)Math.Round(Timer[item] * percent);
}
}
public static string GetProgressText(byte id) => string.Format(GetString("DamoclesTimeLeft"), Timer.TryGetValue(id, out var time) ? time : StartingTime);
}
}
+30 -37
View File
@@ -169,52 +169,45 @@ namespace TOHE.Roles.Crewmate
SendRPCSyncAbilityUse(pc.PlayerId);
}
public static void OnCheckPlayerPosition(PlayerControl pc)
{
if (!IsEnable || !GameStates.IsInTask || Triggers.Count <= 0 || playerIdList.Contains(pc.PlayerId)) return;
foreach (var triggers in Triggers.ToArray()) // Check for all Druids' traps - Most likely just 1 loop
{
foreach (var trigger in triggers.Value.Where(trigger => Vector2.Distance(trigger.Key, pc.Pos()) <= 1.5f)) // Check for all traps of the current Druid - Most likely 0-3 loops
{
GetPlayerById(triggers.Key).Notify(string.Format(GetString("DruidTriggerTriggered"), GetFormattedRoomName(trigger.Value), GetFormattedVectorText(trigger.Key)));
Triggers[triggers.Key].Remove(trigger.Key);
SendRPCRemoveTrigger(triggers.Key, trigger.Key);
}
}
}
public static void OnFixedUpdate()
{
if (!IsEnable || !GameStates.IsInTask || Triggers.Count == 0 && TriggerDelays.Count == 0) return;
if (!IsEnable || !GameStates.IsInTask || TriggerDelays.Count <= 0) return;
long now = GetTimeStamp();
if (TriggerDelays.Count > 0)
foreach (var x in TriggerDelays.ToArray())
{
foreach (var x in TriggerDelays.ToArray())
var id = x.Key;
var pc = GetPlayerById(id);
if (pc == null) continue;
if (x.Value + TriggerPlaceDelay.GetInt() < now)
{
var id = x.Key;
var pc = GetPlayerById(id);
if (pc == null) continue;
if (x.Value + TriggerPlaceDelay.GetInt() < now)
{
TriggerDelays.Remove(id);
var (LOCATION, ROOM_NAME) = pc.GetPositionInfo();
if (!Triggers.ContainsKey(id)) Triggers.Add(id, []);
Triggers[id].TryAdd(LOCATION, ROOM_NAME);
SendRPCAddTrigger(id, LOCATION, ROOM_NAME);
continue;
}
var timeLeft = TriggerPlaceDelay.GetInt() - (now - x.Value);
if (lastUpdate < now) pc.Notify(string.Format(GetString("DruidTimeLeft"), timeLeft, 2f));
TriggerDelays.Remove(id);
var (LOCATION, ROOM_NAME) = pc.GetPositionInfo();
if (!Triggers.ContainsKey(id)) Triggers.Add(id, []);
Triggers[id].TryAdd(LOCATION, ROOM_NAME);
SendRPCAddTrigger(id, LOCATION, ROOM_NAME);
continue;
}
}
if (Triggers.Count > 0)
{
foreach (var pc in Main.AllAlivePlayerControls.Where(pc => !playerIdList.Contains(pc.PlayerId)).ToArray()) // Check for all alive players except Druids - Worst case scenario it's 14 loops
{
foreach (var triggers in Triggers.ToArray()) // Check for all Druids' traps - Most likely just 1 loop
{
foreach (var trigger in triggers.Value.ToArray()) // Check for all traps of the current Druid - Most likely 0-3 loops
{
if (Vector2.Distance(trigger.Key, pc.Pos()) <= 1.5f)
{
GetPlayerById(triggers.Key).Notify(string.Format(GetString("DruidTriggerTriggered"), GetFormattedRoomName(trigger.Value), GetFormattedVectorText(trigger.Key)));
Triggers[triggers.Key].Remove(trigger.Key);
SendRPCRemoveTrigger(triggers.Key, trigger.Key);
}
}
}
}
var timeLeft = TriggerPlaceDelay.GetInt() - (now - x.Value);
if (lastUpdate < now) pc.Notify(string.Format(GetString("DruidTimeLeft"), timeLeft, 2f));
}
lastUpdate = now;
+5 -1
View File
@@ -24,6 +24,7 @@ public static class Medic
public static OptionItem GuesserIgnoreShield;
private static OptionItem AmountOfShields;
public static OptionItem UsePet;
public static OptionItem CD;
public static readonly string[] MedicWhoCanSeeProtectName =
[
@@ -67,6 +68,9 @@ public static class Medic
AmountOfShields = IntegerOptionItem.Create(Id + 34, "MedicAmountOfShields", new(1, 14, 1), 1, TabGroup.CrewmateRoles, false)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Medic]);
UsePet = Options.CreatePetUseSetting(Id + 36, CustomRoles.Medic);
CD = FloatOptionItem.Create(Id + 38, "AbilityCooldown", new(0f, 180f, 2.5f), 7.5f, TabGroup.CrewmateRoles, false)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Medic])
.SetValueFormat(OptionFormat.Seconds);
}
public static void Init()
{
@@ -124,7 +128,7 @@ public static class Medic
public static bool CanUseKillButton(byte playerId)
=> !Main.PlayerStates[playerId].IsDead
&& (ProtectLimit.TryGetValue(playerId, out var x) ? x : 1) >= 1;
public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = CanUseKillButton(id) ? 5f : 300f;
public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = CanUseKillButton(id) ? CD.GetFloat() : 300f;
public static string GetSkillLimit(byte playerId) => Utils.ColorString(CanUseKillButton(playerId) ? Utils.GetRoleColor(CustomRoles.Medic).ShadeColor(0.25f) : Color.gray, ProtectLimit.TryGetValue(playerId, out var protectLimit) ? $"({protectLimit})" : "Invalid");
public static bool InProtect(byte id) => ProtectList.Contains(id) && Main.PlayerStates.TryGetValue(id, out var ps) && !ps.IsDead;
public static void OnCheckMurderFormedicaler(PlayerControl killer, PlayerControl target)
+28 -12
View File
@@ -49,22 +49,30 @@ namespace TOHE.Roles.Crewmate
FinishPatrolling();
return;
}
}
public void OnCheckPlayerPosition(PlayerControl pc)
{
if (!IsPatrolling) return;
long now = GetTimeStamp();
if (LastUpdate >= now) return;
LastUpdate = now;
var killers = NearbyKillers;
foreach (var pc in Main.AllAlivePlayerControls)
{
bool nowInRange = killers.Any(x => x.PlayerId == pc.PlayerId);
bool wasInRange = LastNearbyKillers.Contains(pc.PlayerId);
bool nowInRange = killers.Any(x => x.PlayerId == pc.PlayerId);
bool wasInRange = LastNearbyKillers.Contains(pc.PlayerId);
if (wasInRange && !nowInRange)
{
pc.Notify(GetString("KillerEscapedFromSentinel"));
}
if (nowInRange)
{
pc.Notify(string.Format(GetString("KillerNotifyPatrol"), PatrolDuration - (now - PatrolStartTimeStamp)));
}
if (wasInRange && !nowInRange)
{
pc.Notify(GetString("KillerEscapedFromSentinel"));
LastNearbyKillers.Remove(pc.PlayerId);
}
if (nowInRange)
{
pc.Notify(string.Format(GetString("KillerNotifyPatrol"), PatrolDuration - (GetTimeStamp() - PatrolStartTimeStamp)));
LastNearbyKillers.Add(pc.PlayerId);
}
}
@@ -171,5 +179,13 @@ namespace TOHE.Roles.Crewmate
state.Update();
}
}
public static void OnCheckPlayerPosition(PlayerControl pc)
{
if (!IsEnable) return;
foreach (PatrollingState state in PatrolStates)
{
state.OnCheckPlayerPosition(pc);
}
}
}
}
+6 -8
View File
@@ -104,7 +104,7 @@ namespace TOHE.Roles.Crewmate
Tornados.Add(info, now);
SendRPCAddTornado(info.LOCATION, info.ROOM_NAME, now);
}
public static void OnFixedUpdate(PlayerControl tornadoPc)
public static void OnCheckPlayerPosition(PlayerControl pc)
{
if (!IsEnable || !GameStates.IsInTask || Tornados.Count == 0) return;
@@ -114,10 +114,8 @@ namespace TOHE.Roles.Crewmate
var tornadoRange = TornadoRange.GetFloat();
var tornadoDuration = TornadoDuration.GetInt();
foreach (var pc in Main.AllAlivePlayerControls)
foreach (var tornadoPc in playerIdList.Select(x => GetPlayerById(x)).Where(x => x.PlayerId != pc.PlayerId).ToArray())
{
if (playerIdList.Contains(pc.PlayerId)) continue;
foreach (var tornado in Tornados)
{
if (Vector2.Distance(tornado.Key.LOCATION, pc.Pos()) <= tornadoRange)
@@ -139,11 +137,11 @@ namespace TOHE.Roles.Crewmate
SendRPCRemoveTornado(tornado.Key.LOCATION, tornado.Key.ROOM_NAME);
}
}
}
if (tornadoPc == null || LastNotify >= now || !tornadoPc.Is(CustomRoles.Tornado) || tornadoPc.HasAbilityCD()) return;
NotifyRoles(SpecifySeer: tornadoPc, SpecifyTarget: tornadoPc);
LastNotify = now;
if (tornadoPc == null || LastNotify >= now || !tornadoPc.Is(CustomRoles.Tornado) || tornadoPc.HasAbilityCD()) return;
NotifyRoles(SpecifySeer: tornadoPc, SpecifyTarget: tornadoPc);
LastNotify = now;
}
}
public static string GetSuffixText(byte playerId, bool isHUD = false) => string.Join(isHUD ? "\n" : ", ", Tornados.Select(x => $"Tornado {GetFormattedRoomName(x.Key.ROOM_NAME)} {GetFormattedVectorText(x.Key.LOCATION)} ({(int)(TornadoDuration.GetInt() - (GetTimeStamp() - x.Value) + 1)}s)"));
}
+2 -2
View File
@@ -103,7 +103,7 @@ public static class BallLightning
RealKiller.TryAdd(killer.PlayerId, target);
StartConvertCountDown(target, killer);
}
public static void OnFixedUpdate()
public static void OnCheckPlayerPosition(PlayerControl pc)
{
if (!IsEnable || !GameStates.IsInTask) return;
List<byte> deList = [];
@@ -115,7 +115,7 @@ public static class BallLightning
deList.Add(gs.PlayerId);
continue;
}
foreach (var pc in Main.AllAlivePlayerControls.Where(x => x.PlayerId != gs.PlayerId && x.IsAlive() && !x.Is(CustomRoles.BallLightning) && !IsGhost(x) && !Pelican.IsEaten(x.PlayerId)).ToArray())
if (pc.PlayerId != gs.PlayerId && pc.IsAlive() && !pc.Is(CustomRoles.BallLightning) && !IsGhost(pc) && !Pelican.IsEaten(pc.PlayerId))
{
var pos = gs.transform.position;
var dis = Vector2.Distance(pos, pc.Pos());
+19 -16
View File
@@ -1,4 +1,5 @@
using System;
using MS.Internal.Xml.XPath;
using System;
using System.Collections.Generic;
using System.Linq;
using TOHE.Roles.Crewmate;
@@ -33,8 +34,8 @@ namespace TOHE.Roles.Impostor
public static OptionItem IgnorePestilence;
public static OptionItem PositiveEffectChance;
public static byte EffectID = byte.MaxValue;
public static bool isPositiveEffect;
public static Dictionary<byte, byte> EffectID = [];
public static Dictionary<byte, bool> isPositiveEffect = [];
public static Dictionary<byte, long> waitingDelayedKills = [];
public static Dictionary<byte, long> isShielded = [];
@@ -43,7 +44,7 @@ namespace TOHE.Roles.Impostor
public static void SetupCustomOption()
{
SetupSingleRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Gambler, 1);
SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Gambler);
KillCooldown = FloatOptionItem.Create(Id + 10, "KillCooldown", new(0f, 60f, 2.5f), 25f, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Gambler])
.SetValueFormat(OptionFormat.Seconds);
KillDelay = IntegerOptionItem.Create(Id + 11, "GamblerKillDelay", new(0, 10, 1), 3, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Gambler])
@@ -74,17 +75,18 @@ namespace TOHE.Roles.Impostor
IgnoreVeteranAlert = BooleanOptionItem.Create(Id + 25, "GamblerIgnoreVeteranAlert", false, TabGroup.ImpostorRoles, false).SetParent(WhatToIgnore);
IgnorePestilence = BooleanOptionItem.Create(Id + 26, "GamblerIgnorePestilence", false, TabGroup.ImpostorRoles, false).SetParent(WhatToIgnore);
PositiveEffectChance = IntegerOptionItem.Create(Id + 27, "GamblerPositiveEffectChance", new(0, 100, 5), 70, TabGroup.ImpostorRoles, false)
.SetParent(CustomRoleSpawnChances[CustomRoles.Gambler])
.SetValueFormat(OptionFormat.Percent);
.SetParent(CustomRoleSpawnChances[CustomRoles.Gambler])
.SetValueFormat(OptionFormat.Percent);
}
public static void Init()
{
playerIdList = [];
EffectID = byte.MaxValue;
EffectID = [];
waitingDelayedKills = [];
isSpeedChange = [];
isVisionChange = [];
isPositiveEffect = [];
}
public static void Add(byte playerId)
@@ -99,17 +101,17 @@ namespace TOHE.Roles.Impostor
if (killer == null) return false;
if (target == null) return false;
if (EffectID != byte.MaxValue)
if (EffectID.TryGetValue(killer.PlayerId, out var id) && id != byte.MaxValue)
{
return true;
}
var rd = IRandom.Instance;
isPositiveEffect = rd.Next(1, 101) <= PositiveEffectChance.GetInt();
if (isPositiveEffect)
isPositiveEffect[killer.PlayerId] = rd.Next(1, 101) <= PositiveEffectChance.GetInt();
if (isPositiveEffect[killer.PlayerId])
{
EffectID = (byte)rd.Next(1, 8);
switch (EffectID)
EffectID[killer.PlayerId] = (byte)rd.Next(1, 8);
switch (EffectID[killer.PlayerId])
{
case 1: // Delayed kill
killer.Notify(string.Format(GetString("GamblerGet.DelayedKill"), KillDelay.GetInt()));
@@ -176,8 +178,8 @@ namespace TOHE.Roles.Impostor
}
else
{
EffectID = (byte)rd.Next(1, 5);
switch (EffectID)
EffectID[killer.PlayerId] = (byte)rd.Next(1, 5);
switch (EffectID[killer.PlayerId])
{
case 1: // BSR
var delay = Math.Max(0.15f, BSRDelay.GetFloat());
@@ -211,7 +213,7 @@ namespace TOHE.Roles.Impostor
}
}
EffectID = byte.MaxValue;
EffectID[killer.PlayerId] = byte.MaxValue;
return true;
}
@@ -260,7 +262,8 @@ namespace TOHE.Roles.Impostor
public static void OnReportDeadBody()
{
EffectID = byte.MaxValue;
EffectID.Clear();
isPositiveEffect.Clear();
foreach (var playerId in waitingDelayedKills.Keys.ToArray())
{
var pc = GetPlayerById(playerId);
+4 -7
View File
@@ -129,6 +129,7 @@ namespace TOHE.Roles.Impostor
if (librarian == null) return true;
reporter.SetRealKiller(librarian);
if (librarian.RpcCheckAndMurder(reporter))
{
sssh.Add(librarian.PlayerId);
@@ -143,7 +144,7 @@ namespace TOHE.Roles.Impostor
return false;
}
public static bool OnShapeshift(PlayerControl pc)
public static bool OnShapeshift(PlayerControl pc, bool shapeshifting)
{
if (!IsEnable) return false;
if (pc == null) return false;
@@ -153,7 +154,7 @@ namespace TOHE.Roles.Impostor
isInSilencingMode[id] = (!isInSilencingMode[id].SILENCING, GetTimeStamp());
SendRPC(id, isInSilencingMode[id].SILENCING);
return ShowSSAnimation.GetBool();
return !shapeshifting || ShowSSAnimation.GetBool();
}
public static void OnFixedUpdate()
@@ -179,13 +180,9 @@ namespace TOHE.Roles.Impostor
sssh.Clear();
}
public static string GetNameTextForSuffix(byte playerId)
{
if (!IsEnable) return string.Empty;
return isInSilencingMode.TryGetValue(playerId, out var x) && x.SILENCING && sssh.Contains(playerId) && GameStates.IsInTask
public static string GetNameTextForSuffix(byte playerId) => IsEnable && isInSilencingMode.TryGetValue(playerId, out var x) && x.SILENCING && sssh.Contains(playerId) && GameStates.IsInTask
? GetString("LibrarianNameText")
: string.Empty;
}
public static string GetSelfSuffixAndHUDText(byte playerId)
{
+9 -6
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using static TOHE.Options;
using static TOHE.Translator;
using static TOHE.Utils;
@@ -59,7 +60,7 @@ namespace TOHE.Roles.Impostor
return killer.CheckDoubleTrigger(target, () =>
{
killer.SetKillCooldown(time: ManipulateCD);
if (target.HasKillButton() || target.GetPlayerTaskState().hasTasks)
if (target.HasKillButton() || target.GetPlayerTaskState().hasTasks || UsePets.GetBool())
{
ManipulateDelays.TryAdd(target.PlayerId, GetTimeStamp());
NotifyRoles(SpecifySeer: killer, SpecifyTarget: target);
@@ -85,13 +86,13 @@ namespace TOHE.Roles.Impostor
ManipulateDelays.Remove(x.Key);
ManipulatedPlayers.TryAdd(x.Key, GetTimeStamp());
if (!pc.GetPlayerTaskState().hasTasks)
if (!pc.GetPlayerTaskState().hasTasks || UsePets.GetBool())
{
TempKCDs.TryAdd(pc.PlayerId, Main.KillTimers[pc.PlayerId]);
pc.SetKillCooldown(time: 1f);
}
NotifyRoles(SpecifySeer: Mastermind_, SpecifyTarget: Mastermind_);
NotifyRoles(SpecifySeer: Mastermind_, SpecifyTarget: pc);
}
}
@@ -115,7 +116,7 @@ namespace TOHE.Roles.Impostor
var time = TimeLimit.GetInt() - (GetTimeStamp() - x.Value);
player.Notify(string.Format(GetString(player.GetPlayerTaskState().hasTasks ? "ManipulateTaskNotify" : "ManipulateNotify"), time), 1.1f);
player.Notify(string.Format(GetString(UsePets.GetBool() ? "ManipulatePetNotify" : player.GetPlayerTaskState().hasTasks ? "ManipulateTaskNotify" : "ManipulateNotify"), time), 1.1f);
}
}
@@ -157,7 +158,9 @@ namespace TOHE.Roles.Impostor
_ = new LateTask(() =>
{
killer.SetKillCooldown(time: TempKCDs.TryGetValue(killer.PlayerId, out var cd) ? cd : 0f + Main.AllPlayerKillCooldown[killer.PlayerId]);
var kcd = TempKCDs.TryGetValue(killer.PlayerId, out var cd) ? cd : Main.AllPlayerKillCooldown.TryGetValue(killer.PlayerId, out var baseKCD) ? baseKCD : DefaultKillCooldown;
killer.SetKillCooldown(time: kcd);
if (killer.GetCustomRole().PetActivatedAbility()) killer.AddAbilityCD((int)Math.Round(kcd));
TempKCDs.Remove(killer.PlayerId);
}, 0.1f, "Set KCD for Manipulated Kill");
+1 -1
View File
@@ -70,7 +70,7 @@ namespace TOHE.Roles.Impostor
public static bool OnCheckMurder(PlayerControl killer, PlayerControl target)
{
if (!IsEnable) return false;
if (killer == null || target == null) return false;
if (killer == null || target == null || !killer.Is(CustomRoles.YinYanger)) return false;
if (YinYangedPlayers.Count == 2)
{
+37 -12
View File
@@ -1,7 +1,9 @@
using AmongUs.GameOptions;
using HarmonyLib;
using Hazel;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using static TOHE.Options;
using static TOHE.Utils;
@@ -92,29 +94,52 @@ namespace TOHE.Roles.Neutral
if (!IsEnable || !GameStates.IsInTask || EncasedPlayers.Count == 0) return;
long now = GetTimeStamp();
foreach (var id in EncasedPlayers.Where(item => item.Value + ExplodeDelay.GetInt() < now).Select(item => item.Key).ToArray())
foreach (var kvp in EncasedPlayers)
{
var players = GetPlayersInRadius(ExplosionRadius.GetFloat(), GetPlayerById(id).Pos());
foreach (var pc in players)
var id = kvp.Key;
var encasedPc = GetPlayerById(id);
if (kvp.Value + ExplodeDelay.GetInt() < now)
{
if (pc == null) continue;
if (pc.PlayerId == BubbleId)
if (!encasedPc.IsAlive())
{
if (BubbleDiesIfInRange.GetBool()) _ = new LateTask(() => { if (GameStates.IsInTask) pc.Suicide(); }, 0.2f, log: false);
else continue;
EncasedPlayers.Remove(id);
SendRPC(id, remove: true);
continue;
}
pc.Suicide(realKiller: Bubble_);
var players = GetPlayersInRadius(ExplosionRadius.GetFloat(), encasedPc.Pos());
foreach (var pc in players)
{
if (pc == null) continue;
if (pc.PlayerId == BubbleId)
{
if (BubbleDiesIfInRange.GetBool()) _ = new LateTask(() => { if (GameStates.IsInTask) pc.Suicide(PlayerState.DeathReason.Bombed); }, 0.5f, log: false);
continue;
}
pc.Suicide(PlayerState.DeathReason.Bombed, Bubble_);
}
EncasedPlayers.Remove(id);
SendRPC(id, remove: true);
continue;
}
if (kvp.Value + NotifyDelay.GetInt() < now)
{
Main.AllAlivePlayerControls.Where(x => Vector2.Distance(x.Pos(), encasedPc.Pos()) < 5f).Do(x => NotifyRoles(SpecifySeer: x, SpecifyTarget: encasedPc));
}
EncasedPlayers.Remove(id);
SendRPC(id, remove: true);
}
}
public static void OnReportDeadBody()
{
if (IsEnable) return;
foreach (var pc in EncasedPlayers.Keys.Select(x => GetPlayerById(x)).Where(x => x != null && x.IsAlive())) pc.Suicide(realKiller: Bubble_);
if (!IsEnable) return;
foreach (var pc in EncasedPlayers.Keys.Select(x => GetPlayerById(x)).Where(x => x != null && x.IsAlive())) pc.Suicide(PlayerState.DeathReason.Bombed, Bubble_);
EncasedPlayers.Clear();
SendRPC(clear: true);
}
public static string GetEncasedPlayerSuffix(PlayerControl seer, PlayerControl target)
{
if (!IsEnable || target == null || !EncasedPlayers.TryGetValue(target.PlayerId, out var ts) || (ts + NotifyDelay.GetInt() >= GetTimeStamp())) return string.Empty;
return ColorString(GetRoleColor(CustomRoles.Bubble), $"{ExplodeDelay.GetInt() - (GetTimeStamp() - ts) + 1}s");
}
}
}
+31 -30
View File
@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using UnityEngine;
using static TOHE.Options;
using static TOHE.Translator;
using static TOHE.Utils;
namespace TOHE.Roles.Neutral
@@ -93,56 +94,56 @@ namespace TOHE.Roles.Neutral
public static void ReceiveRPC(MessageReader reader) => UseLimit = reader.ReadInt32();
public static void PlaceTrap()
{
if (!IsEnable || Sprayer_.HasAbilityCD() || UseLimit <= 0) return;
if (!IsEnable || UseLimit <= 0 || Sprayer_.HasAbilityCD()) return;
Traps.Add(Sprayer_.Pos());
UseLimit--;
SendRPC();
if (UseLimit > 0) Sprayer_.AddAbilityCD(CD.GetInt());
Sprayer_.Notify(GetString("SprayerNotify"));
}
public static void OnFixedUpdate()
public static void OnCheckPlayerPosition(PlayerControl pc)
{
if (!IsEnable || !GameStates.IsInTask || Traps.Count == 0) return;
long now = GetTimeStamp();
foreach (var pc in Main.AllAlivePlayerControls)
if (pc.PlayerId == SprayerId) return;
if (!LastUpdate.ContainsKey(pc.PlayerId)) LastUpdate.Add(pc.PlayerId, now);
if (LastUpdate[pc.PlayerId] + 3 > now) return;
LastUpdate[pc.PlayerId] = now;
foreach (var trap in Traps.ToArray())
{
if (pc.PlayerId == SprayerId) continue;
if (!LastUpdate.ContainsKey(pc.PlayerId)) LastUpdate.Add(pc.PlayerId, now);
if (LastUpdate[pc.PlayerId] + 3 > now) continue;
LastUpdate[pc.PlayerId] = now;
foreach (var trap in Traps.ToArray())
if (Vector2.Distance(pc.Pos(), trap) <= 2f)
{
if (Vector2.Distance(pc.Pos(), trap) <= 2f)
byte playerId = pc.PlayerId;
var tempSpeed = Main.AllPlayerSpeed[playerId];
Main.AllPlayerSpeed[playerId] = LoweredSpeed.GetFloat();
LowerVisionList.Add(playerId);
TrappedCount[playerId]++;
if (TrappedCount[playerId] > MaxTrappedTimes.GetInt())
{
byte playerId = pc.PlayerId;
var tempSpeed = Main.AllPlayerSpeed[playerId];
Main.AllPlayerSpeed[playerId] = LoweredSpeed.GetFloat();
LowerVisionList.Add(playerId);
TrappedCount[playerId]++;
if (TrappedCount[playerId] > MaxTrappedTimes.GetInt())
pc.Suicide(realKiller: Sprayer_);
TrappedCount.Remove(playerId);
}
else
{
pc.MarkDirtySettings();
_ = new LateTask(() =>
{
pc.Suicide(realKiller: Sprayer_);
TrappedCount.Remove(playerId);
}
else
{
pc.MarkDirtySettings();
_ = new LateTask(() =>
{
Main.AllPlayerSpeed[playerId] = tempSpeed;
LowerVisionList.Remove(playerId);
if (GameStates.IsInTask) pc.MarkDirtySettings();
}, EffectDuration.GetFloat(), "Sprayer Revert Effects");
}
Main.AllPlayerSpeed[playerId] = tempSpeed;
LowerVisionList.Remove(playerId);
if (GameStates.IsInTask) pc.MarkDirtySettings();
}, EffectDuration.GetFloat(), "Sprayer Revert Effects");
}
}
}
}
public static void OnReportDeadBody()
{
Traps.Clear();
+2 -1
View File
@@ -18,6 +18,7 @@
</ItemGroup>
<ItemGroup>
<None Remove="Modules\zqihthf4.eqf~" />
<None Remove="resources\modnews\english\TOHE+.v1.2.0.txt" />
<None Remove="resources\modnews\english\TOHE+.v1.3.0.txt" />
<None Remove="resources\modnews\english\TOHE+.v1.4.0.txt" />
@@ -35,7 +36,7 @@
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2023.11.28" PrivateAssets="all" />
<PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.1.0-rc.1" />
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.682" Private="false" ExcludeAssets="runtime;native" />
<PackageReference Include="Samboy063.Cpp2IL.Core" Version="2022.1.0-development.898" />
<PackageReference Include="Samboy063.Cpp2IL.Core" Version="2022.1.0-pre-release.13" />
</ItemGroup>
<ItemGroup>
+268 -280
View File
@@ -33,8 +33,8 @@ public class Main : BasePlugin
public static ConfigEntry<string> DebugKeyInput { get; private set; }
public static readonly string MainMenuText = " ";
public const string PluginGuid = "com.gurge44.toheplus";
public const string PluginVersion = "2.2.2";
public const string PluginDisplayVersion = "2.2.2";
public const string PluginVersion = "2.2.4";
public const string PluginDisplayVersion = "2.2.4";
public static readonly string SupportedAUVersion = "2023.10.24";
public const int PluginCreate = 3;
public const bool Canary = false;
@@ -653,84 +653,80 @@ public enum CustomRoles
//Impostors
BountyHunter,
FireWorks,
Mafia,
Godfather,
SerialKiller,
//ShapeMaster,
Wildling,
EvilGuesser,
Minimalism,
Zombie,
Sniper,
Vampire,
Witch,
Warlock,
Assassin,
Undertaker,
Vindicator,
Hacker,
Miner,
Escapee,
Inhibitor,
Librarian,
Chronomancer,
Nullifier,
Stealth,
Penguin,
Sapper,
Mastermind,
Hitman,
RiftMaker,
Gambler,
Puppeteer,
TimeThief,
EvilTracker,
Hacker, // Anonymous
AntiAdminer,
Consort,
Sans,
Bomber,
Nuker,
BoobyTrap,
Scavenger,
Capitalism,
Gangster,
Cleaner,
BallLightning,
Greedier,
CursedWolf,
ImperiusCurse,
QuickShooter,
Eraser,
OverKiller,
Hangman,
Sans, // Arrogance
Bard,
Mafioso,
Trickster,
Swooper,
Cantankerous,
Duellist,
YinYanger,
Crewpostor,
Parasite,
Disperser,
Blackmailer,
Bomber,
BountyHunter,
OverKiller, // Butcher
Camouflager,
Saboteur,
Capitalism,
Cantankerous,
Chronomancer,
EvilDiviner, // Consigliere
Consort,
Councillor,
Dazzler,
Crewpostor,
CursedWolf,
Deathpact,
Devourer,
EvilDiviner,
Morphling,
Twister,
Blackmailer,
Disperser,
Duellist,
Dazzler,
Escapee,
Eraser,
EvilGuesser,
EvilTracker,
FireWorks,
Gambler,
Gangster,
Godfather,
Greedier,
Hangman,
Hitman,
Inhibitor,
Minimalism, // Killing Machine
BallLightning, // Lightning
Librarian,
Lurker,
Convict,
Visionary,
Mafia,
Mafioso,
Mastermind,
SerialKiller, // Mercenary
Miner,
Morphling,
Assassin, // Ninja
Nuker,
Nullifier,
Parasite,
Penguin,
Puppeteer,
QuickShooter,
Refugee,
RiftMaker,
Saboteur,
Sapper,
Scavenger,
Sniper,
ImperiusCurse, // Soul Catcher
Swooper,
Stealth,
TimeThief,
BoobyTrap, // Trapster
Trickster,
Twister,
Underdog,
// Flashbang,
Undertaker,
Vampire,
Vindicator,
Visionary,
Warlock,
Wildling,
Witch,
YinYanger,
Zombie,
//Crewmates (Vanilla)
Engineer,
@@ -744,178 +740,169 @@ public enum CustomRoles
// Crewmate
Luckey,
Needy,
SuperStar,
CyberStar,
Demolitionist,
Ventguard,
Express,
NiceEraser,
TaskManager,
Shiftguard,
Mole,
Sentinel,
Electric,
Philantropist,
Tornado,
Insight,
Tunneler,
Detour,
Gaulois,
Druid,
Drainer,
CameraMan,
NiceHacker,
Spy,
Ricochet,
Doormaster,
Tether,
Admirer,
Addict,
Aid,
Benefactor,
GuessManager,
Escort,
DonutDelivery,
Alchemist,
Altruist,
Analyzer,
Mayor,
Jailor,
Paranoia,
Psychic,
SabotageMaster,
Sheriff,
Snitch,
Enigma,
Marshall,
SpeedBooster,
Lookout,
Autocrat,
Benefactor,
Bodyguard,
CameraMan,
CyberStar, // Celebrity
Chameleon,
Cleaner,
Cleanser,
CopyCat,
Bloodhound, // Coroner
Crusader,
Demolitionist,
Deputy,
Detective,
Detour,
Dictator,
Doctor,
Detective,
SwordsMan,
NiceGuesser,
Transporter,
NiceSwapper,
Altruist,
Transmitter,
Autocrat,
Nightmare,
TimeManager,
Veteran,
Bodyguard,
//Counterfeiter,
Witness,
Grenadier,
Lighter,
SecurityGuard,
Medic,
Divinator,
Glitch,
Judge,
Mortician,
Mediumshiper,
Observer,
DonutDelivery,
Doormaster,
DovesOfNeace,
Monarch,
CopyCat,
Drainer,
Druid,
Electric,
Enigma,
Escort,
Express,
Farseer,
Bloodhound,
Tracker,
Merchant,
//Retributionist,
Deputy,
Divinator, // Fortune Teller
Gaulois,
Glitch,
Grenadier,
GuessManager,
Guardian,
Addict,
Alchemist,
Tracefinder,
Ignitor,
Oracle,
Spiritualist,
Chameleon,
ParityCop,
Admirer,
TimeMaster,
Insight,
ParityCop, // Inspector
Jailor,
Judge,
Needy, // Lazy Guy
Lighter,
Lookout,
Luckey,
Marshall,
Mayor,
SabotageMaster, // Mechanic
Medic,
Mediumshiper,
Merchant,
Monitor,
Crusader,
Cleanser,
//Reverie,
Mole,
Monarch,
Mortician,
NiceEraser,
NiceGuesser,
NiceHacker,
NiceSwapper,
Nightmare,
Observer,
Oracle,
Paranoia,
Philantropist,
Psychic,
Ricochet,
Sentinel,
SecurityGuard,
Sheriff,
Shiftguard,
Snitch,
Spiritualist,
Speedrunner,
SpeedBooster,
Spy,
SuperStar,
TaskManager,
Tether,
TimeManager,
TimeMaster,
Tornado,
Tracker,
Transmitter,
Transporter,
Tracefinder,
Tunneler,
Ventguard,
Veteran,
SwordsMan, // Vigilante
Witness,
//Neutrals
Arsonist,
HexMaster,
Jester,
God,
Opportunist,
Mario,
Terrorist,
Executioner,
Bandit,
Lawyer,
Jackal,
Poisoner,
//NWitch,
Innocent,
Pelican,
Revolutionist,
NSerialKiller,
Enderman,
Mycologist,
Bubble,
Hookshot,
Sprayer,
PlagueDoctor,
Postman,
Reckless,
Magician,
WeaponMaster,
Eclipse,
Pyromaniac,
Vengeance,
HeadHunter,
Imitator,
Werewolf,
Juggernaut,
Infectious,
FFF,
Konan,
Gamer,
DarkHide,
Workaholic,
Speedrunner,
Collector,
Agitater,
Provocateur,
Sunnyboy,
BloodKnight,
Wraith,
Totocalcio,
Romantic,
VengefulRomantic,
RuthlessRomantic,
Succubus,
Virus,
Pursuer,
Phantom,
Jinx,
Maverick,
//CursedSoul,
//Pirate,
Ritualist,
Doppelganger,
Pickpocket,
Traitor,
Vulture,
PlagueBearer,
Pestilence,
Medusa,
Sidekick,
//Baker,
//Famine,
Spiritcaller,
Amnesiac,
Arsonist,
Bandit,
BloodKnight,
Bubble,
Collector,
Gamer, // Demon
Doppelganger,
Doomsayer,
//Masochist,
// Flux,
Eclipse,
Enderman,
Executioner,
Totocalcio, // Follower
God,
FFF, // Hater
HeadHunter,
HexMaster,
Hookshot,
Imitator,
Infectious,
Innocent,
Jackal,
Jester,
Jinx,
Juggernaut,
Konan,
Lawyer,
Magician,
Mario,
Maverick,
Medusa,
Mycologist,
Opportunist,
Pelican,
Pestilence,
Phantom,
Pickpocket,
PlagueBearer,
PlagueDoctor,
Poisoner,
Postman,
Provocateur,
Pursuer,
Pyromaniac,
Reckless,
Revolutionist,
Ritualist,
Romantic,
RuthlessRomantic,
NSerialKiller, // Serial Killer
Sidekick,
Spiritcaller,
Sprayer,
DarkHide, // Stalker
Succubus,
Sunnyboy,
Terrorist,
Traitor,
Vengeance,
VengefulRomantic,
Virus,
Vulture,
Wraith,
Werewolf,
WeaponMaster,
Workaholic,
//SoloKombat
KB_Normal,
@@ -926,66 +913,67 @@ public enum CustomRoles
//GM
GM,
// ????
Convict,
// Sub-role after 500
NotAssigned = 500,
LastImpostor,
Lovers,
Ntr,
Madmate,
Watcher,
Flashman,
Torch,
Seer,
Brakar,
Oblivious,
Bewilder,
Sunglasses,
Workhorse,
Fool,
Avanger,
Youtuber,
Egoist,
TicketsStealer,
DualPersonality,
Mimic,
Guesser,
Necroview,
Reach,
Charmed,
Bait,
Trapper,
Infected,
Onbound,
Knighted,
Contagious,
Cleansed,
Unreportable,
DeadlyQuota,
Damocles,
Stressed,
Rogue,
Lucky,
Unlucky,
DoubleShot,
// Reflective,
Rascal,
Soulless,
Gravestone,
Lazy,
Autopsy,
Loyal,
EvilSpirit,
Recruit,
Admired,
Glow,
Diseased,
Antidote,
Swift,
Autopsy,
Avanger,
Bait,
Trapper, // Beartrap
Bewilder,
Charmed,
Cleansed,
Contagious,
Damocles,
DeadlyQuota,
Diseased,
Unreportable, // Disregarded
DoubleShot,
Egoist,
EvilSpirit,
Flashman,
Fool,
Ghoul,
Glow,
Gravestone,
Guesser,
Infected,
Knighted,
LastImpostor,
Lazy,
Lovers,
Loyal,
Lucky,
Madmate,
Mare,
Mimic,
Necroview,
Ntr, // Neptune
Nimble,
Oblivious,
Onbound,
Physicist,
// QuickFix
Rascal,
Reach,
Recruit,
Rogue,
DualPersonality, // Schizophrenic
Seer,
Soulless,
TicketsStealer, // Stealer
Stressed,
Swift,
Sunglasses,
Brakar, // Tiebreaker
Torch,
Unlucky,
Watcher,
Workhorse,
Youtuber
}
//WinData
public enum CustomWinner