Prompts, Achievements API, Prevent CNOs on modded servers, Duellist nerf

This commit is contained in:
Gurge44 committed 2024-12-29 13:46:29 +01:00
1 parent 4978ca7a92
commit ba9059e401
18 files changed
+411 -192

No files matched your search

+1
View File
@@ -407,6 +407,7 @@ public enum CustomRoles
// Sub-role after 500
NotAssigned = 500,
Allergic,
Anchor,
Antidote,
AntiTP,
Asthmatic,
+1 -1
View File
@@ -7,7 +7,7 @@
<Description>EHR</Description>
<Authors>Gurge44</Authors>
<langVersion>preview</langVersion>
<AmongUs>E:\Program Files\AmongUs</AmongUs>
<AmongUs>D:\AmongUs</AmongUs>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>True</Optimize>
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
+3 -2
View File
@@ -35,9 +35,10 @@ public class Main : BasePlugin
private const string DebugKeyHash = "c0fd562955ba56af3ae20d7ec9e64c664f0facecef4b3e366e109306adeae29d";
private const string DebugKeySalt = "59687b";
private const string PluginGuid = "com.gurge44.endlesshostroles";
public const string PluginVersion = "5.2.0";
public const string PluginDisplayVersion = "5.2.0";
public const string PluginVersion = "5.3.0";
public const string PluginDisplayVersion = "5.3.0";
public const bool TestBuild = false;
public const string NeutralColor = "#ffab1b";
public const string ImpostorColor = "#ff1919";
public const string CrewmateColor = "#8cffff";
+64 -3
View File
@@ -1,7 +1,9 @@
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using UnityEngine;
using UnityEngine.Networking;
// ReSharper disable InconsistentNaming
@@ -109,6 +111,10 @@ public static class Achievements
const string SaveFilePath = "./EHR_DATA/Achievements.json";
const string ApiBaseUrl = "https://gurge44.pythonanywhere.com/achievements";
const string ApiSaveEndpoint = $"{ApiBaseUrl}/save";
const string ApiLoadEndpoint = $"{ApiBaseUrl}/load";
public static readonly HashSet<Type> WaitingAchievements = [];
public static HashSet<Type> CompletedAchievements = [];
@@ -176,13 +182,68 @@ public static class Achievements
{
var json = JsonSerializer.Serialize(CompletedAchievements);
File.WriteAllText(SaveFilePath, json);
Main.Instance.StartCoroutine(SendAchievementsToApiAsync());
return;
IEnumerator SendAchievementsToApiAsync()
{
while (PlayerControl.LocalPlayer == null) yield return null;
var userId = PlayerControl.LocalPlayer.GetClient().GetHashedPuid();
var data = new
{
userId,
achievements = CompletedAchievements
};
var payload = JsonSerializer.Serialize(data);
var request = new UnityWebRequest(ApiSaveEndpoint, UnityWebRequest.kHttpVerbPOST)
{
uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(payload)),
downloadHandler = new DownloadHandlerBuffer()
};
request.SetRequestHeader("Content-Type", "application/json");
yield return request.SendWebRequest();
Logger.Msg(request.result != UnityWebRequest.Result.Success ? $"Error saving achievements: {request.error}" : "Achievements saved successfully", "Achievements.SaveAllData");
}
}
public static void LoadAllData()
{
if (!File.Exists(SaveFilePath)) return;
if (File.Exists(SaveFilePath))
{
var json = File.ReadAllText(SaveFilePath);
CompletedAchievements = JsonSerializer.Deserialize<HashSet<Type>>(json);
}
else
{
Main.Instance.StartCoroutine(FetchAchievementsFromApiAsync());
return;
var json = File.ReadAllText(SaveFilePath);
CompletedAchievements = JsonSerializer.Deserialize<HashSet<Type>>(json);
IEnumerator FetchAchievementsFromApiAsync()
{
while (PlayerControl.LocalPlayer == null) yield return null;
var userId = PlayerControl.LocalPlayer.GetClient().GetHashedPuid();
var url = $"{ApiLoadEndpoint}?userId={userId}";
var request = UnityWebRequest.Get(url);
yield return request.SendWebRequest();
if (request.result != UnityWebRequest.Result.Success) { Logger.Error($"Error loading achievements: {request.error}", "Achievements.LoadAllData"); }
else
{
var json = request.downloadHandler.text;
CompletedAchievements = JsonSerializer.Deserialize<HashSet<Type>>(json);
yield return File.WriteAllTextAsync(SaveFilePath, json);
Logger.Info("Achievements loaded successfully.", "Achievements.LoadAllData");
}
}
}
}
}
+90 -117
View File
@@ -189,7 +189,7 @@ namespace EHR
msg.EndMessage();
AmongUsClient.Instance.SendOrDisconnect(msg);
msg.Recycle();
if (PlayerControl.AllPlayerControls.Contains(playerControl))
PlayerControl.AllPlayerControls.Remove(playerControl);
@@ -327,7 +327,7 @@ namespace EHR
protected void CreateNetObject(string sprite, Vector2 position)
{
if (GameStates.IsEnded) return;
if (GameStates.IsEnded || GameStates.CurrentServerType == GameStates.ServerType.Modded) return;
Logger.Info($" Create Custom Net Object {GetType().Name} (ID {MaxId + 1}) at {position}", "CNO.CreateNetObject");
playerControl = Object.Instantiate(AmongUsClient.Instance.PlayerPrefab, Vector2.zero, Quaternion.identity);
playerControl.PlayerId = 255;
@@ -480,105 +480,102 @@ namespace EHR
AllObjects.ToArray().Do(x => x.Despawn());
AllObjects.Clear();
}
catch (Exception e)
{
Utils.ThrowException(e);
}
catch (Exception e) { Utils.ThrowException(e); }
}
}
/*
internal sealed class Explosion : CustomNetObject
{
private readonly float Duration;
private readonly float Size;
private int Frame;
private float Timer;
public Explosion(float size, float duration, Vector2 position)
/*
internal sealed class Explosion : CustomNetObject
{
Size = size;
Duration = duration;
Timer = -0.1f;
Frame = 0;
CreateNetObject($"<size={Size}><line-height=67%><font=\"VCR SDF\"><br><#0000>███<#ff0000>█<#0000>███<br><#ff0000>█<#0000>█<#ff0000>███<#0000>█<#ff0000>█<br>█<#ff8000>██<#ffff00>█<#ff8000>██<#ffff00>█<br>██<#ff8000>█<#ffff00>█<#ff8000>█<#ffff00>██<br><#ff8000>█<#ffff80>██<#ffff00>█<#ffff80>██<#ff8000>█<br><#0000>█<#ff8000>█<#ffff80>███<#ff8000>█<#0000>█<br>██<#ff8000>███<#0000>██", position);
private readonly float Duration;
private readonly float Size;
private int Frame;
private float Timer;
public Explosion(float size, float duration, Vector2 position)
{
Size = size;
Duration = duration;
Timer = -0.1f;
Frame = 0;
CreateNetObject($"<size={Size}><line-height=67%><font=\"VCR SDF\"><br><#0000>███<#ff0000>█<#0000>███<br><#ff0000>█<#0000>█<#ff0000>███<#0000>█<#ff0000>█<br>█<#ff8000>██<#ffff00>█<#ff8000>██<#ffff00>█<br>██<#ff8000>█<#ffff00>█<#ff8000>█<#ffff00>██<br><#ff8000>█<#ffff80>██<#ffff00>█<#ffff80>██<#ff8000>█<br><#0000>█<#ff8000>█<#ffff80>███<#ff8000>█<#0000>█<br>██<#ff8000>███<#0000>██", position);
}
protected override void OnFixedUpdate()
{
base.OnFixedUpdate();
Timer += Time.deltaTime;
if (Timer >= Duration / 5f && Frame == 0)
{
RpcChangeSprite($"<size={Size}><line-height=67%><font=\"VCR SDF\"><br><#0000>█<#ff0000>█<#0000>█<#ff0000>█<#0000>█<#ff0000>█<#0000>█<br><#ff0000>█<#ff8000>█<#ff0000>█<#ff8000>█<#ff0000>█<#ff8000>█<#ff0000>█<br><#ff8000>██<#ffff00>█<#ff8000>█<#ffff00>█<#ff8000>██<br><#ffff00>███████<br><#ff8000>█<#ffff00>█████<#ff8000>█<br>██<#ffff00>█<#ff8000>█<#ffff00>█<#ff8000>██<br><#ff0000>█<#0000>█<#ff8000>█<#ff0000>█<#ff8000>█<#0000>█<#ff0000>█");
Frame = 1;
}
if (Timer >= Duration / 5f * 2f && Frame == 1)
{
RpcChangeSprite($"<size={Size}><line-height=67%><font=\"VCR SDF\"><br><#0000>█<#c0c0c0>█<#ff0000>█<#000000>█<#ff0000>█<#c0c0c0>█<#0000>█<br><#c0c0c0>█<#808080>█<#ff0000>█<#ff8000>█<#ff0000>█<#c0c0c0>██<br><#ff0000>██<#ff8000>█<#ffff00>█<#ff8000>█<#ff0000>██<br><#c0c0c0>█<#ff8000>█<#ffff00>█<#ffff80>█<#ffff00>█<#ff8000>█<#808080>█<br><#ff0000>██<#ff8000>█<#ffff00>█<#ff8000>█<#ff0000>██<br><#c0c0c0>█<#808080>█<#ff0000>█<#ff8000>█<#ff0000>█<#000000>█<#c0c0c0>█<br><#0000>█<#c0c0c0>█<#ff0000>█<#c0c0c0>█<#ff0000>█<#c0c0c0>█<#0000>█");
Frame = 2;
}
if (Timer >= Duration / 5f * 3f && Frame == 2)
{
RpcChangeSprite($"<size={Size}><line-height=67%><font=\"VCR SDF\"><br><#ff0000>█<#ff8000>█<#0000>█<#808080>█<#0000>█<#ff8000>█<#ff0000>█<br><#ff8000>█<#0000>█<#ffff00>█<#c0c0c0>█<#ffff00>█<#0000>█<#ff8000>█<br><#0000>█<#ffff00>█<#c0c0c0>███<#ffff00>█<#0000>█<br><#808080>█<#c0c0c0>█████<#808080>█<br><#0000>█<#ffff00>█<#c0c0c0>███<#ffff00>█<#0000>█<br><#ff8000>█<#0000>█<#ffff00>█<#c0c0c0>█<#ffff00>█<#0000>█<#ff8000>█<br><#ff0000>█<#ff8000>█<#0000>█<#808080>█<#0000>█<#ff8000>█<#ff0000>█");
Frame = 3;
}
if (Timer >= Duration / 5f * 4f && Frame == 3)
{
RpcChangeSprite($"<size={Size}><line-height=67%><font=\"VCR SDF\"><br><#0000>█<#808080>█<#0000>██<#c0c0c0>█<#0000>█<#808080>█<br><#ffff00>█<#0000>██<#c0c0c0>█<#0000>█<#808080>█<#0000>█<br>█<#808080>█<#c0c0c0>████<#0000>█<br>█<#c0c0c0>██████<br>█<#0000>█<#c0c0c0>███<#808080>█<#0000>█<br>█<#c0c0c0>█<#0000>█<#c0c0c0>█<#0000>█<#c0c0c0>██<br><#808080>█<#0000>█<#c0c0c0>█<#0000>█<#808080>█<#0000>█<#ffff00>█");
Frame = 4;
}
if (Timer >= Duration && Frame == 4)
{
Despawn();
}
}
}
protected override void OnFixedUpdate()
internal sealed class TrapArea : CustomNetObject
{
base.OnFixedUpdate();
private readonly float Size;
public readonly List<byte> VisibleList;
private readonly float WaitDuration;
private int State;
private float Timer;
Timer += Time.deltaTime;
if (Timer >= Duration / 5f && Frame == 0)
public TrapArea(float radius, float waitDuration, Vector2 position, List<byte> visibleList)
{
RpcChangeSprite($"<size={Size}><line-height=67%><font=\"VCR SDF\"><br><#0000>█<#ff0000>█<#0000>█<#ff0000>█<#0000>█<#ff0000>█<#0000>█<br><#ff0000>█<#ff8000>█<#ff0000>█<#ff8000>█<#ff0000>█<#ff8000>█<#ff0000>█<br><#ff8000>██<#ffff00>█<#ff8000>█<#ffff00>█<#ff8000>██<br><#ffff00>███████<br><#ff8000>█<#ffff00>█████<#ff8000>█<br>██<#ffff00>█<#ff8000>█<#ffff00>█<#ff8000>██<br><#ff0000>█<#0000>█<#ff8000>█<#ff0000>█<#ff8000>█<#0000>█<#ff0000>█");
Frame = 1;
VisibleList = visibleList;
Size = radius * 25f;
Timer = -0.1f;
WaitDuration = waitDuration;
State = 0;
CreateNetObject($"<size={Size}><font=\"VCR SDF\"><#c7c7c769>●", position);
Main.AllAlivePlayerControls.ExceptBy(visibleList, x => x.PlayerId).Do(Hide);
}
if (Timer >= Duration / 5f * 2f && Frame == 1)
protected override void OnFixedUpdate()
{
RpcChangeSprite($"<size={Size}><line-height=67%><font=\"VCR SDF\"><br><#0000>█<#c0c0c0>█<#ff0000>█<#000000>█<#ff0000>█<#c0c0c0>█<#0000>█<br><#c0c0c0>█<#808080>█<#ff0000>█<#ff8000>█<#ff0000>█<#c0c0c0>██<br><#ff0000>██<#ff8000>█<#ffff00>█<#ff8000>█<#ff0000>██<br><#c0c0c0>█<#ff8000>█<#ffff00>█<#ffff80>█<#ffff00>█<#ff8000>█<#808080>█<br><#ff0000>██<#ff8000>█<#ffff00>█<#ff8000>█<#ff0000>██<br><#c0c0c0>█<#808080>█<#ff0000>█<#ff8000>█<#ff0000>█<#000000>█<#c0c0c0>█<br><#0000>█<#c0c0c0>█<#ff0000>█<#c0c0c0>█<#ff0000>█<#c0c0c0>█<#0000>█");
Frame = 2;
}
base.OnFixedUpdate();
if (Timer >= Duration / 5f * 3f && Frame == 2)
{
RpcChangeSprite($"<size={Size}><line-height=67%><font=\"VCR SDF\"><br><#ff0000>█<#ff8000>█<#0000>█<#808080>█<#0000>█<#ff8000>█<#ff0000>█<br><#ff8000>█<#0000>█<#ffff00>█<#c0c0c0>█<#ffff00>█<#0000>█<#ff8000>█<br><#0000>█<#ffff00>█<#c0c0c0>███<#ffff00>█<#0000>█<br><#808080>█<#c0c0c0>█████<#808080>█<br><#0000>█<#ffff00>█<#c0c0c0>███<#ffff00>█<#0000>█<br><#ff8000>█<#0000>█<#ffff00>█<#c0c0c0>█<#ffff00>█<#0000>█<#ff8000>█<br><#ff0000>█<#ff8000>█<#0000>█<#808080>█<#0000>█<#ff8000>█<#ff0000>█");
Frame = 3;
}
Timer += Time.deltaTime;
if (Timer >= WaitDuration * 0.75f && State == 0)
{
RpcChangeSprite($"<size={Size}><font=\"VCR SDF\"><#fff70069>●");
State = 1;
}
if (Timer >= Duration / 5f * 4f && Frame == 3)
{
RpcChangeSprite($"<size={Size}><line-height=67%><font=\"VCR SDF\"><br><#0000>█<#808080>█<#0000>██<#c0c0c0>█<#0000>█<#808080>█<br><#ffff00>█<#0000>██<#c0c0c0>█<#0000>█<#808080>█<#0000>█<br>█<#808080>█<#c0c0c0>████<#0000>█<br>█<#c0c0c0>██████<br>█<#0000>█<#c0c0c0>███<#808080>█<#0000>█<br>█<#c0c0c0>█<#0000>█<#c0c0c0>█<#0000>█<#c0c0c0>██<br><#808080>█<#0000>█<#c0c0c0>█<#0000>█<#808080>█<#0000>█<#ffff00>█");
Frame = 4;
}
if (Timer >= Duration && Frame == 4)
{
Despawn();
if (Timer >= WaitDuration * 0.95f && State == 1)
{
RpcChangeSprite($"<size={Size}><font=\"VCR SDF\"><#ff000069>●");
State = 2;
}
}
}
}
internal sealed class TrapArea : CustomNetObject
{
private readonly float Size;
public readonly List<byte> VisibleList;
private readonly float WaitDuration;
private int State;
private float Timer;
public TrapArea(float radius, float waitDuration, Vector2 position, List<byte> visibleList)
{
VisibleList = visibleList;
Size = radius * 25f;
Timer = -0.1f;
WaitDuration = waitDuration;
State = 0;
CreateNetObject($"<size={Size}><font=\"VCR SDF\"><#c7c7c769>●", position);
Main.AllAlivePlayerControls.ExceptBy(visibleList, x => x.PlayerId).Do(Hide);
}
protected override void OnFixedUpdate()
{
base.OnFixedUpdate();
Timer += Time.deltaTime;
if (Timer >= WaitDuration * 0.75f && State == 0)
{
RpcChangeSprite($"<size={Size}><font=\"VCR SDF\"><#fff70069>●");
State = 1;
}
if (Timer >= WaitDuration * 0.95f && State == 1)
{
RpcChangeSprite($"<size={Size}><font=\"VCR SDF\"><#ff000069>●");
State = 2;
}
}
}
*/
*/
internal sealed class TornadoObject : CustomNetObject
{
private readonly long SpawnTimeStamp;
@@ -607,14 +604,8 @@ namespace EHR
}
catch (NullReferenceException)
{
try
{
Despawn();
}
finally
{
Gone = true;
}
try { Despawn(); }
finally { Gone = true; }
}
}
}
@@ -782,32 +773,14 @@ internal static class RawSetNamePatch
var exception = false;
try
{
__instance.gameObject.name = name;
}
catch
{
exception = true;
}
try { __instance.gameObject.name = name; }
catch { exception = true; }
try
{
__instance.cosmetics.SetName(name);
}
catch
{
exception = true;
}
try { __instance.cosmetics.SetName(name); }
catch { exception = true; }
try
{
__instance.cosmetics.SetNameMask(true);
}
catch
{
exception = true;
}
try { __instance.cosmetics.SetNameMask(true); }
catch { exception = true; }
LateTask.New(() =>
{
+1
View File
@@ -1508,6 +1508,7 @@ internal static class CustomRolesHelper
CustomRoles.Generator => RoleOptionType.Impostor_Miscellaneous,
CustomRoles.Visionary => RoleOptionType.Impostor_Miscellaneous,
CustomRoles.Wildling => RoleOptionType.Impostor_Miscellaneous,
CustomRoles.DoubleAgent => RoleOptionType.Crewmate_Investigate,
_ => role.IsCrewmate() ? RoleOptionType.Crewmate_Miscellaneous : RoleOptionType.Neutral_Benign
};
}
+4 -4
View File
@@ -12,6 +12,8 @@ public static class DevManager
{
private static readonly TagInfo DefaultDevUser = new();
private static int Attempts;
private static Dictionary<string, TagInfo> Tags { get; set; } = [];
public static TagInfo GetDevUser(this string code)
@@ -20,8 +22,6 @@ public static class DevManager
return Tags.GetValueOrDefault(code, DefaultDevUser);
}
private static int Attempts;
private static IEnumerator FetchTags()
{
Attempts++;
@@ -31,7 +31,7 @@ public static class DevManager
Logger.Error($"Failed to fetch tags after {Attempts - 1} attempts.", "DevManager.FetchTags");
yield break;
}
UnityWebRequest request = UnityWebRequest.Get("https://gurge44.pythonanywhere.com/get_all_tags");
yield return request.SendWebRequest();
@@ -72,6 +72,6 @@ public static class DevManager
public bool HasTag() => !string.IsNullOrEmpty(tag_name);
public string GetTag() => !HasTag() ? "" : $"<size=1.4><color={tag_color}>{tag_name}</color></size>\r\n";
public string GetTag() => !HasTag() ? "" : $"<size=1.5><color={tag_color}>{tag_name}</color></size>\r\n";
}
}
+23 -7
View File
@@ -78,10 +78,10 @@ public class PlayerState(byte playerId)
private readonly byte PlayerId = playerId;
public readonly List<CustomRoles> SubRoles = [];
public readonly Dictionary<byte, string> TargetColorData = [];
public NetworkedPlayerInfo.PlayerOutfit NormalOutfit;
public CountTypes countTypes = CountTypes.Crew;
public PlainShipRoom LastRoom;
public CustomRoles MainRole = CustomRoles.NotAssigned;
public NetworkedPlayerInfo.PlayerOutfit NormalOutfit;
public (DateTime TimeStamp, byte ID) RealKiller = (DateTime.MinValue, byte.MaxValue);
public RoleBase Role = new VanillaRole();
@@ -502,6 +502,14 @@ public class PlayerVersion(Version ver, string tagStr, string forkId)
public static class GameStates
{
public enum ServerType
{
Vanilla,
Modded,
Niko,
Custom
}
public static bool InGame;
public static bool AlreadyDied;
public static bool IsModHost => PlayerControl.AllPlayerControls.ToArray().Any(x => x.IsHost() && x.IsModClient());
@@ -518,18 +526,26 @@ public static class GameStates
public static bool IsCountDown => GameStartManager.InstanceExists && GameStartManager.Instance.startState == GameStartManager.StartingStates.Countdown;
public static bool IsVanillaServer
public static ServerType CurrentServerType
{
get
{
if (IsLocalGame && !IsNotJoined) return true;
if (IsLocalGame && !IsNotJoined) return ServerType.Vanilla;
const string domain = "among.us";
// From Reactor.gg
return ServerManager.Instance.CurrentRegion?.TryCast<StaticHttpRegionInfo>() is { } regionInfo &&
regionInfo.PingServer.EndsWith(domain, StringComparison.Ordinal) &&
regionInfo.Servers.All(serverInfo => serverInfo.Ip.EndsWith(domain, StringComparison.Ordinal));
if (ServerManager.Instance.CurrentRegion?.TryCast<StaticHttpRegionInfo>() is { } regionInfo &&
regionInfo.PingServer.EndsWith(domain, StringComparison.Ordinal) &&
regionInfo.Servers.All(serverInfo => serverInfo.Ip.EndsWith(domain, StringComparison.Ordinal)))
return ServerType.Vanilla;
string regionName = Utils.GetRegionName();
if (regionName.Contains("Niko", StringComparison.OrdinalIgnoreCase)) return ServerType.Niko;
if (regionName.StartsWith('M') && regionName.Length == 3) return ServerType.Modded;
return ServerType.Custom;
}
}
@@ -550,4 +566,4 @@ public static class MeetingStates
public static bool IsExistDeadBody => DeadBodies.Length > 0;
public static NetworkedPlayerInfo ReportTarget { get; set; }
}
}
+98
View File
@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Linq;
using HarmonyLib;
namespace EHR.Modules;
public static class Prompt
{
private static readonly List<(string Question, Action OnYes, Action OnNo)> Queue = [];
private static SimpleButton YesButton;
private static SimpleButton NoButton;
private static string CurrentQuestion = string.Empty;
public static void Show(string question, Action onYes, Action onNo)
{
try
{
HudManager hud = DestroyableSingleton<HudManager>.Instance;
if (CurrentQuestion != string.Empty || !hud)
{
if (Queue.All(x => x.Question != question) && CurrentQuestion != question)
Queue.Add((question, onYes, onNo));
return;
}
CurrentQuestion = question;
hud.ShowPopUp(question);
Action closePromt = () =>
{
HidePromt();
CurrentQuestion = string.Empty;
hud.Dialogue.Hide();
if (Queue.Count > 0)
{
(string q, Action y, Action n) = Queue[0];
Queue.RemoveAt(0);
LateTask.New(() => Show(q, y, n), 0.01f, log: false);
}
};
onYes += closePromt;
onNo += closePromt;
YesButton = new SimpleButton(
hud.Dialogue.transform,
"PromtYesButton",
new(1f, -1.25f),
new(0, 255, 165, 255),
new(0, 255, 255, 255),
onYes,
Translator.GetString("Yes"));
NoButton = new SimpleButton(
hud.Dialogue.transform,
"PromtNoButton",
new(-1f, -1.25f),
new(0, 165, 255, 255),
new(0, 255, 255, 255),
onNo,
Translator.GetString("No"));
}
catch (Exception e) { Utils.ThrowException(e); }
}
private static void HidePromt()
{
Object.Destroy(YesButton?.Button.gameObject);
Object.Destroy(NoButton?.Button.gameObject);
YesButton = null;
NoButton = null;
}
public static void ClearQueue()
{
Queue.Clear();
}
[HarmonyPatch(typeof(DialogueBox), nameof(DialogueBox.Hide))]
static class DialogueBoxHidePatch
{
public static void Prefix()
{
if (CurrentQuestion != string.Empty)
{
ClearQueue();
HidePromt();
}
}
}
}
+40
View File
@@ -3306,6 +3306,46 @@ public static class Utils
return name;
}
public static void EnterQuickSetupRoles(bool addons)
{
int all = Options.CustomRoleSpawnChances.Keys.Count(x => addons ? x.IsAdditionRole() : !x.IsAdditionRole());
int count = 0;
foreach ((CustomRoles role, StringOptionItem option) in Options.CustomRoleSpawnChances)
{
if (addons ? !role.IsAdditionRole() : role.IsAdditionRole() || role.IsVanilla() || role.IsForOtherGameMode()) continue;
count++;
string str = GetString($"{role}InfoLong");
string infoLong;
try { infoLong = HnSManager.AllHnSRoles.Contains(role) ? str : str[(str.IndexOf('\n') + 1)..str.Split("\n\n")[0].Length]; }
catch { infoLong = str; }
string rotStr;
if (!role.IsAdditionRole())
{
RoleOptionType rot = role.GetRoleOptionType();
rotStr = ColorString(rot.GetRoleOptionTypeColor(), GetString($"ROT.{rot}"));
}
else
{
AddonTypes at = Options.GroupedAddons.First(x => x.Value.Contains(role)).Key;
rotStr = ColorString(at.GetAddonTypeColor(), GetString($"ROT.AddonType.{at}"));
}
Prompt.Show(
string.Format(GetString("Promt.EnableRole"), count, all, rotStr, role.ToColoredString(), infoLong),
() => option.SetValue(1),
() => option.SetValue(0));
}
if (addons) return;
Prompt.Show(GetString("Promt.ContinueWithQuickSetupAddons"), () => EnterQuickSetupRoles(true), () => { });
}
private static int PlayersCount(CountTypes countTypes)
{
var count = 0;
+7 -7
View File
@@ -335,7 +335,7 @@ internal static class ChatCommands
private static void CheckAnagramGuess(byte id, string text)
{
if (text.Contains(CurrentAnagram))
if (CurrentAnagram != string.Empty && text.Contains(CurrentAnagram))
{
Utils.SendMessage("\n", title: string.Format(GetString("Anagram.CorrectGuess"), id.ColoredPlayerName(), CurrentAnagram));
CurrentAnagram = string.Empty;
@@ -504,7 +504,7 @@ internal static class ChatCommands
if (!player.Is(CustomRoles.NoteKiller) || args.Length < 2) return;
if (!player.IsLocalPlayer()) ChatManager.SendPreviousMessagesToAll();
if (!NoteKiller.CanGuess)
{
Utils.SendMessage(GetString("DeathNoteCommand.CanNotGuess"), player.PlayerId);
@@ -560,7 +560,10 @@ internal static class ChatCommands
private static void EnableAllRolesCommand(ChatController __instance, PlayerControl player, string text, string[] args)
{
Options.CustomRoleSpawnChances.Values.DoIf(x => x.GetValue() == 0, x => x.SetValue(1));
Prompt.Show(
GetString("Promt.EnableAllRoles"),
() => Options.CustomRoleSpawnChances.Values.DoIf(x => x.GetValue() == 0, x => x.SetValue(1)),
() => Utils.EnterQuickSetupRoles(false));
}
private static void ReadyCheckCommand(ChatController __instance, PlayerControl player, string text, string[] args)
@@ -1717,10 +1720,7 @@ internal static class ChatCommands
Utils.SendMessage("\n", player.PlayerId, string.Format(GetString("RoleSelected"), resultId.ColoredPlayerName(), roleToSet.ToColoredString()));
if (roleToSet.OnlySpawnsWithPets() && !Options.UsePets.GetBool())
{
Options.UsePets.SetValue(1);
Utils.SendMessage(GetString("SetRoleUsePetsMessage"), player.PlayerId);
}
Prompt.Show(GetString("Promt.SetRoleRequiresPets"), () => Options.UsePets.SetValue(1), () => { });
}
private static void UpCommand(ChatController __instance, PlayerControl player, string text, string[] args)
+8 -29
View File
@@ -173,10 +173,7 @@ public class InnerNetClientPatch
{
GameManager gameManager = innerNetObject as GameManager;
if (gameManager != null)
{
__instance.SendGameManager(clientId, gameManager);
}
if (gameManager != null) { __instance.SendGameManager(clientId, gameManager); }
else
{
if (innerNetObject is not NetworkedPlayerInfo)
@@ -211,10 +208,7 @@ public class InnerNetClientPatch
{
if (messageWriter.Length > 500) break;
if (player != null && player.ClientId != clientId && !player.Disconnected)
{
__instance.WriteSpawnMessage(player, player.OwnerId, player.SpawnFlags, messageWriter);
}
if (player != null && player.ClientId != clientId && !player.Disconnected) { __instance.WriteSpawnMessage(player, player.OwnerId, player.SpawnFlags, messageWriter); }
players.Remove(player);
}
@@ -247,19 +241,10 @@ public class InnerNetClientPatch
try
{
if (innerNetObject.Serialize(messageWriter, false))
{
messageWriter.EndMessage();
}
else
{
messageWriter.CancelMessage();
}
if (innerNetObject.Serialize(messageWriter, false)) { messageWriter.EndMessage(); }
else { messageWriter.CancelMessage(); }
if (innerNetObject.Chunked && innerNetObject.IsDirty)
{
__result = true;
}
if (innerNetObject.Chunked && innerNetObject.IsDirty) { __result = true; }
}
catch (Exception ex)
{
@@ -340,10 +325,7 @@ public class InnerNetClientPatch
}
}
if (!__instance.AmHost)
{
Debug.LogError("Tried to spawn while not host:" + (netObjParent?.ToString()));
}
if (!__instance.AmHost) { Debug.LogError("Tried to spawn while not host:" + (netObjParent?.ToString())); }
}
[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.FixedUpdate))]
@@ -372,10 +354,7 @@ public class InnerNetClientPatch
try
{
if (player.Serialize(messageWriter, false))
{
messageWriter.EndMessage();
}
if (player.Serialize(messageWriter, false)) { messageWriter.EndMessage(); }
else
{
messageWriter.CancelMessage();
@@ -417,7 +396,7 @@ internal static class AuthTimeoutPatch
// https://github.com/NuclearPowered/Reactor/blob/master/Reactor/Patches/Miscellaneous/CustomServersPatch.cs
public static bool CoWaitforNoncePrefix(ref bool __result)
{
if (GameStates.IsVanillaServer) return true;
if (GameStates.CurrentServerType == GameStates.ServerType.Vanilla) return true;
__result = false;
return false;
+28 -10
View File
@@ -126,22 +126,40 @@ internal static class ControllerManagerUpdatePatch
Utils.ShowActiveSettings();
}
if (KeysDown(KeyCode.Delete, KeyCode.LeftControl, KeyCode.LeftShift) && !IsResetting)
if (GameStates.IsLobby && KeysDown(KeyCode.Delete, KeyCode.LeftControl, KeyCode.LeftShift) && !IsResetting)
{
IsResetting = true;
Main.Instance.StartCoroutine(Reset());
Prompt.Show(GetString("Promt.ResetAllOptions"), ResetAllOptions, () => { });
IEnumerator Reset()
void ResetAllOptions()
{
for (var index = 0; index < OptionItem.AllOptions.Count; index++)
IsResetting = true;
Main.Instance.StartCoroutine(Reset());
return;
IEnumerator Reset()
{
OptionItem option = OptionItem.AllOptions[index];
if (option.Id > 0) option.SetValue(option.DefaultValue);
yield return new WaitForSeconds(0.1f);
if (index % 100 == 0) yield return null;
DestroyableSingleton<HudManager>.Instance.ShowPopUp(string.Format(GetString("ResettingOptions"), 0, OptionItem.AllOptions.Count));
DestroyableSingleton<HudManager>.Instance.Dialogue.BackButton.gameObject.SetActive(false);
for (var index = 0; index < OptionItem.AllOptions.Count; index++)
{
OptionItem option = OptionItem.AllOptions[index];
if (option.Id > 0) option.SetValue(option.DefaultValue);
if (index % 10 == 0)
{
DestroyableSingleton<HudManager>.Instance.Dialogue.target.text = string.Format(GetString("ResettingOptions"), index, OptionItem.AllOptions.Count);
yield return null;
}
}
DestroyableSingleton<HudManager>.Instance.Dialogue.BackButton.gameObject.SetActive(true);
DestroyableSingleton<HudManager>.Instance.Dialogue.Hide();
IsResetting = false;
}
IsResetting = false;
}
}
+3 -3
View File
@@ -17,7 +17,7 @@ internal static class Crowded
{
private static CreateOptionsPicker Instance;
public static readonly int MaxImpostors = GameOptionsManager.Instance.currentHostOptions.MaxPlayers / 2;
private static int MaxPlayers => GameStates.IsVanillaServer ? 15 : 127;
private static int MaxPlayers => GameStates.CurrentServerType == GameStates.ServerType.Vanilla ? 15 : 127;
[HarmonyPatch(typeof(CreateOptionsPicker), nameof(CreateOptionsPicker.Awake))]
public static class CreateOptionsPickerAwake
@@ -27,7 +27,7 @@ internal static class Crowded
{
Instance = __instance;
if (GameStates.IsVanillaServer)
if (GameStates.CurrentServerType == GameStates.ServerType.Vanilla)
{
if (GameOptionsManager.Instance.GameHostOptions != null)
{
@@ -158,7 +158,7 @@ internal static class Crowded
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public static void Postfix()
{
if (GameStates.IsVanillaServer)
if (GameStates.CurrentServerType == GameStates.ServerType.Vanilla)
{
if (GameOptionsManager.Instance.GameHostOptions != null && GameOptionsManager.Instance.GameHostOptions.MaxPlayers > 15)
GameOptionsManager.Instance.GameHostOptions.SetInt(Int32OptionNames.MaxPlayers, 15);
+26 -7
View File
@@ -647,9 +647,18 @@ public static class StringOptionPatch
if (role.ToString().Contains("GuardianAngel")) role = CustomRoles.GA;
name = name.RemoveHtmlTags();
if (Options.UsePets.GetBool() && role.PetActivatedAbility()) name += Translator.GetString("SupportsPetIndicator");
if (!Options.UsePets.GetBool() && role.OnlySpawnsWithPets()) name += Translator.GetString("RequiresPetIndicator");
if (role.IsExperimental()) name += Translator.GetString("ExperimentalRoleIndicator");
switch (Options.UsePets.GetBool())
{
case false when role.OnlySpawnsWithPets():
name += Translator.GetString("RequiresPetIndicator");
break;
case true when role.PetActivatedAbility():
name += Translator.GetString("SupportsPetIndicator");
break;
}
if (role.IsExperimental()) name += $"<size=2>{Translator.GetString("ExperimentalRoleIndicator")}</size>";
if (role.IsGhostRole()) name += GetGhostRoleTeam(role);
__instance.TitleText.fontWeight = FontWeight.Black;
@@ -751,9 +760,19 @@ public static class StringOptionPatch
if (role.ToString().Contains("GuardianAngel")) role = CustomRoles.GA;
name = name.RemoveHtmlTags();
if (Options.UsePets.GetBool() && role.PetActivatedAbility()) name += Translator.GetString("SupportsPetIndicator");
if (!Options.UsePets.GetBool() && role.OnlySpawnsWithPets()) name += Translator.GetString("RequiresPetIndicator");
if (role.IsExperimental()) name += Translator.GetString("ExperimentalRoleIndicator");
switch (Options.UsePets.GetBool())
{
case true when role.PetActivatedAbility():
name += Translator.GetString("SupportsPetIndicator");
break;
case false when role.OnlySpawnsWithPets():
name += Translator.GetString("RequiresPetIndicator");
Prompt.Show(Translator.GetString("Promt.RequiresPets"), () => Options.UsePets.SetValue(1), () => { });
break;
}
if (role.IsExperimental()) name += $"<size=2>{Translator.GetString("ExperimentalRoleIndicator")}</size>";
if (role.IsGhostRole()) name += GetGhostRoleTeam(role);
__instance.TitleText.fontWeight = FontWeight.Black;
@@ -1251,7 +1270,7 @@ public class GameSettingMenuPatch
ModSettingsButtons = [];
ModSettingsTabs = [];
if ((CustomGameMode.NaturalDisasters.IsActiveOrIntegrated() || CustomGameMode.CaptureTheFlag.IsActiveOrIntegrated()) && !GameStates.IsVanillaServer && GameOptionsMenuPatch.UIReloadTS + 1 < Utils.TimeStamp)
if ((CustomGameMode.NaturalDisasters.IsActiveOrIntegrated() || CustomGameMode.CaptureTheFlag.IsActiveOrIntegrated()) && GameStates.CurrentServerType == GameStates.ServerType.Modded && GameOptionsMenuPatch.UIReloadTS + 1 < Utils.TimeStamp)
DestroyableSingleton<HudManager>.Instance.ShowPopUp(Translator.GetString("ModdedServerDoesntSupportCNOMessage"));
}
}
+2 -2
View File
@@ -76,7 +76,7 @@ internal static class OnGameJoinedPatch
{
JoiningGame = false;
if (GameStates.IsOnlineGame && GameStates.IsVanillaServer)
if (GameStates.IsOnlineGame && GameStates.CurrentServerType is GameStates.ServerType.Vanilla or GameStates.ServerType.Niko)
{
try
{
@@ -371,7 +371,7 @@ internal static class InnerNetClientSpawnPatch
{
LateTask.New(() =>
{
if (GameStates.IsLobby && client.Character != null && LobbyBehaviour.Instance != null && GameStates.IsVanillaServer)
if (GameStates.IsLobby && client.Character != null && LobbyBehaviour.Instance != null && GameStates.CurrentServerType == GameStates.ServerType.Vanilla)
{
// Only for vanilla
if (!client.Character.IsModClient())
+6
View File
@@ -3013,6 +3013,12 @@
"Back": "Back",
"Yes": "Yes",
"No": "No",
"ResettingOptions": "Resetting Options, hold on.... {0}/{1}",
"Promt.EnableRole": "<size=60%>({0}/{1}) {2}\\n</size><size=80%>Enable {3}?</size><size=60%>\\n\\n{4}</size>",
"Promt.RequiresPets": "You've enabled a role that requires additional ability triggers (pet/vanish button/unshift button). Would you like to enable the use of the Pet button (setting in Game Modifiers)?",
"Promt.ResetAllOptions": "Are you sure you want to reset all options? This action is irreversible and may take few minutes.",
"Promt.EnableAllRoles": "Enable all roles and add-ons?<size=80%>\\n\\n<b>Yes</b> - Enable all roles and add-ons\\n<b>No</b> - Enter the quick setup dialog of roles and add-ons</size>",
"Promt.ContinueWithQuickSetupAddons": "<b><#00ffa5>You've finished setting up every role!</color></b> Would you like to continue with the quick setup dialog of add-ons?",
"RpcAntiBlackOutIgnored": "Because of <b>{0}</b>, an unknown error occurred, RPC will be ignored.",
"RpcAntiBlackOutEndGame": "Because of <b>{0}</b>, an unknown error occurred, game will end to prevent black screen.",
"RpcAntiBlackOutNotifyInLobby": "Because of <b>{0}</b>, an unknown error occurred, to prevent black screen, turn off [{1}] in settings.",
+6
View File
@@ -61,6 +61,12 @@ public class Duellist : RoleBase
{
if (Main.KillTimers[duellist.PlayerId] < 1f) duellist.SetKillCooldown(1f); // Give the other player a chance to kill
if (DuelPair.TryGetValue(duellist.PlayerId, out var previousTargetId))
{
var previousTarget = GetPlayerById(previousTargetId);
if (previousTarget != null) previousTarget.TPToRandomVent();
}
duellist.TP(pos);
DuelPair[duellist.PlayerId] = target.PlayerId;
}