Compare commits

...
7 Commits
Author SHA1 Message Date
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
Gurge44 3f9277e88b Fix infolong, Remove Admired setting from Hater, Code Cleanup 2024-04-01 20:57:33 +02:00
Gurge44 9e8d3a6b1d Merge branch 'main' of https://github.com/Gurge44/TOHE_PLUS 2024-04-01 20:45:43 +02:00
Gurge44 8855ad19d5 CTA license, fix ghost role assignment, april fools patch try-catch, Warden everlasting speed fix, fix Seekers being able to kill each other in H&S 2024-04-01 20:45:40 +02:00
Gurge44 9f4c0117c5 Update README.md 2024-04-01 12:56:46 +02:00
54 changed files with 878 additions and 285 deletions

No files matched your search

+1
View File
@@ -114,6 +114,7 @@ public enum CustomRoles
// Crewmate
Addict,
Adventurer,
Aid,
Alchemist,
Altruist,
+9 -2
View File
@@ -1,4 +1,12 @@
<Window x:Class="CustomTeamAssigner.MainWindow"
<!--
Copyright (c) 2024, Gurge44
All rights reserved.
This source code is licensed under the BSD-style license found in the
README file in the root directory of this source tree.
-->
<Window x:Class="CustomTeamAssigner.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
@@ -6,7 +14,6 @@
mc:Ignorable="d"
Title="Custom Team Assigner" Height="720" Width="1280" FontSize="20" ResizeMode="CanMinimize" WindowStyle="None">
<!--Create a default style for the buttons (modern style)-->
<Window.Resources>
<Style TargetType="Button">
<Setter Property="Background" Value="LightGray"/>
@@ -2,6 +2,14 @@
using System.IO;
using System.Windows;
/*
* Copyright (c) 2024, Gurge44
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* README file in the root directory of this source tree.
*/
namespace CustomTeamAssigner
{
public partial class MainWindow : Window
@@ -1,4 +1,12 @@
<Page x:Class="CustomTeamAssigner.PlaySetListerPage"
<!--
Copyright (c) 2024, Gurge44
All rights reserved.
This source code is licensed under the BSD-style license found in the
README file in the root directory of this source tree.
-->
<Page x:Class="CustomTeamAssigner.PlaySetListerPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -2,6 +2,14 @@
using System.Windows;
using System.Windows.Controls;
/*
* Copyright (c) 2024, Gurge44
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* README file in the root directory of this source tree.
*/
namespace CustomTeamAssigner
{
public partial class PlaySetListerPage : Page
+8
View File
@@ -2,6 +2,14 @@
using System.Text;
using System.Windows;
/*
* Copyright (c) 2024, Gurge44
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* README file in the root directory of this source tree.
*/
namespace CustomTeamAssigner
{
public class Team(string teamName)
+10 -9
View File
@@ -1,4 +1,12 @@
<Page x:Class="CustomTeamAssigner.TeamEditorPage"
<!--
Copyright (c) 2024, Gurge44
All rights reserved.
This source code is licensed under the BSD-style license found in the
README file in the root directory of this source tree.
-->
<Page x:Class="CustomTeamAssigner.TeamEditorPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -84,7 +92,7 @@
</Style>
</Page.Resources>
<Grid Name="MainGrid">
<Grid>
<Grid.Background>
<ImageBrush ImageSource="bg.jpg"/>
</Grid.Background>
@@ -109,23 +117,18 @@
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<!-- Team Name -->
<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="Team Name" FontWeight="Bold"/>
<TextBox Grid.Row="0" Grid.Column="2" x:Name="TeamNameTextBox" Text="Really Cool Team" Width="720" FontWeight="Bold" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Center" MaxLines="1"/>
<!-- Team Color (with a CheckBox deciding whether to override this) -->
<CheckBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" x:Name="OverrideColorCheckBox" Content=" Override Team Color" FontWeight="Bold" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Center" Checked="OverrideColorCheck" Unchecked="OverrideColorCheck"/>
<TextBox Grid.Row="1" Grid.Column="2" x:Name="TeamColorTextBox" Text="#00ffa5" Width="128" FontWeight="Bold" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Center" IsEnabled="False" MaxLength="9" MaxLines="1" TextChanged="ColorTextChanged"/>
<!-- Team Display Title (with a CheckBox deciding whether to override this) -->
<CheckBox Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" x:Name="OverrideTitleCheckBox" Content=" Override Team Display Title" FontWeight="Bold" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Center" Checked="OverrideTitleCheck" Unchecked="OverrideTitleCheck"/>
<TextBox Grid.Row="2" Grid.Column="2" x:Name="TeamTitleTextBox" Text="Teamed" Width="720" FontWeight="Bold" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Center" IsEnabled="False" MaxLines="1"/>
<!-- Team Display SubTitle (with a CheckBox deciding whether to override this) -->
<CheckBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" x:Name="OverrideSubTitleCheckBox" Content=" Override Team Display Subtitle" FontWeight="Bold" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Center" Checked="OverrideSubTitleCheck" Unchecked="OverrideSubTitleCheck"/>
<TextBox Grid.Row="3" Grid.Column="2" x:Name="TeamSubTitleTextBox" Text="You're in a Custom Team!" Width="720" FontWeight="Bold" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Center" IsEnabled="False" MaxLines="1"/>
<!-- Left 2 columns: ListBox (for the members of the team), right side: "Members" label, ComboBox containing all values of the CustomRoles enum, and 2 buttons to add a member or remove one -->
<Label Grid.Row="5" Grid.Column="2" Content="Team Members" FontWeight="Bold" Margin="0" VerticalContentAlignment="Top" VerticalAlignment="Top"/>
<Grid Grid.Row="5" Grid.Column="0" Grid.RowSpan="4" Grid.ColumnSpan="2" x:Name="TeamMembersGridBase" Background="DarkGray" HorizontalAlignment="Left" VerticalAlignment="Top">
<ScrollViewer VerticalScrollBarVisibility="Auto">
@@ -143,10 +146,8 @@
<ComboBox x:Name="MemberComboBox" FontWeight="Bold" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Center" Width="300"/>
<Button Content=" Add Member " FontWeight="Bold" HorizontalAlignment="Left" VerticalAlignment="Center" Click="AddMember"/>
</StackPanel>
<!-- Add a label that tells the user to click on a member to remove it -->
<Label Grid.Row="8" Grid.Column="2" Content="Click on a member to remove it" FontWeight="Bold" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<!-- Cancel, Delete and Save Buttons -->
<Button Grid.Row="10" Grid.Column="0" Content=" Cancel " FontWeight="Bold" HorizontalAlignment="Left" VerticalAlignment="Center" Click="Cancel"/>
<Button Grid.Row="10" Grid.Column="1" Content=" Delete Team " FontWeight="Bold" HorizontalAlignment="Left" VerticalAlignment="Center" Click="Delete"/>
<Button Grid.Row="10" Grid.Column="2" Content=" Save " FontWeight="Bold" HorizontalAlignment="Right" VerticalAlignment="Center" Click="Save"/>
@@ -3,6 +3,14 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
/*
* Copyright (c) 2024, Gurge44
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* README file in the root directory of this source tree.
*/
namespace CustomTeamAssigner
{
public partial class TeamEditorPage : Page
+8
View File
@@ -4,6 +4,14 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
/*
* Copyright (c) 2024, Gurge44
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* README file in the root directory of this source tree.
*/
namespace CustomTeamAssigner
{
internal static class Utils
+1
View File
@@ -114,6 +114,7 @@ public enum CustomRoles
// Crewmate
Addict,
Adventurer,
Aid,
Alchemist,
Altruist,
+8
View File
@@ -1,6 +1,7 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AU/@EntryIndexedValue">AU</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CD/@EntryIndexedValue">CD</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CK/@EntryIndexedValue">CK</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DLL/@EntryIndexedValue">DLL</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DY/@EntryIndexedValue">DY</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EHR/@EntryIndexedValue">EHR</s:String>
@@ -9,8 +10,15 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=FPS/@EntryIndexedValue">FPS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GM/@EntryIndexedValue">GM</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HUD/@EntryIndexedValue">HUD</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NB/@EntryIndexedValue">NB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NC/@EntryIndexedValue">NC</s:String>
<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>
+1 -1
View File
@@ -224,7 +224,7 @@ namespace EHR
public static void OnCheckMurder(PlayerControl killer, PlayerControl target)
{
if (killer == null || target == null || !killer.Is(CustomRoles.Seeker)) return;
if (killer == null || target == null || !killer.Is(CustomRoles.Seeker) || target.Is(CustomRoles.Seeker)) return;
killer.Kill(target);
+12 -4
View File
@@ -3,6 +3,8 @@ 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;
@@ -147,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,
@@ -670,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
@@ -867,7 +871,7 @@ internal static class CustomRolesHelper
CustomRoles.Autopsy when pc.Is(CustomRoles.Doctor) || pc.Is(CustomRoles.Tracefinder) || pc.Is(CustomRoles.Scientist) || pc.Is(CustomRoles.ScientistEHR) || pc.Is(CustomRoles.Sunnyboy) => false,
CustomRoles.Necroview when pc.Is(CustomRoles.Doctor) => false,
CustomRoles.Lazy when pc.Is(CustomRoles.Speedrunner) => false,
CustomRoles.Mischievous when pc.Is(Team.Impostor) || pc.GetCustomRole().GetDYRole() != RoleTypes.Impostor || !pc.IsNeutralKiller() => false,
CustomRoles.Mischievous when pc.Is(Team.Impostor) || pc.GetCustomRole().GetDYRole() != RoleTypes.Impostor || !pc.IsNeutralKiller() || Main.PlayerStates[pc.PlayerId].Role.CanUseSabotage(pc) => false,
CustomRoles.Loyal when pc.IsCrewmate() && !Options.CrewCanBeLoyal.GetBool() => false,
CustomRoles.DualPersonality when pc.IsCrewmate() && !Options.CrewCanBeDualPersonality.GetBool() => false,
CustomRoles.Lazy when pc.Is(CustomRoles.Needy) || pc.Is(CustomRoles.Snitch) || pc.Is(CustomRoles.Marshall) || pc.Is(CustomRoles.Transporter) || pc.Is(CustomRoles.Guardian) => false,
@@ -887,7 +891,8 @@ internal static class CustomRolesHelper
CustomRoles.Egoist when !pc.GetCustomRole().IsImpostor() => false,
CustomRoles.Damocles when pc.GetCustomRole() is CustomRoles.Bomber or CustomRoles.Nuker or CustomRoles.SerialKiller or CustomRoles.Cantankerous => false,
CustomRoles.Damocles when !pc.CanUseKillButton() => false,
CustomRoles.Flashman when pc.Is(CustomRoles.Swiftclaw) => false,
CustomRoles.Flashman when pc.Is(CustomRoles.Swiftclaw) || pc.Is(CustomRoles.Giant) => false,
CustomRoles.Giant when pc.Is(CustomRoles.Flashman) => false,
CustomRoles.Necroview when pc.Is(CustomRoles.Visionary) => false,
CustomRoles.Mimic when pc.Is(CustomRoles.Mafia) => false,
CustomRoles.Rascal when !pc.IsCrewmate() => false,
@@ -1230,6 +1235,9 @@ internal static class CustomRolesHelper
public static string ToColoredString(this CustomRoles role) => Utils.ColorString(Utils.GetRoleColor(role), Translator.GetString($"{role}"));
}
#pragma warning disable IDE0079
[SuppressMessage("ReSharper", "InconsistentNaming")]
#pragma warning restore IDE0079
public enum RoleOptionType
{
Impostor,
+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;
+26 -5
View File
@@ -1,8 +1,10 @@
using AmongUs.GameOptions;
using EHR.Roles.AddOns.GhostRoles;
using HarmonyLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace EHR.Modules
{
@@ -14,7 +16,6 @@ namespace EHR.Modules
public static void Initialize()
{
AssignedGhostRoles = [];
if (GhostRoles.Count > 0) return;
GhostRoles = EnumHelper.GetAllValues<CustomRoles>().Where(x => x != CustomRoles.EvilSpirit && x.IsGhostRole() && x.IsEnable()).ToList();
Logger.Msg($"Ghost roles: {GhostRoles.Join()}", "GhostRoles");
@@ -30,7 +31,7 @@ namespace EHR.Modules
pc.RpcSetCustomRole(suitableRole);
pc.RpcSetRole(RoleTypes.GuardianAngel);
IGhostRole instance = Utils.CreateGhostRoleInstance(suitableRole);
IGhostRole instance = CreateGhostRoleInstance(suitableRole);
instance.OnAssign(pc);
AssignedGhostRoles[pc.PlayerId] = (suitableRole, instance);
}
@@ -42,7 +43,7 @@ namespace EHR.Modules
var pc = Utils.GetPlayerById(id);
if (set) pc.RpcSetRole(RoleTypes.GuardianAngel);
IGhostRole instance = Utils.CreateGhostRoleInstance(role);
IGhostRole instance = CreateGhostRoleInstance(role);
instance.OnAssign(pc);
AssignedGhostRoles[id] = (role, instance);
}
@@ -56,7 +57,7 @@ namespace EHR.Modules
var suitableRole = GetSuitableGhostRole(pc);
return suitableRole.IsGhostRole() && !AssignedGhostRoles.Any(x => x.Key == pc.PlayerId || x.Value.Role == suitableRole);
}
catch (System.Exception e)
catch (Exception e)
{
Utils.ThrowException(e);
return false;
@@ -65,7 +66,27 @@ namespace EHR.Modules
public static CustomRoles GetSuitableGhostRole(PlayerControl pc)
{
return GhostRoles.FirstOrDefault(x => AssignedGhostRoles.All(r => r.Value.Role != x) && (Utils.CreateGhostRoleInstance(x)?.Team & pc.GetTeam()) != 0);
return GhostRoles.FirstOrDefault(x => AssignedGhostRoles.All(r => r.Value.Role != x) && (CreateGhostRoleInstance(x)?.Team & pc.GetTeam()) != 0);
}
public static IGhostRole CreateGhostRoleInstance(CustomRoles ghostRole)
{
try
{
var ghostRoleClass = Assembly.GetExecutingAssembly().GetTypes().First(x => typeof(IGhostRole).IsAssignableFrom(x) && !x.IsInterface && x.Name == $"{ghostRole}");
var ghostRoleInstance = (IGhostRole)Activator.CreateInstance(ghostRoleClass);
return ghostRoleInstance;
}
catch (InvalidOperationException)
{
Logger.Error($"Ghost role {ghostRole} not found", "CreateGhostRoleInstance");
return null;
}
catch (Exception e)
{
Utils.ThrowException(e);
return null;
}
}
}
}
+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
+13 -19
View File
@@ -360,8 +360,6 @@ public static class Options
public static OptionItem SpeedrunnerNotifyAtXTasksLeft;
public static OptionItem ReportBaitAtAllCost;
public static OptionItem TryFixBlackScreen;
public static OptionItem SkeldChance;
public static OptionItem MiraChance;
public static OptionItem PolusChance;
@@ -931,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;
@@ -1187,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();
@@ -2180,9 +2177,6 @@ public static class Options
.SetGameMode(CustomGameMode.Standard)
.SetColor(new Color32(193, 255, 209, byte.MaxValue));
TryFixBlackScreen = BooleanOptionItem.Create(24451, "TryFixBlackScreen", false, TabGroup.GameSettings, false)
.SetGameMode(CustomGameMode.Standard)
.SetColor(new Color32(193, 255, 209, byte.MaxValue));
TextOptionItem.Create(100029, "MenuTitle.Ghost", TabGroup.GameSettings)
.SetGameMode(CustomGameMode.Standard)
+3 -3
View File
@@ -1,6 +1,3 @@
using System;
using System.Linq;
namespace EHR;
public class StringOptionItem(int id, string name, int defaultValue, TabGroup tab, bool isSingleValue, string[] selections, bool noTranslation = false) : OptionItem(id, name, defaultValue, tab, isSingleValue)
@@ -14,11 +11,13 @@ public class StringOptionItem(int id, string name, int defaultValue, TabGroup ta
// Getter
public override int GetInt() => Rule.GetValueByIndex(CurrentValue);
public override float GetFloat() => Rule.GetValueByIndex(CurrentValue);
public override string GetString()
{
var str = Selections[Rule.GetValueByIndex(CurrentValue)];
return noTranslation ? str : Translator.GetString(str);
}
public int GetChance()
{
//For 0% or 100%
@@ -33,6 +32,7 @@ public class StringOptionItem(int id, string name, int defaultValue, TabGroup ta
var rate = index * 5;
return rate;
}
public override int GetValue()
=> Rule.RepeatIndex(base.GetValue());
+7 -2
View File
@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
namespace EHR.Modules;
@@ -21,6 +20,7 @@ public static class OptionSaver
string presetNmber = File.ReadAllText(DefaultPresetFileInfo.FullName);
if (int.TryParse(presetNmber, out int number) && number >= 0 && number <= 4) return number;
}
return 0;
}
@@ -31,10 +31,12 @@ public static class OptionSaver
SaveDataDirectoryInfo.Create();
SaveDataDirectoryInfo.Attributes |= FileAttributes.Hidden;
}
if (!OptionSaverFileInfo.Exists)
{
OptionSaverFileInfo.Create().Dispose();
}
if (!DefaultPresetFileInfo.Exists)
{
DefaultPresetFileInfo.Create().Dispose();
@@ -59,6 +61,7 @@ public static class OptionSaver
Logger.Warn($"Duplicate preset option ID: {option.Id}", "Options Load");
}
}
DefaultPresetNumber = singleOptions[0];
return new()
{
@@ -76,6 +79,7 @@ public static class OptionSaver
Save();
return;
}
Dictionary<int, int> singleOptions = serializableOptionsData.SingleOptions;
Dictionary<int, int[]> presetOptions = serializableOptionsData.PresetOptions;
foreach ((int id, int value) in singleOptions)
@@ -114,6 +118,7 @@ public static class OptionSaver
Save();
return;
}
LoadOptionsData(JsonSerializer.Deserialize<SerializableOptionsData>(jsonString));
}
@@ -125,4 +130,4 @@ public static class OptionSaver
}
public static readonly int Version;
}
}
+45 -49
View File
@@ -4,7 +4,6 @@ using EHR.Modules;
using EHR.Patches;
using EHR.Roles.AddOns.Common;
using EHR.Roles.AddOns.Crewmate;
using EHR.Roles.AddOns.GhostRoles;
using EHR.Roles.AddOns.Impostor;
using EHR.Roles.Crewmate;
using EHR.Roles.Impostor;
@@ -43,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)
{
@@ -649,26 +648,6 @@ public static class Utils
public static int TotalTaskCount => Main.RealOptionsData.GetInt(Int32OptionNames.NumCommonTasks) + Main.RealOptionsData.GetInt(Int32OptionNames.NumLongTasks) + Main.RealOptionsData.GetInt(Int32OptionNames.NumShortTasks);
public static IGhostRole CreateGhostRoleInstance(CustomRoles ghostRole)
{
try
{
var ghostRoleClass = Assembly.GetExecutingAssembly().GetTypes().First(x => typeof(IGhostRole).IsAssignableFrom(x) && !x.IsInterface && x.Name == $"{ghostRole}");
var ghostRoleInstance = (IGhostRole)Activator.CreateInstance(ghostRoleClass);
return ghostRoleInstance;
}
catch (InvalidOperationException)
{
Logger.Error($"Ghost role {ghostRole} not found", "CreateGhostRoleInstance");
return null;
}
catch (Exception e)
{
ThrowException(e);
return null;
}
}
public static bool CanBeMadmate(this PlayerControl pc)
{
return pc != null && pc.IsCrewmate() && !pc.Is(CustomRoles.Madmate)
@@ -725,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) ||
@@ -737,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) ||
@@ -1807,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())
@@ -1954,7 +1935,23 @@ public static class Utils
if (!isForMeeting && MeetingStates.FirstMeeting && Options.ChangeNameToRoleInfo.GetBool() && Options.CurrentGameMode is not CustomGameMode.FFA and not CustomGameMode.MoveAndStop and not CustomGameMode.HotPotato)
{
if (Options.CurrentGameMode == CustomGameMode.HideAndSeek)
var team = CustomTeamManager.GetCustomTeam(seer.PlayerId);
if (team != null)
{
SeerRealName = ColorString(
team.RoleRevealScreenBackgroundColor == "*" || !ColorUtility.TryParseHtmlString(team.RoleRevealScreenBackgroundColor, out var teamColor)
? Color.yellow
: teamColor,
string.Format(
GetString("CustomTeamHelp"),
team.RoleRevealScreenTitle == "*"
? team.TeamName
: team.RoleRevealScreenTitle,
team.RoleRevealScreenSubtitle == "*"
? string.Empty
: team.RoleRevealScreenSubtitle));
}
else if (Options.CurrentGameMode == CustomGameMode.HideAndSeek)
{
SeerRealName = CustomHideAndSeekManager.GetRoleInfoText(seer);
}
@@ -2143,6 +2140,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) ||
@@ -2417,33 +2415,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.TryFixBlackScreen.GetBool() && !pc.IsModClient())
{
pc.ReactorFlash(0.2f); // This should fix black screens
var pos = pc.Pos();
pc.MyPhysics?.RpcBootFromVent(0);
_ = new LateTask(() => { pc.TP(pos); }, 0.5f, log: false);
}
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();
@@ -2568,6 +2563,7 @@ public static class Utils
Tracefinder.OnPlayerDead(target);
Vulture.OnPlayerDead(target);
Tracker.OnPlayerDeath(target);
Adventurer.OnAnyoneDead(target);
FixedUpdatePatch.LoversSuicide(target.PlayerId, onMeeting);
}
+87 -61
View File
@@ -39,51 +39,57 @@ public static class GetHnsBodyTypePatch
{
public static void Postfix(ref PlayerBodyTypes __result, [HarmonyArgument(0)] PlayerControl player)
{
if (player == null || player.Data == null || player.Data.Role == null)
try
{
if (Main.HorseMode.Value)
if (player == null || player.Data == null || player.Data.Role == null)
{
__result = PlayerBodyTypes.Horse;
return;
}
if (Main.HorseMode.Value)
{
__result = PlayerBodyTypes.Horse;
return;
}
if (Main.LongMode.Value)
{
__result = PlayerBodyTypes.Long;
return;
}
if (Main.LongMode.Value)
{
__result = PlayerBodyTypes.Long;
return;
}
__result = PlayerBodyTypes.Normal;
}
else if (Main.HorseMode.Value)
{
if (player.Data.Role.IsImpostor)
{
__result = PlayerBodyTypes.Normal;
return;
}
__result = PlayerBodyTypes.Horse;
}
else if (Main.LongMode.Value)
{
if (player.Data.Role.IsImpostor)
else if (Main.HorseMode.Value)
{
__result = PlayerBodyTypes.LongSeeker;
return;
}
if (player.Data.Role.IsImpostor)
{
__result = PlayerBodyTypes.Normal;
return;
}
__result = PlayerBodyTypes.Long;
}
else
{
if (player.Data.Role.IsImpostor)
__result = PlayerBodyTypes.Horse;
}
else if (Main.LongMode.Value)
{
__result = PlayerBodyTypes.Seeker;
return;
}
if (player.Data.Role.IsImpostor)
{
__result = PlayerBodyTypes.LongSeeker;
return;
}
__result = PlayerBodyTypes.Normal;
__result = PlayerBodyTypes.Long;
}
else
{
if (player.Data.Role.IsImpostor)
{
__result = PlayerBodyTypes.Seeker;
return;
}
__result = PlayerBodyTypes.Normal;
}
}
catch
{
}
}
}
@@ -95,10 +101,17 @@ public static class LongBoiPatches
[HarmonyPrefix]
public static bool LongBoyAwake_Patch(LongBoiPlayerBody __instance)
{
__instance.cosmeticLayer.OnSetBodyAsGhost += (Action)__instance.SetPoolableGhost;
__instance.cosmeticLayer.OnColorChange += (Action<int>)__instance.SetHeightFromColor;
__instance.cosmeticLayer.OnCosmeticSet += (Action<string, int, CosmeticKind>)__instance.OnCosmeticSet;
__instance.gameObject.layer = 8;
try
{
__instance.cosmeticLayer.OnSetBodyAsGhost += (Action)__instance.SetPoolableGhost;
__instance.cosmeticLayer.OnColorChange += (Action<int>)__instance.SetHeightFromColor;
__instance.cosmeticLayer.OnCosmeticSet += (Action<string, int, CosmeticKind>)__instance.OnCosmeticSet;
__instance.gameObject.layer = 8;
}
catch
{
}
return false;
}
@@ -106,31 +119,37 @@ public static class LongBoiPatches
[HarmonyPrefix]
public static bool LongBoyStart_Patch(LongBoiPlayerBody __instance)
{
__instance.ShouldLongAround = true;
if (__instance.hideCosmeticsQC)
try
{
__instance.cosmeticLayer.SetHatVisorVisible(false);
}
__instance.SetupNeckGrowth();
if (__instance.isExiledPlayer)
{
ShipStatus instance = ShipStatus.Instance;
if (instance == null || instance.Type != ShipStatus.MapType.Fungle)
__instance.ShouldLongAround = true;
if (__instance.hideCosmeticsQC)
{
__instance.cosmeticLayer.AdjustCosmeticRotations(-17.75f);
__instance.cosmeticLayer.SetHatVisorVisible(false);
}
__instance.SetupNeckGrowth();
if (__instance.isExiledPlayer)
{
ShipStatus instance = ShipStatus.Instance;
if (instance == null || instance.Type != ShipStatus.MapType.Fungle)
{
__instance.cosmeticLayer.AdjustCosmeticRotations(-17.75f);
}
}
if (!__instance.isPoolablePlayer)
{
__instance.cosmeticLayer.ValidateCosmetics();
}
if (__instance.myPlayerControl)
{
__instance.StopAllCoroutines();
__instance.SetHeightFromColor(__instance.myPlayerControl.Data.DefaultOutfit.ColorId);
}
}
if (!__instance.isPoolablePlayer)
catch
{
__instance.cosmeticLayer.ValidateCosmetics();
}
if (__instance.myPlayerControl)
{
__instance.StopAllCoroutines();
__instance.SetHeightFromColor(__instance.myPlayerControl.Data.DefaultOutfit.ColorId);
}
return false;
@@ -140,8 +159,15 @@ public static class LongBoiPatches
[HarmonyPrefix]
public static bool LongBoyNeckSize_Patch(LongBoiPlayerBody __instance, ref float distance)
{
__instance.targetHeight = distance / 10f + 0.5f;
__instance.SetupNeckGrowth(true);
try
{
__instance.targetHeight = distance / 10f + 0.5f;
__instance.SetupNeckGrowth(true);
}
catch
{
}
return false;
}
+5 -6
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())
{
@@ -1417,4 +1416,4 @@ internal class RpcSendChatPatch
__result = true;
return false;
}
}
}
+6 -1
View File
@@ -146,7 +146,7 @@ class GameEndChecker
WinnerIds.Add(pc.PlayerId);
AdditionalWinnerTeams.Add(AdditionalWinners.Provocateur);
break;
case CustomRoles.FFF when (Main.PlayerStates[pc.PlayerId].Role as FFF).isWon:
case CustomRoles.FFF when (Main.PlayerStates[pc.PlayerId].Role as FFF).IsWon:
WinnerIds.Add(pc.PlayerId);
AdditionalWinnerTeams.Add(AdditionalWinners.FFF);
break;
@@ -218,6 +218,11 @@ class GameEndChecker
.Do(p => WinnerIds.Add(p.PlayerId));
}
if (WinnerTeam != CustomWinner.CustomTeam)
{
WinnerIds.RemoveWhere(x => CustomTeamManager.GetCustomTeam(x) != null);
}
if (WinnerTeam == CustomWinner.Lovers || WinnerIds.Any(x => Main.PlayerStates[x].SubRoles.Contains(CustomRoles.Lovers)))
{
if (WinnerTeam != CustomWinner.Lovers) AdditionalWinnerTeams.Add(AdditionalWinners.Lovers);
+3 -2
View File
@@ -164,7 +164,7 @@ class HudManagerPatch
bool usesPetInsteadOfKill = player.GetCustomRole().UsesPetInsteadOfKill();
if (usesPetInsteadOfKill)
{
__instance.PetButton?.OverrideText("KillButtonText");
__instance.PetButton?.OverrideText(GetString("KillButtonText"));
}
ActionButton usedButton = __instance.KillButton;
@@ -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();
+3 -2
View File
@@ -1,11 +1,11 @@
using AmongUs.GameOptions;
using EHR.Modules;
using EHR.Roles.Neutral;
using HarmonyLib;
using Il2CppSystem.Collections.Generic;
using System;
using System.Linq;
using System.Threading.Tasks;
using EHR.Modules;
using EHR.Roles.Neutral;
using UnityEngine;
using static EHR.Translator;
@@ -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))
+26 -8
View File
@@ -1,3 +1,4 @@
using EHR.Modules;
using EHR.Roles.Crewmate;
using EHR.Roles.Impostor;
using EHR.Roles.Neutral;
@@ -6,7 +7,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EHR.Modules;
using UnityEngine;
using static EHR.Translator;
using Object = UnityEngine.Object;
@@ -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) ||
+11 -17
View File
@@ -12,10 +12,8 @@ using HarmonyLib;
using Hazel;
using InnerNet;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using TMPro;
@@ -332,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))
@@ -662,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;
}
@@ -722,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);
}
}
}
}
@@ -1556,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);
+1 -1
View File
@@ -720,7 +720,7 @@ internal class SelectRolesPatch
private static void AssignLoversRolesFromList()
{
if (CustomRoles.Lovers.IsEnable())
if (CustomRoles.Lovers.IsEnable() && !RoleResult.ContainsValue(CustomRoles.Romantic))
{
Main.LoversPlayers.Clear();
Main.IsLoversDead = false;
+46 -7
View File
@@ -1,6 +1,6 @@
<h1 align="center">Endless Host Roles</h1>
<h4 align="center">Previously known as EHR+</h4>
<h4 align="center">Previously known as TOHE+</h4>
<br>
@@ -196,11 +196,11 @@
<br>
## Credit to these mods and their developers for the code and help:
### :star: [EHRN](https://github.com/0xDrMoe/TownofHost-Enhanced) :
### :star: [TOHER/TOHRE/TOHEN](https://github.com/0xDrMoe/TownofHost-Enhanced) :
>
> - Our repo is forked from EHRN
> - Our repo is forked from TOHEN
>
### :star: [EHR/TONX](https://github.com/KARPED1EM/TownOfHostEdited) :
### :star: [TOHE/TONX](https://github.com/KARPED1EM/TownOfHostEdited) :
>
> - Our repo is a continuation of EHR
> - TONX reference: Modify character limit for chat messages
@@ -256,10 +256,49 @@
> - Reference: Some custom button images
>
### :star: [EHRX](https://github.com/EHRX-Official/TownOfHostEdited-Xi) :
### :star: [TOHEX/TONEX](https://github.com/TOHEX-Official/TownOfHostEdited-Xi) :
>
> - Provided role: Swapper
> - Reference: Store message history
>
>
> CTA app background image: [Designed by kjpargeter / Freepik](http://www.freepik.com)
### Endless Host Roles (EHR), with Endless Possibilities, brought to you by the Endless Network.
- Contributors:
- Gurge44 (main)
- Dx
- PH_Gaming
# License for the Custom Team Assinger application
Copyright (c) 2024, Gurge44
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by the Endless Network.
4. Neither the name of the Endless Network nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> CTA app
background image: [Designed by kjpargeter / Freepik](http://www.freepik.com)
+28 -1
View File
@@ -818,7 +818,7 @@
"KnightedInfoLong": "(Add-ons):\\nWhen a Monarch knights someone, they get an extra vote.",
"AsthmaticInfoLong": "(Add-ons):\\nYou always have a symbol below your name with a timer that is red or green. You cannot move when the symbol/timer is red. The timer indicates when the color will change.",
"UnreportableInfoLong": "(Add-ons):\\nWith the Disregarded add-on, your corpse cannot be reported.",
"HasteInfoLong": "(Add-ons):\\nWith the Disregarded add-on, your kill cooldown continues to go down at all times.",
"HasteInfoLong": "(Add-ons):\\nWith the Haste add-on, your kill cooldown continues to go down at all times.",
"ContagiousInfoLong": "(Betrayal Add-ons):\\nWhen the Virus infects you, you become contagious.\\nContagious players are on the Virus team.\\n\\nWhether or not you die after a meeting depends on the settings for the Virus.",
"RogueInfoLong": "(Betrayal Add-ons):\\nAs the Rogue, you work against your team and work with other Rogues.\\n\\nYou cannot win with your original team.",
"LuckyInfoLong": "(Add-ons):\\nWith the Lucky add-on there is a probability for you to evade the kill, the specific probability is set by the host. When the evasion takes effect, the killer will see the shield-animation, but you not know anything.",
@@ -2895,6 +2895,7 @@
"SpawnAdditionalRefugeeMinAlivePlayers": "Minimum Number of Alive Players to Spawn",
"HorseMode": "Horse Mode",
"LongMode": "Long Mode",
"CustomTeamHelp": "You are in the {0}!{1}\\nWork with your team members to win together!",
"NoPetActionMsg1": "You just ate a cookie",
"NoPetActionMsg2": "You look around",
"NoPetActionMsg3": "You start wondering whether you are sus or not",
@@ -3105,6 +3106,32 @@
"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}",
"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.",
+5 -3
View File
@@ -1,5 +1,5 @@
using System.Collections.Generic;
using EHR.Roles.Impostor;
using EHR.Roles.Impostor;
using System.Collections.Generic;
using static EHR.Options;
namespace EHR.Roles.AddOns.Common
@@ -17,6 +17,7 @@ namespace EHR.Roles.AddOns.Common
}
private static readonly Dictionary<byte, long> LastChange = [];
private static void ChangeColor(PlayerControl pc)
{
int colorId = IRandom.Instance.Next(0, 18);
@@ -36,6 +37,7 @@ namespace EHR.Roles.AddOns.Common
sender.SendMessage();
}
}
public static void OnFixedUpdate(PlayerControl pc)
{
if (!pc.Is(CustomRoles.Disco) || !GameStates.IsInTask || pc.IsShifted() || Camouflager.IsActive || (Utils.IsActive(SystemTypes.Comms) && CommsCamouflage.GetBool())) return;
@@ -45,4 +47,4 @@ namespace EHR.Roles.AddOns.Common
LastChange[pc.PlayerId] = now;
}
}
}
}
+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");
}
+5 -2
View File
@@ -1,4 +1,6 @@
namespace EHR.Roles.AddOns.GhostRoles
using System;
namespace EHR.Roles.AddOns.GhostRoles
{
internal class Warden : IGhostRole, ISettingHolder
{
@@ -10,6 +12,7 @@
public void OnProtect(PlayerControl pc, PlayerControl target)
{
float speed = Main.AllPlayerSpeed[target.PlayerId];
if (Math.Abs(speed - (speed + ExtraSpeed.GetFloat())) < 0.1f || speed > speed + ExtraSpeed.GetFloat()) return;
Main.AllPlayerSpeed[target.PlayerId] += ExtraSpeed.GetFloat();
target.MarkDirtySettings();
target.Notify(Translator.GetString("WardenNotify"));
@@ -27,7 +30,7 @@
ExtraSpeedDuration = IntegerOptionItem.Create(649202, "ExpressSpeedDur", new(1, 90, 1), 5, TabGroup.OtherRoles, false)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Warden])
.SetValueFormat(OptionFormat.Seconds);
ExtraSpeed = FloatOptionItem.Create(649203, "ExpressSpeed", new(0.5f, 3f, 0.1f), 1.5f, TabGroup.OtherRoles, false)
ExtraSpeed = FloatOptionItem.Create(649203, "ExpressSpeed", new(0.5f, 3f, 0.1f), 0.25f, TabGroup.OtherRoles, false)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Warden])
.SetValueFormat(OptionFormat.Multiplier);
}
+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"), $"{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"),
$"{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;
}
}
}
+2 -2
View File
@@ -1,7 +1,7 @@
using System;
using AmongUs.GameOptions;
using System;
using System.Collections.Generic;
using System.Linq;
using AmongUs.GameOptions;
using UnityEngine;
namespace EHR.Roles.Impostor
+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
View File
@@ -1,5 +1,4 @@
using EHR.Modules;
using HarmonyLib;
using Hazel;
using System;
using System.Collections.Generic;
+9 -11
View File
@@ -8,7 +8,7 @@ namespace EHR.Roles.Neutral
public class FFF : RoleBase
{
private const int Id = 11300;
public static List<byte> playerIdList = [];
public static List<byte> PlayerIdList = [];
public static bool On;
public static OptionItem CanVent;
@@ -18,14 +18,13 @@ namespace EHR.Roles.Neutral
public static OptionItem CanKillLovers;
public static OptionItem CanKillMadmate;
public static OptionItem CanKillCharmed;
public static OptionItem CanKillAdmired;
public static OptionItem CanKillSidekicks;
public static OptionItem CanKillEgoists;
public static OptionItem CanKillInfected;
public static OptionItem CanKillContagious;
public static OptionItem CanKillUndead;
public bool isWon;
public bool IsWon;
public static void SetupCustomOption()
{
@@ -39,22 +38,21 @@ namespace EHR.Roles.Neutral
CanKillEgoists = BooleanOptionItem.Create(Id + 17, "FFFCanKillEgoist", true, TabGroup.NeutralRoles, false).SetParent(ChooseConverted);
CanKillInfected = BooleanOptionItem.Create(Id + 18, "FFFCanKillInfected", true, TabGroup.NeutralRoles, false).SetParent(ChooseConverted);
CanKillContagious = BooleanOptionItem.Create(Id + 19, "FFFCanKillContagious", true, TabGroup.NeutralRoles, false).SetParent(ChooseConverted);
CanKillAdmired = BooleanOptionItem.Create(Id + 20, "FFFCanKillAdmired", true, TabGroup.NeutralRoles, false).SetParent(ChooseConverted);
CanKillUndead = BooleanOptionItem.Create(Id + 21, "FFFCanKillUndead", true, TabGroup.NeutralRoles, false).SetParent(ChooseConverted);
}
public override void Init()
{
playerIdList = [];
PlayerIdList = [];
On = false;
isWon = false;
IsWon = false;
}
public override void Add(byte playerId)
{
playerIdList.Add(playerId);
PlayerIdList.Add(playerId);
On = true;
isWon = false;
IsWon = false;
if (!AmongUsClient.Instance.AmHost) return;
if (!Main.ResetCamPlayerList.Contains(playerId))
@@ -66,7 +64,7 @@ namespace EHR.Roles.Neutral
public override bool CanUseKillButton(PlayerControl pc)
{
return pc.IsAlive() && !isWon;
return pc.IsAlive() && !IsWon;
}
public override void ApplyGameOptions(IGameOptions opt, byte playerId)
@@ -84,7 +82,7 @@ namespace EHR.Roles.Neutral
{
if (!ChooseConverted.GetBool())
{
if (killer.RpcCheckAndMurder(target)) isWon = true;
if (killer.RpcCheckAndMurder(target)) IsWon = true;
Logger.Info($"{killer.GetRealName()} killed right target case 1", "FFF");
return false;
}
@@ -101,7 +99,7 @@ namespace EHR.Roles.Neutral
|| ((target.Is(CustomRoles.Contagious) || target.Is(CustomRoles.Virus)) && CanKillContagious.GetBool())
)
{
if (killer.RpcCheckAndMurder(target)) isWon = true;
if (killer.RpcCheckAndMurder(target)) IsWon = true;
Logger.Info($"{killer.GetRealName()} killed right target case 2", "FFF");
return false;
}
+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();
}
-2
View File
@@ -1,7 +1,5 @@
using AmongUs.GameOptions;
using EHR.Modules;
using EHR.Patches;
using Hazel;
using System.Collections.Generic;
using System.Linq;
using static EHR.Options;
+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.0";
public const string PluginDisplayVersion = "3.1.0";
public const string PluginVersion = "3.1.2";
public const string PluginDisplayVersion = "3.1.2";
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" },