mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-20 01:46:25 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2db423411f | ||
|
|
3d120a5924 | ||
|
|
f91f0cd09c | ||
|
|
3f9277e88b | ||
|
|
9e8d3a6b1d | ||
|
|
8855ad19d5 | ||
|
|
9f4c0117c5 |
No files matched your search
@@ -114,6 +114,7 @@ public enum CustomRoles
|
||||
// Crewmate
|
||||
|
||||
Addict,
|
||||
Adventurer,
|
||||
Aid,
|
||||
Alchemist,
|
||||
Altruist,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -114,6 +114,7 @@ public enum CustomRoles
|
||||
// Crewmate
|
||||
|
||||
Addict,
|
||||
Adventurer,
|
||||
Aid,
|
||||
Alchemist,
|
||||
Altruist,
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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();
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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) ||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
@@ -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.",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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,5 +1,4 @@
|
||||
using EHR.Modules;
|
||||
using HarmonyLib;
|
||||
using Hazel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
+9
-11
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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;
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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" },
|
||||
|
||||
Reference in new issue
Block a user