Compare commits

..
7 Commits
Author SHA1 Message Date
Gurge44 dbb5c39dea Minor fixes 2024-04-03 21:25:25 +02:00
Gurge44 a13cbd9f88 Merge branch 'main' of https://github.com/Gurge44/TOHE_PLUS 2024-04-03 20:24:12 +02:00
Gurge44 333dfbee6f Teamed FFA 2024-04-03 20:24:03 +02:00
PHGaming121 0431d18127 make adventurer things translatable + a little fix 💀 (#50)
* Update Adventurer.cs

* Update en_US.json

* also, heres a little fix lol
2024-04-03 12:06:55 +02:00
Gurge44 2db423411f Merge branch 'main' of https://github.com/Gurge44/TOHE_PLUS 2024-04-02 19:58:39 +02:00
Gurge44 3d120a5924 New role Adventurer & Bug Fixes 2024-04-02 19:58:34 +02:00
Gurge44 f91f0cd09c Translation (#48)
* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Portuguese, Brazilian)
2024-04-02 15:51:54 +02:00
39 changed files with 787 additions and 235 deletions

No files matched your search

+1
View File
@@ -114,6 +114,7 @@ public enum CustomRoles
// Crewmate
Addict,
Adventurer,
Aid,
Alchemist,
Altruist,
+1
View File
@@ -114,6 +114,7 @@ public enum CustomRoles
// Crewmate
Addict,
Adventurer,
Aid,
Alchemist,
Altruist,
+2
View File
@@ -15,8 +15,10 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NE/@EntryIndexedValue">NE</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NK/@EntryIndexedValue">NK</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NNK/@EntryIndexedValue">NNK</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RNG/@EntryIndexedValue">RNG</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RPC/@EntryIndexedValue">RPC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SK/@EntryIndexedValue">SK</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=TMP/@EntryIndexedValue">TMP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EHR/@EntryIndexedValue">EHR</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=VN/@EntryIndexedValue">VN</s:String></wpf:ResourceDictionary>
+139 -90
View File
@@ -22,6 +22,20 @@ internal static class FFAManager
public static string LatestChatMessage = string.Empty;
public static Dictionary<byte, int> PlayerTeams = [];
public static readonly Dictionary<int, string> TeamColors = new()
{
{ 0, "#00ffff" },
{ 1, "#ffff00" },
{ 2, "#ff00ff" },
{ 3, "#ff0000" },
{ 4, "#00ff00" },
{ 5, "#0000ff" },
{ 6, "#ffffff" },
{ 7, "#000000" }
};
public static OptionItem FFAGameTime;
public static OptionItem FFAKcd;
public static OptionItem FFALowerVision;
@@ -36,6 +50,8 @@ internal static class FFAManager
public static OptionItem FFAEnableRandomTwists;
public static OptionItem FFAShieldIsOneTimeUse;
public static OptionItem FFAChatDuringGame;
public static OptionItem FFATeamMode;
public static OptionItem FFATeamNumber;
public static void SetupCustomOption()
{
@@ -84,6 +100,14 @@ internal static class FFAManager
FFAChatDuringGame = BooleanOptionItem.Create(67_223_014, "FFA_ChatDuringGame", false, TabGroup.GameSettings, false)
.SetGameMode(CustomGameMode.FFA)
.SetColor(new Color32(0, 255, 165, byte.MaxValue));
FFATeamMode = BooleanOptionItem.Create(67_223_015, "FFA_TeamMode", false, TabGroup.GameSettings, false)
.SetGameMode(CustomGameMode.FFA)
.SetHeader(true)
.SetColor(new Color32(0, 255, 165, byte.MaxValue));
FFATeamNumber = IntegerOptionItem.Create(67_223_016, "FFA_TeamNumber", new(2, 7, 1), 2, TabGroup.GameSettings, false)
.SetParent(FFATeamMode)
.SetGameMode(CustomGameMode.FFA)
.SetColor(new Color32(0, 255, 165, byte.MaxValue));
}
public static void Init()
@@ -99,10 +123,30 @@ internal static class FFAManager
KillCount = [];
RoundTime = FFAGameTime.GetInt() + 8;
foreach (PlayerControl pc in Main.AllAlivePlayerControls)
PlayerTeams = [];
var allPlayers = Main.AllAlivePlayerControls;
foreach (PlayerControl pc in allPlayers)
{
KillCount[pc.PlayerId] = 0;
}
if (FFATeamMode.GetBool())
{
var teamNum = FFATeamNumber.GetInt();
var playerNum = allPlayers.Length;
int memberNum = (teamNum > 5 && playerNum == 15) || playerNum % teamNum == 0 ? playerNum / teamNum : playerNum / teamNum + 1;
var teamMembers = allPlayers.Select(x => x.PlayerId).Shuffle(IRandom.Instance).Chunk(memberNum).ToList();
for (int i = 0; i < teamMembers.Count; i++)
{
foreach (var id in teamMembers[i])
{
PlayerTeams.Add(id, i);
}
}
}
}
private static void SendRPCSyncFFAPlayer(byte playerId)
@@ -146,15 +190,6 @@ internal static class FFAManager
}
}
public static string GetDisplayScore(byte playerId)
{
int rank = GetRankOfScore(playerId);
string score = KillCount.TryGetValue(playerId, out var s) ? $"{s}" : "Invalid";
string text = string.Format(GetString("KBDisplayScore"), rank.ToString(), score);
Color color = Utils.GetRoleColor(CustomRoles.Killer);
return Utils.ColorString(color, text);
}
public static int GetRankOfScore(byte playerId)
{
try
@@ -184,6 +219,12 @@ internal static class FFAManager
return;
}
if (FFATeamMode.GetBool() && PlayerTeams[killer.PlayerId] == PlayerTeams[target.PlayerId])
{
Logger.Info("Killer and Target are in the same team, attack blocked", "FFA");
return;
}
var totalalive = Main.AllAlivePlayerControls.Length;
if (FFAShieldedList.TryGetValue(target.PlayerId, out var dur))
{
@@ -206,7 +247,7 @@ internal static class FFAManager
if (totalalive == 3)
{
PlayerControl otherPC = null;
foreach (var pc in Main.AllAlivePlayerControls.Where(a => a.PlayerId != killer.PlayerId && a.PlayerId != target.PlayerId && a.IsAlive()).ToArray())
foreach (var pc in Main.AllAlivePlayerControls.Where(a => a.PlayerId != killer.PlayerId && a.PlayerId != target.PlayerId && a.IsAlive()))
{
TargetArrow.Add(killer.PlayerId, pc.PlayerId);
TargetArrow.Add(pc.PlayerId, killer.PlayerId);
@@ -222,90 +263,99 @@ internal static class FFAManager
bool mark = false;
var nowKCD = Main.AllPlayerKillCooldown[killer.PlayerId];
byte EffectType;
if (Main.NormalOptions.MapId != 4) EffectType = (byte)HashRandom.Next(0, 10);
else EffectType = (byte)HashRandom.Next(4, 10);
if (EffectType <= 7) // Buff
if (Main.NormalOptions.MapId != 4) EffectType = (byte)IRandom.Instance.Next(0, 10);
else EffectType = (byte)IRandom.Instance.Next(4, 10);
switch (EffectType)
{
byte EffectID = (byte)HashRandom.Next(0, 3);
if (Main.NormalOptions.MapId == 4) EffectID = 2;
switch (EffectID)
// Buff
case <= 7:
{
case 0:
FFAShieldedList.TryAdd(killer.PlayerId, Utils.TimeStamp);
killer.Notify(GetString("FFA-Event-GetShield"), FFAShieldDuration.GetFloat());
Main.AllPlayerKillCooldown[killer.PlayerId] = FFAKcd.GetFloat();
break;
case 1:
if (FFAIncreasedSpeedList.ContainsKey(killer.PlayerId))
{
FFAIncreasedSpeedList.Remove(killer.PlayerId);
FFAIncreasedSpeedList.Add(killer.PlayerId, Utils.TimeStamp);
}
else
{
FFAIncreasedSpeedList.TryAdd(killer.PlayerId, Utils.TimeStamp);
originalSpeed.TryAdd(killer.PlayerId, Main.AllPlayerSpeed[killer.PlayerId]);
Main.AllPlayerSpeed[killer.PlayerId] = FFAIncreasedSpeed.GetFloat();
}
byte EffectID = (byte)IRandom.Instance.Next(0, 3);
if (Main.NormalOptions.MapId == 4) EffectID = 2;
switch (EffectID)
{
case 0:
FFAShieldedList.TryAdd(killer.PlayerId, Utils.TimeStamp);
killer.Notify(GetString("FFA-Event-GetShield"), FFAShieldDuration.GetFloat());
Main.AllPlayerKillCooldown[killer.PlayerId] = FFAKcd.GetFloat();
break;
case 1:
if (FFAIncreasedSpeedList.ContainsKey(killer.PlayerId))
{
FFAIncreasedSpeedList.Remove(killer.PlayerId);
FFAIncreasedSpeedList.Add(killer.PlayerId, Utils.TimeStamp);
}
else
{
FFAIncreasedSpeedList.TryAdd(killer.PlayerId, Utils.TimeStamp);
originalSpeed.TryAdd(killer.PlayerId, Main.AllPlayerSpeed[killer.PlayerId]);
Main.AllPlayerSpeed[killer.PlayerId] = FFAIncreasedSpeed.GetFloat();
}
killer.Notify(GetString("FFA-Event-GetIncreasedSpeed"), FFAModifiedSpeedDuration.GetFloat());
Main.AllPlayerKillCooldown[killer.PlayerId] = FFAKcd.GetFloat();
mark = true;
break;
case 2:
Main.AllPlayerKillCooldown[killer.PlayerId] = Math.Clamp(FFAKcd.GetFloat() - 3f, 1f, 60f);
killer.Notify(GetString("FFA-Event-GetLowKCD"));
sync = true;
break;
default:
Main.AllPlayerKillCooldown[killer.PlayerId] = FFAKcd.GetFloat();
break;
killer.Notify(GetString("FFA-Event-GetIncreasedSpeed"), FFAModifiedSpeedDuration.GetFloat());
Main.AllPlayerKillCooldown[killer.PlayerId] = FFAKcd.GetFloat();
mark = true;
break;
case 2:
Main.AllPlayerKillCooldown[killer.PlayerId] = Math.Clamp(FFAKcd.GetFloat() - 3f, 1f, 60f);
killer.Notify(GetString("FFA-Event-GetLowKCD"));
sync = true;
break;
default:
Main.AllPlayerKillCooldown[killer.PlayerId] = FFAKcd.GetFloat();
break;
}
break;
}
}
else if (EffectType == 8) // De-Buff
{
byte EffectID = (byte)HashRandom.Next(0, 3);
if (Main.NormalOptions.MapId == 4) EffectID = 1;
switch (EffectID)
// De-Buff
case 8:
{
case 0:
if (FFADecreasedSpeedList.ContainsKey(killer.PlayerId))
{
FFADecreasedSpeedList.Remove(killer.PlayerId);
FFADecreasedSpeedList.Add(killer.PlayerId, Utils.TimeStamp);
}
else
{
FFADecreasedSpeedList.TryAdd(killer.PlayerId, Utils.TimeStamp);
originalSpeed.TryAdd(killer.PlayerId, Main.AllPlayerSpeed[killer.PlayerId]);
Main.AllPlayerSpeed[killer.PlayerId] = FFADecreasedSpeed.GetFloat();
}
byte EffectID = (byte)IRandom.Instance.Next(0, 3);
if (Main.NormalOptions.MapId == 4) EffectID = 1;
switch (EffectID)
{
case 0:
if (FFADecreasedSpeedList.ContainsKey(killer.PlayerId))
{
FFADecreasedSpeedList.Remove(killer.PlayerId);
FFADecreasedSpeedList.Add(killer.PlayerId, Utils.TimeStamp);
}
else
{
FFADecreasedSpeedList.TryAdd(killer.PlayerId, Utils.TimeStamp);
originalSpeed.TryAdd(killer.PlayerId, Main.AllPlayerSpeed[killer.PlayerId]);
Main.AllPlayerSpeed[killer.PlayerId] = FFADecreasedSpeed.GetFloat();
}
killer.Notify(GetString("FFA-Event-GetDecreasedSpeed"), FFAModifiedSpeedDuration.GetFloat());
Main.AllPlayerKillCooldown[killer.PlayerId] = FFAKcd.GetFloat();
mark = true;
break;
case 1:
Main.AllPlayerKillCooldown[killer.PlayerId] = Math.Clamp(FFAKcd.GetFloat() + 3f, 1f, 60f);
killer.Notify(GetString("FFA-Event-GetHighKCD"));
sync = true;
break;
case 2:
FFALowerVisionList.TryAdd(killer.PlayerId, Utils.TimeStamp);
Main.AllPlayerKillCooldown[killer.PlayerId] = FFAKcd.GetFloat();
killer.Notify(GetString("FFA-Event-GetLowVision"));
mark = true;
break;
default:
Main.AllPlayerKillCooldown[killer.PlayerId] = FFAKcd.GetFloat();
break;
killer.Notify(GetString("FFA-Event-GetDecreasedSpeed"), FFAModifiedSpeedDuration.GetFloat());
Main.AllPlayerKillCooldown[killer.PlayerId] = FFAKcd.GetFloat();
mark = true;
break;
case 1:
Main.AllPlayerKillCooldown[killer.PlayerId] = Math.Clamp(FFAKcd.GetFloat() + 3f, 1f, 60f);
killer.Notify(GetString("FFA-Event-GetHighKCD"));
sync = true;
break;
case 2:
FFALowerVisionList.TryAdd(killer.PlayerId, Utils.TimeStamp);
Main.AllPlayerKillCooldown[killer.PlayerId] = FFAKcd.GetFloat();
killer.Notify(GetString("FFA-Event-GetLowVision"));
mark = true;
break;
default:
Main.AllPlayerKillCooldown[killer.PlayerId] = FFAKcd.GetFloat();
break;
}
break;
}
}
else // Mixed
{
_ = new LateTask(() => { killer.TPtoRndVent(); }, 0.5f, "FFA-Event-TP");
killer.Notify(GetString("FFA-Event-GetTP"));
Main.AllPlayerKillCooldown[killer.PlayerId] = FFAKcd.GetFloat();
// Mixed
default:
_ = new LateTask(() => { killer.TPtoRndVent(); }, 0.5f, "FFA-Event-TP");
killer.Notify(GetString("FFA-Event-GetTP"));
Main.AllPlayerKillCooldown[killer.PlayerId] = FFAKcd.GetFloat();
break;
}
if (sync || Math.Abs(nowKCD - Main.AllPlayerKillCooldown[killer.PlayerId]) > 0.1f)
@@ -384,8 +434,7 @@ internal static class FFAManager
var rd = IRandom.Instance;
byte FFAdoTPdecider = (byte)rd.Next(0, 100);
bool FFAdoTP = false;
if (FFAdoTPdecider == 0) FFAdoTP = true;
bool FFAdoTP = FFAdoTPdecider == 0;
if (FFAEnableRandomTwists.GetBool() && FFAdoTP)
{
+5 -2
View File
@@ -3,6 +3,7 @@ using EHR.Roles.Crewmate;
using EHR.Roles.Impostor;
using EHR.Roles.Neutral;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using UnityEngine;
@@ -148,6 +149,7 @@ internal static class CustomRolesHelper
CustomRoles.Express => CustomRoles.Crewmate,
CustomRoles.NiceEraser => CustomRoles.Crewmate,
CustomRoles.TaskManager => CustomRoles.Crewmate,
CustomRoles.Adventurer => CustomRoles.Engineer,
CustomRoles.Randomizer => CustomRoles.Crewmate,
CustomRoles.Beacon => CustomRoles.Crewmate,
CustomRoles.Rabbit => CustomRoles.Crewmate,
@@ -671,14 +673,15 @@ internal static class CustomRolesHelper
_ => false,
};
public static readonly CustomRoles[] OnlySpawnsWithPetsRoleList =
public static readonly List<CustomRoles> OnlySpawnsWithPetsRoleList =
[
CustomRoles.Tunneler,
CustomRoles.Tornado,
CustomRoles.Swiftclaw,
CustomRoles.Adventurer
];
public static bool OnlySpawnsWithPets(this CustomRoles role) => OnlySpawnsWithPetsRoleList.Any(x => x.ToString() == role.ToString());
public static bool OnlySpawnsWithPets(this CustomRoles role) => OnlySpawnsWithPetsRoleList.Contains(role);
public static bool NeedUpdateOnLights(this CustomRoles role) => (!role.UsesPetInsteadOfKill()) && (role.GetDYRole() != RoleTypes.GuardianAngel || role is
CustomRoles.Convict or
+8 -5
View File
@@ -86,14 +86,17 @@ namespace EHR.Modules
{
if (CustomTeams.Count == 0 || CustomTeamPlayerIds.Count == 0) return false;
CustomTeamPlayerIds.Values.Do(x => x.RemoveWhere(p =>
CustomTeamPlayerIds.Do(x => x.Value.RemoveWhere(p =>
{
var pc = Utils.GetPlayerById(p);
return pc == null || !pc.IsAlive() || pc.Data.Disconnected;
return pc == null || pc.Data.Disconnected;
}));
var team = CustomTeamPlayerIds.Keys.First();
if (CustomTeamPlayerIds.Count == 1 && Main.AllAlivePlayerControls.All(x =>
var aliveTeamPlayers = CustomTeamPlayerIds.ToDictionary(x => x.Key, x => x.Value);
aliveTeamPlayers.Do(x => x.Value.RemoveWhere(p => !Utils.GetPlayerById(p).IsAlive()));
var team = aliveTeamPlayers.Keys.First();
if (aliveTeamPlayers.Count == 1 && Main.AllAlivePlayerControls.All(x =>
{
var customTeam = GetCustomTeam(x.PlayerId);
return customTeam != null && customTeam.Equals(team);
@@ -101,7 +104,7 @@ namespace EHR.Modules
{
WinnerTeam = team;
CustomWinnerHolder.ResetAndSetWinner(CustomWinner.CustomTeam);
CustomWinnerHolder.WinnerIds = CustomTeamPlayerIds.Values.First();
CustomWinnerHolder.WinnerIds = aliveTeamPlayers.Values.First();
return true;
}
+1 -1
View File
@@ -25,7 +25,7 @@ public static class DevManager
public static void Init()
{
// Dev
DevUserList.Add(new(code: "actorour#0029", color: "#ffc0cb", tag: "EHR/TONX Developer", isUp: true, isDev: true, deBug: true, colorCmd: true, upName: "KARPED1EM"));
DevUserList.Add(new(code: "actorour#0029", color: "#ffc0cb", tag: "TOHE/TONX Developer", isUp: true, isDev: true, deBug: true, colorCmd: true, upName: "KARPED1EM"));
DevUserList.Add(new(code: "pinklaze#1776", color: "#30548e", tag: "#Dev", isUp: true, isDev: true, deBug: true, colorCmd: false, upName: "NCSIMON"));
DevUserList.Add(new(code: "keepchirpy#6354", color: "#1FF3C6", tag: "Переводчик", isUp: true, isDev: false, deBug: false, colorCmd: true, upName: "TommyXL")); //Tommy-XL
DevUserList.Add(new(code: "taskunsold#2701", color: "null", tag: "<color=#426798>Tem</color><color=#f6e509>mie</color>", isUp: false, isDev: true, deBug: false, colorCmd: false, upName: null)); //Tem
+13 -7
View File
@@ -323,15 +323,21 @@ internal class EAC
if (amount is not 64 and not 65) goto YesCheat;
break;
case SystemTypes.Comms:
if (amount == 0)
switch (amount)
{
if (Mapid is 1 or 5) goto YesCheat;
case 0:
{
if (Mapid is 1 or 5) goto YesCheat;
break;
}
case 64 or 65 or 32 or 33 or 16 or 17:
{
if (Mapid is not (1 or 5)) goto YesCheat;
break;
}
default:
goto YesCheat;
}
else if (amount is 64 or 65 or 32 or 33 or 16 or 17)
{
if (!(Mapid is 1 or 5)) goto YesCheat;
}
else goto YesCheat;
break;
case SystemTypes.Electrical:
@@ -16,41 +16,59 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender
{
public static void SetDirty(byte playerId)
{
foreach (var sender in AllSenders.OfType<PlayerGameOptionsSender>().Where(sender => sender.player.PlayerId == playerId))
foreach (GameOptionsSender allSender in AllSenders)
{
sender.SetDirty();
if (allSender is PlayerGameOptionsSender sender && sender.player.PlayerId == playerId)
{
sender.SetDirty();
}
}
}
public static void SetDirtyToAll()
{
foreach (var sender in AllSenders.OfType<PlayerGameOptionsSender>())
foreach (GameOptionsSender allSender in AllSenders)
{
sender.SetDirty();
if (allSender is PlayerGameOptionsSender sender)
{
sender.SetDirty();
}
}
}
// For lights call/fix
public static void SetDirtyToAllV2()
{
foreach (var sender in AllSenders.OfType<PlayerGameOptionsSender>().Where(sender => !sender.IsDirty && sender.player.IsAlive() && (sender.player.GetCustomRole().NeedUpdateOnLights() || sender.player.Is(CustomRoles.Torch) || sender.player.Is(CustomRoles.Mare))))
foreach (GameOptionsSender allSender in AllSenders)
{
sender.SetDirty();
if (allSender is PlayerGameOptionsSender { IsDirty: false } sender && sender.player.IsAlive() && (sender.player.GetCustomRole().NeedUpdateOnLights() || sender.player.Is(CustomRoles.Torch) || sender.player.Is(CustomRoles.Mare)))
{
sender.SetDirty();
}
}
}
// For Grenadier blidning/restoring
public static void SetDirtyToAllV3()
{
foreach (var sender in AllSenders.OfType<PlayerGameOptionsSender>().Where(sender => !sender.IsDirty && sender.player.IsAlive() && ((Grenadier.GrenadierBlinding.Count > 0 && (sender.player.GetCustomRole().IsImpostor() || (sender.player.GetCustomRole().IsNeutral() && Options.GrenadierCanAffectNeutral.GetBool()))) || (Grenadier.MadGrenadierBlinding.Count > 0 && !sender.player.GetCustomRole().IsImpostorTeam() && !sender.player.Is(CustomRoles.Madmate)))))
foreach (GameOptionsSender allSender in AllSenders)
{
sender.SetDirty();
if (allSender is PlayerGameOptionsSender { IsDirty: false } sender && sender.player.IsAlive() && ((Grenadier.GrenadierBlinding.Count > 0 && (sender.player.GetCustomRole().IsImpostor() || (sender.player.GetCustomRole().IsNeutral() && Options.GrenadierCanAffectNeutral.GetBool()))) || (Grenadier.MadGrenadierBlinding.Count > 0 && !sender.player.GetCustomRole().IsImpostorTeam() && !sender.player.Is(CustomRoles.Madmate))))
{
sender.SetDirty();
}
}
}
// For players with kill buttons
public static void SetDirtyToAllV4()
{
foreach (var sender in AllSenders.OfType<PlayerGameOptionsSender>().Where(sender => !sender.IsDirty && sender.player.IsAlive() && sender.player.CanUseKillButton()).ToArray())
foreach (GameOptionsSender allSender in AllSenders)
{
sender.SetDirty();
if (allSender is PlayerGameOptionsSender { IsDirty: false } sender && sender.player.IsAlive() && sender.player.CanUseKillButton())
{
sender.SetDirty();
}
}
}
@@ -324,6 +342,13 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender
opt.SetFloat(FloatOptionNames.ImpostorLightMod, 0);
}
if (player.IsCrewmate() && Main.PlayerStates.Values.Any(s => s.Role is Adventurer { IsEnable: true } av && av.ActiveWeapons.Contains(Adventurer.Weapon.Lantern)))
{
opt.SetVision(true);
opt.SetFloat(FloatOptionNames.CrewLightMod, 1.5f);
opt.SetFloat(FloatOptionNames.ImpostorLightMod, 1.5f);
}
if (Changeling.ChangedRole.TryGetValue(player.PlayerId, out var changed) && changed && player.GetRoleTypes() != RoleTypes.Shapeshifter)
{
AURoleOptions.ShapeshifterCooldown = 300f;
+13 -20
View File
@@ -106,24 +106,18 @@ public static class GuessManager
return true;
}
if (!pc.Is(CustomRoles.NiceGuesser))
if (!pc.Is(CustomRoles.NiceGuesser) && pc.IsCrewmate() && !Options.CrewmatesCanGuess.GetBool() && !pc.Is(CustomRoles.Guesser) && !pc.Is(CustomRoles.Judge) && !pc.Is(CustomRoles.NiceSwapper))
{
if (pc.IsCrewmate() && !Options.CrewmatesCanGuess.GetBool() && !pc.Is(CustomRoles.Guesser) && !pc.Is(CustomRoles.Judge) && !pc.Is(CustomRoles.NiceSwapper))
{
if (!isUI) Utils.SendMessage(GetString("GuessNotAllowed"), pc.PlayerId);
else pc.ShowPopUp(GetString("GuessNotAllowed"));
return true;
}
if (!isUI) Utils.SendMessage(GetString("GuessNotAllowed"), pc.PlayerId);
else pc.ShowPopUp(GetString("GuessNotAllowed"));
return true;
}
if (!pc.Is(CustomRoles.EvilGuesser))
if (!pc.Is(CustomRoles.EvilGuesser) && pc.GetCustomRole().IsImpostor() && !Options.ImpostorsCanGuess.GetBool() && !pc.Is(CustomRoles.Guesser) && !pc.Is(CustomRoles.Councillor))
{
if (pc.GetCustomRole().IsImpostor() && !Options.ImpostorsCanGuess.GetBool() && !pc.Is(CustomRoles.Guesser) && !pc.Is(CustomRoles.Councillor))
{
if (!isUI) Utils.SendMessage(GetString("GuessNotAllowed"), pc.PlayerId);
else pc.ShowPopUp(GetString("GuessNotAllowed"));
return true;
}
if (!isUI) Utils.SendMessage(GetString("GuessNotAllowed"), pc.PlayerId);
else pc.ShowPopUp(GetString("GuessNotAllowed"));
return true;
}
if (pc.IsNeutralKiller() && !Options.NeutralKillersCanGuess.GetBool() && !pc.Is(CustomRoles.Guesser))
@@ -147,12 +141,11 @@ public static class GuessManager
return true;
case 2:
{
if (
(pc.Is(CustomRoles.NiceGuesser) && Options.GGTryHideMsg.GetBool()) ||
if ((pc.Is(CustomRoles.NiceGuesser) && Options.GGTryHideMsg.GetBool()) ||
(pc.Is(CustomRoles.EvilGuesser) && Options.EGTryHideMsg.GetBool()) ||
(pc.Is(CustomRoles.Doomsayer) && Doomsayer.DoomsayerTryHideMsg.GetBool()) ||
(pc.Is(CustomRoles.Guesser) && Options.GTryHideMsg.GetBool()) || (Options.GuesserMode.GetBool() && Options.HideGuesserCommands.GetBool())
) /*TryHideMsg();*/ ChatManager.SendPreviousMessagesToAll();
(pc.Is(CustomRoles.Guesser) && Options.GTryHideMsg.GetBool()) || (Options.GuesserMode.GetBool() && Options.HideGuesserCommands.GetBool()))
ChatManager.SendPreviousMessagesToAll();
else if (pc.AmOwner && !isUI) Utils.SendMessage(originMsg, 255, pc.GetRealName());
if (!MsgToPlayerAndRole(msg, out byte targetId, out CustomRoles role, out string error))
@@ -960,7 +953,7 @@ public static class GuessManager
CustomRoleTypes.Impostor => new(255, 25, 25, byte.MaxValue),
CustomRoleTypes.Neutral => new(255, 171, 27, byte.MaxValue),
CustomRoleTypes.Addon => new Color32(255, 154, 206, byte.MaxValue),
_ => throw new NotImplementedException(),
_ => throw new NotImplementedException()
};
Logger.Info(Teamlabel.color.ToString(), ((CustomRoleTypes)index).ToString());
Teamlabel.text = GetString("Type" + ((CustomRoleTypes)index));
@@ -1026,7 +1019,7 @@ public static class GuessManager
Pagelabel.transform.localScale *= 1.6f;
Pagelabel.autoSizeTextContainer = true;
if (!IsNext && Page <= 1) Pagebutton.GetComponent<SpriteRenderer>().color = new(1, 1, 1, 0.1f);
Pagebutton.GetComponent<PassiveButton>().OnClick.AddListener((Action)(() => ClickEvent()));
Pagebutton.GetComponent<PassiveButton>().OnClick.AddListener((Action)(ClickEvent));
PageButtons.Add(Pagebutton.GetComponent<SpriteRenderer>());
return;
+1 -6
View File
@@ -83,12 +83,7 @@ static class LocateArrow
/// <returns></returns>
public static string GetArrows(PlayerControl seer)
{
var arrows = string.Empty;
foreach (var arrowInfo in LocateArrows.Keys.Where(ai => ai.From == seer.PlayerId))
{
arrows += LocateArrows[arrowInfo];
}
return arrows;
return LocateArrows.Keys.Where(ai => ai.From == seer.PlayerId).Aggregate(string.Empty, (current, arrowInfo) => current + LocateArrows[arrowInfo]);
}
/// <summary>
/// Check target arrow every FixedUpdate
+4
View File
@@ -39,6 +39,10 @@ public static class NameColorManager
switch (Options.CurrentGameMode)
{
case CustomGameMode.FFA when FFAManager.FFATeamMode.GetBool():
if (FFAManager.PlayerTeams[seer.PlayerId] == FFAManager.PlayerTeams[target.PlayerId])
color = FFAManager.TeamColors[FFAManager.PlayerTeams[seer.PlayerId]];
return true;
case CustomGameMode.MoveAndStop:
color = "#ffffff";
return true;
+13 -14
View File
@@ -929,7 +929,6 @@ public static class Options
public static OptionItem MinWaitAutoStart;
public static OptionItem MaxWaitAutoStart;
public static OptionItem PlayerAutoStart;
//public static OptionItem SidekickCountMode;
public static OptionItem DumpLogAfterGameEnd;
@@ -1185,21 +1184,21 @@ public static class Options
var tab = roleClasses.Key.GetTabFromOptionType();
var categorySuffix = roleClasses.Key switch
{
RoleOptionType.Neutral_Killing => "NK",
RoleOptionType.Neutral_NonKilling => "NNK",
_ => string.Empty
};
TextOptionItem.Create(titleId, $"ROT.Basic{categorySuffix}", tab)
.SetGameMode(CustomGameMode.Standard)
.SetColor(Color.gray)
.SetHeader(true);
titleId += 10;
var key = roleClasses.Key.GetSimpleRoleOptionType();
if (simpleRoleClasses.TryGetValue(key, out ISettingHolder[] value))
if (simpleRoleClasses.TryGetValue(key, out ISettingHolder[] value) && value.Length > 0)
{
var categorySuffix = roleClasses.Key switch
{
RoleOptionType.Neutral_Killing => "NK",
RoleOptionType.Neutral_NonKilling => "NNK",
_ => string.Empty
};
TextOptionItem.Create(titleId, $"ROT.Basic{categorySuffix}", tab)
.SetGameMode(CustomGameMode.Standard)
.SetColor(Color.gray)
.SetHeader(true);
titleId += 10;
foreach (ISettingHolder holder in value)
{
holder.SetupCustomOption();
+31 -20
View File
@@ -42,9 +42,9 @@ other: ∟ ⌠ ⌡ ╬ ╨ ▓ ▒ ░ « » █ ▄ ▌▀▐│ ┤ ╡ ╢
public static class Utils
{
private static readonly DateTime timeStampStartTime = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static long GetTimeStamp(DateTime? dateTime = null) => (long)((dateTime ?? DateTime.Now).ToUniversalTime() - timeStampStartTime).TotalSeconds;
public static long TimeStamp => GetTimeStamp();
private static readonly DateTime TimeStampStartTime = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static long GetTimeStamp(DateTime? dateTime = null) => (long)((dateTime ?? DateTime.Now).ToUniversalTime() - TimeStampStartTime).TotalSeconds;
public static long TimeStamp => (long)(DateTime.Now.ToUniversalTime() - TimeStampStartTime).TotalSeconds;
public static void ErrorEnd(string text)
{
@@ -704,6 +704,7 @@ public static class Utils
__instance.Is(CustomRoleTypes.Impostor) && PlayerControl.LocalPlayer.Is(CustomRoleTypes.Impostor) && Options.ImpKnowAlliesRole.GetBool() ||
__instance.Is(CustomRoleTypes.Impostor) && PlayerControl.LocalPlayer.Is(CustomRoles.Madmate) && Options.MadmateKnowWhosImp.GetBool() ||
CustomTeamManager.AreInSameCustomTeam(__instance.PlayerId, PlayerControl.LocalPlayer.PlayerId) ||
Adventurer.KnowRole(PlayerControl.LocalPlayer, __instance) ||
Totocalcio.KnowRole(PlayerControl.LocalPlayer, __instance) ||
Romantic.KnowRole(PlayerControl.LocalPlayer, __instance) ||
Lawyer.KnowRole(PlayerControl.LocalPlayer, __instance) ||
@@ -716,7 +717,6 @@ public static class Utils
PlayerControl.LocalPlayer.IsRevealedPlayer(__instance) ||
PlayerControl.LocalPlayer.Is(CustomRoles.God) ||
PlayerControl.LocalPlayer.Is(CustomRoles.GM) ||
Totocalcio.KnowRole(PlayerControl.LocalPlayer, __instance) ||
Lawyer.KnowRole(PlayerControl.LocalPlayer, __instance) ||
EvilDiviner.IsShowTargetRole(PlayerControl.LocalPlayer, __instance) ||
Executioner.KnowRole(PlayerControl.LocalPlayer, __instance) ||
@@ -1786,6 +1786,8 @@ public static class Utils
if (Options.CurrentGameMode != CustomGameMode.Standard) goto GameMode;
SelfSuffix.Append(Adventurer.GetSuffixAndHUDText(seer, isForMeeting: isForMeeting));
if (!isForMeeting)
{
if (Options.UsePets.GetBool() && Main.AbilityCD.TryGetValue(seer.PlayerId, out var time) && !seer.IsModClient())
@@ -2028,13 +2030,15 @@ public static class Utils
seer.RpcSetNamePrivate(SelfName, true, force: NoCache);
// Run the second loop only when necessary, such as when seer is dead
if (seer.Data.IsDead || !seer.IsAlive() || NoCache || CamouflageIsForMeeting || MushroomMixup || IsActive(SystemTypes.MushroomMixupSabotage) || ForceLoop || seerList.Length == 1 || targetList.Length == 1)
if (GameStates.IsLobby || seer.Data.IsDead || !seer.IsAlive() || NoCache || CamouflageIsForMeeting || MushroomMixup || IsActive(SystemTypes.MushroomMixupSabotage) || ForceLoop || seerList.Length == 1 || targetList.Length == 1)
{
foreach (PlayerControl target in targetList)
{
if (target.PlayerId == seer.PlayerId) continue;
Logger.Info($"NotifyRoles-Loop2-{target.GetNameWithRole().RemoveHtmlTags()}:START", "NotifyRoles");
ApplySuffix(target);
if ((IsActive(SystemTypes.MushroomMixupSabotage) || MushroomMixup) && target.IsAlive() && !seer.Is(CustomRoleTypes.Impostor) && Main.ResetCamPlayerList.Contains(seer.PlayerId))
{
seer.RpcSetNamePrivate("<size=0%>", true, force: NoCache);
@@ -2138,6 +2142,7 @@ public static class Utils
(seer.Is(CustomRoleTypes.Crewmate) && target.Is(CustomRoles.Marshall) && target.GetTaskState().IsTaskFinished) ||
(Main.PlayerStates[target.PlayerId].deathReason == PlayerState.DeathReason.Vote && Options.SeeEjectedRolesInMeeting.GetBool()) ||
CustomTeamManager.AreInSameCustomTeam(seer.PlayerId, target.PlayerId) ||
Adventurer.KnowRole(seer, target) ||
Totocalcio.KnowRole(seer, target) ||
Romantic.KnowRole(seer, target) ||
Lawyer.KnowRole(seer, target) ||
@@ -2412,25 +2417,30 @@ public static class Utils
public static void AfterMeetingTasks()
{
foreach (var pc in Main.AllAlivePlayerControls)
foreach (var pc in Main.AllPlayerControls)
{
pc.AddKillTimerToDict();
if (pc.Is(CustomRoles.Truant))
if (pc.IsAlive())
{
float beforeSpeed = Main.AllPlayerSpeed[pc.PlayerId];
Main.AllPlayerSpeed[pc.PlayerId] = Main.MinSpeed;
pc.MarkDirtySettings();
_ = new LateTask(() =>
{
Main.AllPlayerSpeed[pc.PlayerId] = beforeSpeed;
pc.MarkDirtySettings();
}, Options.TruantWaitingTime.GetFloat(), $"Truant Waiting: {pc.GetNameWithRole()}");
pc.AddKillTimerToDict();
if (pc.Is(CustomRoles.Truant))
{
float beforeSpeed = Main.AllPlayerSpeed[pc.PlayerId];
Main.AllPlayerSpeed[pc.PlayerId] = Main.MinSpeed;
pc.MarkDirtySettings();
_ = new LateTask(() =>
{
Main.AllPlayerSpeed[pc.PlayerId] = beforeSpeed;
pc.MarkDirtySettings();
}, Options.TruantWaitingTime.GetFloat(), $"Truant Waiting: {pc.GetNameWithRole()}");
}
if (Options.UsePets.GetBool()) pc.AddAbilityCD(includeDuration: false);
Main.PlayerStates[pc.PlayerId].Role.AfterMeetingTasks();
}
if (Options.UsePets.GetBool()) pc.AddAbilityCD(includeDuration: false);
Main.PlayerStates[pc.PlayerId].Role.AfterMeetingTasks();
if (pc.Is(CustomRoles.Specter) || pc.Is(CustomRoles.Haunter)) pc.RpcResetAbilityCooldown();
}
CopyCat.ResetRole();
@@ -2555,6 +2565,7 @@ public static class Utils
Tracefinder.OnPlayerDead(target);
Vulture.OnPlayerDead(target);
Tracker.OnPlayerDeath(target);
Adventurer.OnAnyoneDead(target);
FixedUpdatePatch.LoversSuicide(target.PlayerId, onMeeting);
}
+4 -5
View File
@@ -353,7 +353,7 @@ internal class ChatCommands
settings.Append("</size>");
var txt = sb.ToString();
_ = sb.Clear().Append(txt.RemoveHtmlTags());
if (role.PetActivatedAbility()) sb.Append("<size=50%>" + GetString("SupportsPetMessage").RemoveHtmlTags() + "</size>");
if (role.PetActivatedAbility() && sb.Length < 1000) sb.Append("<size=50%>" + GetString("SupportsPetMessage").RemoveHtmlTags() + "</size>");
sb.Append("<size=70%>");
foreach (CustomRoles subRole in Main.PlayerStates[localPlayerId].SubRoles.ToArray())
{
@@ -939,7 +939,7 @@ internal class ChatCommands
_ = sb.Clear().Append(txt);
}
if (rl.PetActivatedAbility()) sb.Append($"<size=50%>{GetString("SupportsPetMessage")}</size>");
if (rl.PetActivatedAbility() && sb.Length < 1000) sb.Append($"<size=50%>{GetString("SupportsPetMessage")}</size>");
Utils.SendMessage(text: "\n", sendTo: playerId, title: settings.ToString());
Utils.SendMessage(text: sb.ToString(), sendTo: playerId, title: title);
return;
@@ -968,8 +968,7 @@ internal class ChatCommands
if (GuessManager.GuesserMsg(player, text))
{
if (GuessManager.GuesserMsg(player, text) ||
Judge.TrialMsg(player, text) ||
if (Judge.TrialMsg(player, text) ||
NiceSwapper.SwapMsg(player, text) ||
ParityCop.ParityCheckMsg(player, text) ||
Councillor.MurderMsg(player, text))
@@ -1045,7 +1044,7 @@ internal class ChatCommands
settings.Append("</size>");
var txt = sb.ToString();
_ = sb.Clear().Append(txt.RemoveHtmlTags());
if (role.PetActivatedAbility()) sb.Append("<size=50%>" + GetString("SupportsPetMessage").RemoveHtmlTags() + "</size>");
if (role.PetActivatedAbility() && sb.Length < 1000) sb.Append("<size=50%>" + GetString("SupportsPetMessage").RemoveHtmlTags() + "</size>");
sb.Append("<size=70%>");
foreach (CustomRoles subRole in Main.PlayerStates[player.PlayerId].SubRoles.ToArray())
{
+19 -5
View File
@@ -515,21 +515,35 @@ class GameEndChecker
Logger.Warn($"Winner: {winner.GetRealName().RemoveHtmlTags()}", "FFA");
WinnerIds =
[
winnerId
];
WinnerIds = [winnerId];
Main.DoBlockNameChange = true;
return true;
}
if (FFAManager.FFATeamMode.GetBool())
{
var teams = FFAManager.PlayerTeams.GroupBy(x => x.Value, x => x.Key).Select(x => x.Where(p =>
{
var pc = GetPlayerById(p);
return pc != null && !pc.Data.Disconnected && pc.IsAlive();
}).ToHashSet()).Where(x => x.Count > 0).ToArray();
if (teams.Length == 1)
{
WinnerIds = teams[0];
Main.DoBlockNameChange = true;
return true;
}
}
switch (Main.AllAlivePlayerControls.Length)
{
case 1:
{
var winner = Main.AllAlivePlayerControls.First();
var winner = Main.AllAlivePlayerControls[0];
Logger.Info($"Winner: {winner.GetRealName().RemoveHtmlTags()}", "FFA");
+2 -1
View File
@@ -377,6 +377,7 @@ class HudManagerPatch
CustomRoles.Swooper or CustomRoles.Wraith or CustomRoles.Chameleon => Swooper.GetHudText(player),
CustomRoles.HeadHunter => HeadHunter.GetHudText(player),
CustomRoles.Alchemist => Alchemist.GetHudText(player),
CustomRoles.Adventurer => Adventurer.GetSuffixAndHUDText(player, hud: true),
CustomRoles.Werewolf => Werewolf.GetHudText(player),
CustomRoles.Glitch => Glitch.GetHudText(player),
CustomRoles.NiceHacker => NiceHacker.GetHudText(player),
@@ -773,7 +774,7 @@ class TaskPanelBehaviourPatch
List<(int, byte)> list3 = [];
foreach (var id in Main.PlayerStates.Keys) list3.Add((MoveAndStopManager.GetRankOfScore(id), id));
list3.Sort();
list3 = [.. list3.OrderBy(x => Utils.GetPlayerById(x.Item2).IsAlive())];
list3 = [.. list3.OrderBy(x => !Utils.GetPlayerById(x.Item2).IsAlive())];
foreach (var id in list3.Where(x => SummaryText3.ContainsKey(x.Item2)).ToArray())
{
bool alive = Utils.GetPlayerById(id.Item2).IsAlive();
+23 -1
View File
@@ -182,6 +182,7 @@ class BeginCrewmatePatch
var team = CustomTeamManager.GetCustomTeam(PlayerControl.LocalPlayer.PlayerId);
if (team != null)
{
teamToDisplay = new();
foreach (var pc in Main.AllPlayerControls)
{
if (CustomTeamManager.AreInSameCustomTeam(pc.PlayerId, PlayerControl.LocalPlayer.PlayerId))
@@ -192,6 +193,18 @@ class BeginCrewmatePatch
}
}
if (Options.CurrentGameMode == CustomGameMode.FFA && FFAManager.FFATeamMode.GetBool() && FFAManager.PlayerTeams.TryGetValue(PlayerControl.LocalPlayer.PlayerId, out var ffaTeam))
{
teamToDisplay = new();
foreach (var pc in Main.AllPlayerControls)
{
if (FFAManager.PlayerTeams.TryGetValue(pc.PlayerId, out var team) && team == ffaTeam)
{
teamToDisplay.Add(pc);
}
}
}
return true;
}
@@ -441,33 +454,42 @@ class BeginCrewmatePatch
break;
}
case CustomGameMode.FFA:
{
__instance.TeamTitle.text = GetString("Killer");
__instance.TeamTitle.color = __instance.BackgroundBar.material.color = new Color32(0, 255, 255, byte.MaxValue);
var color = FFAManager.PlayerTeams.TryGetValue(PlayerControl.LocalPlayer.PlayerId, out var team) && ColorUtility.TryParseHtmlString(FFAManager.TeamColors[team], out var teamColor) ? teamColor : new(0, 255, 255, byte.MaxValue);
__instance.TeamTitle.color = __instance.BackgroundBar.material.color = color;
PlayerControl.LocalPlayer.Data.Role.IntroSound = GetIntroSound(RoleTypes.Shapeshifter);
__instance.ImpostorText.gameObject.SetActive(true);
__instance.ImpostorText.text = GetString("KillerInfo");
break;
}
case CustomGameMode.MoveAndStop:
{
__instance.TeamTitle.text = GetString("MoveAndStop");
__instance.TeamTitle.color = __instance.BackgroundBar.material.color = new Color32(0, 255, 160, byte.MaxValue);
PlayerControl.LocalPlayer.Data.Role.IntroSound = GetIntroSound(RoleTypes.Shapeshifter);
__instance.ImpostorText.gameObject.SetActive(true);
__instance.ImpostorText.text = GetString("TaskerInfo");
break;
}
case CustomGameMode.HotPotato:
{
__instance.TeamTitle.text = GetString("HotPotato");
__instance.TeamTitle.color = __instance.BackgroundBar.material.color = new Color32(232, 205, 70, byte.MaxValue);
PlayerControl.LocalPlayer.Data.Role.IntroSound = GetIntroSound(RoleTypes.Shapeshifter);
__instance.ImpostorText.gameObject.SetActive(true);
__instance.ImpostorText.text = GetString("PotatoInfo");
break;
}
case CustomGameMode.HideAndSeek:
{
__instance.TeamTitle.text = GetString("HideAndSeek");
__instance.TeamTitle.color = __instance.BackgroundBar.material.color = new Color32(52, 94, 235, byte.MaxValue);
PlayerControl.LocalPlayer.Data.Role.IntroSound = GetIntroSound(RoleTypes.Impostor);
__instance.ImpostorText.gameObject.SetActive(true);
__instance.ImpostorText.text = GetString("SubText.HideAndSeek");
break;
}
}
if (Input.GetKey(KeyCode.RightShift))
+25 -7
View File
@@ -121,7 +121,7 @@ class CheckForEndVotingPatch
}
}
if (__instance.playerStates.TakeWhile(_ => !shouldSkip).Any(ps => !(Main.PlayerStates[ps.TargetPlayerId].IsDead || ps.DidVote)))
if (!shouldSkip && !__instance.playerStates.All(ps => Main.PlayerStates[ps.TargetPlayerId].IsDead || ps.DidVote || Utils.GetPlayerById(ps.TargetPlayerId).Data.Disconnected))
{
return false;
}
@@ -132,7 +132,7 @@ class CheckForEndVotingPatch
foreach (var ps in __instance.playerStates)
{
if (ps == null) continue;
voteLog.Info($"{ps.TargetPlayerId,-2}{$"({Utils.GetVoteName(ps.TargetPlayerId)})".PadRightV2(40)}:{ps.VotedFor,-3}{$"({Utils.GetVoteName(ps.VotedFor)})"}");
voteLog.Info($"{ps.TargetPlayerId,-2}{$"({Utils.GetVoteName(ps.TargetPlayerId)})".PadRightV2(40)}:{ps.VotedFor,-3}({Utils.GetVoteName(ps.VotedFor)})");
var voter = Utils.GetPlayerById(ps.TargetPlayerId);
if (voter == null || voter.Data == null || voter.Data.Disconnected) continue;
if (Options.VoteMode.GetBool())
@@ -195,9 +195,6 @@ class CheckForEndVotingPatch
VotedForId = ps.VotedFor
});
Blackmailer.OnCheckForEndVoting();
NiceSwapper.OnCheckForEndVoting();
if (CheckRole(ps.TargetPlayerId, CustomRoles.Mayor) && !Mayor.MayorHideVote.GetBool()) //Mayorの投票数
{
for (var i2 = 0; i2 < Mayor.MayorAdditionalVote.GetFloat(); i2++)
@@ -221,8 +218,20 @@ class CheckForEndVotingPatch
});
}
}
if (Main.PlayerStates[ps.TargetPlayerId].Role is Adventurer { IsEnable: true } av && av.ActiveWeapons.Contains(Adventurer.Weapon.Proxy))
{
statesList.Add(new()
{
VoterId = ps.TargetPlayerId,
VotedForId = ps.VotedFor
});
}
}
Blackmailer.OnCheckForEndVoting();
NiceSwapper.OnCheckForEndVoting();
states = [.. statesList];
var VotingData = __instance.CustomCalculateVotes();
@@ -387,7 +396,10 @@ class CheckForEndVotingPatch
if (Options.ShowTeamNextToRoleNameOnEject.GetBool())
{
name += " (";
if (player.GetCustomRole().IsImpostor() || player.Is(CustomRoles.Madmate))
var team = CustomTeamManager.GetCustomTeam(player.PlayerId);
if (team != null)
name += Utils.ColorString(team.RoleRevealScreenBackgroundColor == "*" || !ColorUtility.TryParseHtmlString(team.RoleRevealScreenBackgroundColor, out var color) ? Color.yellow : color, team.RoleRevealScreenTitle == "*" ? team.TeamName : team.RoleRevealScreenTitle);
else if (player.GetCustomRole().IsImpostor() || player.Is(CustomRoles.Madmate))
name += Utils.ColorString(new(255, 25, 25, byte.MaxValue), GetString("TeamImpostor"));
else if (player.GetCustomRole().IsNeutral() || player.Is(CustomRoles.Charmed))
name += Utils.ColorString(new(255, 171, 27, byte.MaxValue), GetString("TeamNeutral"));
@@ -584,6 +596,11 @@ static class ExtendedMeetingHud
) VoteNum += VoteNum;
}
if (Main.PlayerStates[ps.TargetPlayerId].Role is Adventurer { IsEnable: true } av && av.ActiveWeapons.Contains(Adventurer.Weapon.Proxy))
{
VoteNum++;
}
if (CheckForEndVotingPatch.CheckRole(ps.TargetPlayerId, CustomRoles.TicketsStealer))
{
var ps1 = ps;
@@ -654,7 +671,7 @@ class MeetingHudStartPatch
AddMsg(string.Format(GetString("WorkaholicAdviceAlive"), string.Join(separator, workaholicAliveList)), 255, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Workaholic), GetString("WorkaholicAliveTitle")));
}
//Bait Notify
// Bait Notify
if (MeetingStates.FirstMeeting && CustomRoles.Bait.RoleExist() && Options.BaitNotification.GetBool())
{
foreach (var pc in Main.AllAlivePlayerControls.Where(x => x.Is(CustomRoles.Bait)).ToArray())
@@ -780,6 +797,7 @@ class MeetingHudStartPatch
(pc.Is(CustomRoles.Marshall) && PlayerControl.LocalPlayer.Is(CustomRoleTypes.Crewmate) && pc.GetTaskState().IsTaskFinished) ||
(Main.PlayerStates[pc.PlayerId].deathReason == PlayerState.DeathReason.Vote && Options.SeeEjectedRolesInMeeting.GetBool()) ||
CustomTeamManager.AreInSameCustomTeam(pc.PlayerId, PlayerControl.LocalPlayer.PlayerId) ||
Adventurer.KnowRole(PlayerControl.LocalPlayer, pc) ||
Totocalcio.KnowRole(PlayerControl.LocalPlayer, pc) ||
Romantic.KnowRole(PlayerControl.LocalPlayer, pc) ||
EvilDiviner.IsShowTargetRole(PlayerControl.LocalPlayer, pc) ||
+1 -1
View File
@@ -231,7 +231,7 @@ class SetEverythingUpPatch
{
var winnerId = CustomWinnerHolder.WinnerIds.FirstOrDefault();
__instance.BackgroundBar.material.color = new Color32(0, 255, 255, 255);
WinnerText.text = Main.AllPlayerNames[winnerId] + " wins!";
WinnerText.text = FFAManager.FFATeamMode.GetBool() ? string.Empty : Main.AllPlayerNames[winnerId] + " wins!";
WinnerText.color = Main.PlayerColors[winnerId];
goto EndOfText;
}
+13 -17
View File
@@ -330,6 +330,8 @@ class CheckMurderPatch
if (Penguin.IsVictim(killer)) return false;
if (!Adventurer.OnAnyoneCheckMurder(target)) return false;
if (killer.Is(CustomRoles.Refugee) && target.Is(CustomRoleTypes.Impostor)) return false;
if (SoulHunter.IsSoulHunterTarget(killer.PlayerId) && target.Is(CustomRoles.SoulHunter))
@@ -660,7 +662,7 @@ class ShapeshiftPatch
if (Main.CheckShapeshift.TryGetValue(shapeshifter.PlayerId, out var last) && last == shapeshifting)
{
// Dunno how you would get here but ok
// Don't know how you would get here but ok
return true;
}
@@ -720,6 +722,11 @@ class ShapeshiftPatch
{
pc.Notify(shapeshifting ? GetString("ShiftguardNotifySS") : "ShiftguardNotifyUnshift");
}
if (Main.PlayerStates[pc.PlayerId].Role is Adventurer { IsEnable: true } av)
{
Adventurer.OnAnyoneShapeshiftLoop(av, __instance);
}
}
}
}
@@ -1261,6 +1268,8 @@ class FixedUpdatePatch
var seer = PlayerControl.LocalPlayer;
var target = __instance;
bool self = seer.PlayerId == target.PlayerId;
Mark.Clear();
Suffix.Clear();
@@ -1320,8 +1329,6 @@ class FixedUpdatePatch
break;
}
bool self = seer.PlayerId == target.PlayerId;
switch (seer.GetCustomRole())
{
case CustomRoles.Lookout:
@@ -1554,20 +1561,9 @@ class FixedUpdatePatch
offset += 0.15f;
}
if (!seer.IsAlive())
{
offset += 0.1f;
}
if (isProgressTextLong)
{
offset += 0.3f;
}
if (Options.CurrentGameMode == CustomGameMode.MoveAndStop)
{
offset += 0.2f;
}
if (!seer.IsAlive()) offset += 0.1f;
if (isProgressTextLong) offset += 0.3f;
if (Options.CurrentGameMode == CustomGameMode.MoveAndStop) offset += 0.2f;
RoleText.transform.SetLocalY(offset);
}
+12 -5
View File
@@ -71,7 +71,7 @@ class RepairSystemPatch
if (RepairSender.enabled && AmongUsClient.Instance.NetworkMode != NetworkModes.OnlineGame)
Logger.SendInGame("SystemType: " + systemType + ", PlayerName: " + player.GetNameWithRole().RemoveHtmlTags() + ", amount: " + amount);
if (!AmongUsClient.Instance.AmHost) return true; //Execute the following only on the host
if (!AmongUsClient.Instance.AmHost) return true; // Execute the following only on the host
IsComms = PlayerControl.LocalPlayer.myTasks.ToArray().Any(x => x.TaskType == TaskTypes.FixComms);
@@ -79,7 +79,7 @@ class RepairSystemPatch
if (Options.DisableSabotage.GetBool() && systemType == SystemTypes.Sabotage) return false;
//Note: "SystemTypes.Laboratory" сauses bugs in the Host, it is better not to use
// Note: "SystemTypes.Laboratory" сauses bugs in the Host, it is better not to use
if (player.Is(CustomRoles.Fool) &&
(systemType is
SystemTypes.Comms or
@@ -168,20 +168,27 @@ class RepairSystemPatch
var SwitchSystem = ShipStatus.Instance?.Systems?[SystemTypes.Electrical]?.Cast<SwitchSystem>();
if (SwitchSystem is { IsActive: true })
{
switch (player.GetCustomRole())
switch (Main.PlayerStates[player.PlayerId].Role)
{
case CustomRoles.SabotageMaster:
case SabotageMaster:
Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()} instant-fix-lights", "SwitchSystem");
SabotageMaster.SwitchSystemRepair(player.PlayerId, SwitchSystem, amount);
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
break;
case CustomRoles.Alchemist when Main.PlayerStates[player.PlayerId].Role is Alchemist { FixNextSabo: true } am:
case Alchemist { FixNextSabo: true } am:
Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()} instant-fix-lights", "SwitchSystem");
SwitchSystem.ActualSwitches = 0;
SwitchSystem.ExpectedSwitches = 0;
am.FixNextSabo = false;
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
break;
case Adventurer av:
Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()} instant-fix-lights", "SwitchSystem");
SwitchSystem.ActualSwitches = 0;
SwitchSystem.ExpectedSwitches = 0;
av.OnLightsFix();
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
break;
}
if (player.Is(CustomRoles.Damocles) && Damocles.countRepairSabotage) Damocles.OnRepairSabotage(player.PlayerId);
+38 -2
View File
@@ -3106,6 +3106,40 @@
"CandleLighterEndVision": "End Vision (Smallest Vision)",
"CandleLighterTimeMoveMeeting": "Time Moves During Meetings",
"CandleLighterTasksFinishedVision": "Vision after completing all tasks",
"AprilFoolsMode": "April Fools Mode",
"SilenceMode": "Silencing Method",
"Adventurer": "Adventurer",
"AdventurerInfo": "Collect Resources to Perform Actions",
"AdventurerInfoLong": "(Crewmates):\\nAs the Adventurer, you can collect resources listed below and craft them into weapons if you have the required amount of materials for it.<size=70%>\\n\\n<u><b>Resources (and how to obtain them):</b></u>\\n- ❖ (Complete a Task)\\n- Θ (Players Leave This Behind<sup>*</sup>)\\n- ♳ (Dead Bodies<sup>*</sup>)\\n- ⁂ (Shapeshift Skins<sup>*</sup>)\\n- \u2600 (Fix Lights)\\n- ○ (Found in Groups<sup>*</sup>)\\n<size=50%><sup>*</sup> When this resource is available somewhere, you get an arrow pointing towards that location. (Except dead bodies.) Go there to collect it.</size>\\n\\n<u><b>Weapons (and their ingredients):</b></u>\\n- Gun (1 ♳ + 1 ❖) (Kill someone (pet near them))\\n- Shield (3 ❖) (Gives someone a 1-time shield)\\n- Lantern (1 \u2600 + 1 ❖) (Increases crewmates' vision for some time)\\n- Portal (2 Θ) (Swaps you with a random player)\\n- Wrench (1 \u2600 + 2 ❖) (Clears the current sabotage)\\n- Proxy (2 ○ + 1 ❖) (Gives you +1 vote in the next meeting)\\n- Prediction (1 ♳ + 2 ⁂ + 1 ❖) (Reveals the nearest player's role)\\n- RNG (2 Θ + 2 ❖) (Makes a random weapon)</size>",
"AdventurerWeaponDescription.Gun": "Kill the next player you go near",
"AdventurerWeaponDescription.Shield": "Gives someone a 1-time shield",
"AdventurerWeaponDescription.Lantern": "Increases crewmates' vision for some time",
"AdventurerWeaponDescription.Portal": "Swaps you with a random player",
"AdventurerWeaponDescription.Wrench": "Clears the current sabotage",
"AdventurerWeaponDescription.Proxy": "Gives you +1 vote in the next meeting",
"AdventurerWeaponDescription.Prediction": "Reveals the nearest player's role",
"AdventurerWeaponDescription.RNG": "Makes a random weapon",
"AdventurerIncreasedVisionDuration": "Increased Vision Duration",
"AdventurerWeaponEnabled.Gun": "Gun Enabled",
"AdventurerWeaponEnabled.Shield": "Healthy Dose Enabled",
"AdventurerWeaponEnabled.Lantern": "Lantern Enabled",
"AdventurerWeaponEnabled.Portal": "Portal Enabled",
"AdventurerWeaponEnabled.Wrench": "Wrench Enabled",
"AdventurerWeaponEnabled.Proxy": "Proxy Enabled",
"AdventurerWeaponEnabled.Prediction": "Prediction Enabled",
"AdventurerWeaponEnabled.RNG": "RNG Enabled",
"AdventurerVentToEnterCrafting": "Vent to Enter Crafting Menu",
"AdventurerIngredientsDisplay": "{0}: {1}\\nVent to craft this weapon / Pet to cycle to next weapon",
"AdventurerWeaponCrafted": "Crafted Weapon: {0}",
"AdventurerFound": "Found Resource: {0}",
"AdventurerGun.Gun": "Gun",
"AdventurerGun.Shield": "Shield",
"AdventurerGun.Lantern": "Lantern",
"AdventurerGun.Portal": "Portal",
"AdventurerGun.Wrench": "Wrench",
"AdventurerGun.Proxy": "Proxy",
"AdventurerGun.Prediction": "Prediction",
"AdventurerGun.RNG": "RNG",
"Imitator": "Imitator",
"ImitatorInfo": "Your kill cooldown shifts",
"ImitatorInfoLong": "(Neutral):\\nAs the Imitator, your kill cooldown is different after every even numbered kill and every odd numbered kill of yours. You have a separate cooldown after meetings. Your first kill after every meeting will set your cooldown to the Even-Numbered Kill Cooldown, your second kill will set it to the Odd-Numbered Kill Cooldown, and the process repeats until a meeting is called again.",
@@ -3203,6 +3237,8 @@
"FFA_LowerVision": "Lowered Vision",
"FFA_ModifiedVisionDuration": "Lowered Vision Duration",
"FFA_EnableRandomTwists": "Enable Random Swaps from time to time",
"FFA_TeamMode": "Enable Team Mode",
"FFA_TeamNumber": "Number of Teams",
"FFA-Event-GetShield": "You have a temporary shield!",
"FFA-Event-GetIncreasedSpeed": "You have a temporary speed boost!",
"FFA-Event-GetLowKCD": "You got a lower kill cooldown!",
@@ -3301,8 +3337,8 @@
"CommanderInfo": "Command your team",
"CommanderInfoLong": "(Impostors):\\nAs the Commander, you can switch between 6 modes by venting/petting your pet. You can execute the selected action by shapeshifting.<size=70%>\\n\\n<b><u>Mark:</u></b> Marks your shapeshift target with a unique color visible to all impostors. Use this to command them to kill that player!\\n\\n<b><u>Whistle:</u></b> This tells all or 1 specific<sup>*</sup> impostor(s) to come to you and gives them (each) an arrow pointing towards you.\\n\\n<b><u>Kill Anyone:</u></b> Notifies all or 1 specific<sup>*</sup> impostor(s) to kill anyone.\\n\\n<b><u>Leave Player Alive:</u></b> Shapeshifting into a crewmate marks that player with a unique color and text telling other impostors to not kill that player. Shapeshifting into an impostor tells that impostor to not kill anyone.\\n\\n<b><u>Don't Sabotage:</u></b> Notifies all impostors to not call any sabotage.\\n\\n<b><u>Use Ability:</u></b> Notifies all or 1 specific<sup>*</sup> impostor(s) to use their ability.\\n\\n<size=60%><sup>*</sup> If you shapeshift into an impostor, the action executes specifically and only on them.</size></size>",
"CommanderNotify": "The Commander wants you to meet with them",
"CommanderTarget": "<size=1.7>Commander's target</color>",
"CommanderDontKill": "<size=1.7>Don't kill this player</color>",
"CommanderTarget": "<size=1.7>Commander's target</size>",
"CommanderDontKill": "<size=1.7>Don't kill this player</size>",
"CommanderWhistling": "Whistling",
"CommanderKillAnyoneNotify": "Commander wants you to kill anyone",
"CommanderDontSabotageNotify": "Commander wants you to not sabotage",
+1 -1
View File
@@ -27,7 +27,7 @@ namespace EHR.Roles.AddOns.GhostRoles
GameData.Instance.RpcSetTasks(pc.PlayerId, Array.Empty<byte>());
pc.SyncSettings();
pc.RpcResetAbilityCooldown();
_ = new LateTask(pc.RpcResetAbilityCooldown, 1f, log: false);
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
}, 1f, "Specter Assign");
}
+366
View File
@@ -0,0 +1,366 @@
using EHR.Patches;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace EHR.Roles.Crewmate
{
internal class Adventurer : RoleBase
{
public static bool On;
public override bool IsEnable => On;
enum Resource
{
TaskCompletion,
Random,
DeadBody,
ShapeshiftSkin,
LightsFix,
Grouping
}
public enum Weapon
{
Gun,
Shield,
Lantern,
Portal,
Wrench,
Proxy,
Prediction,
RNG
}
private static readonly Dictionary<Resource, (char Icon, Color Color)> ResourceDisplayData = new()
{
{ Resource.TaskCompletion, ('\u2756', Color.blue) },
{ Resource.Random, ('Θ', Color.cyan) },
{ Resource.DeadBody, ('\u2673', Color.magenta) },
{ Resource.ShapeshiftSkin, ('⁂', Color.gray) },
{ Resource.LightsFix, ('\u2600', Color.yellow) },
{ Resource.Grouping, ('\u25cb', Color.green) }
};
private static readonly Dictionary<Weapon, List<(Resource Resource, int Count)>> Ingredients = new()
{
{ Weapon.Gun, [(Resource.DeadBody, 1), (Resource.TaskCompletion, 1)] },
{ Weapon.Shield, [(Resource.TaskCompletion, 3)] },
{ Weapon.Lantern, [(Resource.LightsFix, 1), (Resource.TaskCompletion, 1)] },
{ Weapon.Portal, [(Resource.Random, 2)] },
{ Weapon.Wrench, [(Resource.LightsFix, 1), (Resource.TaskCompletion, 2)] },
{ Weapon.Proxy, [(Resource.Grouping, 2), (Resource.TaskCompletion, 1)] },
{ Weapon.Prediction, [(Resource.DeadBody, 1), (Resource.ShapeshiftSkin, 2), (Resource.TaskCompletion, 1)] },
{ Weapon.RNG, [(Resource.Random, 2), (Resource.TaskCompletion, 2)] }
};
private static OptionItem IncreasedVisionDuration;
private static readonly Dictionary<Weapon, OptionItem> WeaponEnabledSettings = [];
private static List<Weapon> EnabledWeapons = [];
static OptionItem CreateWeaponEnabledSetting(int id, Weapon weapon) => BooleanOptionItem.Create(id, $"AdventurerWeaponEnabled.{weapon}", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Adventurer]);
public static void SetupCustomOption()
{
Options.SetupRoleOptions(11330, TabGroup.CrewmateRoles, CustomRoles.Adventurer);
IncreasedVisionDuration = IntegerOptionItem.Create(11332, "AdventurerIncreasedVisionDuration", new(1, 60, 1), 30, TabGroup.CrewmateRoles, false)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Adventurer])
.SetValueFormat(OptionFormat.Seconds);
foreach (var weapon in EnumHelper.GetAllValues<Weapon>())
{
WeaponEnabledSettings[weapon] = CreateWeaponEnabledSetting(11333 + (int)weapon, weapon);
}
}
private PlayerControl AdventurerPC;
private readonly Dictionary<Resource, int> ResourceCounts = [];
public bool InCraftingMode;
private Weapon SelectedWeaponToCraft;
public List<Weapon> OrderedWeapons;
public List<Weapon> ActiveWeapons;
public HashSet<byte> ShieldedPlayers;
public HashSet<byte> RevealedPlayers;
private long LastRandomResourceTimeStamp;
private long LastGroupingResourceTimeStamp;
private Dictionary<Resource, Vector2> ResourceLocations;
public override void Add(byte playerId)
{
On = true;
AdventurerPC = Utils.GetPlayerById(playerId);
InCraftingMode = false;
SelectedWeaponToCraft = new();
OrderedWeapons = [];
ActiveWeapons = [];
ShieldedPlayers = [];
RevealedPlayers = [];
LastRandomResourceTimeStamp = Utils.TimeStamp + 8;
LastGroupingResourceTimeStamp = Utils.TimeStamp + 20;
ResourceLocations = [];
foreach (var resource in EnumHelper.GetAllValues<Resource>())
{
ResourceCounts[resource] = 0;
}
}
public override void Init()
{
On = false;
EnabledWeapons = WeaponEnabledSettings
.Where(x => x.Value.GetBool())
.Select(x => x.Key)
.ToList();
}
public override void OnExitVent(PlayerControl pc, Vent vent)
{
InCraftingMode = !InCraftingMode;
switch (InCraftingMode)
{
case true:
OrderedWeapons = [.. EnabledWeapons.OrderBy(x => !Ingredients[x].All(r => r.Count <= ResourceCounts[r.Resource]))];
SelectedWeaponToCraft = OrderedWeapons.FirstOrDefault();
break;
case false when Ingredients[SelectedWeaponToCraft].All(x => x.Count <= ResourceCounts[x.Resource]):
var weapon = SelectedWeaponToCraft == Weapon.RNG ? EnabledWeapons[IRandom.Instance.Next(EnabledWeapons.Count)] : SelectedWeaponToCraft;
ActiveWeapons.Add(weapon);
pc.Notify(string.Format(Translator.GetString("AdventurerWeaponCrafted"), Translator.GetString($"AdventurerGun.{weapon}")));
foreach ((Resource resource, int count) in Ingredients[weapon])
{
ResourceCounts[resource] -= count;
}
switch (weapon)
{
case Weapon.Lantern:
Utils.MarkEveryoneDirtySettings();
_ = new LateTask(() => { ActiveWeapons.Remove(Weapon.Lantern); }, IncreasedVisionDuration.GetInt(), log: false);
break;
case Weapon.Portal:
_ = new LateTask(() =>
{
var e = Main.AllAlivePlayerControls.Where(x => x.PlayerId != pc.PlayerId && !x.inVent && !x.inMovingPlat && !x.onLadder);
var filtered = e as PlayerControl[] ?? e.ToArray();
if (filtered.Length == 0) return;
var target = filtered[IRandom.Instance.Next(filtered.Length)];
target.TP(pc);
pc.TP(target);
ActiveWeapons.Remove(weapon);
}, 1f, log: false);
break;
case Weapon.Wrench:
if (Utils.IsActive(SystemTypes.Electrical))
{
var SwitchSystem = ShipStatus.Instance?.Systems?[SystemTypes.Electrical]?.TryCast<SwitchSystem>();
if (SwitchSystem != null)
{
SwitchSystem.ActualSwitches = 0;
SwitchSystem.ExpectedSwitches = 0;
}
}
else if (Utils.IsActive(SystemTypes.Reactor))
{
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Reactor, 16);
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Reactor, 17);
}
else if (Utils.IsActive(SystemTypes.Laboratory))
{
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Laboratory, 67);
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Laboratory, 66);
}
else if (Utils.IsActive(SystemTypes.LifeSupp))
{
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.LifeSupp, 67);
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.LifeSupp, 66);
}
else if (Utils.IsActive(SystemTypes.Comms))
{
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Comms, 16);
ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Comms, 17);
}
ActiveWeapons.Remove(weapon);
break;
case Weapon.Prediction:
var closest = Main.AllAlivePlayerControls.Where(x => x.PlayerId != pc.PlayerId).MinBy(x => Vector2.Distance(pc.Pos(), x.Pos()));
RevealedPlayers.Add(closest.PlayerId);
ActiveWeapons.Remove(weapon);
break;
}
break;
}
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
}
public override void OnPet(PlayerControl pc)
{
switch (InCraftingMode)
{
case true:
SelectedWeaponToCraft = OrderedWeapons[(OrderedWeapons.IndexOf(SelectedWeaponToCraft) + 1) % OrderedWeapons.Count];
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
break;
case false when ActiveWeapons.Count > 0:
var target = ExternalRpcPetPatch.SelectKillButtonTarget(pc);
switch (ActiveWeapons[0])
{
case Weapon.Gun when target != null:
pc.RpcCheckAndMurder(target);
ActiveWeapons.RemoveAt(0);
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
break;
case Weapon.Shield when target != null:
ShieldedPlayers.Add(target.PlayerId);
ActiveWeapons.RemoveAt(0);
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
break;
}
break;
}
}
public override void OnTaskComplete(PlayerControl pc, int completedTaskCount, int totalTaskCount)
{
ResourceCounts[Resource.TaskCompletion]++;
}
public override void OnGlobalFixedUpdate(PlayerControl pc, bool lowLoad)
{
long now = Utils.TimeStamp;
if (lowLoad) return;
if (!GameStates.IsInTask)
{
LastGroupingResourceTimeStamp = now;
LastRandomResourceTimeStamp = now;
return;
}
if (LastRandomResourceTimeStamp + 20 <= now && pc.PlayerId != AdventurerPC.PlayerId && IRandom.Instance.Next(50) == 0)
{
var pos = pc.Pos();
LocateArrow.Add(AdventurerPC.PlayerId, pos);
ResourceLocations[Resource.Random] = pos;
LastRandomResourceTimeStamp = now;
Utils.NotifyRoles(SpecifySeer: AdventurerPC, SpecifyTarget: AdventurerPC);
}
if (LastGroupingResourceTimeStamp + 20 <= now && Main.AllAlivePlayerControls.Count(x => x.PlayerId != pc.PlayerId && Vector2.Distance(x.Pos(), pc.Pos()) < 2f) >= 2)
{
var pos = pc.Pos();
LocateArrow.Add(AdventurerPC.PlayerId, pos);
ResourceLocations[Resource.Grouping] = pos;
LastGroupingResourceTimeStamp = now;
Utils.NotifyRoles(SpecifySeer: AdventurerPC, SpecifyTarget: AdventurerPC);
}
}
public override void OnFixedUpdate(PlayerControl pc)
{
foreach ((Resource resource, Vector2 location) in ResourceLocations)
{
if (Vector2.Distance(pc.Pos(), location) < 2f)
{
ResourceCounts[resource]++;
ResourceLocations.Remove(resource);
LocateArrow.Remove(pc.PlayerId, location);
var displayData = ResourceDisplayData[resource];
pc.Notify(string.Format(Translator.GetString("AdventurerFound"), Utils.ColorString(displayData.Color, $"{displayData.Icon}")));
break;
}
}
}
public override void AfterMeetingTasks()
{
ActiveWeapons.Remove(Weapon.Proxy);
}
public void OnLightsFix()
{
ResourceCounts[Resource.LightsFix]++;
}
public static void OnAnyoneShapeshiftLoop(Adventurer av, PlayerControl shapeshifter)
{
av.ResourceLocations[Resource.ShapeshiftSkin] = shapeshifter.Pos();
}
public static void OnAnyoneDead(PlayerControl target)
{
foreach (var state in Main.PlayerStates.Values)
{
if (state.Role is Adventurer { IsEnable: true } av)
{
av.ResourceLocations[Resource.DeadBody] = target.Pos();
}
}
}
public static bool OnAnyoneCheckMurder(PlayerControl target)
{
bool any = false;
foreach (var s in Main.PlayerStates.Values)
{
if (s.Role is Adventurer { IsEnable: true } av && av.ShieldedPlayers.Contains(target.PlayerId))
{
any = true;
av.ShieldedPlayers.Remove(target.PlayerId);
break;
}
}
return !any;
}
public static bool KnowRole(PlayerControl seer, PlayerControl target)
{
return Main.PlayerStates[seer.PlayerId].Role is Adventurer { IsEnable: true } av && av.RevealedPlayers.Contains(target.PlayerId);
}
public static string GetSuffixAndHUDText(PlayerControl pc, bool hud = false, bool isForMeeting = false)
{
if (pc.IsModClient() && !hud) return string.Empty;
if (Main.PlayerStates[pc.PlayerId].Role is not Adventurer { IsEnable: true } av) return string.Empty;
IEnumerable<string> resources =
from resource in EnumHelper.GetAllValues<Resource>()
let displayData = ResourceDisplayData[resource]
select $"{Utils.ColorString(displayData.Color, $"{displayData.Icon}")}{av.ResourceCounts[resource]}";
string finalText = string.Join(' ', resources);
if (isForMeeting) return finalText;
finalText += $"\n{LocateArrow.GetArrows(pc)}\n";
finalText += "<size=80%>";
finalText += av.InCraftingMode
? string.Format(
Translator.GetString("AdventurerIngredientsDisplay"),
Translator.GetString($"AdventurerGun.{av.SelectedWeaponToCraft}"),
string.Join(' ', Ingredients[av.SelectedWeaponToCraft]
.Select(x => $"{Utils.ColorString(ResourceDisplayData[x.Resource].Color, $"{ResourceDisplayData[x.Resource].Icon}")}" +
$"{Utils.ColorString(x.Count > av.ResourceCounts[x.Resource] ? Color.red : Color.white, $"{x.Count}")}")))
: Translator.GetString("AdventurerVentToEnterCrafting");
finalText += "</size>";
return finalText;
}
}
}
+1 -1
View File
@@ -221,7 +221,7 @@ public class Witch : RoleBase
{
if (Main.PlayerStates[id].Role is Witch { IsEnable: true } wc && wc.IsSpelled(target))
{
return Utils.ColorString(Palette.ImpostorRed, "†");
return Utils.ColorString(wc.IsHM ? Utils.GetRoleColor(CustomRoles.HexMaster) : Palette.ImpostorRed, "†");
}
}
+1 -1
View File
@@ -52,7 +52,7 @@ namespace EHR.Roles.Neutral
public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(true);
public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => true;
public override bool CanUseSabotage(PlayerControl pc) => pc.IsAlive();
public override void OnPet(PlayerControl pc)
{
+1 -1
View File
@@ -96,7 +96,7 @@ public class Glitch : RoleBase
public override bool IsEnable => playerIdList.Count > 0;
public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => true;
public override bool CanUseSabotage(PlayerControl pc) => pc.IsAlive();
void SendRPCSyncTimers()
{
+1 -1
View File
@@ -52,7 +52,7 @@ namespace EHR.Roles.Neutral
public override bool IsEnable => HookshotId != byte.MaxValue;
public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => true;
public override bool CanUseSabotage(PlayerControl pc) => pc.IsAlive();
public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool());
void SendRPC()
+1 -1
View File
@@ -88,7 +88,7 @@ public class Jackal : RoleBase
public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
public static bool CanRecruit(byte id) => id.GetAbilityUseLimit() > 0;
public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => CanSabotage.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => CanSabotage.GetBool() && pc.IsAlive();
public override void SetButtonTexts(HudManager hud, byte id)
{
+1 -1
View File
@@ -107,7 +107,7 @@ public class Magician : RoleBase
public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool());
public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => true;
public override bool CanUseSabotage(PlayerControl pc) => pc.IsAlive();
public override void OnMurder(PlayerControl killer, PlayerControl target)
{
+1 -1
View File
@@ -139,6 +139,6 @@ namespace EHR.Roles.Neutral
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) => IsEnable && target != null && InfectedPlayers.Contains(target.PlayerId);
public override void AfterMeetingTasks() => Mycologist_.AddAbilityCD(CD.GetInt());
public override bool CanUseImpostorVentButton(PlayerControl pc) => true;
public override bool CanUseSabotage(PlayerControl pc) => SpreadAction.GetValue() == 1;
public override bool CanUseSabotage(PlayerControl pc) => SpreadAction.GetValue() == 1 && pc.IsAlive();
}
}
+1 -1
View File
@@ -26,5 +26,5 @@ public class Sidekick : RoleBase
public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = Jackal.KillCooldownSK.GetFloat();
public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(Jackal.HasImpostorVision.GetBool());
public override void SetButtonTexts(HudManager __instance, byte id) => __instance.SabotageButton.ToggleVisible(Jackal.CanSabotageSK.GetBool());
public override bool CanUseSabotage(PlayerControl pc) => Jackal.CanSabotageSK.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => Jackal.CanSabotageSK.GetBool() && pc.IsAlive();
}
+1 -1
View File
@@ -85,7 +85,7 @@ namespace EHR.Roles.Neutral
public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool());
public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => true;
public override bool CanUseSabotage(PlayerControl pc) => pc.IsAlive();
public override bool OnSabotage(PlayerControl pc)
{
+1 -1
View File
@@ -60,7 +60,7 @@ namespace EHR.Roles.Neutral
public override bool CanUseSabotage(PlayerControl pc)
{
return true;
return pc.IsAlive();
}
public override bool OnSabotage(PlayerControl pc)
+1 -1
View File
@@ -43,5 +43,5 @@ public class Traitor : RoleBase
public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool());
public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => CanSabotage.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => CanSabotage.GetBool() && pc.IsAlive();
}
+1 -1
View File
@@ -88,7 +88,7 @@ public class WeaponMaster : RoleBase
public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool();
public override bool CanUseSabotage(PlayerControl pc) => true;
public override bool CanUseSabotage(PlayerControl pc) => pc.IsAlive();
public override void ApplyGameOptions(IGameOptions opt, byte id)
{
+1 -1
View File
@@ -51,7 +51,7 @@ namespace EHR
public virtual bool CanUseSabotage(PlayerControl pc)
{
return pc.Is(Team.Impostor) || pc.Is(CustomRoles.Mischievous) || (pc.Is(CustomRoles.Bloodlust) && Bloodlust.HasImpVision.GetBool());
return pc.Is(Team.Impostor) || (pc.Is(CustomRoles.Mischievous) || (pc.Is(CustomRoles.Bloodlust) && Bloodlust.HasImpVision.GetBool()) && pc.IsAlive());
}
public virtual void ApplyGameOptions(IGameOptions opt, byte playerId)
+3 -2
View File
@@ -35,8 +35,8 @@ public class Main : BasePlugin
public const string DebugKeySalt = "59687b";
public static ConfigEntry<string> DebugKeyInput { get; private set; }
public const string PluginGuid = "com.gurge44.endlesshostroles";
public const string PluginVersion = "3.1.1";
public const string PluginDisplayVersion = "3.1.1";
public const string PluginVersion = "3.1.3";
public const string PluginDisplayVersion = "3.1.3";
public static readonly string SupportedAUVersion = "2024.3.5";
public Harmony Harmony { get; } = new(PluginGuid);
@@ -305,6 +305,7 @@ public class Main : BasePlugin
{ CustomRoles.Express, "#00ffff" },
{ CustomRoles.NiceEraser, "#00a5ff" },
{ CustomRoles.TaskManager, "#00ffa5" },
{ CustomRoles.Adventurer, "#fbbb04" },
{ CustomRoles.Randomizer, "#fcba03" },
{ CustomRoles.Beacon, "#a3fdff" },
{ CustomRoles.Rabbit, "#88d2ff" },