Compare commits

...
12 Commits
Author SHA1 Message Date
Gurge44 d9b06aff9a fix 2024-01-07 21:46:40 +01:00
Gurge44 063b9ff964 change version 2024-01-07 21:24:15 +01:00
Gurge44 9a944d9fd3 Some fixes 2024-01-07 21:10:00 +01:00
Gurge44 b2013dc25f Last minute addition 2024-01-07 00:08:09 +01:00
Gurge44 cc8244f487 Remove unnecessary code 2024-01-06 23:30:08 +01:00
Gurge44 0dc6fc2164 Delete String.csv 2024-01-06 23:25:19 +01:00
Gurge44 1e57d4e171 /ban 2024-01-06 23:14:48 +01:00
Gurge44 9abed63369 Fix & Improve some roles & add-ons, Optimize 2024-01-06 21:44:21 +01:00
Gurge44 2713b69f86 CSV => JSON, Fix Librarian & Bubble, Sort guesser UI alphabetically 2024-01-06 19:01:05 +01:00
Gurge44 2260f90180 Extend setting cap 2024-01-05 21:07:22 +01:00
Gurge44 9c1464582c Add Indicator if a role requires pets and pet setting isn't on & add /up 2024-01-05 20:35:08 +01:00
Gurge44 3c5b8f982b Fix a LOT of bugs & Add RPCs 2024-01-05 19:02:49 +01:00
41 changed files with 4725 additions and 5056 deletions

No files matched your search

+1 -1
View File
@@ -293,7 +293,7 @@ internal static class FFAManager
}
else // Mixed
{
_ = new LateTask(killer.TPtoRndVent, 0.5f, "FFA-Event-TP");
_ = new LateTask(() => { killer.TPtoRndVent(); }, 0.5f, "FFA-Event-TP");
killer.Notify(GetString("FFA-Event-GetTP"));
Main.AllPlayerKillCooldown[killer.PlayerId] = FFA_KCD.GetFloat();
}
+1 -4
View File
@@ -88,15 +88,12 @@ internal class CustomRoleSelector
{
object cr = list[i1];
CustomRoles role = (CustomRoles)Enum.Parse(typeof(CustomRoles), cr.ToString());
if (role.IsVanilla() || role.IsAdditionRole()) continue;
if (!Main.UseVersionProtocol.Value && !role.IsAbleToHostPublic()) continue;
if (role.IsVanilla() || role.IsAdditionRole() || (CustomRolesHelper.OnlySpawnsWithPetsRoleList.Contains(role) && !Options.UsePets.GetBool()) || (!Main.UseVersionProtocol.Value && !role.IsAbleToHostPublic())) continue;
switch (role)
{
case CustomRoles.DarkHide when (MapNames)Main.NormalOptions.MapId == MapNames.Fungle:
case CustomRoles.Pelican when roleList.Contains(CustomRoles.Duellist):
case CustomRoles.Duellist when roleList.Contains(CustomRoles.Pelican):
case CustomRoles.Tunneler when !Options.UsePets.GetBool():
case CustomRoles.Tornado when !Options.UsePets.GetBool():
case CustomRoles.GM:
case CustomRoles.NotAssigned:
continue;
+348 -420
View File
@@ -1,4 +1,5 @@
using AmongUs.GameOptions;
using System.Collections.Generic;
using System.Linq;
using TOHE.Roles.Crewmate;
using TOHE.Roles.Impostor;
@@ -194,95 +195,92 @@ internal static class CustomRolesHelper
};
}
public static CustomRoles GetErasedRole(this CustomRoles role)
{
return role.IsVanilla()
? role
: role switch
{
CustomRoles.Tracker => CustomRoles.CrewmateTOHE,
CustomRoles.Mayor => Options.MayorHasPortableButton.GetBool() ? CustomRoles.EngineerTOHE : CustomRoles.CrewmateTOHE,
CustomRoles.Observer => CustomRoles.CrewmateTOHE,
CustomRoles.DovesOfNeace => CustomRoles.EngineerTOHE,
CustomRoles.Monitor => Monitor.CanVent.GetBool() ? CustomRoles.EngineerTOHE : CustomRoles.CrewmateTOHE,
CustomRoles.Judge => CustomRoles.CrewmateTOHE,
CustomRoles.NiceSwapper => CustomRoles.CrewmateTOHE,
CustomRoles.Mortician => CustomRoles.CrewmateTOHE,
CustomRoles.Mediumshiper => CustomRoles.CrewmateTOHE,
CustomRoles.Bodyguard => CustomRoles.CrewmateTOHE,
CustomRoles.ParityCop => CustomRoles.CrewmateTOHE,
CustomRoles.Enigma => CustomRoles.CrewmateTOHE,
CustomRoles.Grenadier => CustomRoles.EngineerTOHE,
CustomRoles.SecurityGuard => CustomRoles.EngineerTOHE,
CustomRoles.Lighter => CustomRoles.EngineerTOHE,
CustomRoles.Ignitor => CustomRoles.EngineerTOHE,
CustomRoles.Speedrunner => CustomRoles.CrewmateTOHE,
CustomRoles.Transporter => CustomRoles.CrewmateTOHE,
CustomRoles.Veteran => CustomRoles.CrewmateTOHE,
CustomRoles.GuardianAngelTOHE => CustomRoles.GuardianAngel,
CustomRoles.Detective => CustomRoles.CrewmateTOHE,
CustomRoles.NiceGuesser => CustomRoles.CrewmateTOHE,
CustomRoles.Cleanser => CustomRoles.CrewmateTOHE,
CustomRoles.Luckey => CustomRoles.CrewmateTOHE,
CustomRoles.Lookout => CustomRoles.CrewmateTOHE,
CustomRoles.CyberStar => CustomRoles.CrewmateTOHE,
CustomRoles.Demolitionist => CustomRoles.CrewmateTOHE,
CustomRoles.Ventguard => CustomRoles.EngineerTOHE,
CustomRoles.Express => CustomRoles.CrewmateTOHE,
CustomRoles.NiceEraser => CustomRoles.CrewmateTOHE,
CustomRoles.TaskManager => CustomRoles.CrewmateTOHE,
CustomRoles.Shiftguard => CustomRoles.CrewmateTOHE,
CustomRoles.Mole => CustomRoles.EngineerTOHE,
CustomRoles.Sentinel => CustomRoles.EngineerTOHE,
CustomRoles.Electric => CustomRoles.CrewmateTOHE,
CustomRoles.Philantropist => CustomRoles.CrewmateTOHE,
CustomRoles.Tornado => CustomRoles.CrewmateTOHE,
CustomRoles.Druid => CustomRoles.EngineerTOHE,
CustomRoles.Insight => CustomRoles.CrewmateTOHE,
CustomRoles.Tunneler => CustomRoles.CrewmateTOHE,
CustomRoles.Detour => CustomRoles.CrewmateTOHE,
CustomRoles.Drainer => CustomRoles.EngineerTOHE,
CustomRoles.GuessManager => CustomRoles.CrewmateTOHE,
CustomRoles.Benefactor => CustomRoles.CrewmateTOHE,
CustomRoles.Altruist => CustomRoles.CrewmateTOHE,
CustomRoles.Transmitter => CustomRoles.CrewmateTOHE,
CustomRoles.Autocrat => CustomRoles.CrewmateTOHE,
CustomRoles.Nightmare => CustomRoles.CrewmateTOHE,
CustomRoles.CameraMan => CustomRoles.EngineerTOHE,
CustomRoles.Spy => CustomRoles.CrewmateTOHE,
CustomRoles.Ricochet => CustomRoles.CrewmateTOHE,
CustomRoles.Aid => CustomRoles.CrewmateTOHE,
CustomRoles.DonutDelivery => CustomRoles.CrewmateTOHE,
CustomRoles.Gaulois => CustomRoles.CrewmateTOHE,
CustomRoles.Analyzer => CustomRoles.CrewmateTOHE,
CustomRoles.Escort => CustomRoles.CrewmateTOHE,
CustomRoles.Doormaster => CustomRoles.EngineerTOHE,
CustomRoles.Tether => CustomRoles.EngineerTOHE,
CustomRoles.Psychic => CustomRoles.CrewmateTOHE,
CustomRoles.Needy => CustomRoles.CrewmateTOHE,
CustomRoles.SuperStar => CustomRoles.CrewmateTOHE,
CustomRoles.Paranoia => CustomRoles.EngineerTOHE,
CustomRoles.EngineerTOHE => CustomRoles.EngineerTOHE,
CustomRoles.TimeMaster => CustomRoles.EngineerTOHE,
CustomRoles.CrewmateTOHE => CustomRoles.CrewmateTOHE,
CustomRoles.Doctor => CustomRoles.ScientistTOHE,
CustomRoles.ScientistTOHE => CustomRoles.ScientistTOHE,
CustomRoles.Tracefinder => CustomRoles.ScientistTOHE,
CustomRoles.SpeedBooster => CustomRoles.CrewmateTOHE,
CustomRoles.Dictator => CustomRoles.CrewmateTOHE,
CustomRoles.Snitch => CustomRoles.CrewmateTOHE,
CustomRoles.Marshall => CustomRoles.CrewmateTOHE,
CustomRoles.SabotageMaster => CustomRoles.EngineerTOHE,
//CustomRoles.Retributionist => CustomRoles.Crewmate,
CustomRoles.Witness => CustomRoles.CrewmateTOHE,
CustomRoles.Guardian => CustomRoles.CrewmateTOHE,
CustomRoles.Addict => CustomRoles.EngineerTOHE,
CustomRoles.Alchemist => CustomRoles.EngineerTOHE,
CustomRoles.Oracle => CustomRoles.CrewmateTOHE,
CustomRoles.Chameleon => CustomRoles.EngineerTOHE,
_ => role.IsImpostor() ? CustomRoles.ImpostorTOHE : CustomRoles.CrewmateTOHE,
};
}
public static CustomRoles GetErasedRole(this CustomRoles role) => role.IsVanilla()
? role
: role switch
{
CustomRoles.Tracker => CustomRoles.CrewmateTOHE,
CustomRoles.Mayor => Options.MayorHasPortableButton.GetBool() ? CustomRoles.EngineerTOHE : CustomRoles.CrewmateTOHE,
CustomRoles.Observer => CustomRoles.CrewmateTOHE,
CustomRoles.DovesOfNeace => CustomRoles.EngineerTOHE,
CustomRoles.Monitor => Monitor.CanVent.GetBool() ? CustomRoles.EngineerTOHE : CustomRoles.CrewmateTOHE,
CustomRoles.Judge => CustomRoles.CrewmateTOHE,
CustomRoles.NiceSwapper => CustomRoles.CrewmateTOHE,
CustomRoles.Mortician => CustomRoles.CrewmateTOHE,
CustomRoles.Mediumshiper => CustomRoles.CrewmateTOHE,
CustomRoles.Bodyguard => CustomRoles.CrewmateTOHE,
CustomRoles.ParityCop => CustomRoles.CrewmateTOHE,
CustomRoles.Enigma => CustomRoles.CrewmateTOHE,
CustomRoles.Grenadier => CustomRoles.EngineerTOHE,
CustomRoles.SecurityGuard => CustomRoles.EngineerTOHE,
CustomRoles.Lighter => CustomRoles.EngineerTOHE,
CustomRoles.Ignitor => CustomRoles.EngineerTOHE,
CustomRoles.Speedrunner => CustomRoles.CrewmateTOHE,
CustomRoles.Transporter => CustomRoles.CrewmateTOHE,
CustomRoles.Veteran => CustomRoles.CrewmateTOHE,
CustomRoles.GuardianAngelTOHE => CustomRoles.GuardianAngel,
CustomRoles.Detective => CustomRoles.CrewmateTOHE,
CustomRoles.NiceGuesser => CustomRoles.CrewmateTOHE,
CustomRoles.Cleanser => CustomRoles.CrewmateTOHE,
CustomRoles.Luckey => CustomRoles.CrewmateTOHE,
CustomRoles.Lookout => CustomRoles.CrewmateTOHE,
CustomRoles.CyberStar => CustomRoles.CrewmateTOHE,
CustomRoles.Demolitionist => CustomRoles.CrewmateTOHE,
CustomRoles.Ventguard => CustomRoles.EngineerTOHE,
CustomRoles.Express => CustomRoles.CrewmateTOHE,
CustomRoles.NiceEraser => CustomRoles.CrewmateTOHE,
CustomRoles.TaskManager => CustomRoles.CrewmateTOHE,
CustomRoles.Shiftguard => CustomRoles.CrewmateTOHE,
CustomRoles.Mole => CustomRoles.EngineerTOHE,
CustomRoles.Sentinel => CustomRoles.EngineerTOHE,
CustomRoles.Electric => CustomRoles.CrewmateTOHE,
CustomRoles.Philantropist => CustomRoles.CrewmateTOHE,
CustomRoles.Tornado => CustomRoles.CrewmateTOHE,
CustomRoles.Druid => CustomRoles.EngineerTOHE,
CustomRoles.Insight => CustomRoles.CrewmateTOHE,
CustomRoles.Tunneler => CustomRoles.CrewmateTOHE,
CustomRoles.Detour => CustomRoles.CrewmateTOHE,
CustomRoles.Drainer => CustomRoles.EngineerTOHE,
CustomRoles.GuessManager => CustomRoles.CrewmateTOHE,
CustomRoles.Benefactor => CustomRoles.CrewmateTOHE,
CustomRoles.Altruist => CustomRoles.CrewmateTOHE,
CustomRoles.Transmitter => CustomRoles.CrewmateTOHE,
CustomRoles.Autocrat => CustomRoles.CrewmateTOHE,
CustomRoles.Nightmare => CustomRoles.CrewmateTOHE,
CustomRoles.CameraMan => CustomRoles.EngineerTOHE,
CustomRoles.Spy => CustomRoles.CrewmateTOHE,
CustomRoles.Ricochet => CustomRoles.CrewmateTOHE,
CustomRoles.Aid => CustomRoles.CrewmateTOHE,
CustomRoles.DonutDelivery => CustomRoles.CrewmateTOHE,
CustomRoles.Gaulois => CustomRoles.CrewmateTOHE,
CustomRoles.Analyzer => CustomRoles.CrewmateTOHE,
CustomRoles.Escort => CustomRoles.CrewmateTOHE,
CustomRoles.Doormaster => CustomRoles.EngineerTOHE,
CustomRoles.Tether => CustomRoles.EngineerTOHE,
CustomRoles.Psychic => CustomRoles.CrewmateTOHE,
CustomRoles.Needy => CustomRoles.CrewmateTOHE,
CustomRoles.SuperStar => CustomRoles.CrewmateTOHE,
CustomRoles.Paranoia => CustomRoles.EngineerTOHE,
CustomRoles.EngineerTOHE => CustomRoles.EngineerTOHE,
CustomRoles.TimeMaster => CustomRoles.EngineerTOHE,
CustomRoles.CrewmateTOHE => CustomRoles.CrewmateTOHE,
CustomRoles.Doctor => CustomRoles.ScientistTOHE,
CustomRoles.ScientistTOHE => CustomRoles.ScientistTOHE,
CustomRoles.Tracefinder => CustomRoles.ScientistTOHE,
CustomRoles.SpeedBooster => CustomRoles.CrewmateTOHE,
CustomRoles.Dictator => CustomRoles.CrewmateTOHE,
CustomRoles.Snitch => CustomRoles.CrewmateTOHE,
CustomRoles.Marshall => CustomRoles.CrewmateTOHE,
CustomRoles.SabotageMaster => CustomRoles.EngineerTOHE,
//CustomRoles.Retributionist => CustomRoles.Crewmate,
CustomRoles.Witness => CustomRoles.CrewmateTOHE,
CustomRoles.Guardian => CustomRoles.CrewmateTOHE,
CustomRoles.Addict => CustomRoles.EngineerTOHE,
CustomRoles.Alchemist => CustomRoles.EngineerTOHE,
CustomRoles.Oracle => CustomRoles.CrewmateTOHE,
CustomRoles.Chameleon => CustomRoles.EngineerTOHE,
_ => role.IsImpostor() ? CustomRoles.ImpostorTOHE : CustomRoles.CrewmateTOHE,
};
public static RoleTypes GetDYRole(this CustomRoles role)
{
@@ -375,9 +373,7 @@ internal static class CustomRolesHelper
_ => RoleTypes.GuardianAngel
};
}
public static bool IsAdditionRole(this CustomRoles role)
{
return role is
public static bool IsAdditionRole(this CustomRoles role) => role is
CustomRoles.Lovers or
CustomRoles.LastImpostor or
CustomRoles.Ntr or
@@ -435,10 +431,8 @@ internal static class CustomRolesHelper
CustomRoles.DoubleShot or
CustomRoles.Ghoul or
CustomRoles.EvilSpirit;
}
public static bool IsNonNK(this CustomRoles role) // ROLE ASSIGNING, NOT NEUTRAL TYPE
{
return role is
=> role is
CustomRoles.Jester or
CustomRoles.Terrorist or
CustomRoles.Opportunist or
@@ -458,7 +452,7 @@ internal static class CustomRolesHelper
CustomRoles.Gamer or
CustomRoles.FFF or
CustomRoles.Workaholic or
// CustomRoles.Pelican or
// CustomRoles.Pelican or
CustomRoles.Collector or
CustomRoles.Sunnyboy or
CustomRoles.Maverick or
@@ -469,11 +463,9 @@ internal static class CustomRolesHelper
CustomRoles.VengefulRomantic or
CustomRoles.Doomsayer or
CustomRoles.Succubus;
}
public static bool IsAmneMaverick(this CustomRoles role) // ROLE ASSIGNING, NOT NEUTRAL TYPE
{
return role is
=> role is
CustomRoles.Jester or
CustomRoles.Terrorist or
CustomRoles.Opportunist or
@@ -499,7 +491,7 @@ internal static class CustomRolesHelper
CustomRoles.Gamer or
CustomRoles.FFF or
CustomRoles.Workaholic or
// CustomRoles.Pelican or
// CustomRoles.Pelican or
CustomRoles.Collector or
CustomRoles.Sunnyboy or
CustomRoles.Arsonist or
@@ -518,10 +510,7 @@ internal static class CustomRolesHelper
// CustomRoles.Poisoner or
// CustomRoles.HexMaster or
CustomRoles.Totocalcio;
}
public static bool IsAmneNK(this CustomRoles role)
{
return role is
public static bool IsAmneNK(this CustomRoles role) => role is
CustomRoles.Sidekick or
CustomRoles.Infectious or
CustomRoles.Glitch or
@@ -551,11 +540,8 @@ internal static class CustomRolesHelper
CustomRoles.Virus or
CustomRoles.Spiritcaller or
CustomRoles.Succubus;
}
public static bool IsNK(this CustomRoles role)
{
return role is
public static bool IsNK(this CustomRoles role) => role is
CustomRoles.Jackal or
CustomRoles.Glitch or
CustomRoles.Sidekick or
@@ -600,10 +586,7 @@ internal static class CustomRolesHelper
CustomRoles.RuthlessRomantic or
CustomRoles.PlagueBearer or
CustomRoles.Pestilence;
}
public static bool IsSnitchTarget(this CustomRoles role)
{
return role is
public static bool IsSnitchTarget(this CustomRoles role) => role is
CustomRoles.Jackal or
CustomRoles.Sidekick or
CustomRoles.HexMaster or
@@ -645,10 +628,7 @@ internal static class CustomRolesHelper
CustomRoles.RuthlessRomantic or
CustomRoles.PlagueBearer or
CustomRoles.Pestilence;
}
public static bool IsNE(this CustomRoles role)
{
return role is
public static bool IsNE(this CustomRoles role) => role is
CustomRoles.Jester or
CustomRoles.Gamer or
//CustomRoles.Masochist or
@@ -656,10 +636,7 @@ internal static class CustomRolesHelper
CustomRoles.Executioner or
CustomRoles.Doomsayer or
CustomRoles.Innocent;
}
public static bool IsNB(this CustomRoles role)
{
return role is
public static bool IsNB(this CustomRoles role) => role is
CustomRoles.Opportunist or
CustomRoles.Lawyer or
CustomRoles.Amnesiac or
@@ -672,10 +649,7 @@ internal static class CustomRolesHelper
CustomRoles.Romantic or
CustomRoles.VengefulRomantic or
CustomRoles.Totocalcio;
}
public static bool IsNC(this CustomRoles role)
{
return role is
public static bool IsNC(this CustomRoles role) => role is
CustomRoles.Mario or
CustomRoles.Terrorist or
//CustomRoles.Pirate or
@@ -688,10 +662,7 @@ internal static class CustomRolesHelper
CustomRoles.Workaholic or
CustomRoles.Collector or
CustomRoles.Provocateur;
}
public static bool IsNeutralKilling(this CustomRoles role)
{
return role is
public static bool IsNeutralKilling(this CustomRoles role) => role is
CustomRoles.Terrorist or
CustomRoles.Arsonist or
CustomRoles.Juggernaut or
@@ -743,10 +714,7 @@ internal static class CustomRolesHelper
CustomRoles.RuthlessRomantic or
CustomRoles.PlagueBearer or
CustomRoles.Pestilence;
}
public static bool IsCK(this CustomRoles role)
{
return role is
public static bool IsCK(this CustomRoles role) => role is
CustomRoles.SwordsMan or
CustomRoles.Veteran or
CustomRoles.CopyCat or
@@ -758,10 +726,8 @@ internal static class CustomRolesHelper
//CustomRoles.Retributionist or
CustomRoles.Sheriff or
CustomRoles.Jailor;
}
public static bool IsImpostor(this CustomRoles role) // IsImp
{
return role is
=> role is
CustomRoles.Impostor or
CustomRoles.Godfather or
CustomRoles.Shapeshifter or
@@ -839,10 +805,7 @@ internal static class CustomRolesHelper
CustomRoles.Camouflager or
CustomRoles.Twister or
CustomRoles.Lurker;
}
public static bool IsNeutral(this CustomRoles role)
{
return role is
public static bool IsNeutral(this CustomRoles role) => role is
//SoloKombat
CustomRoles.KB_Normal or
//FFA
@@ -929,11 +892,8 @@ internal static class CustomRolesHelper
CustomRoles.Succubus or
CustomRoles.Doomsayer or
CustomRoles.Spiritcaller;
}
public static bool IsAbleToBeSidekicked(this CustomRoles role)
{
return role is
public static bool IsAbleToBeSidekicked(this CustomRoles role) => role is
CustomRoles.BloodKnight or
CustomRoles.Virus or
CustomRoles.Medusa or
@@ -1000,11 +960,7 @@ internal static class CustomRolesHelper
CustomRoles.Parasite or
CustomRoles.PlagueBearer;
}
public static bool IsEvilAddons(this CustomRoles role)
{
return role is
public static bool IsEvilAddons(this CustomRoles role) => role is
CustomRoles.Madmate or
CustomRoles.Egoist or
CustomRoles.Charmed or
@@ -1014,19 +970,13 @@ internal static class CustomRolesHelper
CustomRoles.Rogue or
CustomRoles.Rascal or
CustomRoles.Soulless;
}
public static bool IsMadmate(this CustomRoles role)
{
return role is
public static bool IsMadmate(this CustomRoles role) => role is
CustomRoles.Crewpostor or
CustomRoles.Convict or
CustomRoles.Refugee or
CustomRoles.Parasite;
}
public static bool IsTasklessCrewmate(this CustomRoles role)
{
return !role.UsesPetInsteadOfKill() && role is
public static bool IsTasklessCrewmate(this CustomRoles role) => !role.UsesPetInsteadOfKill() && role is
CustomRoles.Sheriff or
CustomRoles.Admirer or
CustomRoles.Medic or
@@ -1045,98 +995,93 @@ internal static class CustomRolesHelper
CustomRoles.Farseer or
CustomRoles.SwordsMan or
CustomRoles.Deputy;
}
public static bool PetActivatedAbility(this CustomRoles role)
public static bool PetActivatedAbility(this CustomRoles role) => Options.UsePets.GetBool() && role switch
{
return Options.UsePets.GetBool() && role switch
{
CustomRoles.Doormaster or
CustomRoles.Tether or
CustomRoles.Mayor or
CustomRoles.Paranoia or
CustomRoles.Grenadier or
CustomRoles.Veteran or
CustomRoles.Lighter or
CustomRoles.SecurityGuard or
CustomRoles.DovesOfNeace or
CustomRoles.Alchemist or
CustomRoles.TimeMaster or
CustomRoles.Sapper or
CustomRoles.CameraMan or
CustomRoles.NiceHacker or
CustomRoles.Druid or
CustomRoles.Tunneler or
CustomRoles.Tornado or
CustomRoles.Sentinel or
CustomRoles.Lookout or
CustomRoles.Sniper or
CustomRoles.Warlock or
CustomRoles.Assassin or
CustomRoles.Undertaker or
CustomRoles.Disperser or
CustomRoles.Twister or
CustomRoles.QuickShooter or
CustomRoles.Miner or
CustomRoles.Escapee or
CustomRoles.RiftMaker or
CustomRoles.Bomber or
CustomRoles.Nuker or
CustomRoles.Glitch or
CustomRoles.Magician or
CustomRoles.WeaponMaster or
CustomRoles.Enderman or
CustomRoles.Mycologist or
CustomRoles.Hookshot or
CustomRoles.Sprayer
=> true,
CustomRoles.Doormaster or
CustomRoles.Tether or
CustomRoles.Mayor or
CustomRoles.Paranoia or
CustomRoles.Grenadier or
CustomRoles.Veteran or
CustomRoles.Lighter or
CustomRoles.SecurityGuard or
CustomRoles.DovesOfNeace or
CustomRoles.Alchemist or
CustomRoles.TimeMaster or
CustomRoles.Sapper or
CustomRoles.CameraMan or
CustomRoles.NiceHacker or
CustomRoles.Druid or
CustomRoles.Tunneler or
CustomRoles.Tornado or
CustomRoles.Sentinel or
CustomRoles.Lookout or
CustomRoles.Sniper or
CustomRoles.Warlock or
CustomRoles.Assassin or
CustomRoles.Undertaker or
CustomRoles.Disperser or
CustomRoles.Twister or
CustomRoles.QuickShooter or
CustomRoles.Miner or
CustomRoles.Escapee or
CustomRoles.RiftMaker or
CustomRoles.Bomber or
CustomRoles.Nuker or
CustomRoles.Glitch or
CustomRoles.Magician or
CustomRoles.WeaponMaster or
CustomRoles.Enderman or
CustomRoles.Mycologist or
CustomRoles.Hookshot or
CustomRoles.Sprayer
=> true,
CustomRoles.Gaulois when Gaulois.UsePet.GetBool() => true,
CustomRoles.Aid when Aid.UsePet.GetBool() => true,
CustomRoles.Escort when Escort.UsePet.GetBool() => true,
CustomRoles.DonutDelivery when DonutDelivery.UsePet.GetBool() => true,
CustomRoles.Analyzer when Analyzer.UsePet.GetBool() => true,
CustomRoles.Jailor when Jailor.UsePet.GetBool() => true,
CustomRoles.Sheriff when Sheriff.UsePet.GetBool() => true,
CustomRoles.SwordsMan when SwordsMan.UsePet.GetBool() => true,
CustomRoles.Medic when Medic.UsePet.GetBool() => true,
CustomRoles.Monarch when Monarch.UsePet.GetBool() => true,
CustomRoles.CopyCat when CopyCat.UsePet.GetBool() => true,
CustomRoles.Farseer when Farseer.UsePet.GetBool() => true,
CustomRoles.Deputy when Deputy.UsePet.GetBool() => true,
CustomRoles.Admirer when Admirer.UsePet.GetBool() => true,
CustomRoles.Crusader when Crusader.UsePet.GetBool() => true,
CustomRoles.Witness when Options.WitnessUsePet.GetBool() => true,
CustomRoles.Gaulois when Gaulois.UsePet.GetBool() => true,
CustomRoles.Aid when Aid.UsePet.GetBool() => true,
CustomRoles.Escort when Escort.UsePet.GetBool() => true,
CustomRoles.DonutDelivery when DonutDelivery.UsePet.GetBool() => true,
CustomRoles.Analyzer when Analyzer.UsePet.GetBool() => true,
CustomRoles.Jailor when Jailor.UsePet.GetBool() => true,
CustomRoles.Sheriff when Sheriff.UsePet.GetBool() => true,
CustomRoles.SwordsMan when SwordsMan.UsePet.GetBool() => true,
CustomRoles.Medic when Medic.UsePet.GetBool() => true,
CustomRoles.Monarch when Monarch.UsePet.GetBool() => true,
CustomRoles.CopyCat when CopyCat.UsePet.GetBool() => true,
CustomRoles.Farseer when Farseer.UsePet.GetBool() => true,
CustomRoles.Deputy when Deputy.UsePet.GetBool() => true,
CustomRoles.Admirer when Admirer.UsePet.GetBool() => true,
CustomRoles.Crusader when Crusader.UsePet.GetBool() => true,
CustomRoles.Witness when Options.WitnessUsePet.GetBool() => true,
_ => false,
};
}
public static bool UsesPetInsteadOfKill(this CustomRoles role)
_ => false,
};
public static bool UsesPetInsteadOfKill(this CustomRoles role) => Options.UsePets.GetBool() && role switch
{
return Options.UsePets.GetBool() && role switch
{
CustomRoles.Gaulois when Gaulois.UsePet.GetBool() => true,
CustomRoles.Aid when Aid.UsePet.GetBool() => true,
CustomRoles.Escort when Escort.UsePet.GetBool() => true,
CustomRoles.DonutDelivery when DonutDelivery.UsePet.GetBool() => true,
CustomRoles.Analyzer when Analyzer.UsePet.GetBool() => true,
CustomRoles.Jailor when Jailor.UsePet.GetBool() => true,
CustomRoles.Sheriff when Sheriff.UsePet.GetBool() => true,
CustomRoles.SwordsMan when SwordsMan.UsePet.GetBool() => true,
CustomRoles.Medic when Medic.UsePet.GetBool() => true,
CustomRoles.Monarch when Monarch.UsePet.GetBool() => true,
CustomRoles.CopyCat when CopyCat.UsePet.GetBool() => true,
CustomRoles.Farseer when Farseer.UsePet.GetBool() => true,
CustomRoles.Deputy when Deputy.UsePet.GetBool() => true,
CustomRoles.Admirer when Admirer.UsePet.GetBool() => true,
CustomRoles.Crusader when Crusader.UsePet.GetBool() => true,
CustomRoles.Witness when Options.WitnessUsePet.GetBool() => true,
CustomRoles.Gaulois when Gaulois.UsePet.GetBool() => true,
CustomRoles.Aid when Aid.UsePet.GetBool() => true,
CustomRoles.Escort when Escort.UsePet.GetBool() => true,
CustomRoles.DonutDelivery when DonutDelivery.UsePet.GetBool() => true,
CustomRoles.Analyzer when Analyzer.UsePet.GetBool() => true,
CustomRoles.Jailor when Jailor.UsePet.GetBool() => true,
CustomRoles.Sheriff when Sheriff.UsePet.GetBool() => true,
CustomRoles.SwordsMan when SwordsMan.UsePet.GetBool() => true,
CustomRoles.Medic when Medic.UsePet.GetBool() => true,
CustomRoles.Monarch when Monarch.UsePet.GetBool() => true,
CustomRoles.CopyCat when CopyCat.UsePet.GetBool() => true,
CustomRoles.Farseer when Farseer.UsePet.GetBool() => true,
CustomRoles.Deputy when Deputy.UsePet.GetBool() => true,
CustomRoles.Admirer when Admirer.UsePet.GetBool() => true,
CustomRoles.Crusader when Crusader.UsePet.GetBool() => true,
CustomRoles.Witness when Options.WitnessUsePet.GetBool() => true,
_ => false,
};
}
public static bool NeedUpdateOnLights(this CustomRoles role)
{
return (!role.UsesPetInsteadOfKill()) && (role.GetDYRole() != RoleTypes.GuardianAngel || role is
_ => false,
};
public static List<CustomRoles> OnlySpawnsWithPetsRoleList = [
CustomRoles.Tunneler,
CustomRoles.Tornado
];
public static bool NeedUpdateOnLights(this CustomRoles role) => (!role.UsesPetInsteadOfKill()) && (role.GetDYRole() != RoleTypes.GuardianAngel || role is
CustomRoles.Sheriff or
CustomRoles.Medic or
CustomRoles.CopyCat or
@@ -1221,35 +1166,28 @@ internal static class CustomRolesHelper
CustomRoles.Bandit or
CustomRoles.Agitater or
CustomRoles.Deputy);
}
public static bool IsBetrayalAddon(this CustomRoles role)
{
return role is CustomRoles.Charmed or
CustomRoles.Recruit or
CustomRoles.Infected or
CustomRoles.Contagious or
CustomRoles.Lovers or
CustomRoles.Madmate or
CustomRoles.Soulless or
CustomRoles.Admired or
CustomRoles.Egoist;
}
public static bool IsBetrayalAddon(this CustomRoles role) => role is
CustomRoles.Charmed or
CustomRoles.Recruit or
CustomRoles.Infected or
CustomRoles.Contagious or
CustomRoles.Lovers or
CustomRoles.Madmate or
CustomRoles.Soulless or
CustomRoles.Admired or
CustomRoles.Egoist;
public static bool IsImpOnlyAddon(this CustomRoles role)
{
return role is CustomRoles.Mare or
CustomRoles.LastImpostor or
CustomRoles.Mare or
CustomRoles.Mimic or
CustomRoles.Damocles or
CustomRoles.DeadlyQuota or
CustomRoles.TicketsStealer or
CustomRoles.Swift;
}
public static bool IsTaskBasedCrewmate(this CustomRoles role)
{
return role is
public static bool IsImpOnlyAddon(this CustomRoles role) => role is
CustomRoles.Mare or
CustomRoles.LastImpostor or
CustomRoles.Mare or
CustomRoles.Mimic or
CustomRoles.Damocles or
CustomRoles.DeadlyQuota or
CustomRoles.TicketsStealer or
CustomRoles.Swift;
public static bool IsTaskBasedCrewmate(this CustomRoles role) => role is
CustomRoles.Snitch or
CustomRoles.Divinator or
CustomRoles.Marshall or
@@ -1259,154 +1197,147 @@ internal static class CustomRolesHelper
CustomRoles.Merchant or
CustomRoles.Mayor or
CustomRoles.Transporter;
}
public static bool IsNotKnightable(this CustomRoles role)
public static bool IsNotKnightable(this CustomRoles role) => role is
CustomRoles.Mayor or
CustomRoles.Vindicator or
CustomRoles.Dictator or
CustomRoles.Knighted or
CustomRoles.Glitch or
CustomRoles.Pickpocket or
CustomRoles.TicketsStealer;
public static bool CheckAddonConflictV2(CustomRoles addon, CustomRoles mainRole) => addon.IsAdditionRole() && mainRole is not CustomRoles.GuardianAngelTOHE and not CustomRoles.God and not CustomRoles.GM && addon is not CustomRoles.Lovers && addon switch
{
return role is
CustomRoles.Mayor or
CustomRoles.Vindicator or
CustomRoles.Dictator or
CustomRoles.Knighted or
CustomRoles.Glitch or
CustomRoles.Pickpocket or
CustomRoles.TicketsStealer;
}
public static bool CheckAddonConflictV2(CustomRoles addon, CustomRoles mainRole)
{
return addon.IsAdditionRole() && mainRole is not CustomRoles.GuardianAngelTOHE and not CustomRoles.God and not CustomRoles.GM && addon is not CustomRoles.Lovers && addon switch
{
CustomRoles.Lovers when mainRole is CustomRoles.RuthlessRomantic or CustomRoles.Romantic or CustomRoles.VengefulRomantic => false,
CustomRoles.Autopsy when mainRole is CustomRoles.Doctor or CustomRoles.Tracefinder or CustomRoles.Scientist or CustomRoles.ScientistTOHE or CustomRoles.Sunnyboy => false,
CustomRoles.Necroview when mainRole is CustomRoles.Doctor => false,
CustomRoles.Lazy when mainRole is CustomRoles.Speedrunner => false,
CustomRoles.Loyal when mainRole.IsCrewmate() && !Options.CrewCanBeLoyal.GetBool() => false,
CustomRoles.DualPersonality when mainRole.IsCrewmate() && !Options.CrewCanBeDualPersonality.GetBool() => false,
CustomRoles.Lazy when mainRole is CustomRoles.Needy or CustomRoles.Snitch or CustomRoles.Marshall or CustomRoles.Transporter or CustomRoles.Guardian => false,
CustomRoles.Ghoul when mainRole is CustomRoles.Needy or CustomRoles.Snitch or CustomRoles.Marshall or CustomRoles.Transporter or CustomRoles.Guardian => false,
CustomRoles.Egoist when mainRole.IsCrewmate() && !Options.CrewCanBeEgoist.GetBool() => false,
CustomRoles.Brakar when mainRole is CustomRoles.Dictator => false,
CustomRoles.Stressed when !mainRole.IsCrewmate() || mainRole.IsTasklessCrewmate() => false,
CustomRoles.Avanger when mainRole.IsImpostor() && !Options.ImpCanBeAvanger.GetBool() => false,
CustomRoles.Ghoul when mainRole.IsNeutral() || mainRole.IsImpostor() || mainRole.IsTasklessCrewmate() || mainRole.IsTaskBasedCrewmate() => false,
CustomRoles.Lazy when mainRole.IsNeutral() || mainRole.IsImpostor() || mainRole.IsTasklessCrewmate() && !Options.TasklessCrewCanBeLazy.GetBool() || mainRole.IsTaskBasedCrewmate() && !Options.TaskBasedCrewCanBeLazy.GetBool() => false,
CustomRoles.TicketsStealer or CustomRoles.Swift or CustomRoles.DeadlyQuota or CustomRoles.Damocles or CustomRoles.Mare when mainRole is CustomRoles.Bomber or CustomRoles.Nuker or CustomRoles.BoobyTrap or CustomRoles.Capitalism => false,
CustomRoles.TicketsStealer or CustomRoles.Mimic or CustomRoles.Swift or CustomRoles.DeadlyQuota or CustomRoles.Damocles or CustomRoles.Mare when !mainRole.IsImpostor() => false,
CustomRoles.Torch when !mainRole.IsCrewmate() || mainRole is CustomRoles.Bewilder or CustomRoles.Sunglasses or CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Bewilder when mainRole is CustomRoles.Torch or CustomRoles.GuardianAngelTOHE or CustomRoles.Sunglasses => false,
CustomRoles.Sunglasses when mainRole is CustomRoles.Torch or CustomRoles.GuardianAngelTOHE or CustomRoles.Bewilder => false,
CustomRoles.Guesser when mainRole.IsCrewmate() && (!Options.CrewCanBeGuesser.GetBool() || mainRole is CustomRoles.NiceGuesser) || mainRole.IsNeutral() && !Options.NeutralCanBeGuesser.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeGuesser.GetBool() || mainRole is CustomRoles.EvilGuesser or CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Madmate when mainRole is CustomRoles.Egoist or CustomRoles.Rascal => false,
CustomRoles.Oblivious when mainRole is CustomRoles.Detective or CustomRoles.Cleaner or CustomRoles.Medusa or CustomRoles.Mortician or CustomRoles.Mediumshiper or CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Youtuber when !mainRole.IsCrewmate() || mainRole is CustomRoles.Madmate or CustomRoles.Sheriff or CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Egoist when mainRole.IsImpostor() && !Options.ImpCanBeEgoist.GetBool() => false,
CustomRoles.Egoist when mainRole.IsNeutral() || mainRole is CustomRoles.Madmate => false,
CustomRoles.Damocles when mainRole is CustomRoles.Bomber or CustomRoles.Nuker or CustomRoles.SerialKiller or CustomRoles.Cantankerous => false,
CustomRoles.Necroview when mainRole is CustomRoles.Visionary => false,
CustomRoles.Ghoul when mainRole is CustomRoles.Lazy => false,
CustomRoles.Ghoul when mainRole is CustomRoles.Needy => false,
CustomRoles.Lazy when mainRole is CustomRoles.Ghoul => false,
CustomRoles.Mimic when mainRole is CustomRoles.Mafia => false,
CustomRoles.Rascal when !mainRole.IsCrewmate() => false,
CustomRoles.Needy when mainRole.IsAdditionRole() => false,
CustomRoles.TicketsStealer when mainRole is CustomRoles.Vindicator => false,
CustomRoles.Mare when mainRole is CustomRoles.Underdog => false,
CustomRoles.Mare when mainRole is CustomRoles.Inhibitor => false,
CustomRoles.Mare when mainRole is CustomRoles.Saboteur => false,
CustomRoles.Mare when mainRole is CustomRoles.Swift => false,
CustomRoles.Mare when mainRole is CustomRoles.Mafia => false,
CustomRoles.Mare when mainRole is CustomRoles.Sniper => false,
CustomRoles.Mare when mainRole is CustomRoles.FireWorks => false,
CustomRoles.Mare when mainRole is CustomRoles.Swooper => false,
CustomRoles.Mare when mainRole is CustomRoles.Vampire => false,
CustomRoles.Torch when mainRole is CustomRoles.Lighter => false,
CustomRoles.Torch when mainRole is CustomRoles.Ignitor => false,
CustomRoles.Bewilder when mainRole is CustomRoles.Lighter => false,
CustomRoles.Bewilder when mainRole is CustomRoles.Ignitor => false,
CustomRoles.Sunglasses when mainRole is CustomRoles.Lighter => false,
CustomRoles.Sunglasses when mainRole is CustomRoles.Ignitor => false,
CustomRoles.Bait when mainRole is CustomRoles.Demolitionist => false,
CustomRoles.Trapper when mainRole is CustomRoles.Demolitionist => false,
CustomRoles.Lovers when mainRole is CustomRoles.Romantic => false,
CustomRoles.Mare when mainRole is CustomRoles.LastImpostor => false,
CustomRoles.Swift when mainRole is CustomRoles.Mare => false,
CustomRoles.DualPersonality when !mainRole.IsImpostor() && !mainRole.IsCrewmate() || mainRole is CustomRoles.Madmate => false,
CustomRoles.DualPersonality when mainRole.IsImpostor() && !Options.ImpCanBeDualPersonality.GetBool() => false,
CustomRoles.Loyal when !mainRole.IsImpostor() && !mainRole.IsCrewmate() || mainRole is CustomRoles.Madmate => false,
CustomRoles.Loyal when mainRole.IsImpostor() && !Options.ImpCanBeLoyal.GetBool() => false,
CustomRoles.Seer when mainRole.IsCrewmate() && (!Options.CrewCanBeSeer.GetBool() || mainRole is CustomRoles.Mortician) || mainRole.IsNeutral() && !Options.NeutralCanBeSeer.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeSeer.GetBool() || mainRole is CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Bait when mainRole.IsCrewmate() && !Options.CrewCanBeBait.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeBait.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeBait.GetBool() => false,
CustomRoles.Bewilder when mainRole.IsCrewmate() && !Options.CrewCanBeBewilder.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeBewilder.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeBewilder.GetBool() => false,
CustomRoles.Sunglasses when mainRole.IsCrewmate() && !Options.CrewCanBeSunglasses.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeSunglasses.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeSunglasses.GetBool() => false,
CustomRoles.Autopsy when mainRole.IsCrewmate() && !Options.CrewCanBeAutopsy.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeAutopsy.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeAutopsy.GetBool() => false,
CustomRoles.Glow when mainRole.IsCrewmate() && !Options.CrewCanBeGlow.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeGlow.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeGlow.GetBool() => false,
CustomRoles.Trapper when mainRole.IsCrewmate() && !Options.CrewCanBeTrapper.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeTrapper.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeTrapper.GetBool() => false,
CustomRoles.Sidekick when mainRole is CustomRoles.Madmate => false,
CustomRoles.Onbound when mainRole is CustomRoles.SuperStar => false,
CustomRoles.Rascal when mainRole is CustomRoles.SuperStar or CustomRoles.Madmate => false,
CustomRoles.Madmate when mainRole is CustomRoles.SuperStar => false,
CustomRoles.Gravestone when mainRole is CustomRoles.SuperStar => false,
CustomRoles.Sidekick when mainRole.IsNeutral() && !Options.NeutralCanBeSidekick.GetBool() => false,
CustomRoles.Sidekick when mainRole.IsCrewmate() && !Options.CrewmateCanBeSidekick.GetBool() => false,
CustomRoles.Sidekick when mainRole.IsImpostor() && !Options.ImpostorCanBeSidekick.GetBool() => false,
CustomRoles.Sidekick when mainRole is CustomRoles.Jackal => false,
CustomRoles.Lucky when mainRole is CustomRoles.Guardian => false,
CustomRoles.Bait when mainRole is CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Bait when mainRole is CustomRoles.Trapper => false,
CustomRoles.Trapper when mainRole is CustomRoles.Bait => false,
CustomRoles.DualPersonality when mainRole is CustomRoles.Dictator => false,
CustomRoles.Swift when mainRole is CustomRoles.Swooper => false,
CustomRoles.Swift when mainRole is CustomRoles.Vampire => false,
CustomRoles.Swift when mainRole is CustomRoles.Scavenger => false,
CustomRoles.Swift when mainRole is CustomRoles.Puppeteer => false,
CustomRoles.Swift when mainRole is CustomRoles.Warlock => false,
CustomRoles.Swift when mainRole is CustomRoles.EvilDiviner => false,
CustomRoles.Swift when mainRole is CustomRoles.Witch => false,
CustomRoles.Swift when mainRole is CustomRoles.Mafia => false,
CustomRoles.Reach when mainRole is CustomRoles.Mafioso => false,
CustomRoles.Trapper when mainRole is CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Watcher when mainRole.IsCrewmate() && !Options.CrewCanBeWatcher.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeWatcher.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeWatcher.GetBool() => false,
CustomRoles.Diseased when mainRole.IsCrewmate() && !Options.CrewCanBeDiseased.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeDiseased.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeDiseased.GetBool() => false,
CustomRoles.Antidote when mainRole.IsCrewmate() && !Options.CrewCanBeAntidote.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeAntidote.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeAntidote.GetBool() => false,
CustomRoles.Diseased when mainRole is CustomRoles.Antidote => false,
CustomRoles.Antidote when mainRole is CustomRoles.Diseased => false,
CustomRoles.Necroview when mainRole.IsCrewmate() && !Options.CrewCanBeNecroview.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeNecroview.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeNecroview.GetBool() => false,
CustomRoles.Oblivious when mainRole.IsCrewmate() && !Options.CrewCanBeOblivious.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeOblivious.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeOblivious.GetBool() => false,
CustomRoles.Brakar when mainRole.IsCrewmate() && !Options.CrewCanBeTiebreaker.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeTiebreaker.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeTiebreaker.GetBool() => false,
CustomRoles.Guesser when mainRole.IsCrewmate() && !Options.CrewCanBeGuesser.GetBool() && mainRole is CustomRoles.NiceGuesser || mainRole.IsNeutral() && !Options.NeutralCanBeGuesser.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeGuesser.GetBool() && mainRole is CustomRoles.EvilGuesser => false,
CustomRoles.Onbound when mainRole.IsCrewmate() && !Options.CrewCanBeOnbound.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeOnbound.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeOnbound.GetBool() => false,
CustomRoles.Unreportable when mainRole.IsCrewmate() && !Options.CrewCanBeUnreportable.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeUnreportable.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeUnreportable.GetBool() => false,
CustomRoles.Lucky when mainRole.IsCrewmate() && !Options.CrewCanBeLucky.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeLucky.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeLucky.GetBool() => false,
CustomRoles.Unlucky when mainRole.IsCrewmate() && !Options.CrewCanBeUnlucky.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeUnlucky.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeUnlucky.GetBool() => false,
CustomRoles.Rogue when mainRole.IsCrewmate() && !Options.CrewCanBeRogue.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeRogue.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeRogue.GetBool() => false,
CustomRoles.Gravestone when mainRole.IsCrewmate() && !Options.CrewCanBeGravestone.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeGravestone.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeGravestone.GetBool() => false,
CustomRoles.Flashman when mainRole is CustomRoles.Swooper or CustomRoles.Wraith or CustomRoles.Chameleon or CustomRoles.Alchemist => false,
CustomRoles.Bait when mainRole is CustomRoles.Unreportable => false,
CustomRoles.Nimble when !mainRole.IsCrewmate() => false,
CustomRoles.Physicist when !mainRole.IsCrewmate() => false,
CustomRoles.Unreportable when mainRole is CustomRoles.Bait => false,
CustomRoles.Oblivious when mainRole is CustomRoles.Bloodhound => false,
CustomRoles.Oblivious when mainRole is CustomRoles.Vulture => false,
CustomRoles.Vulture when mainRole is CustomRoles.Oblivious => false,
CustomRoles.Guesser when mainRole is CustomRoles.CopyCat or CustomRoles.Doomsayer => false,
CustomRoles.CopyCat when mainRole is CustomRoles.Guesser => false,
CustomRoles.DoubleShot when mainRole is CustomRoles.CopyCat => false,
CustomRoles.CopyCat when mainRole is CustomRoles.DoubleShot => false,
CustomRoles.Brakar when mainRole is CustomRoles.Dictator => false,
CustomRoles.Lucky when mainRole is CustomRoles.Luckey => false,
CustomRoles.Unlucky when mainRole is CustomRoles.Luckey => false,
CustomRoles.Unlucky when mainRole is CustomRoles.Lucky => false,
CustomRoles.Lucky when mainRole is CustomRoles.Unlucky => false,
CustomRoles.Fool when mainRole.IsCrewmate() && !Options.CrewCanBeFool.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeFool.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeFool.GetBool() || mainRole is CustomRoles.SabotageMaster or CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Bloodhound when mainRole is CustomRoles.Oblivious => false,
CustomRoles.DoubleShot when mainRole.GetCustomRoleTypes() is CustomRoleTypes.Impostor && !Options.ImpCanBeDoubleShot.GetBool() || mainRole.GetCustomRoleTypes() is CustomRoleTypes.Crewmate && !Options.CrewCanBeDoubleShot.GetBool() || mainRole.GetCustomRoleTypes() is CustomRoleTypes.Neutral && !Options.NeutralCanBeDoubleShot.GetBool() => false,
CustomRoles.DoubleShot when mainRole is not CustomRoles.EvilGuesser && mainRole is not CustomRoles.NiceGuesser && !Options.GuesserMode.GetBool() => false,
CustomRoles.DoubleShot when Options.ImpCanBeDoubleShot.GetBool() && mainRole is not CustomRoles.Guesser && mainRole is not CustomRoles.EvilGuesser && mainRole.GetCustomRoleTypes() is CustomRoleTypes.Impostor && !Options.ImpostorsCanGuess.GetBool() => false,
CustomRoles.DoubleShot when Options.CrewCanBeDoubleShot.GetBool() && mainRole is not CustomRoles.Guesser && mainRole is not CustomRoles.NiceGuesser && mainRole.GetCustomRoleTypes() is CustomRoleTypes.Crewmate && !Options.CrewmatesCanGuess.GetBool() => false,
CustomRoles.DoubleShot when Options.NeutralCanBeDoubleShot.GetBool() && mainRole is not CustomRoles.Guesser && (mainRole.IsNonNK() && !Options.PassiveNeutralsCanGuess.GetBool() || mainRole.IsNK() && !Options.NeutralKillersCanGuess.GetBool()) => false,
_ => true
};
}
CustomRoles.Lovers when mainRole is CustomRoles.RuthlessRomantic or CustomRoles.Romantic or CustomRoles.VengefulRomantic => false,
CustomRoles.Autopsy when mainRole is CustomRoles.Doctor or CustomRoles.Tracefinder or CustomRoles.Scientist or CustomRoles.ScientistTOHE or CustomRoles.Sunnyboy => false,
CustomRoles.Necroview when mainRole is CustomRoles.Doctor => false,
CustomRoles.Lazy when mainRole is CustomRoles.Speedrunner => false,
CustomRoles.Loyal when mainRole.IsCrewmate() && !Options.CrewCanBeLoyal.GetBool() => false,
CustomRoles.DualPersonality when mainRole.IsCrewmate() && !Options.CrewCanBeDualPersonality.GetBool() => false,
CustomRoles.Lazy when mainRole is CustomRoles.Needy or CustomRoles.Snitch or CustomRoles.Marshall or CustomRoles.Transporter or CustomRoles.Guardian => false,
CustomRoles.Ghoul when mainRole is CustomRoles.Needy or CustomRoles.Snitch or CustomRoles.Marshall or CustomRoles.Transporter or CustomRoles.Guardian => false,
CustomRoles.Egoist when mainRole.IsCrewmate() && !Options.CrewCanBeEgoist.GetBool() => false,
CustomRoles.Brakar when mainRole is CustomRoles.Dictator => false,
CustomRoles.Stressed when !mainRole.IsCrewmate() || mainRole.IsTasklessCrewmate() => false,
CustomRoles.Avanger when mainRole.IsImpostor() && !Options.ImpCanBeAvanger.GetBool() => false,
CustomRoles.Ghoul when mainRole.IsNeutral() || mainRole.IsImpostor() || mainRole.IsTasklessCrewmate() || mainRole.IsTaskBasedCrewmate() => false,
CustomRoles.Lazy when mainRole.IsNeutral() || mainRole.IsImpostor() || mainRole.IsTasklessCrewmate() && !Options.TasklessCrewCanBeLazy.GetBool() || mainRole.IsTaskBasedCrewmate() && !Options.TaskBasedCrewCanBeLazy.GetBool() => false,
CustomRoles.TicketsStealer or CustomRoles.Swift or CustomRoles.DeadlyQuota or CustomRoles.Damocles or CustomRoles.Mare when mainRole is CustomRoles.Bomber or CustomRoles.Nuker or CustomRoles.BoobyTrap or CustomRoles.Capitalism => false,
CustomRoles.TicketsStealer or CustomRoles.Mimic or CustomRoles.Swift or CustomRoles.DeadlyQuota or CustomRoles.Damocles or CustomRoles.Mare when !mainRole.IsImpostor() => false,
CustomRoles.Torch when !mainRole.IsCrewmate() || mainRole is CustomRoles.Bewilder or CustomRoles.Sunglasses or CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Bewilder when mainRole is CustomRoles.Torch or CustomRoles.GuardianAngelTOHE or CustomRoles.Sunglasses => false,
CustomRoles.Sunglasses when mainRole is CustomRoles.Torch or CustomRoles.GuardianAngelTOHE or CustomRoles.Bewilder => false,
CustomRoles.Guesser when mainRole.IsCrewmate() && (!Options.CrewCanBeGuesser.GetBool() || mainRole is CustomRoles.NiceGuesser) || mainRole.IsNeutral() && !Options.NeutralCanBeGuesser.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeGuesser.GetBool() || mainRole is CustomRoles.EvilGuesser or CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Madmate when mainRole is CustomRoles.Egoist or CustomRoles.Rascal => false,
CustomRoles.Oblivious when mainRole is CustomRoles.Detective or CustomRoles.Cleaner or CustomRoles.Medusa or CustomRoles.Mortician or CustomRoles.Mediumshiper or CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Youtuber when !mainRole.IsCrewmate() || mainRole is CustomRoles.Madmate or CustomRoles.Sheriff or CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Egoist when mainRole.IsImpostor() && !Options.ImpCanBeEgoist.GetBool() => false,
CustomRoles.Egoist when mainRole.IsNeutral() || mainRole is CustomRoles.Madmate => false,
CustomRoles.Damocles when mainRole is CustomRoles.Bomber or CustomRoles.Nuker or CustomRoles.SerialKiller or CustomRoles.Cantankerous => false,
CustomRoles.Necroview when mainRole is CustomRoles.Visionary => false,
CustomRoles.Ghoul when mainRole is CustomRoles.Lazy => false,
CustomRoles.Ghoul when mainRole is CustomRoles.Needy => false,
CustomRoles.Lazy when mainRole is CustomRoles.Ghoul => false,
CustomRoles.Mimic when mainRole is CustomRoles.Mafia => false,
CustomRoles.Rascal when !mainRole.IsCrewmate() => false,
CustomRoles.Needy when mainRole.IsAdditionRole() => false,
CustomRoles.TicketsStealer when mainRole is CustomRoles.Vindicator => false,
CustomRoles.Mare when mainRole is CustomRoles.Underdog => false,
CustomRoles.Mare when mainRole is CustomRoles.Inhibitor => false,
CustomRoles.Mare when mainRole is CustomRoles.Saboteur => false,
CustomRoles.Mare when mainRole is CustomRoles.Swift => false,
CustomRoles.Mare when mainRole is CustomRoles.Mafia => false,
CustomRoles.Mare when mainRole is CustomRoles.Sniper => false,
CustomRoles.Mare when mainRole is CustomRoles.FireWorks => false,
CustomRoles.Mare when mainRole is CustomRoles.Swooper => false,
CustomRoles.Mare when mainRole is CustomRoles.Vampire => false,
CustomRoles.Torch when mainRole is CustomRoles.Lighter => false,
CustomRoles.Torch when mainRole is CustomRoles.Ignitor => false,
CustomRoles.Bewilder when mainRole is CustomRoles.Lighter => false,
CustomRoles.Bewilder when mainRole is CustomRoles.Ignitor => false,
CustomRoles.Sunglasses when mainRole is CustomRoles.Lighter => false,
CustomRoles.Sunglasses when mainRole is CustomRoles.Ignitor => false,
CustomRoles.Bait when mainRole is CustomRoles.Demolitionist => false,
CustomRoles.Trapper when mainRole is CustomRoles.Demolitionist => false,
CustomRoles.Lovers when mainRole is CustomRoles.Romantic => false,
CustomRoles.Mare when mainRole is CustomRoles.LastImpostor => false,
CustomRoles.Swift when mainRole is CustomRoles.Mare => false,
CustomRoles.DualPersonality when !mainRole.IsImpostor() && !mainRole.IsCrewmate() || mainRole is CustomRoles.Madmate => false,
CustomRoles.DualPersonality when mainRole.IsImpostor() && !Options.ImpCanBeDualPersonality.GetBool() => false,
CustomRoles.Loyal when !mainRole.IsImpostor() && !mainRole.IsCrewmate() || mainRole is CustomRoles.Madmate => false,
CustomRoles.Loyal when mainRole.IsImpostor() && !Options.ImpCanBeLoyal.GetBool() => false,
CustomRoles.Seer when mainRole.IsCrewmate() && (!Options.CrewCanBeSeer.GetBool() || mainRole is CustomRoles.Mortician) || mainRole.IsNeutral() && !Options.NeutralCanBeSeer.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeSeer.GetBool() || mainRole is CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Bait when mainRole.IsCrewmate() && !Options.CrewCanBeBait.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeBait.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeBait.GetBool() => false,
CustomRoles.Bewilder when mainRole.IsCrewmate() && !Options.CrewCanBeBewilder.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeBewilder.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeBewilder.GetBool() => false,
CustomRoles.Sunglasses when mainRole.IsCrewmate() && !Options.CrewCanBeSunglasses.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeSunglasses.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeSunglasses.GetBool() => false,
CustomRoles.Autopsy when mainRole.IsCrewmate() && !Options.CrewCanBeAutopsy.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeAutopsy.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeAutopsy.GetBool() => false,
CustomRoles.Glow when mainRole.IsCrewmate() && !Options.CrewCanBeGlow.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeGlow.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeGlow.GetBool() => false,
CustomRoles.Trapper when mainRole.IsCrewmate() && !Options.CrewCanBeTrapper.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeTrapper.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeTrapper.GetBool() => false,
CustomRoles.Sidekick when mainRole is CustomRoles.Madmate => false,
CustomRoles.Onbound when mainRole is CustomRoles.SuperStar => false,
CustomRoles.Rascal when mainRole is CustomRoles.SuperStar or CustomRoles.Madmate => false,
CustomRoles.Madmate when mainRole is CustomRoles.SuperStar => false,
CustomRoles.Gravestone when mainRole is CustomRoles.SuperStar => false,
CustomRoles.Sidekick when mainRole.IsNeutral() && !Options.NeutralCanBeSidekick.GetBool() => false,
CustomRoles.Sidekick when mainRole.IsCrewmate() && !Options.CrewmateCanBeSidekick.GetBool() => false,
CustomRoles.Sidekick when mainRole.IsImpostor() && !Options.ImpostorCanBeSidekick.GetBool() => false,
CustomRoles.Sidekick when mainRole is CustomRoles.Jackal => false,
CustomRoles.Lucky when mainRole is CustomRoles.Guardian => false,
CustomRoles.Bait when mainRole is CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Bait when mainRole is CustomRoles.Trapper => false,
CustomRoles.Trapper when mainRole is CustomRoles.Bait => false,
CustomRoles.DualPersonality when mainRole is CustomRoles.Dictator => false,
CustomRoles.Swift when mainRole is CustomRoles.Swooper => false,
CustomRoles.Swift when mainRole is CustomRoles.Vampire => false,
CustomRoles.Swift when mainRole is CustomRoles.Scavenger => false,
CustomRoles.Swift when mainRole is CustomRoles.Puppeteer => false,
CustomRoles.Swift when mainRole is CustomRoles.Warlock => false,
CustomRoles.Swift when mainRole is CustomRoles.EvilDiviner => false,
CustomRoles.Swift when mainRole is CustomRoles.Witch => false,
CustomRoles.Swift when mainRole is CustomRoles.Mafia => false,
CustomRoles.Reach when mainRole is CustomRoles.Mafioso => false,
CustomRoles.Trapper when mainRole is CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Watcher when mainRole.IsCrewmate() && !Options.CrewCanBeWatcher.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeWatcher.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeWatcher.GetBool() => false,
CustomRoles.Diseased when mainRole.IsCrewmate() && !Options.CrewCanBeDiseased.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeDiseased.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeDiseased.GetBool() => false,
CustomRoles.Antidote when mainRole.IsCrewmate() && !Options.CrewCanBeAntidote.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeAntidote.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeAntidote.GetBool() => false,
CustomRoles.Diseased when mainRole is CustomRoles.Antidote => false,
CustomRoles.Antidote when mainRole is CustomRoles.Diseased => false,
CustomRoles.Necroview when mainRole.IsCrewmate() && !Options.CrewCanBeNecroview.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeNecroview.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeNecroview.GetBool() => false,
CustomRoles.Oblivious when mainRole.IsCrewmate() && !Options.CrewCanBeOblivious.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeOblivious.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeOblivious.GetBool() => false,
CustomRoles.Brakar when mainRole.IsCrewmate() && !Options.CrewCanBeTiebreaker.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeTiebreaker.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeTiebreaker.GetBool() => false,
CustomRoles.Guesser when mainRole.IsCrewmate() && !Options.CrewCanBeGuesser.GetBool() && mainRole is CustomRoles.NiceGuesser || mainRole.IsNeutral() && !Options.NeutralCanBeGuesser.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeGuesser.GetBool() && mainRole is CustomRoles.EvilGuesser => false,
CustomRoles.Onbound when mainRole.IsCrewmate() && !Options.CrewCanBeOnbound.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeOnbound.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeOnbound.GetBool() => false,
CustomRoles.Unreportable when mainRole.IsCrewmate() && !Options.CrewCanBeUnreportable.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeUnreportable.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeUnreportable.GetBool() => false,
CustomRoles.Lucky when mainRole.IsCrewmate() && !Options.CrewCanBeLucky.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeLucky.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeLucky.GetBool() => false,
CustomRoles.Unlucky when mainRole.IsCrewmate() && !Options.CrewCanBeUnlucky.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeUnlucky.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeUnlucky.GetBool() => false,
CustomRoles.Rogue when mainRole.IsCrewmate() && !Options.CrewCanBeRogue.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeRogue.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeRogue.GetBool() => false,
CustomRoles.Gravestone when mainRole.IsCrewmate() && !Options.CrewCanBeGravestone.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeGravestone.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeGravestone.GetBool() => false,
CustomRoles.Flashman when mainRole is CustomRoles.Swooper or CustomRoles.Wraith or CustomRoles.Chameleon or CustomRoles.Alchemist => false,
CustomRoles.Bait when mainRole is CustomRoles.Unreportable => false,
CustomRoles.Nimble when !mainRole.IsCrewmate() => false,
CustomRoles.Physicist when !mainRole.IsCrewmate() => false,
CustomRoles.Unreportable when mainRole is CustomRoles.Bait => false,
CustomRoles.Oblivious when mainRole is CustomRoles.Bloodhound => false,
CustomRoles.Oblivious when mainRole is CustomRoles.Vulture => false,
CustomRoles.Vulture when mainRole is CustomRoles.Oblivious => false,
CustomRoles.Guesser when mainRole is CustomRoles.CopyCat or CustomRoles.Doomsayer => false,
CustomRoles.CopyCat when mainRole is CustomRoles.Guesser => false,
CustomRoles.DoubleShot when mainRole is CustomRoles.CopyCat => false,
CustomRoles.CopyCat when mainRole is CustomRoles.DoubleShot => false,
CustomRoles.Brakar when mainRole is CustomRoles.Dictator => false,
CustomRoles.Lucky when mainRole is CustomRoles.Luckey => false,
CustomRoles.Unlucky when mainRole is CustomRoles.Luckey => false,
CustomRoles.Unlucky when mainRole is CustomRoles.Lucky => false,
CustomRoles.Lucky when mainRole is CustomRoles.Unlucky => false,
CustomRoles.Fool when mainRole.IsCrewmate() && !Options.CrewCanBeFool.GetBool() || mainRole.IsNeutral() && !Options.NeutralCanBeFool.GetBool() || mainRole.IsImpostor() && !Options.ImpCanBeFool.GetBool() || mainRole is CustomRoles.SabotageMaster or CustomRoles.GuardianAngelTOHE => false,
CustomRoles.Bloodhound when mainRole is CustomRoles.Oblivious => false,
CustomRoles.DoubleShot when mainRole.GetCustomRoleTypes() is CustomRoleTypes.Impostor && !Options.ImpCanBeDoubleShot.GetBool() || mainRole.GetCustomRoleTypes() is CustomRoleTypes.Crewmate && !Options.CrewCanBeDoubleShot.GetBool() || mainRole.GetCustomRoleTypes() is CustomRoleTypes.Neutral && !Options.NeutralCanBeDoubleShot.GetBool() => false,
CustomRoles.DoubleShot when mainRole is not CustomRoles.EvilGuesser && mainRole is not CustomRoles.NiceGuesser && !Options.GuesserMode.GetBool() => false,
CustomRoles.DoubleShot when Options.ImpCanBeDoubleShot.GetBool() && mainRole is not CustomRoles.Guesser && mainRole is not CustomRoles.EvilGuesser && mainRole.GetCustomRoleTypes() is CustomRoleTypes.Impostor && !Options.ImpostorsCanGuess.GetBool() => false,
CustomRoles.DoubleShot when Options.CrewCanBeDoubleShot.GetBool() && mainRole is not CustomRoles.Guesser && mainRole is not CustomRoles.NiceGuesser && mainRole.GetCustomRoleTypes() is CustomRoleTypes.Crewmate && !Options.CrewmatesCanGuess.GetBool() => false,
CustomRoles.DoubleShot when Options.NeutralCanBeDoubleShot.GetBool() && mainRole is not CustomRoles.Guesser && (mainRole.IsNonNK() && !Options.PassiveNeutralsCanGuess.GetBool() || mainRole.IsNK() && !Options.NeutralKillersCanGuess.GetBool()) => false,
_ => true
};
public static bool CheckAddonConflict(CustomRoles role, PlayerControl pc)
{
if (!role.IsAdditionRole()) return false;
@@ -1632,16 +1563,13 @@ internal static class CustomRolesHelper
public static bool IsNeutralKillerTeam(this CustomRoles role) => role.IsNK() && !role.IsMadmate();
public static bool IsPassiveNeutralTeam(this CustomRoles role) => role.IsNonNK() && !role.IsMadmate();
public static bool IsNNK(this CustomRoles role) => role.IsNeutral() && !role.IsNK();
public static bool IsVanilla(this CustomRoles role)
{
return role is
public static bool IsVanilla(this CustomRoles role) => role is
CustomRoles.Crewmate or
CustomRoles.Engineer or
CustomRoles.Scientist or
CustomRoles.GuardianAngel or
CustomRoles.Impostor or
CustomRoles.Shapeshifter;
}
public static CustomRoleTypes GetCustomRoleTypes(this CustomRoles role)
{
CustomRoleTypes type = CustomRoleTypes.Crewmate;
+3 -1
View File
@@ -15,7 +15,7 @@ public class DevUser(string code = "", string color = "null", string tag = "null
public string UpName { get; set; } = upName;
public bool HasTag() => Tag != "null";
public string GetTag() => Color == "null" ? $"<size=1>{Tag}</size>\r\n" : $"<color={Color}><size=1>{(Tag == "#Dev" ? Translator.GetString("Developer") : Tag)}</size></color>\r\n";
public string GetTag() => Color == "null" ? $"<size=1.4>{Tag}</size>\r\n" : $"<color={Color}><size=1.4>{(Tag == "#Dev" ? Translator.GetString("Developer") : Tag)}</size></color>\r\n";
}
public static class DevManager
@@ -72,6 +72,8 @@ public static class DevManager
DevUserList.Add(new(code: "swiftlord#0872", color: "null", tag: "null", isUp: true, isDev: false, deBug: false, colorCmd: false, upName: "But What About"));
DevUserList.Add(new(code: "ovalinstep#2984", color: "null", tag: "null", isUp: true, isDev: false, deBug: false, colorCmd: false, upName: "Seleneous"));
DevUserList.Add(new(code: "innerruler#4140", color: "null", tag: "null", isUp: true, isDev: false, deBug: false, colorCmd: false, upName: "thewhiskas27"));
DevUserList.Add(new(code: "urbanecalf#4975", color: "#420773", tag: "Streamer", isUp: true, isDev: false, deBug: false, colorCmd: false, upName: "Gugutsik"));
DevUserList.Add(new(code: "crustzonal#9589", color: "null", tag: "null", isUp: true, isDev: false, deBug: false, colorCmd: false, upName: "aviiiv0102"));
// Sponsor
DevUserList.Add(new(code: "recentduct#6068", color: "#FF00FF", tag: "高冷男模法师", isUp: false, isDev: false, colorCmd: false, deBug: true, upName: null));
+12 -10
View File
@@ -213,7 +213,10 @@ static class ExtendedPlayerControl
Main.PlayerStates[pc.PlayerId].deathReason = deathReason;
Main.PlayerStates[pc.PlayerId].SetDead();
if (realKiller != null) pc.SetRealKiller(realKiller);
Medic.IsDead(pc);
if (realKiller != null && realKiller.Is(CustomRoles.Damocles)) Damocles.OnMurder(realKiller.PlayerId);
pc.Kill(pc);
}
@@ -624,8 +627,8 @@ static class ExtendedPlayerControl
CustomRoles.YinYanger => pc.IsAlive(),
CustomRoles.Librarian => pc.IsAlive() && Librarian.CanUseKillButton(pc),
CustomRoles.Cantankerous => pc.IsAlive() && Cantankerous.CanUseKillButton(pc.PlayerId),
CustomRoles.Inhibitor => !Utils.IsActive(SystemTypes.Electrical) && !Utils.IsActive(SystemTypes.Comms) && !Utils.IsActive(SystemTypes.MushroomMixupSabotage) && !Utils.IsActive(SystemTypes.Laboratory) && !Utils.IsActive(SystemTypes.LifeSupp) && !Utils.IsActive(SystemTypes.Reactor) && !Utils.IsActive(SystemTypes.HeliSabotage),
CustomRoles.Saboteur => Utils.IsActive(SystemTypes.Electrical) || Utils.IsActive(SystemTypes.Comms) || Utils.IsActive(SystemTypes.MushroomMixupSabotage) || Utils.IsActive(SystemTypes.Laboratory) || Utils.IsActive(SystemTypes.LifeSupp) || Utils.IsActive(SystemTypes.Reactor) || Utils.IsActive(SystemTypes.HeliSabotage),
CustomRoles.Inhibitor => !IsActive(SystemTypes.Electrical) && !IsActive(SystemTypes.Comms) && !IsActive(SystemTypes.MushroomMixupSabotage) && !IsActive(SystemTypes.Laboratory) && !IsActive(SystemTypes.LifeSupp) && !IsActive(SystemTypes.Reactor) && !IsActive(SystemTypes.HeliSabotage),
CustomRoles.Saboteur => IsActive(SystemTypes.Electrical) || IsActive(SystemTypes.Comms) || IsActive(SystemTypes.MushroomMixupSabotage) || IsActive(SystemTypes.Laboratory) || IsActive(SystemTypes.LifeSupp) || IsActive(SystemTypes.Reactor) || IsActive(SystemTypes.HeliSabotage),
CustomRoles.Sniper => Sniper.CanUseKillButton(pc),
CustomRoles.Sheriff => Sheriff.CanUseKillButton(pc.PlayerId),
CustomRoles.Crusader => Crusader.CanUseKillButton(pc.PlayerId),
@@ -1209,7 +1212,6 @@ static class ExtendedPlayerControl
case CustomRoles.Medusa:
Medusa.SetKillCooldown(player.PlayerId);
break;
case CustomRoles.Cleaner:
Main.AllPlayerKillCooldown[player.PlayerId] = Options.CleanerKillCooldown.GetFloat();
break;
@@ -1382,17 +1384,17 @@ static class ExtendedPlayerControl
return (pos, roomName);
}
public static void TP(this PlayerControl pc, PlayerControl target)
public static bool TP(this PlayerControl pc, PlayerControl target)
{
Utils.TP(pc.NetTransform, target.Pos());
return Utils.TP(pc.NetTransform, target.Pos());
}
public static void TP(this PlayerControl pc, Vector2 location)
public static bool TP(this PlayerControl pc, Vector2 location)
{
Utils.TP(pc.NetTransform, location);
return Utils.TP(pc.NetTransform, location);
}
public static void TPtoRndVent(this PlayerControl pc)
public static bool TPtoRndVent(this PlayerControl pc)
{
Utils.TPtoRndVent(pc.NetTransform);
return Utils.TPtoRndVent(pc.NetTransform);
}
public static void Kill(this PlayerControl killer, PlayerControl target)
{
@@ -1402,7 +1404,7 @@ static class ExtendedPlayerControl
if (target.GetTeam() is Team.Impostor or Team.Neutral) Stressed.OnNonCrewmateDead();
if (killer.Is(CustomRoles.Damocles)) Damocles.OnMurder();
if (killer.Is(CustomRoles.Damocles)) Damocles.OnMurder(killer.PlayerId);
else if (killer.Is(Team.Impostor)) Damocles.OnOtherImpostorMurder();
if (target.Is(Team.Impostor)) Damocles.OnImpostorDeath();
+2 -2
View File
@@ -1124,7 +1124,7 @@ public static class Options
NameDisplayAddons = BooleanOptionItem.Create(210, "NameDisplayAddons", true, TabGroup.Addons, false)
.SetGameMode(CustomGameMode.Standard)
.SetHeader(true);
NoLimitAddonsNumMax = IntegerOptionItem.Create(211, "NoLimitAddonsNumMax", new(1, 15, 1), 1, TabGroup.Addons, false)
NoLimitAddonsNumMax = IntegerOptionItem.Create(211, "NoLimitAddonsNumMax", new(1, 90, 1), 1, TabGroup.Addons, false)
.SetGameMode(CustomGameMode.Standard);
//==================================================================================================================================//
@@ -3705,7 +3705,7 @@ public static class Options
.SetHeader(true)
.SetGameMode(customGameMode) as StringOptionItem;
var countOption = IntegerOptionItem.Create(id + 1, "Maximum", new(1, canSetNum ? 10 : 1, 1), 1, tab, false)
var countOption = IntegerOptionItem.Create(id + 1, "Maximum", new(1, canSetNum ? 15 : 1, 1), 1, tab, false)
.SetParent(spawnOption)
.SetValueFormat(OptionFormat.Players)
.SetHidden(!canSetNum)
+2 -8
View File
@@ -6,14 +6,8 @@ public class StringOptionItem(int id, string name, int defaultValue, TabGroup ta
public IntegerValueRule Rule = (0, selections.Length - 1, 1);
public string[] Selections = selections;
public static StringOptionItem Create(
int id, string name, string[] selections, int defaultIndex, TabGroup tab, bool isSingleValue
)
{
return new StringOptionItem(
id, name, defaultIndex, tab, isSingleValue, selections
);
}
public static StringOptionItem Create(int id, string name, string[] selections, int defaultIndex, TabGroup tab, bool isSingleValue)
=> new(id, name, defaultIndex, tab, isSingleValue, selections);
// Getter
public override int GetInt() => Rule.GetValueByIndex(CurrentValue);
+8
View File
@@ -58,6 +58,8 @@ enum CustomRPC
//Roles
SetDrawPlayer,
SyncMycologist,
SyncBubble,
AddTornado,
RemoveTornado,
SyncSprayer,
@@ -585,6 +587,12 @@ internal class RPCHandlerPatch
case CustomRPC.SendFireWorksState:
FireWorks.ReceiveRPC(reader);
break;
case CustomRPC.SyncMycologist:
Mycologist.ReceiveRPC(reader);
break;
case CustomRPC.SyncBubble:
Bubble.ReceiveRPC(reader);
break;
case CustomRPC.SetCurrentDousingTarget:
byte arsonistId = reader.ReadByte();
byte dousingTargetId = reader.ReadByte();
+147 -47
View File
@@ -1,4 +1,3 @@
using Csv;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using System;
@@ -7,6 +6,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace TOHE;
@@ -17,55 +17,105 @@ public static class Translator
public const string LANGUAGE_FOLDER_NAME = "Language";
public static void Init()
{
Logger.Info("Loading language file...", "Translator");
Logger.Info("Loading Custom Translations...", "Translator");
LoadLangs();
Logger.Info("Language file loaded successfully", "Translator");
Logger.Info("Loaded Custom Translations", "Translator");
}
public static void LoadLangs()
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var stream = assembly.GetManifestResourceStream("TOHE.Resources.String.csv");
translateMaps = [];
try
{
// Get the directory containing the JSON files (e.g., TOHE.Resources.Lang)
string jsonDirectory = "TOHE.Resources.Lang";
// Get the assembly containing the resources
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
string[] jsonFileNames = GetJsonFileNames(assembly, jsonDirectory);
var options = new CsvOptions()
{
HeaderMode = HeaderMode.HeaderPresent,
AllowNewLineInEnclosedFieldValues = false,
};
foreach (var line in CsvReader.ReadFromStream(stream, options))
{
if (line.Values[0][0] == '#') continue;
try
translateMaps = [];
if (jsonFileNames.Length == 0)
{
Dictionary<int, string> dic = [];
for (int i = 1; i < line.ColumnCount; i++)
Logger.Warn("Json Translation files does not exist.", "Translator");
return;
}
foreach (string jsonFileName in jsonFileNames)
{
// Read the JSON file content
using Stream resourceStream = assembly.GetManifestResourceStream(jsonFileName);
if (resourceStream != null)
{
int id = int.Parse(line.Headers[i]);
dic[id] = line.Values[i].Replace("\\n", "\n").Replace("\\r", "\r");
using StreamReader reader = new(resourceStream);
string jsonContent = reader.ReadToEnd();
// Deserialize the JSON into a dictionary
Dictionary<string, string> jsonDictionary = JsonSerializer.Deserialize<Dictionary<string, string>>(jsonContent);
if (jsonDictionary.TryGetValue("LanguageID", out string languageIdObj) && int.TryParse(languageIdObj, out int languageId))
{
// Remove the "LanguageID" entry
jsonDictionary.Remove("LanguageID");
// Handle the rest of the data and merge it into the resulting translation map
MergeJsonIntoTranslationMap(translateMaps, languageId, jsonDictionary);
}
else
{
//Logger.Warn(jsonDictionary["HostText"], "Translator");
Logger.Warn($"Invalid JSON format in {jsonFileName}: Missing or invalid 'LanguageID' field.", "Translator");
}
}
if (!translateMaps.TryAdd(line.Values[0], dic))
Logger.Warn($"Duplicate in CSV file to be translated: line {line.Index} => \"{line.Values[0]}\"", "Translator");
}
catch (Exception ex)
// Convert the resulting translation map to JSON
string mergedJson = JsonSerializer.Serialize(translateMaps, new JsonSerializerOptions
{
Logger.Warn($"Translation file error: line {line.Index} => \"{line.Values[0]}\"", "Translator");
Logger.Warn(ex.ToString(), "Translator");
}
WriteIndented = true
});
}
catch (Exception ex)
{
Logger.Error($"Error: {ex}", "Translator");
}
// カスタム翻訳ファイルの読み込み
// Loading custom translation files
if (!Directory.Exists(LANGUAGE_FOLDER_NAME)) Directory.CreateDirectory(LANGUAGE_FOLDER_NAME);
// 翻訳テンプレートの作成
// Creating a translation template
CreateTemplateFile();
System.Collections.IList list = Enum.GetValues(typeof(SupportedLangs));
for (int i = 0; i < list.Count; i++)
foreach (var lang in EnumHelper.GetAllValues<SupportedLangs>())
{
object lang = list[i];
if (File.Exists(@$"./{LANGUAGE_FOLDER_NAME}/{lang}.dat"))
LoadCustomTranslation($"{lang}.dat", (SupportedLangs)lang);
{
UpdateCustomTranslation($"{lang}.dat", lang);
LoadCustomTranslation($"{lang}.dat", lang);
}
}
}
static void MergeJsonIntoTranslationMap(Dictionary<string, Dictionary<int, string>> translationMaps, int languageId, Dictionary<string, string> jsonDictionary)
{
foreach (var kvp in jsonDictionary)
{
string textString = kvp.Key;
if (kvp.Value is string translation)
{
// If the textString is not already in the translation map, add it
if (!translationMaps.ContainsKey(textString))
{
translationMaps[textString] = [];
}
// Add or update the translation for the current id and textString
translationMaps[textString][languageId] = translation.Replace("\\n", "\n").Replace("\\r", "\r");
}
}
}
// Function to get a list of JSON file names in a directory
static string[] GetJsonFileNames(System.Reflection.Assembly assembly, string directoryName)
{
string[] resourceNames = assembly.GetManifestResourceNames();
return resourceNames.Where(resourceName => resourceName.StartsWith(directoryName) && resourceName.EndsWith(".json")).ToArray();
}
public static string GetString(string s, Dictionary<string, string> replacementDic = null, bool console = false)
{
@@ -93,8 +143,8 @@ public static class Translator
}
if (!translateMaps.ContainsKey(str)) //translateMapsにない場合、StringNamesにあれば取得する
{
var stringNames = Enum.GetValues(typeof(StringNames)).Cast<StringNames>().Where(x => x.ToString() == str);
if (stringNames != null && stringNames.Any())
var stringNames = EnumHelper.GetAllValues<StringNames>().Where(x => x.ToString() == str).ToArray();
if (stringNames != null && stringNames.Length > 0)
res = GetString(stringNames.FirstOrDefault());
}
}
@@ -132,34 +182,84 @@ public static class Translator
return SupportedLangs.English;
}
}
static void UpdateCustomTranslation(string filename, SupportedLangs lang)
{
string path = @$"./{LANGUAGE_FOLDER_NAME}/{filename}";
if (File.Exists(path))
{
Logger.Info("Updating Custom Translations", "UpdateCustomTranslation");
try
{
List<string> textStrings = [];
using (StreamReader reader = new(path, Encoding.GetEncoding("UTF-8")))
{
string line;
while ((line = reader.ReadLine()) != null)
{
// Split the line by ':' to get the first part
string[] parts = line.Split(':');
// Check if there is at least one part before ':'
if (parts.Length >= 1)
{
// Trim any leading or trailing spaces and add it to the list
string textString = parts[0].Trim();
textStrings.Add(textString);
}
}
}
var sb = new StringBuilder();
foreach (var templateString in translateMaps.Keys)
{
if (!textStrings.Contains(templateString)) sb.Append($"{templateString}:\n");
}
using FileStream fileStream = new(path, FileMode.Append, FileAccess.Write);
using StreamWriter writer = new(fileStream);
writer.WriteLine(sb.ToString());
}
catch (Exception e)
{
Logger.Error("An error occurred: " + e.Message, "Translator");
}
}
}
public static void LoadCustomTranslation(string filename, SupportedLangs lang)
{
string path = @$"./{LANGUAGE_FOLDER_NAME}/{filename}";
if (File.Exists(path))
{
Logger.Info($"Loading custom translation file:{filename}", "LoadCustomTranslation");
using StreamReader sr = new(path, Encoding.GetEncoding("UTF-8"));
string text;
string[] tmp = [];
while ((text = sr.ReadLine()) != null)
Logger.Info($"Loading Custom Translation File:{filename}", "LoadCustomTranslation");
try
{
tmp = text.Split(":");
if (tmp.Length > 1 && tmp[1] != "")
using StreamReader sr = new(path, Encoding.GetEncoding("UTF-8"));
string text;
string[] tmp = [];
while ((text = sr.ReadLine()) != null)
{
try
tmp = text.Split(":");
if (tmp.Length > 1 && tmp[1] != "")
{
translateMaps[tmp[0]][(int)lang] = tmp.Skip(1).Join(delimiter: ":").Replace("\\n", "\n").Replace("\\r", "\r");
}
catch (KeyNotFoundException)
{
Logger.Warn($"Invalid key:{tmp[0]}", "LoadCustomTranslation");
try
{
translateMaps[tmp[0]][(int)lang] = tmp.Skip(1).Join(delimiter: ":").Replace("\\n", "\n").Replace("\\r", "\r");
}
catch (KeyNotFoundException)
{
Logger.Warn($"Invalid Key:{tmp[0]}", "LoadCustomTranslation");
}
}
}
}
catch (ObjectDisposedException) { }
catch (Exception e)
{
Logger.Error(e.ToString(), "Translator.LoadCustomTranslation");
}
}
else
{
Logger.Error($"Custom translation file not found:{filename}", "LoadCustomTranslation");
Logger.Error($"Custom Translation File Not Found:{filename}", "LoadCustomTranslation");
}
}
+18 -37
View File
@@ -79,13 +79,13 @@ public static class Utils
}
}
public static void TP(CustomNetworkTransform nt, Vector2 location)
public static bool TP(CustomNetworkTransform nt, Vector2 location)
{
var pc = nt.myPlayer;
if (pc.inVent || pc.inMovingPlat || !pc.IsAlive())
if (pc.inVent || pc.inMovingPlat || !pc.IsAlive() || pc.MyPhysics.Animations.IsPlayingAnyLadderAnimation() || pc.MyPhysics.Animations.IsPlayingEnterVentAnimation())
{
Logger.Warn($"Target ({pc.GetNameWithRole().RemoveHtmlTags()}) is in an un-teleportable state - Teleporting canceled", "TP");
return;
return false;
}
// Modded
@@ -98,15 +98,16 @@ public static class Utils
AmongUsClient.Instance.FinishRpcImmediately(messageWriter);
Logger.Info($"{pc.GetNameWithRole().RemoveHtmlTags()} => {location}", "TP");
return true;
}
public static void TPtoRndVent(CustomNetworkTransform nt)
public static bool TPtoRndVent(CustomNetworkTransform nt)
{
var vents = UnityEngine.Object.FindObjectsOfType<Vent>();
var vent = vents[IRandom.Instance.Next(0, vents.Count)];
Logger.Info($"{nt.myPlayer.GetNameWithRole().RemoveHtmlTags()} => {vent.transform.position} (vent)", "TP");
TP(nt, new Vector2(vent.transform.position.x, vent.transform.position.y + 0.3636f));
return TP(nt, new Vector2(vent.transform.position.x, vent.transform.position.y + 0.3636f));
}
public static ClientData GetClientById(int id)
{
@@ -382,32 +383,8 @@ public static class Utils
if (Options.NameDisplayAddons.GetBool() && !pure && self)
{
if (Options.AddBracketsToAddons.GetBool())
{
if (Options.ImpEgoistVisibalToAllies.GetBool())
{
foreach (var subRole in targetSubRoles.Where(x => x is not CustomRoles.LastImpostor and not CustomRoles.Madmate and not CustomRoles.Charmed and not CustomRoles.Recruit and not CustomRoles.Admired and not CustomRoles.Soulless and not CustomRoles.Lovers and not CustomRoles.Infected and not CustomRoles.Contagious))
RoleText = ColorString(GetRoleColor(subRole), GetString("PrefixB." + subRole.ToString())) + RoleText;
}
if (!Options.ImpEgoistVisibalToAllies.GetBool())
{
foreach (var subRole in targetSubRoles.Where(x => x is not CustomRoles.LastImpostor and not CustomRoles.Madmate and not CustomRoles.Charmed and not CustomRoles.Recruit and not CustomRoles.Admired and not CustomRoles.Soulless and not CustomRoles.Lovers and not CustomRoles.Infected and not CustomRoles.Contagious))
RoleText = ColorString(GetRoleColor(subRole), GetString("PrefixB." + subRole.ToString())) + RoleText;
}
}
else if (!Options.AddBracketsToAddons.GetBool())
{
if (Options.ImpEgoistVisibalToAllies.GetBool())
{
foreach (var subRole in targetSubRoles.Where(x => x is not CustomRoles.LastImpostor and not CustomRoles.Madmate and not CustomRoles.Charmed and not CustomRoles.Recruit and not CustomRoles.Admired and not CustomRoles.Soulless and not CustomRoles.Lovers and not CustomRoles.Infected and not CustomRoles.Contagious))
RoleText = ColorString(GetRoleColor(subRole), GetString("Prefix." + subRole.ToString())) + RoleText;
}
if (!Options.ImpEgoistVisibalToAllies.GetBool())
{
foreach (var subRole in targetSubRoles.Where(x => x is not CustomRoles.LastImpostor and not CustomRoles.Madmate and not CustomRoles.Charmed and not CustomRoles.Recruit and not CustomRoles.Admired and not CustomRoles.Soulless and not CustomRoles.Lovers and not CustomRoles.Infected and not CustomRoles.Contagious))
RoleText = ColorString(GetRoleColor(subRole), GetString("Prefix." + subRole.ToString())) + RoleText;
}
}
foreach (var subRole in targetSubRoles.Where(x => x is not CustomRoles.LastImpostor and not CustomRoles.Madmate and not CustomRoles.Charmed and not CustomRoles.Recruit and not CustomRoles.Admired and not CustomRoles.Soulless and not CustomRoles.Lovers and not CustomRoles.Infected and not CustomRoles.Contagious))
RoleText = ColorString(GetRoleColor(subRole), (Options.AddBracketsToAddons.GetBool() ? "<#ffffff>(</color>" : string.Empty) + GetString("Prefix." + subRole.ToString()) + (Options.AddBracketsToAddons.GetBool() ? "<#ffffff>)</color>" : string.Empty) + " ") + RoleText;
}
if (targetSubRoles.Contains(CustomRoles.Madmate))
@@ -1153,7 +1130,7 @@ public static class Utils
Logger.Error($"For {pc.GetNameWithRole().RemoveHtmlTags()}, failed to get progress text: " + ex.ToString(), "Utils.GetProgressText");
}
if (pc.Is(CustomRoles.Damocles)) ProgressText.Append(' ' + Damocles.GetProgressText());
if (pc.Is(CustomRoles.Damocles)) ProgressText.Append(' ' + Damocles.GetProgressText(playerId));
if (pc.Is(CustomRoles.Stressed)) ProgressText.Append(' ' + Stressed.GetProgressText(playerId));
if (ProgressText.Length != 0 && !ProgressText.ToString().StartsWith(' '))
@@ -1881,12 +1858,13 @@ public static class Utils
}
DevUser devUser = player.FriendCode.GetDevUser();
if (!name.Contains('\r') && devUser.HasTag())
bool isMod = ChatCommands.IsPlayerModerator(player.FriendCode);
if (!name.Contains('\r') && (devUser.HasTag() || isMod))
{
string tag = devUser.GetTag();
if (player.AmOwner || player.IsModClient())
name = tag + name;
else name = tag.Replace("\r\n", " - ") + name;
name = tag + (isMod ? ("<size=1.4>" + GetString("ModeratorTag") + "\r\n</size>") : string.Empty) + name;
else name = tag.Replace("\r\n", " - ") + (isMod ? ("<size=1.4>" + GetString("ModeratorTag") + " - </size>") : string.Empty) + name;
}
if (player.AmOwner)
@@ -1962,6 +1940,8 @@ public static class Utils
PlayerControl[] seerList = SpecifySeer != null ? ([SpecifySeer]) : Main.AllPlayerControls;
PlayerControl[] targetList = SpecifyTarget != null ? ([SpecifyTarget]) : Main.AllPlayerControls;
Logger.Info($" Seers: {string.Join(", ", seerList.Select(x => x.GetNameWithRole()))} Targets: {string.Join(", ", targetList.Select(x => x.GetNameWithRole()))}", "NR");
//seer: Players who can see changes made here
//target: Players subject to changes that seer can see
foreach (PlayerControl seer in seerList)
@@ -2214,7 +2194,6 @@ public static class Utils
if (target.PlayerId == seer.PlayerId) continue;
Logger.Info("NotifyRoles-Loop2-" + target.GetNameWithRole().RemoveHtmlTags() + ":START", "NotifyRoles");
if ((IsActive(SystemTypes.MushroomMixupSabotage) || MushroomMixup) && target.IsAlive() && !seer.Is(CustomRoleTypes.Impostor) && Main.ResetCamPlayerList.Contains(seer.PlayerId))
{
seer.RpcSetNamePrivate("<size=0%>", true, force: NoCache);
@@ -2490,6 +2469,7 @@ public static class Utils
TargetSuffix.Append(PlagueDoctor.GetLowerTextOthers(seer, target));
TargetSuffix.Append(Stealth.GetSuffix(seer, target));
TargetSuffix.Append(Bubble.GetEncasedPlayerSuffix(seer, target));
if (target.Is(CustomRoles.Librarian)) TargetSuffix.Append(Librarian.GetNameTextForSuffix(target.PlayerId));
@@ -2898,7 +2878,7 @@ public static class Utils
neutralnum++;
}
}
return (notify ? "<#777777>" : string.Empty) +
return (notify ? "<#777777>" : string.Empty) +
(impnum == 1 ? GetString("RemainingText.Prefix.SingleImp") : GetString("RemainingText.Prefix.PluralImp")) +
(notify ? " " : "\n") +
(notify ? "<#ffffff>" : "<b>") +
@@ -3057,4 +3037,5 @@ public static class Utils
public static int PlayersCount(CountTypes countTypes) => Main.PlayerStates.Values.Count(state => state.countTypes == countTypes);
public static int AlivePlayersCount(CountTypes countTypes) => Main.AllAlivePlayerControls.Count(pc => pc.Is(countTypes));
public static int IsOneAlive(CountTypes countTypes) => Main.AllAlivePlayerControls.Any(pc => pc.Is(countTypes)) ? 1 : 0;
public static bool IsNonHostModClient(this byte id) => id != 0 && Main.playerVersion.ContainsKey(id);
}
+46 -36
View File
@@ -20,15 +20,16 @@ namespace TOHE;
internal class ChatCommands
{
// Function to check if a player is a moderator
private static bool IsPlayerModerator(string friendCode)
public static bool IsPlayerModerator(string friendCode)
{
if (friendCode == "" || friendCode == string.Empty) return false;
if (friendCode == "" || friendCode == string.Empty || !Options.ApplyModeratorList.GetBool()) return false;
var friendCodesFilePath = @"./TOHE_DATA/Moderators.txt";
var friendCodes = File.ReadAllLines(friendCodesFilePath);
return friendCodes.Any(code => code.Contains(friendCode));
return friendCodes.Any(code => code.Contains(friendCode, StringComparison.CurrentCultureIgnoreCase));
}
public static List<string> ChatHistory = [];
public static Dictionary<byte, long> LastSentCommand = [];
public static bool Prefix(ChatController __instance)
{
@@ -75,7 +76,7 @@ internal class ChatCommands
switch (args[0])
{
case "/dump":
canceled = true;
//canceled = true;
Utils.DumpLog();
break;
case "/v":
@@ -321,6 +322,7 @@ internal class ChatCommands
Utils.SendMessage(args.Skip(1).Join(delimiter: " "), title: $"<color=#ff0000>{GetString("MessageFromTheHost")}</color>");
break;
case "/ban":
case "/kick":
canceled = true;
// Check if the kick command is enabled in the settings
@@ -365,7 +367,7 @@ internal class ChatCommands
}
// Kick the specified player
AmongUsClient.Instance.KickPlayer(kickedPlayer.GetClientId(), true);
AmongUsClient.Instance.KickPlayer(kickedPlayer.GetClientId(), args[0] == "/ban");
string kickedPlayerName = kickedPlayer.GetRealName();
string textToSend = $"{kickedPlayerName} {GetString("KickCommandKicked")}";
if (GameStates.IsInGame)
@@ -430,11 +432,11 @@ internal class ChatCommands
Utils.SendMessage(string.Format(GetString("Message.SetColor"), subArgs), localPlayerId);
break;
case "/quit":
case "/qt":
canceled = true;
Utils.SendMessage(GetString("Message.CanNotUseByHost"), localPlayerId);
break;
//case "/quit":
//case "/qt":
// canceled = true;
// Utils.SendMessage(GetString("Message.CanNotUseByHost"), localPlayerId);
// break;
case "/xf":
canceled = true;
@@ -817,7 +819,8 @@ internal class ChatCommands
if (isUp) return;
}
var sb = new StringBuilder();
_ = sb.Append($"{devMark}<b>{roleName}</b>{Utils.GetRoleMode(rl)}{GetString($"{rl}InfoLong")}");
var title = $"{devMark}<{Main.roleColors[rl]}>{roleName}</color> {Utils.GetRoleMode(rl)}";
_ = sb.Append($"{GetString($"{rl}InfoLong")}");
var settings = new StringBuilder();
if (Options.CustomRoleSpawnChances.ContainsKey(rl))
{
@@ -828,7 +831,7 @@ internal class ChatCommands
_ = sb.Clear().Append(txt);
}
Utils.SendMessage(text: "\n", sendTo: playerId, title: settings.ToString());
Utils.SendMessage(text: sb.ToString(), sendTo: playerId);
Utils.SendMessage(text: sb.ToString(), sendTo: playerId, title: title);
return;
}
}
@@ -840,6 +843,8 @@ internal class ChatCommands
{
canceled = false;
if (!AmongUsClient.Instance.AmHost) return;
long now = Utils.GetTimeStamp();
if (LastSentCommand.TryGetValue(player.PlayerId, out var ts) && ts + 2 >= now) { Logger.Warn("Command Ignored, it was sent too soon after their last command", "ReceiveChat"); return; }
if (player.PlayerId != 0) ChatManager.SendMessage(player, text);
if (text.StartsWith("\n")) text = text[1..];
//if (!text.StartsWith("/")) return;
@@ -847,22 +852,24 @@ internal class ChatCommands
string subArgs = string.Empty;
//if (text.Length >= 3) if (text[..2] == "/r" && text[..3] != "/rn") args[0] = "/r";
// if (SpamManager.CheckSpam(player, text)) return;
if (GuessManager.GuesserMsg(player, text)) { canceled = true; return; }
if (Judge.TrialMsg(player, text)) { canceled = true; return; }
if (NiceSwapper.SwapMsg(player, text)) { canceled = true; return; }
if (ParityCop.ParityCheckMsg(player, text)) { canceled = true; return; }
if (GuessManager.GuesserMsg(player, text)) { canceled = true; LastSentCommand[player.PlayerId] = now; return; }
if (Judge.TrialMsg(player, text)) { canceled = true; LastSentCommand[player.PlayerId] = now; return; }
if (NiceSwapper.SwapMsg(player, text)) { canceled = true; LastSentCommand[player.PlayerId] = now; return; }
if (ParityCop.ParityCheckMsg(player, text)) { canceled = true; LastSentCommand[player.PlayerId] = now; return; }
//if (Pirate.DuelCheckMsg(player, text)) { canceled = true; return; }
if (Councillor.MurderMsg(player, text)) { canceled = true; return; }
if (Mediumshiper.MsMsg(player, text)) return;
if (MafiaRevengeManager.MafiaMsgCheck(player, text)) return;
if (Councillor.MurderMsg(player, text)) { canceled = true; LastSentCommand[player.PlayerId] = now; return; }
if (Mediumshiper.MsMsg(player, text)) { LastSentCommand[player.PlayerId] = now; return; }
if (MafiaRevengeManager.MafiaMsgCheck(player, text)) { LastSentCommand[player.PlayerId] = now; return; }
//if (RetributionistRevengeManager.RetributionistMsgCheck(player, text)) return;
if (Blackmailer.ForBlackmailer.Contains(player.PlayerId) && player.IsAlive() && player.PlayerId != 0)
{
ChatManager.SendPreviousMessagesToAll();
ChatManager.cancel = false;
canceled = true;
LastSentCommand[player.PlayerId] = now;
return;
}
bool isCommand = true;
switch (args[0])
{
case "/l":
@@ -967,22 +974,22 @@ internal class ChatCommands
}
break;
case "/quit":
case "/qt":
subArgs = args.Length < 2 ? string.Empty : args[1];
var cid = player.PlayerId.ToString();
cid = cid.Length != 1 ? cid.Substring(1, 1) : cid;
if (subArgs.Equals(cid))
{
string name = player.GetRealName();
Utils.SendMessage(string.Format(GetString("Message.PlayerQuitForever"), name));
AmongUsClient.Instance.KickPlayer(player.GetClientId(), true);
}
else
{
Utils.SendMessage(string.Format(GetString("SureUse.quit"), cid), player.PlayerId);
}
break;
//case "/quit":
//case "/qt":
// subArgs = args.Length < 2 ? string.Empty : args[1];
// var cid = player.PlayerId.ToString();
// cid = cid.Length != 1 ? cid.Substring(1, 1) : cid;
// if (subArgs.Equals(cid))
// {
// string name = player.GetRealName();
// Utils.SendMessage(string.Format(GetString("Message.PlayerQuitForever"), name));
// AmongUsClient.Instance.KickPlayer(player.GetClientId(), true);
// }
// else
// {
// Utils.SendMessage(string.Format(GetString("SureUse.quit"), cid), player.PlayerId);
// }
// break;
case "/id":
if (Options.ApplyModeratorList.GetValue() == 0 || !IsPlayerModerator(player.FriendCode)) break;
@@ -994,6 +1001,7 @@ internal class ChatCommands
Utils.SendMessage(msgText, player.PlayerId);
break;
case "/ban":
case "/kick":
// Check if the kick command is enabled in the settings
if (Options.ApplyModeratorList.GetValue() == 0)
@@ -1037,7 +1045,7 @@ internal class ChatCommands
}
// Kick the specified player
AmongUsClient.Instance.KickPlayer(kickedPlayer.GetClientId(), true);
AmongUsClient.Instance.KickPlayer(kickedPlayer.GetClientId(), args[0] == "/ban");
string kickedPlayerName = kickedPlayer.GetRealName();
string textToSend = $"{kickedPlayerName} {GetString("KickCommandKicked")}";
if (GameStates.IsInGame)
@@ -1133,8 +1141,10 @@ internal class ChatCommands
}
default:
isCommand = false;
break;
}
if (isCommand) LastSentCommand[player.PlayerId] = now;
if (SpamManager.CheckSpam(player, text)) return;
}
}
+7 -6
View File
@@ -447,17 +447,18 @@ class GameEndChecker
foreach (PlayerControl x in Main.AllAlivePlayerControls)
{
if (x.GetCustomRole().IsImpostor() && x.Is(CustomRoles.DualPersonality)) Imp++;
if (x.GetCustomRole().IsCrewmate() && x.Is(CustomRoles.DualPersonality)) Crew++;
if (x.GetCustomRole().IsImpostor() && x.Is(CustomRoles.Admired) && x.Is(CustomRoles.DualPersonality)) Crew++;
if (x.GetCustomRole().IsNeutral() && x.Is(CustomRoles.Admired) && x.Is(CustomRoles.DualPersonality)) Crew++;
if (x.GetCustomRole().IsCrewmate() && x.Is(CustomRoles.Admired) && x.Is(CustomRoles.DualPersonality)) Crew++;
CustomRoles role = x.GetCustomRole();
if ((x.Is(CustomRoles.Madmate) && x.Is(CustomRoles.DualPersonality)) ||
(role.IsImpostor() && x.Is(CustomRoles.DualPersonality))) Imp++;
if (role.IsCrewmate() && x.Is(CustomRoles.DualPersonality)) Crew++;
if (role.IsImpostor() && x.Is(CustomRoles.Admired) && x.Is(CustomRoles.DualPersonality)) Crew++;
if (role.IsNeutral() && x.Is(CustomRoles.Admired) && x.Is(CustomRoles.DualPersonality)) Crew++;
if (role.IsCrewmate() && x.Is(CustomRoles.Admired) && x.Is(CustomRoles.DualPersonality)) Crew++;
if (x.Is(CustomRoles.Charmed) && x.Is(CustomRoles.DualPersonality)) roleCounts[(null, CustomWinner.Succubus)]++;
if (x.Is(CustomRoles.Sidekick) && x.Is(CustomRoles.DualPersonality)) roleCounts[(null, CustomWinner.Jackal)]++;
if (x.Is(CustomRoles.Recruit) && x.Is(CustomRoles.DualPersonality)) roleCounts[(null, CustomWinner.Jackal)]++;
if (x.Is(CustomRoles.Infected) && x.Is(CustomRoles.DualPersonality)) roleCounts[(null, CustomWinner.Infectious)]++;
if (x.Is(CustomRoles.Contagious) && x.Is(CustomRoles.DualPersonality)) roleCounts[(null, CustomWinner.Virus)]++;
if (x.Is(CustomRoles.Madmate) && x.Is(CustomRoles.DualPersonality)) Imp++;
}
int totalNKAlive = roleCounts.Values.Sum();
+3
View File
@@ -263,6 +263,9 @@ public class StringOptionEnablePatch
__instance.OnValueChanged = new Action<OptionBehaviour>((o) => { });
__instance.TitleText.text = option.GetName();
if (option.Id == Options.UsePets.Id) LoadLangs();
else if (!Options.UsePets.GetBool() && CustomRolesHelper.OnlySpawnsWithPetsRoleList.Any(role => role.ToString().Equals(option.GetName().RemoveHtmlTags())))
__instance.TitleText.text += GetString("RequiresPetIndicator");
__instance.Value = __instance.oldValue = option.CurrentValue;
__instance.ValueText.text = option.GetString();
+21 -4
View File
@@ -594,14 +594,22 @@ class HudManagerPatch
bool CanUseVent = (player.CanUseImpostorVentButton() || player.inVent || player.MyPhysics.Animations.IsPlayingEnterVentAnimation()) && GameStates.IsInTask;
__instance.ImpostorVentButton?.ToggleVisible(CanUseVent);
player.Data.Role.CanVent = CanUseVent;
if (player.PlayerId == 0 && player.inVent && GameStates.IsInTask)
var vents = Object.FindObjectsOfType<Vent>().ToArray();
if (player.PlayerId == 0 && player.inVent && GameStates.IsInTask) SetVentButtonEnabled(TryMoveToVentPatch.HostVentTarget);
else if (CanUseVent && vents.Any(vent => Vector2.Distance(new Vector2(vent.transform.position.x, vent.transform.position.y + 0.3636f), player.Pos()) < 0.4f))
{
Vent vent = vents.FirstOrDefault(vent => Vector2.Distance(new Vector2(vent.transform.position.x, vent.transform.position.y + 0.3636f), player.Pos()) < 0.4f);
SetVentButtonEnabled(vent);
}
void SetVentButtonEnabled(Vent target)
{
__instance.ImpostorVentButton.canInteract = true;
__instance.ImpostorVentButton.enabled = true;
__instance.ImpostorVentButton.isCoolingDown = false;
__instance.ImpostorVentButton.SetEnabled();
__instance.ImpostorVentButton.currentTarget = TryMoveToVentPatch.HostVentTarget;
__instance.ImpostorVentButton.SetTarget(TryMoveToVentPatch.HostVentTarget);
__instance.ImpostorVentButton.currentTarget = target;
__instance.ImpostorVentButton.SetTarget(target);
}
}
else
@@ -785,9 +793,18 @@ class VentButtonDoClickPatch
if (pc.inVent)
{
pc.MyPhysics.RpcExitVent(TryMoveToVentPatch.HostVentTarget.Id);
TryMoveToVentPatch.HostVentTarget.SetButtons(false);
return true;
}
if (!pc.Is(CustomRoles.Swooper) || !pc.Is(CustomRoles.Wraith) || !pc.Is(CustomRoles.Chameleon) || pc.inVent || __instance.currentTarget == null || !pc.CanMove || !__instance.isActiveAndEnabled) return true;
if (pc.inVent || !pc.CanMove) return true;
var vents = Object.FindObjectsOfType<Vent>().ToArray();
if (vents.Any(vent => Vector2.Distance(new Vector2(vent.transform.position.x, vent.transform.position.y + 0.3636f), pc.Pos()) < 0.4f))
{
Vent vent = vents.FirstOrDefault(vent => Vector2.Distance(new Vector2(vent.transform.position.x, vent.transform.position.y + 0.3636f), pc.Pos()) < 0.4f);
pc.MyPhysics.RpcEnterVent(vent.Id);
vent.SetButtons(true);
return false;
}
pc?.MyPhysics?.RpcEnterVent(__instance.currentTarget.Id);
return false;
}
+1 -1
View File
@@ -157,7 +157,7 @@ class SetEverythingUpPatch
var color = Main.roleColors[role];
var rolename = Utils.GetRoleName(role);
poolablePlayer.cosmetics.nameText.text += $"\n<color={color}>{rolename}</color>";
poolablePlayer.cosmetics.nameText.transform.localPosition = new Vector3(defaultPos.x, !lowered || role.IsImpostor() ? defaultPos.y - 0.6f : defaultPos.y - 1.4f, -15f);
poolablePlayer.cosmetics.nameText.transform.localPosition = new Vector3(defaultPos.x, !lowered || role.IsImpostorTeamV3() || role.IsNK() ? defaultPos.y - 0.6f : defaultPos.y - 1.4f, -15f);
}
}
}
+6
View File
@@ -96,6 +96,12 @@ class ExternalRpcPetPatch
Pelican.IsEaten(pc.PlayerId))
return;
if (Mastermind.ManipulatedPlayers.ContainsKey(pc.PlayerId))
{
var killTarget = SelectKillButtonTarget(pc);
if (killTarget != null) Mastermind.ForceKillForManipulatedPlayer(pc, killTarget);
}
if (pc.HasAbilityCD()) return;
PlayerControl[] AllAlivePlayers = Main.AllAlivePlayerControls;
+29 -23
View File
@@ -214,15 +214,14 @@ class CheckMurderPatch
//非自杀场景下才会触发
switch (killer.GetCustomRole())
{
//==========内鬼阵营==========//
case CustomRoles.BountyHunter: //必须在击杀发生前处理
case CustomRoles.BountyHunter:
BountyHunter.OnCheckMurder(killer, target);
break;
case CustomRoles.Reckless:
Reckless.OnCheckMurder(killer);
break;
case CustomRoles.YinYanger:
if (YinYanger.OnCheckMurder(killer, target)) return false;
if (!YinYanger.OnCheckMurder(killer, target)) return false;
break;
case CustomRoles.Magician:
Magician.OnCheckMurder(killer);
@@ -1395,7 +1394,7 @@ class ShapeshiftPatch
isSSneeded = false;
break;
case CustomRoles.Librarian:
if (shapeshifting) isSSneeded = Librarian.OnShapeshift(shapeshifter);
isSSneeded = Librarian.OnShapeshift(shapeshifter, shapeshifting);
break;
case CustomRoles.Warlock:
if (Main.CursedPlayers[shapeshifter.PlayerId] != null)//呪われた人がいるか確認
@@ -1939,7 +1938,7 @@ class ReportDeadBodyPatch
if (player.Is(CustomRoles.Damocles))
{
Damocles.OnReport();
Damocles.OnReport(player.PlayerId);
}
Damocles.OnMeetingStart();
@@ -1947,6 +1946,7 @@ class ReportDeadBodyPatch
{
Stressed.OnReport(player);
}
Stressed.OnMeetingStart();
if (Options.InhibitorCDAfterMeetings.GetFloat() != Options.InhibitorCD.GetFloat() || Options.SaboteurCD.GetFloat() != Options.SaboteurCDAfterMeetings.GetFloat())
{
@@ -2137,9 +2137,6 @@ class FixedUpdatePatch
case CustomRoles.BountyHunter:
BountyHunter.FixedUpdate(player);
break;
case CustomRoles.Tornado when !lowLoad:
Tornado.OnFixedUpdate(player);
break;
case CustomRoles.Glitch when !lowLoad:
Glitch.UpdateHackCooldown(player);
break;
@@ -2173,9 +2170,6 @@ class FixedUpdatePatch
case CustomRoles.Bubble when !lowLoad:
Bubble.OnFixedUpdate();
break;
case CustomRoles.Sprayer when !lowLoad:
Sprayer.OnFixedUpdate();
break;
case CustomRoles.Sentinel when !lowLoad:
Sentinel.OnFixedUpdate();
break;
@@ -2218,6 +2212,15 @@ class FixedUpdatePatch
PlagueBearer.playerIdList.Remove(playerId);
}
if (GameStates.IsInTask && player != null && player.IsAlive())
{
Druid.OnCheckPlayerPosition(player);
Sentinel.OnCheckPlayerPosition(player);
Tornado.OnCheckPlayerPosition(player);
BallLightning.OnCheckPlayerPosition(player);
Sprayer.OnCheckPlayerPosition(player);
}
if (!lowLoad && Main.PlayerStates.TryGetValue(playerId, out var playerState) && GameStates.IsInTask)
{
if (playerState.SubRoles.Contains(CustomRoles.Damocles))
@@ -2532,10 +2535,6 @@ class FixedUpdatePatch
Pelican.OnFixedUpdate();
break;
case CustomRoles.BallLightning:
BallLightning.OnFixedUpdate();
break;
case CustomRoles.Sapper:
Sapper.OnFixedUpdate(player);
break;
@@ -2936,6 +2935,7 @@ class FixedUpdatePatch
if (PlagueDoctor.IsEnable) Suffix.Append(PlagueDoctor.GetLowerTextOthers(seer, target));
if (Stealth.IsEnable) Suffix.Append(Stealth.GetSuffix(seer, target));
if (Tracker.IsEnable) Suffix.Append(Tracker.GetTrackerArrow(seer, target));
if (Bubble.IsEnable) Suffix.Append(Bubble.GetEncasedPlayerSuffix(seer, target));
if (Deathpact.IsEnable)
{
@@ -3034,6 +3034,10 @@ class FixedUpdatePatch
target.cosmetics.nameText.text = changeTo;
float offset = 0.2f;
if (NameNotifyManager.Notice.TryGetValue(seer.PlayerId, out var notify) && notify.TEXT.Contains('\n'))
{
offset += 0.1f;
}
if (Suffix.ToString() != string.Empty)
{
// If the name is on two lines, the job title text needs to be moved up.
@@ -3041,6 +3045,10 @@ class FixedUpdatePatch
offset += 0.15f;
target.cosmetics.nameText.text += "\r\n" + Suffix.ToString();
}
if (!seer.IsAlive())
{
offset += 0.1f;
}
if (isProgressTextLong)
{
offset += 0.3f;
@@ -3067,14 +3075,12 @@ class FixedUpdatePatch
{
foreach (PlayerControl loversPlayer in Main.LoversPlayers.ToArray())
{
if (!loversPlayer.Data.IsDead && loversPlayer.PlayerId != deathId)
continue;
if (!loversPlayer.Data.IsDead && loversPlayer.PlayerId != deathId) continue;
Main.isLoversDead = true;
for (int i1 = 0; i1 < Main.LoversPlayers.Count; i1++)
{
PlayerControl partnerPlayer = Main.LoversPlayers[i1];
if (loversPlayer.PlayerId == partnerPlayer.PlayerId)
continue;
if (loversPlayer.PlayerId == partnerPlayer.PlayerId) continue;
if (partnerPlayer.PlayerId != deathId && !partnerPlayer.Data.IsDead)
{
if (partnerPlayer.Is(CustomRoles.Lovers))
@@ -3125,7 +3131,7 @@ class TryMoveToVentPatch
{
if (__result && AmongUsClient.Instance.AmHost && PlayerControl.LocalPlayer.PlayerId == 0 && PlayerControl.LocalPlayer.inVent && (HostVentTarget.Equals(__instance) || HostVentTarget == __instance))
{
Logger.Info($"{__instance.name} => {otherVent.name}", "HostVentTarget");
Logger.Info($"(Move) {__instance.name} => {otherVent.name}", "HostVentTarget");
HostVentTarget = otherVent;
}
}
@@ -3139,7 +3145,7 @@ class ExitVentPatch
if (pc.PlayerId == 0)
{
Logger.Info(__instance.name, "HostVentTarget");
Logger.Info("(Exit) " + __instance.name, "HostVentTarget");
TryMoveToVentPatch.HostVentTarget = __instance;
}
@@ -3155,7 +3161,7 @@ class EnterVentPatch
if (pc.PlayerId == 0)
{
Logger.Info(__instance.name, "HostVentTarget");
Logger.Info("(Enter) " + __instance.name, "HostVentTarget");
TryMoveToVentPatch.HostVentTarget = __instance;
}
@@ -3226,7 +3232,7 @@ class EnterVentPatch
if (pc.Is(CustomRoles.Damocles))
{
Damocles.OnEnterVent(__instance.Id);
Damocles.OnEnterVent(pc.PlayerId, __instance.Id);
}
switch (pc.GetCustomRole())
+5 -3
View File
@@ -120,6 +120,9 @@ class RepairSystemPatch
case CustomRoles.Enderman:
Enderman.MarkPosition();
return false;
case CustomRoles.Hookshot:
Hookshot.ExecuteAction();
return false;
case CustomRoles.Mycologist when Mycologist.SpreadAction.GetValue() == 1 || (Mycologist.SpreadAction.GetValue() == 2 && !Options.UsePets.GetBool()):
Mycologist.SpreadSpores();
return false;
@@ -184,10 +187,9 @@ class RepairSystemPatch
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
break;
}
if (player.Is(CustomRoles.Damocles) && Damocles.countRepairSabotage) Damocles.OnRepairSabotage();
if (player.Is(CustomRoles.Damocles) && Damocles.countRepairSabotage) Damocles.OnRepairSabotage(player.PlayerId);
if (player.Is(CustomRoles.Stressed) && Stressed.countRepairSabotage) Stressed.OnRepairSabotage(player);
}
break;
}
@@ -197,7 +199,7 @@ class RepairSystemPatch
case SystemTypes.Laboratory:
case SystemTypes.HeliSabotage:
case SystemTypes.Electrical:
if (player.Is(CustomRoles.Damocles) && Damocles.countRepairSabotage) Damocles.OnRepairSabotage();
if (player.Is(CustomRoles.Damocles) && Damocles.countRepairSabotage) Damocles.OnRepairSabotage(player.PlayerId);
if (player.Is(CustomRoles.Stressed) && Stressed.countRepairSabotage) Stressed.OnRepairSabotage(player);
break;
}
File diff suppressed because it is too large. Load diff
-3976
View File
File diff suppressed because it is too large. Load diff
+9 -4
View File
@@ -103,10 +103,10 @@ namespace TOHE.Roles.AddOns.Crewmate
public static void Update(PlayerControl pc)
{
if (!LastUpdates.TryGetValue(pc.PlayerId, out var x) || x >= GetTimeStamp() || !Timers.ContainsKey(pc.PlayerId) || !IsEnable || !GameStates.IsInTask || !pc.IsAlive() || !pc.Is(CustomRoles.Stressed)) return;
if (!LastUpdates.TryGetValue(pc.PlayerId, out var x) || x >= GetTimeStamp() || !Timers.ContainsKey(pc.PlayerId) || !IsEnable || !GameStates.IsInTask || !pc.Is(CustomRoles.Stressed)) return;
LastUpdates[pc.PlayerId] = GetTimeStamp();
if (pc.GetPlayerTaskState().IsTaskFinished)
if (pc.GetPlayerTaskState().IsTaskFinished || !pc.IsAlive())
{
Main.PlayerStates[pc.PlayerId].RemoveSubRole(CustomRoles.Stressed);
Timers.Remove(pc.PlayerId);
@@ -121,7 +121,7 @@ namespace TOHE.Roles.AddOns.Crewmate
pc.Suicide();
}
if (pc.IsModClient() && pc.PlayerId != 0) SendRPC(pc.PlayerId, Timers[pc.PlayerId], LastUpdates[pc.PlayerId]);
if (pc.IsNonHostModClient()) SendRPC(pc.PlayerId, Timers[pc.PlayerId], LastUpdates[pc.PlayerId]);
if (!pc.IsModClient()) NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
}
@@ -154,7 +154,6 @@ namespace TOHE.Roles.AddOns.Crewmate
public static void AfterMeetingTasks()
{
if (!IsEnable) return;
AdjustTime(TimeAfterMeeting + 9);
countRepairSabotage = true;
}
@@ -188,6 +187,12 @@ namespace TOHE.Roles.AddOns.Crewmate
Timers[pc.PlayerId] += TimeAfterReport;
}
public static void OnMeetingStart()
{
if (!IsEnable) return;
AdjustTime(TimeAfterMeeting + 9);
}
public static string GetProgressText(byte playerId) => Timers.TryGetValue(playerId, out var x) ? string.Format(GetString("DamoclesTimeLeft"), x) : string.Empty;
private static void AdjustTime(int change)
+61 -39
View File
@@ -1,6 +1,7 @@
using Hazel;
using System;
using System.Collections.Generic;
using System.Linq;
using static TOHE.Options;
using static TOHE.Translator;
using static TOHE.Utils;
@@ -19,16 +20,16 @@ namespace TOHE.Roles.AddOns.Impostor
private static int TimeAfterMeeting;
private static int StartingTime;
public static int Timer;
public static Dictionary<byte, int> Timer;
public static long lastUpdate;
public static List<int> PreviouslyEnteredVents;
public static Dictionary<byte, long> lastUpdate;
public static Dictionary<byte, List<int>> PreviouslyEnteredVents;
public static bool countRepairSabotage;
public static void SetupCustomOption()
{
SetupAdtRoleOptions(Id, CustomRoles.Damocles, canSetNum: false);
SetupAdtRoleOptions(Id, CustomRoles.Damocles, canSetNum: true);
DamoclesExtraTimeAfterKill = IntegerOptionItem.Create(Id + 10, "DamoclesExtraTimeAfterKill", new(0, 60, 1), 30, TabGroup.Addons, false)
.SetParent(CustomRoleSpawnChances[CustomRoles.Damocles])
.SetValueFormat(OptionFormat.Seconds);
@@ -46,109 +47,130 @@ namespace TOHE.Roles.AddOns.Impostor
TimeAfterMeeting = DamoclesExtraTimeAfterMeeting.GetInt();
StartingTime = DamoclesStartingTime.GetInt();
Timer = StartingTime;
lastUpdate = GetTimeStamp() + 10;
Timer = [];
lastUpdate = [];
PreviouslyEnteredVents = [];
countRepairSabotage = true;
}
public static void Update(PlayerControl pc)
{
if (lastUpdate >= GetTimeStamp() || !GameStates.IsInTask || pc == null) return;
byte id = pc.PlayerId;
if (lastUpdate.TryGetValue(id, out var ts) && ts >= GetTimeStamp() || !GameStates.IsInTask || pc == null) return;
if (!pc.IsAlive())
{
Main.PlayerStates[pc.PlayerId].RemoveSubRole(CustomRoles.Damocles);
Main.PlayerStates[id].RemoveSubRole(CustomRoles.Damocles);
return;
}
lastUpdate = GetTimeStamp();
lastUpdate[id] = GetTimeStamp();
if (!Timer.ContainsKey(id)) Timer[id] = StartingTime + 8;
Timer--;
Timer[id]--;
if (Timer < 0)
if (Timer[id] < 0)
{
Timer = 0;
Timer[id] = 0;
pc.Suicide();
}
if (pc.IsNonHostModClient()) SendRPC();
NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
if (pc.IsNonHostModClient()) SendRPC(id);
if (!pc.IsModClient()) NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
}
public static void SendRPC()
public static void SendRPC(byte playerId)
{
if (!DoRPC) return;
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncDamoclesTimer, SendOption.Reliable, -1);
writer.Write(Timer);
writer.Write(lastUpdate.ToString());
writer.Write(PreviouslyEnteredVents.Count);
if (PreviouslyEnteredVents.Count > 0) foreach (var vent in PreviouslyEnteredVents.ToArray()) writer.Write(vent);
writer.Write(playerId);
writer.Write(Timer[playerId]);
writer.Write(lastUpdate[playerId].ToString());
writer.Write(PreviouslyEnteredVents[playerId].Count);
if (PreviouslyEnteredVents[playerId].Count > 0) foreach (var vent in PreviouslyEnteredVents[playerId].ToArray()) writer.Write(vent);
AmongUsClient.Instance.FinishRpcImmediately(writer);
}
public static void ReceiveRPC(MessageReader reader)
{
Timer = reader.ReadInt32();
lastUpdate = long.Parse(reader.ReadString());
byte playerId = reader.ReadByte();
Timer[playerId] = reader.ReadInt32();
lastUpdate[playerId] = long.Parse(reader.ReadString());
var elements = reader.ReadInt32();
if (elements > 0) for (int i = 0; i < elements; i++) PreviouslyEnteredVents.Add(reader.ReadInt32());
if (elements > 0) for (int i = 0; i < elements; i++) PreviouslyEnteredVents[playerId].Add(reader.ReadInt32());
}
public static void OnMurder()
public static void OnMurder(byte id)
{
Timer += TimeAfterKill;
Timer[id] += TimeAfterKill;
}
public static void OnOtherImpostorMurder()
{
Timer += 10;
AdjustTime(10);
}
public static void OnEnterVent(int ventId)
public static void OnEnterVent(byte id, int ventId)
{
if (PreviouslyEnteredVents.Contains(ventId)) return;
if (!PreviouslyEnteredVents.ContainsKey(id)) PreviouslyEnteredVents[id] = [];
if (PreviouslyEnteredVents[id].Contains(ventId)) return;
PreviouslyEnteredVents.Add(ventId);
Timer += 10;
PreviouslyEnteredVents[id].Add(ventId);
Timer[id] += 10;
}
public static void AfterMeetingTasks()
{
PreviouslyEnteredVents.Clear();
Timer += TimeAfterMeeting;
AdjustTime(TimeAfterMeeting);
countRepairSabotage = true;
}
public static void OnMeetingStart()
{
Timer += 9;
AdjustTime(9);
}
public static void OnCrewmateEjected()
{
Timer = (int)Math.Round(Timer * 1.3);
AdjustTimeByPercent(1.3);
}
public static void OnRepairSabotage()
public static void OnRepairSabotage(byte id)
{
Timer -= 15;
Timer[id] -= 15;
}
public static void OnImpostorDeath()
{
Timer -= 20;
AdjustTime(-20);
}
public static void OnReport()
public static void OnReport(byte id)
{
Timer = (int)Math.Round(Timer * 0.9);
Timer[id] = (int)Math.Round(Timer[id] * 0.9);
}
public static void OnImpostorEjected()
{
Timer = (int)Math.Round(Timer * 0.8);
AdjustTimeByPercent(0.8);
}
public static string GetProgressText() => string.Format(GetString("DamoclesTimeLeft"), Timer);
private static void AdjustTime(int change)
{
foreach (var item in Timer.Keys.ToArray())
{
Timer[item] += change;
}
}
private static void AdjustTimeByPercent(double percent)
{
foreach (var item in Timer.Keys.ToArray())
{
Timer[item] = (int)Math.Round(Timer[item] * percent);
}
}
public static string GetProgressText(byte id) => string.Format(GetString("DamoclesTimeLeft"), Timer.TryGetValue(id, out var time) ? time : StartingTime);
}
}
+30 -37
View File
@@ -169,52 +169,45 @@ namespace TOHE.Roles.Crewmate
SendRPCSyncAbilityUse(pc.PlayerId);
}
public static void OnCheckPlayerPosition(PlayerControl pc)
{
if (!IsEnable || !GameStates.IsInTask || Triggers.Count <= 0 || playerIdList.Contains(pc.PlayerId)) return;
foreach (var triggers in Triggers.ToArray()) // Check for all Druids' traps - Most likely just 1 loop
{
foreach (var trigger in triggers.Value.Where(trigger => Vector2.Distance(trigger.Key, pc.Pos()) <= 1.5f)) // Check for all traps of the current Druid - Most likely 0-3 loops
{
GetPlayerById(triggers.Key).Notify(string.Format(GetString("DruidTriggerTriggered"), GetFormattedRoomName(trigger.Value), GetFormattedVectorText(trigger.Key)));
Triggers[triggers.Key].Remove(trigger.Key);
SendRPCRemoveTrigger(triggers.Key, trigger.Key);
}
}
}
public static void OnFixedUpdate()
{
if (!IsEnable || !GameStates.IsInTask || Triggers.Count == 0 && TriggerDelays.Count == 0) return;
if (!IsEnable || !GameStates.IsInTask || TriggerDelays.Count <= 0) return;
long now = GetTimeStamp();
if (TriggerDelays.Count > 0)
foreach (var x in TriggerDelays.ToArray())
{
foreach (var x in TriggerDelays.ToArray())
var id = x.Key;
var pc = GetPlayerById(id);
if (pc == null) continue;
if (x.Value + TriggerPlaceDelay.GetInt() < now)
{
var id = x.Key;
var pc = GetPlayerById(id);
if (pc == null) continue;
if (x.Value + TriggerPlaceDelay.GetInt() < now)
{
TriggerDelays.Remove(id);
var (LOCATION, ROOM_NAME) = pc.GetPositionInfo();
if (!Triggers.ContainsKey(id)) Triggers.Add(id, []);
Triggers[id].TryAdd(LOCATION, ROOM_NAME);
SendRPCAddTrigger(id, LOCATION, ROOM_NAME);
continue;
}
var timeLeft = TriggerPlaceDelay.GetInt() - (now - x.Value);
if (lastUpdate < now) pc.Notify(string.Format(GetString("DruidTimeLeft"), timeLeft, 2f));
TriggerDelays.Remove(id);
var (LOCATION, ROOM_NAME) = pc.GetPositionInfo();
if (!Triggers.ContainsKey(id)) Triggers.Add(id, []);
Triggers[id].TryAdd(LOCATION, ROOM_NAME);
SendRPCAddTrigger(id, LOCATION, ROOM_NAME);
continue;
}
}
if (Triggers.Count > 0)
{
foreach (var pc in Main.AllAlivePlayerControls.Where(pc => !playerIdList.Contains(pc.PlayerId)).ToArray()) // Check for all alive players except Druids - Worst case scenario it's 14 loops
{
foreach (var triggers in Triggers.ToArray()) // Check for all Druids' traps - Most likely just 1 loop
{
foreach (var trigger in triggers.Value.ToArray()) // Check for all traps of the current Druid - Most likely 0-3 loops
{
if (Vector2.Distance(trigger.Key, pc.Pos()) <= 1.5f)
{
GetPlayerById(triggers.Key).Notify(string.Format(GetString("DruidTriggerTriggered"), GetFormattedRoomName(trigger.Value), GetFormattedVectorText(trigger.Key)));
Triggers[triggers.Key].Remove(trigger.Key);
SendRPCRemoveTrigger(triggers.Key, trigger.Key);
}
}
}
}
var timeLeft = TriggerPlaceDelay.GetInt() - (now - x.Value);
if (lastUpdate < now) pc.Notify(string.Format(GetString("DruidTimeLeft"), timeLeft, 2f));
}
lastUpdate = now;
+1 -1
View File
@@ -29,7 +29,7 @@ public static class Judge
public static void SetupCustomOption()
{
Options.SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Judge);
TrialLimitPerMeeting = IntegerOptionItem.Create(Id + 10, "TrialLimitPerMeeting", new(1, 10, 1), 1, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge])
TrialLimitPerMeeting = IntegerOptionItem.Create(Id + 10, "TrialLimitPerMeeting", new(1, 15, 1), 1, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge])
.SetValueFormat(OptionFormat.Times);
CanTrialMadmate = BooleanOptionItem.Create(Id + 12, "JudgeCanTrialMadmate", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]);
CanTrialCharmed = BooleanOptionItem.Create(Id + 16, "JudgeCanTrialCharmed", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]);
+5 -1
View File
@@ -24,6 +24,7 @@ public static class Medic
public static OptionItem GuesserIgnoreShield;
private static OptionItem AmountOfShields;
public static OptionItem UsePet;
public static OptionItem CD;
public static readonly string[] MedicWhoCanSeeProtectName =
[
@@ -67,6 +68,9 @@ public static class Medic
AmountOfShields = IntegerOptionItem.Create(Id + 34, "MedicAmountOfShields", new(1, 14, 1), 1, TabGroup.CrewmateRoles, false)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Medic]);
UsePet = Options.CreatePetUseSetting(Id + 36, CustomRoles.Medic);
CD = FloatOptionItem.Create(Id + 38, "AbilityCooldown", new(0f, 180f, 2.5f), 7.5f, TabGroup.CrewmateRoles, false)
.SetParent(Options.CustomRoleSpawnChances[CustomRoles.Medic])
.SetValueFormat(OptionFormat.Seconds);
}
public static void Init()
{
@@ -124,7 +128,7 @@ public static class Medic
public static bool CanUseKillButton(byte playerId)
=> !Main.PlayerStates[playerId].IsDead
&& (ProtectLimit.TryGetValue(playerId, out var x) ? x : 1) >= 1;
public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = CanUseKillButton(id) ? 5f : 300f;
public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = CanUseKillButton(id) ? CD.GetFloat() : 300f;
public static string GetSkillLimit(byte playerId) => Utils.ColorString(CanUseKillButton(playerId) ? Utils.GetRoleColor(CustomRoles.Medic).ShadeColor(0.25f) : Color.gray, ProtectLimit.TryGetValue(playerId, out var protectLimit) ? $"({protectLimit})" : "Invalid");
public static bool InProtect(byte id) => ProtectList.Contains(id) && Main.PlayerStates.TryGetValue(id, out var ps) && !ps.IsDead;
public static void OnCheckMurderFormedicaler(PlayerControl killer, PlayerControl target)
+28 -12
View File
@@ -49,22 +49,30 @@ namespace TOHE.Roles.Crewmate
FinishPatrolling();
return;
}
}
public void OnCheckPlayerPosition(PlayerControl pc)
{
if (!IsPatrolling) return;
long now = GetTimeStamp();
if (LastUpdate >= now) return;
LastUpdate = now;
var killers = NearbyKillers;
foreach (var pc in Main.AllAlivePlayerControls)
{
bool nowInRange = killers.Any(x => x.PlayerId == pc.PlayerId);
bool wasInRange = LastNearbyKillers.Contains(pc.PlayerId);
bool nowInRange = killers.Any(x => x.PlayerId == pc.PlayerId);
bool wasInRange = LastNearbyKillers.Contains(pc.PlayerId);
if (wasInRange && !nowInRange)
{
pc.Notify(GetString("KillerEscapedFromSentinel"));
}
if (nowInRange)
{
pc.Notify(string.Format(GetString("KillerNotifyPatrol"), PatrolDuration - (now - PatrolStartTimeStamp)));
}
if (wasInRange && !nowInRange)
{
pc.Notify(GetString("KillerEscapedFromSentinel"));
LastNearbyKillers.Remove(pc.PlayerId);
}
if (nowInRange)
{
pc.Notify(string.Format(GetString("KillerNotifyPatrol"), PatrolDuration - (GetTimeStamp() - PatrolStartTimeStamp)));
LastNearbyKillers.Add(pc.PlayerId);
}
}
@@ -171,5 +179,13 @@ namespace TOHE.Roles.Crewmate
state.Update();
}
}
public static void OnCheckPlayerPosition(PlayerControl pc)
{
if (!IsEnable) return;
foreach (PatrollingState state in PatrolStates)
{
state.OnCheckPlayerPosition(pc);
}
}
}
}
+6 -8
View File
@@ -104,7 +104,7 @@ namespace TOHE.Roles.Crewmate
Tornados.Add(info, now);
SendRPCAddTornado(info.LOCATION, info.ROOM_NAME, now);
}
public static void OnFixedUpdate(PlayerControl tornadoPc)
public static void OnCheckPlayerPosition(PlayerControl pc)
{
if (!IsEnable || !GameStates.IsInTask || Tornados.Count == 0) return;
@@ -114,10 +114,8 @@ namespace TOHE.Roles.Crewmate
var tornadoRange = TornadoRange.GetFloat();
var tornadoDuration = TornadoDuration.GetInt();
foreach (var pc in Main.AllAlivePlayerControls)
foreach (var tornadoPc in playerIdList.Select(x => GetPlayerById(x)).Where(x => x.PlayerId != pc.PlayerId).ToArray())
{
if (playerIdList.Contains(pc.PlayerId)) continue;
foreach (var tornado in Tornados)
{
if (Vector2.Distance(tornado.Key.LOCATION, pc.Pos()) <= tornadoRange)
@@ -139,11 +137,11 @@ namespace TOHE.Roles.Crewmate
SendRPCRemoveTornado(tornado.Key.LOCATION, tornado.Key.ROOM_NAME);
}
}
}
if (tornadoPc == null || LastNotify >= now || !tornadoPc.Is(CustomRoles.Tornado) || tornadoPc.HasAbilityCD()) return;
NotifyRoles(SpecifySeer: tornadoPc, SpecifyTarget: tornadoPc);
LastNotify = now;
if (tornadoPc == null || LastNotify >= now || !tornadoPc.Is(CustomRoles.Tornado) || tornadoPc.HasAbilityCD()) return;
NotifyRoles(SpecifySeer: tornadoPc, SpecifyTarget: tornadoPc);
LastNotify = now;
}
}
public static string GetSuffixText(byte playerId, bool isHUD = false) => string.Join(isHUD ? "\n" : ", ", Tornados.Select(x => $"Tornado {GetFormattedRoomName(x.Key.ROOM_NAME)} {GetFormattedVectorText(x.Key.LOCATION)} ({(int)(TornadoDuration.GetInt() - (GetTimeStamp() - x.Value) + 1)}s)"));
}
+2 -2
View File
@@ -103,7 +103,7 @@ public static class BallLightning
RealKiller.TryAdd(killer.PlayerId, target);
StartConvertCountDown(target, killer);
}
public static void OnFixedUpdate()
public static void OnCheckPlayerPosition(PlayerControl pc)
{
if (!IsEnable || !GameStates.IsInTask) return;
List<byte> deList = [];
@@ -115,7 +115,7 @@ public static class BallLightning
deList.Add(gs.PlayerId);
continue;
}
foreach (var pc in Main.AllAlivePlayerControls.Where(x => x.PlayerId != gs.PlayerId && x.IsAlive() && !x.Is(CustomRoles.BallLightning) && !IsGhost(x) && !Pelican.IsEaten(x.PlayerId)).ToArray())
if (pc.PlayerId != gs.PlayerId && pc.IsAlive() && !pc.Is(CustomRoles.BallLightning) && !IsGhost(pc) && !Pelican.IsEaten(pc.PlayerId))
{
var pos = gs.transform.position;
var dis = Vector2.Distance(pos, pc.Pos());
+1 -1
View File
@@ -29,7 +29,7 @@ public static class Councillor
Options.SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Councillor);
KillCooldown = FloatOptionItem.Create(Id + 15, "KillCooldown", new(0f, 180f, 2.5f), 25f, TabGroup.ImpostorRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Councillor])
.SetValueFormat(OptionFormat.Seconds);
MurderLimitPerMeeting = IntegerOptionItem.Create(Id + 10, "MurderLimitPerMeeting", new(0, 5, 1), 0, TabGroup.ImpostorRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Councillor])
MurderLimitPerMeeting = IntegerOptionItem.Create(Id + 10, "MurderLimitPerMeeting", new(0, 15, 1), 0, TabGroup.ImpostorRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Councillor])
.SetValueFormat(OptionFormat.Times);
// MurderLimitPerGame = IntegerOptionItem.Create(Id + 13, "MurderLimitPerGame", new(1, 99, 1), 2, TabGroup.ImpostorRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Councillor])
// .SetValueFormat(OptionFormat.Times);
+2 -2
View File
@@ -97,13 +97,13 @@ namespace TOHE.Roles.Impostor
{
DuelPair.Remove(pair.Key);
SendRPC(pair.Key, pair.Value, true);
_ = new LateTask(duellist.TPtoRndVent, 0.5f, log: false);
_ = new LateTask(() => { duellist.TPtoRndVent(); }, 0.5f, log: false);
}
else if (TAlive && !DAlive)
{
DuelPair.Remove(pair.Key);
SendRPC(pair.Key, pair.Value, true);
_ = new LateTask(target.TPtoRndVent, 0.5f, log: false);
_ = new LateTask(() => { target.TPtoRndVent(); }, 0.5f, log: false);
}
else continue;
}
+23 -20
View File
@@ -1,4 +1,5 @@
using System;
using MS.Internal.Xml.XPath;
using System;
using System.Collections.Generic;
using System.Linq;
using TOHE.Roles.Crewmate;
@@ -33,8 +34,8 @@ namespace TOHE.Roles.Impostor
public static OptionItem IgnorePestilence;
public static OptionItem PositiveEffectChance;
public static byte EffectID = byte.MaxValue;
public static bool isPositiveEffect;
public static Dictionary<byte, byte> EffectID = [];
public static Dictionary<byte, bool> isPositiveEffect = [];
public static Dictionary<byte, long> waitingDelayedKills = [];
public static Dictionary<byte, long> isShielded = [];
@@ -43,7 +44,7 @@ namespace TOHE.Roles.Impostor
public static void SetupCustomOption()
{
SetupSingleRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Gambler, 1);
SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Gambler);
KillCooldown = FloatOptionItem.Create(Id + 10, "KillCooldown", new(0f, 60f, 2.5f), 25f, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Gambler])
.SetValueFormat(OptionFormat.Seconds);
KillDelay = IntegerOptionItem.Create(Id + 11, "GamblerKillDelay", new(0, 10, 1), 3, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Gambler])
@@ -60,13 +61,13 @@ namespace TOHE.Roles.Impostor
.SetValueFormat(OptionFormat.Multiplier);
SpeedDur = IntegerOptionItem.Create(Id + 17, "GamblerSpeedupDur", new(1, 20, 1), 5, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Gambler])
.SetValueFormat(OptionFormat.Seconds);
BSRDelay = IntegerOptionItem.Create(Id + 18, "GamblerKillDelay", new(0, 10, 1), 2, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Gambler])
BSRDelay = IntegerOptionItem.Create(Id + 18, "GamblerBSRDelay", new(0, 10, 1), 2, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Gambler])
.SetValueFormat(OptionFormat.Seconds);
HighKCD = FloatOptionItem.Create(Id + 19, "GamblerHighKCD", new(10f, 60f, 2.5f), 30f, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Gambler])
.SetValueFormat(OptionFormat.Seconds);
LowKCD = FloatOptionItem.Create(Id + 20, "GamblerLowKCD", new(10f, 60f, 2.5f), 17.5f, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Gambler])
.SetValueFormat(OptionFormat.Seconds);
TPDelay = IntegerOptionItem.Create(Id + 21, "GamblerKillDelay", new(0, 10, 1), 2, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Gambler])
TPDelay = IntegerOptionItem.Create(Id + 21, "GamblerTPDelay", new(0, 10, 1), 2, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Gambler])
.SetValueFormat(OptionFormat.Seconds);
WhatToIgnore = BooleanOptionItem.Create(Id + 22, "GamblerWhatToIgnore", true, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Gambler]);
IgnoreMedicShield = BooleanOptionItem.Create(Id + 23, "GamblerIgnoreMedicShield", true, TabGroup.ImpostorRoles, false).SetParent(WhatToIgnore);
@@ -74,17 +75,18 @@ namespace TOHE.Roles.Impostor
IgnoreVeteranAlert = BooleanOptionItem.Create(Id + 25, "GamblerIgnoreVeteranAlert", false, TabGroup.ImpostorRoles, false).SetParent(WhatToIgnore);
IgnorePestilence = BooleanOptionItem.Create(Id + 26, "GamblerIgnorePestilence", false, TabGroup.ImpostorRoles, false).SetParent(WhatToIgnore);
PositiveEffectChance = IntegerOptionItem.Create(Id + 27, "GamblerPositiveEffectChance", new(0, 100, 5), 70, TabGroup.ImpostorRoles, false)
.SetParent(CustomRoleSpawnChances[CustomRoles.Gambler])
.SetValueFormat(OptionFormat.Percent);
.SetParent(CustomRoleSpawnChances[CustomRoles.Gambler])
.SetValueFormat(OptionFormat.Percent);
}
public static void Init()
{
playerIdList = [];
EffectID = byte.MaxValue;
EffectID = [];
waitingDelayedKills = [];
isSpeedChange = [];
isVisionChange = [];
isPositiveEffect = [];
}
public static void Add(byte playerId)
@@ -99,17 +101,17 @@ namespace TOHE.Roles.Impostor
if (killer == null) return false;
if (target == null) return false;
if (EffectID != byte.MaxValue)
if (EffectID.TryGetValue(killer.PlayerId, out var id) && id != byte.MaxValue)
{
return true;
}
var rd = IRandom.Instance;
isPositiveEffect = rd.Next(1, 101) <= PositiveEffectChance.GetInt();
if (isPositiveEffect)
isPositiveEffect[killer.PlayerId] = rd.Next(1, 101) <= PositiveEffectChance.GetInt();
if (isPositiveEffect[killer.PlayerId])
{
EffectID = (byte)rd.Next(1, 8);
switch (EffectID)
EffectID[killer.PlayerId] = (byte)rd.Next(1, 8);
switch (EffectID[killer.PlayerId])
{
case 1: // Delayed kill
killer.Notify(string.Format(GetString("GamblerGet.DelayedKill"), KillDelay.GetInt()));
@@ -153,7 +155,7 @@ namespace TOHE.Roles.Impostor
}
else
{
killer.Kill(target);
killer.RpcCheckAndMurder(target);
return false;
}
case 6: // Low KCD
@@ -176,8 +178,8 @@ namespace TOHE.Roles.Impostor
}
else
{
EffectID = (byte)rd.Next(1, 5);
switch (EffectID)
EffectID[killer.PlayerId] = (byte)rd.Next(1, 5);
switch (EffectID[killer.PlayerId])
{
case 1: // BSR
var delay = Math.Max(0.15f, BSRDelay.GetFloat());
@@ -211,7 +213,7 @@ namespace TOHE.Roles.Impostor
}
}
EffectID = byte.MaxValue;
EffectID[killer.PlayerId] = byte.MaxValue;
return true;
}
@@ -260,8 +262,9 @@ namespace TOHE.Roles.Impostor
public static void OnReportDeadBody()
{
EffectID = byte.MaxValue;
foreach (var playerId in waitingDelayedKills.Keys)
EffectID.Clear();
isPositiveEffect.Clear();
foreach (var playerId in waitingDelayedKills.Keys.ToArray())
{
var pc = GetPlayerById(playerId);
if (pc.IsAlive()) pc.Kill(pc);
+4 -7
View File
@@ -129,6 +129,7 @@ namespace TOHE.Roles.Impostor
if (librarian == null) return true;
reporter.SetRealKiller(librarian);
if (librarian.RpcCheckAndMurder(reporter))
{
sssh.Add(librarian.PlayerId);
@@ -143,7 +144,7 @@ namespace TOHE.Roles.Impostor
return false;
}
public static bool OnShapeshift(PlayerControl pc)
public static bool OnShapeshift(PlayerControl pc, bool shapeshifting)
{
if (!IsEnable) return false;
if (pc == null) return false;
@@ -153,7 +154,7 @@ namespace TOHE.Roles.Impostor
isInSilencingMode[id] = (!isInSilencingMode[id].SILENCING, GetTimeStamp());
SendRPC(id, isInSilencingMode[id].SILENCING);
return ShowSSAnimation.GetBool();
return !shapeshifting || ShowSSAnimation.GetBool();
}
public static void OnFixedUpdate()
@@ -179,13 +180,9 @@ namespace TOHE.Roles.Impostor
sssh.Clear();
}
public static string GetNameTextForSuffix(byte playerId)
{
if (!IsEnable) return string.Empty;
return isInSilencingMode.TryGetValue(playerId, out var x) && x.SILENCING && sssh.Contains(playerId) && GameStates.IsInTask
public static string GetNameTextForSuffix(byte playerId) => IsEnable && isInSilencingMode.TryGetValue(playerId, out var x) && x.SILENCING && sssh.Contains(playerId) && GameStates.IsInTask
? GetString("LibrarianNameText")
: string.Empty;
}
public static string GetSelfSuffixAndHUDText(byte playerId)
{
+9 -6
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using static TOHE.Options;
using static TOHE.Translator;
using static TOHE.Utils;
@@ -59,7 +60,7 @@ namespace TOHE.Roles.Impostor
return killer.CheckDoubleTrigger(target, () =>
{
killer.SetKillCooldown(time: ManipulateCD);
if (target.HasKillButton() || target.GetPlayerTaskState().hasTasks)
if (target.HasKillButton() || target.GetPlayerTaskState().hasTasks || UsePets.GetBool())
{
ManipulateDelays.TryAdd(target.PlayerId, GetTimeStamp());
NotifyRoles(SpecifySeer: killer, SpecifyTarget: target);
@@ -85,13 +86,13 @@ namespace TOHE.Roles.Impostor
ManipulateDelays.Remove(x.Key);
ManipulatedPlayers.TryAdd(x.Key, GetTimeStamp());
if (!pc.GetPlayerTaskState().hasTasks)
if (!pc.GetPlayerTaskState().hasTasks || UsePets.GetBool())
{
TempKCDs.TryAdd(pc.PlayerId, Main.KillTimers[pc.PlayerId]);
pc.SetKillCooldown(time: 1f);
}
NotifyRoles(SpecifySeer: Mastermind_, SpecifyTarget: Mastermind_);
NotifyRoles(SpecifySeer: Mastermind_, SpecifyTarget: pc);
}
}
@@ -115,7 +116,7 @@ namespace TOHE.Roles.Impostor
var time = TimeLimit.GetInt() - (GetTimeStamp() - x.Value);
player.Notify(string.Format(GetString(player.GetPlayerTaskState().hasTasks ? "ManipulateTaskNotify" : "ManipulateNotify"), time), 1.1f);
player.Notify(string.Format(GetString(UsePets.GetBool() ? "ManipulatePetNotify" : player.GetPlayerTaskState().hasTasks ? "ManipulateTaskNotify" : "ManipulateNotify"), time), 1.1f);
}
}
@@ -157,7 +158,9 @@ namespace TOHE.Roles.Impostor
_ = new LateTask(() =>
{
killer.SetKillCooldown(time: TempKCDs.TryGetValue(killer.PlayerId, out var cd) ? cd : 0f + Main.AllPlayerKillCooldown[killer.PlayerId]);
var kcd = TempKCDs.TryGetValue(killer.PlayerId, out var cd) ? cd : Main.AllPlayerKillCooldown.TryGetValue(killer.PlayerId, out var baseKCD) ? baseKCD : DefaultKillCooldown;
killer.SetKillCooldown(time: kcd);
if (killer.GetCustomRole().PetActivatedAbility()) killer.AddAbilityCD((int)Math.Round(kcd));
TempKCDs.Remove(killer.PlayerId);
}, 0.1f, "Set KCD for Manipulated Kill");
+1 -1
View File
@@ -70,7 +70,7 @@ namespace TOHE.Roles.Impostor
public static bool OnCheckMurder(PlayerControl killer, PlayerControl target)
{
if (!IsEnable) return false;
if (killer == null || target == null) return false;
if (killer == null || target == null || !killer.Is(CustomRoles.YinYanger)) return false;
if (YinYangedPlayers.Count == 2)
{
+58 -11
View File
@@ -1,6 +1,9 @@
using AmongUs.GameOptions;
using HarmonyLib;
using Hazel;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using static TOHE.Options;
using static TOHE.Utils;
@@ -61,10 +64,29 @@ namespace TOHE.Roles.Neutral
public static bool IsEnable => BubbleId != byte.MaxValue;
public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
public static void ApplyGameOptions(IGameOptions opt) => opt.SetVision(HasImpostorVision.GetBool());
private static void SendRPC(byte id = byte.MaxValue, bool remove = false, bool clear = false)
{
if (!IsEnable || !DoRPC) return;
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncBubble, SendOption.Reliable, -1);
writer.Write(remove);
writer.Write(clear);
writer.Write(id);
AmongUsClient.Instance.FinishRpcImmediately(writer);
}
public static void ReceiveRPC(MessageReader reader)
{
bool remove = reader.ReadBoolean();
bool clear = reader.ReadBoolean();
byte id = reader.ReadByte();
if (clear) EncasedPlayers.Clear();
else if (remove) EncasedPlayers.Remove(id);
else EncasedPlayers.Add(id, GetTimeStamp());
}
public static void OnCheckMurder(PlayerControl target)
{
if (!IsEnable || target == null) return;
EncasedPlayers.Add(target.PlayerId, GetTimeStamp());
SendRPC(target.PlayerId);
Bubble_.SetKillCooldown();
}
public static void OnFixedUpdate()
@@ -72,27 +94,52 @@ namespace TOHE.Roles.Neutral
if (!IsEnable || !GameStates.IsInTask || EncasedPlayers.Count == 0) return;
long now = GetTimeStamp();
foreach (var id in EncasedPlayers.Where(item => item.Value + ExplodeDelay.GetInt() < now).Select(item => item.Key).ToArray())
foreach (var kvp in EncasedPlayers)
{
var players = GetPlayersInRadius(ExplosionRadius.GetFloat(), GetPlayerById(id).Pos());
foreach (var pc in players)
var id = kvp.Key;
var encasedPc = GetPlayerById(id);
if (kvp.Value + ExplodeDelay.GetInt() < now)
{
if (pc == null) continue;
if (pc.PlayerId == BubbleId)
if (!encasedPc.IsAlive())
{
if (BubbleDiesIfInRange.GetBool()) _ = new LateTask(() => { if (GameStates.IsInTask) pc.Suicide(); }, 0.2f, log: false);
else continue;
EncasedPlayers.Remove(id);
SendRPC(id, remove: true);
continue;
}
pc.Suicide(realKiller: Bubble_);
var players = GetPlayersInRadius(ExplosionRadius.GetFloat(), encasedPc.Pos());
foreach (var pc in players)
{
if (pc == null) continue;
if (pc.PlayerId == BubbleId)
{
if (BubbleDiesIfInRange.GetBool()) _ = new LateTask(() => { if (GameStates.IsInTask) pc.Suicide(PlayerState.DeathReason.Bombed); }, 0.5f, log: false);
continue;
}
pc.Suicide(PlayerState.DeathReason.Bombed, Bubble_);
}
EncasedPlayers.Remove(id);
SendRPC(id, remove: true);
continue;
}
if (kvp.Value + NotifyDelay.GetInt() < now)
{
Main.AllAlivePlayerControls.Where(x => Vector2.Distance(x.Pos(), encasedPc.Pos()) < 5f).Do(x => NotifyRoles(SpecifySeer: x, SpecifyTarget: encasedPc));
}
EncasedPlayers.Remove(id);
}
}
public static void OnReportDeadBody()
{
if (IsEnable) return;
foreach (var pc in EncasedPlayers.Keys.Select(x => GetPlayerById(x)).Where(x => x != null && x.IsAlive())) pc.Suicide(realKiller: Bubble_);
if (!IsEnable) return;
foreach (var pc in EncasedPlayers.Keys.Select(x => GetPlayerById(x)).Where(x => x != null && x.IsAlive())) pc.Suicide(PlayerState.DeathReason.Bombed, Bubble_);
EncasedPlayers.Clear();
SendRPC(clear: true);
}
public static string GetEncasedPlayerSuffix(PlayerControl seer, PlayerControl target)
{
if (!IsEnable || target == null || !EncasedPlayers.TryGetValue(target.PlayerId, out var ts) || (ts + NotifyDelay.GetInt() >= GetTimeStamp())) return string.Empty;
return ColorString(GetRoleColor(CustomRoles.Bubble), $"{ExplodeDelay.GetInt() - (GetTimeStamp() - ts) + 1}s");
}
}
}
+22 -11
View File
@@ -51,9 +51,14 @@ namespace TOHE.Roles.Neutral
if (!IsEnable || !DoRPC) return;
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncHookshot, SendOption.Reliable, -1);
writer.Write(ToTargetTP);
writer.Write(MarkedPlayerId);
AmongUsClient.Instance.FinishRpcImmediately(writer);
}
public static void ReceiveRPC(MessageReader reader) => ToTargetTP = reader.ReadBoolean();
public static void ReceiveRPC(MessageReader reader)
{
ToTargetTP = reader.ReadBoolean();
MarkedPlayerId = reader.ReadByte();
}
public static void ExecuteAction()
{
if (MarkedPlayerId == byte.MaxValue) return;
@@ -62,19 +67,20 @@ namespace TOHE.Roles.Neutral
if (markedPlayer == null)
{
MarkedPlayerId = byte.MaxValue;
SendRPC();
return;
}
if (ToTargetTP)
{
Hookshot_.TP(markedPlayer);
}
else
{
markedPlayer.TP(Hookshot_);
}
bool isTPsuccess;
MarkedPlayerId = byte.MaxValue;
if (ToTargetTP) isTPsuccess = Hookshot_.TP(markedPlayer);
else isTPsuccess = markedPlayer.TP(Hookshot_);
if (isTPsuccess)
{
MarkedPlayerId = byte.MaxValue;
SendRPC();
}
}
public static void SwitchActionMode()
{
@@ -89,10 +95,15 @@ namespace TOHE.Roles.Neutral
return Hookshot_.CheckDoubleTrigger(target, () =>
{
MarkedPlayerId = target.PlayerId;
SendRPC();
Hookshot_.SetKillCooldown(5f);
});
}
public static void OnReportDeadBody() => MarkedPlayerId = byte.MaxValue;
public static void OnReportDeadBody()
{
MarkedPlayerId = byte.MaxValue;
SendRPC();
}
public static string SuffixText => $"<#00ffa5>Mode:</color> <#ffffff>{(ToTargetTP ? "TP to Target" : "Pull Target")}</color>";
}
}
+21 -1
View File
@@ -1,4 +1,5 @@
using AmongUs.GameOptions;
using Hazel;
using System.Collections.Generic;
using System.Linq;
using static TOHE.Options;
@@ -45,7 +46,7 @@ namespace TOHE.Roles.Neutral
InfectRadius = FloatOptionItem.Create(Id + 5, "InfectRadius", new(0.1f, 5f, 0.1f), 3f, TabGroup.NeutralRoles, false)
.SetParent(CustomRoleSpawnChances[CustomRoles.Mycologist])
.SetValueFormat(OptionFormat.Multiplier);
InfectTime = IntegerOptionItem.Create(Id + 6, "PlagueDoctorInfectTime", new(0, 60, 1), 5, TabGroup.NeutralRoles, false)
InfectTime = IntegerOptionItem.Create(Id + 6, "InfectDelay", new(0, 60, 1), 5, TabGroup.NeutralRoles, false)
.SetParent(CustomRoleSpawnChances[CustomRoles.Mycologist])
.SetValueFormat(OptionFormat.Seconds);
}
@@ -65,6 +66,23 @@ namespace TOHE.Roles.Neutral
public static bool IsEnable => MycologistId != byte.MaxValue;
public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
public static void ApplyGameOptions(IGameOptions opt) => opt.SetVision(HasImpostorVision.GetBool());
private static void SendRPC()
{
if (!IsEnable || !DoRPC) return;
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncMycologist, SendOption.Reliable, -1);
writer.Write(InfectedPlayers.Count);
if (InfectedPlayers.Count > 0) foreach (var x in InfectedPlayers) writer.Write(x);
AmongUsClient.Instance.FinishRpcImmediately(writer);
}
public static void ReceiveRPC(MessageReader reader)
{
InfectedPlayers.Clear();
var length = reader.ReadInt32();
for (int i = 0; i < length; i++)
{
InfectedPlayers.Add(reader.ReadByte());
}
}
public static void SpreadSpores()
{
if (!IsEnable || Mycologist_.HasAbilityCD()) return;
@@ -72,6 +90,8 @@ namespace TOHE.Roles.Neutral
_ = new LateTask(() =>
{
InfectedPlayers.AddRange(GetPlayersInRadius(InfectRadius.GetFloat(), Mycologist_.Pos()).Select(x => x.PlayerId));
SendRPC();
NotifyRoles(SpecifySeer: Mycologist_);
}, InfectTime.GetFloat(), "Mycologist Infect Time");
Mycologist_.Notify(GetString("MycologistNotify"));
}
+31 -30
View File
@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using UnityEngine;
using static TOHE.Options;
using static TOHE.Translator;
using static TOHE.Utils;
namespace TOHE.Roles.Neutral
@@ -93,56 +94,56 @@ namespace TOHE.Roles.Neutral
public static void ReceiveRPC(MessageReader reader) => UseLimit = reader.ReadInt32();
public static void PlaceTrap()
{
if (!IsEnable || Sprayer_.HasAbilityCD() || UseLimit <= 0) return;
if (!IsEnable || UseLimit <= 0 || Sprayer_.HasAbilityCD()) return;
Traps.Add(Sprayer_.Pos());
UseLimit--;
SendRPC();
if (UseLimit > 0) Sprayer_.AddAbilityCD(CD.GetInt());
Sprayer_.Notify(GetString("SprayerNotify"));
}
public static void OnFixedUpdate()
public static void OnCheckPlayerPosition(PlayerControl pc)
{
if (!IsEnable || !GameStates.IsInTask || Traps.Count == 0) return;
long now = GetTimeStamp();
foreach (var pc in Main.AllAlivePlayerControls)
if (pc.PlayerId == SprayerId) return;
if (!LastUpdate.ContainsKey(pc.PlayerId)) LastUpdate.Add(pc.PlayerId, now);
if (LastUpdate[pc.PlayerId] + 3 > now) return;
LastUpdate[pc.PlayerId] = now;
foreach (var trap in Traps.ToArray())
{
if (pc.PlayerId == SprayerId) continue;
if (!LastUpdate.ContainsKey(pc.PlayerId)) LastUpdate.Add(pc.PlayerId, now);
if (LastUpdate[pc.PlayerId] + 3 > now) continue;
LastUpdate[pc.PlayerId] = now;
foreach (var trap in Traps.ToArray())
if (Vector2.Distance(pc.Pos(), trap) <= 2f)
{
if (Vector2.Distance(pc.Pos(), trap) <= 2f)
byte playerId = pc.PlayerId;
var tempSpeed = Main.AllPlayerSpeed[playerId];
Main.AllPlayerSpeed[playerId] = LoweredSpeed.GetFloat();
LowerVisionList.Add(playerId);
TrappedCount[playerId]++;
if (TrappedCount[playerId] > MaxTrappedTimes.GetInt())
{
byte playerId = pc.PlayerId;
var tempSpeed = Main.AllPlayerSpeed[playerId];
Main.AllPlayerSpeed[playerId] = LoweredSpeed.GetFloat();
LowerVisionList.Add(playerId);
TrappedCount[playerId]++;
if (TrappedCount[playerId] > MaxTrappedTimes.GetInt())
pc.Suicide(realKiller: Sprayer_);
TrappedCount.Remove(playerId);
}
else
{
pc.MarkDirtySettings();
_ = new LateTask(() =>
{
pc.Suicide(realKiller: Sprayer_);
TrappedCount.Remove(playerId);
}
else
{
pc.MarkDirtySettings();
_ = new LateTask(() =>
{
Main.AllPlayerSpeed[playerId] = tempSpeed;
LowerVisionList.Remove(playerId);
if (GameStates.IsInTask) pc.MarkDirtySettings();
}, EffectDuration.GetFloat(), "Sprayer Revert Effects");
}
Main.AllPlayerSpeed[playerId] = tempSpeed;
LowerVisionList.Remove(playerId);
if (GameStates.IsInTask) pc.MarkDirtySettings();
}, EffectDuration.GetFloat(), "Sprayer Revert Effects");
}
}
}
}
public static void OnReportDeadBody()
{
Traps.Clear();
+1 -1
View File
@@ -92,7 +92,7 @@ public static class Vengeance
if (target == null) return false;
if (IsRevenge) return true;
_ = new LateTask(target.TPtoRndVent, 0.01f);
_ = new LateTask(() => { target.TPtoRndVent(); }, 0.01f);
Timer = RevengeTime.GetInt();
Countdown(Timer, target);
+3 -2
View File
@@ -7,7 +7,7 @@
<Description>TOHE+</Description>
<Authors>Gurge44</Authors>
<langVersion>preview</langVersion>
<AmongUs>D:\Epic Games\AmongUs</AmongUs>
<AmongUs>E:\Program Files\AmongUs</AmongUs>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>True</Optimize>
<AssemblyName>$(MSBuildProjectName)+</AssemblyName>
@@ -18,6 +18,7 @@
</ItemGroup>
<ItemGroup>
<None Remove="Modules\zqihthf4.eqf~" />
<None Remove="resources\modnews\english\TOHE+.v1.2.0.txt" />
<None Remove="resources\modnews\english\TOHE+.v1.3.0.txt" />
<None Remove="resources\modnews\english\TOHE+.v1.4.0.txt" />
@@ -35,7 +36,7 @@
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2023.11.28" PrivateAssets="all" />
<PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.1.0-rc.1" />
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.682" Private="false" ExcludeAssets="runtime;native" />
<PackageReference Include="Samboy063.Cpp2IL.Core" Version="2022.1.0-development.898" />
<PackageReference Include="Samboy063.Cpp2IL.Core" Version="2022.1.0-pre-release.13" />
</ItemGroup>
<ItemGroup>
+268 -280
View File
@@ -33,8 +33,8 @@ public class Main : BasePlugin
public static ConfigEntry<string> DebugKeyInput { get; private set; }
public static readonly string MainMenuText = " ";
public const string PluginGuid = "com.gurge44.toheplus";
public const string PluginVersion = "2.2.1";
public const string PluginDisplayVersion = "2.2.1";
public const string PluginVersion = "2.2.4";
public const string PluginDisplayVersion = "2.2.4";
public static readonly string SupportedAUVersion = "2023.10.24";
public const int PluginCreate = 3;
public const bool Canary = false;
@@ -653,84 +653,80 @@ public enum CustomRoles
//Impostors
BountyHunter,
FireWorks,
Mafia,
Godfather,
SerialKiller,
//ShapeMaster,
Wildling,
EvilGuesser,
Minimalism,
Zombie,
Sniper,
Vampire,
Witch,
Warlock,
Assassin,
Undertaker,
Vindicator,
Hacker,
Miner,
Escapee,
Inhibitor,
Librarian,
Chronomancer,
Nullifier,
Stealth,
Penguin,
Sapper,
Mastermind,
Hitman,
RiftMaker,
Gambler,
Puppeteer,
TimeThief,
EvilTracker,
Hacker, // Anonymous
AntiAdminer,
Consort,
Sans,
Bomber,
Nuker,
BoobyTrap,
Scavenger,
Capitalism,
Gangster,
Cleaner,
BallLightning,
Greedier,
CursedWolf,
ImperiusCurse,
QuickShooter,
Eraser,
OverKiller,
Hangman,
Sans, // Arrogance
Bard,
Mafioso,
Trickster,
Swooper,
Cantankerous,
Duellist,
YinYanger,
Crewpostor,
Parasite,
Disperser,
Blackmailer,
Bomber,
BountyHunter,
OverKiller, // Butcher
Camouflager,
Saboteur,
Capitalism,
Cantankerous,
Chronomancer,
EvilDiviner, // Consigliere
Consort,
Councillor,
Dazzler,
Crewpostor,
CursedWolf,
Deathpact,
Devourer,
EvilDiviner,
Morphling,
Twister,
Blackmailer,
Disperser,
Duellist,
Dazzler,
Escapee,
Eraser,
EvilGuesser,
EvilTracker,
FireWorks,
Gambler,
Gangster,
Godfather,
Greedier,
Hangman,
Hitman,
Inhibitor,
Minimalism, // Killing Machine
BallLightning, // Lightning
Librarian,
Lurker,
Convict,
Visionary,
Mafia,
Mafioso,
Mastermind,
SerialKiller, // Mercenary
Miner,
Morphling,
Assassin, // Ninja
Nuker,
Nullifier,
Parasite,
Penguin,
Puppeteer,
QuickShooter,
Refugee,
RiftMaker,
Saboteur,
Sapper,
Scavenger,
Sniper,
ImperiusCurse, // Soul Catcher
Swooper,
Stealth,
TimeThief,
BoobyTrap, // Trapster
Trickster,
Twister,
Underdog,
// Flashbang,
Undertaker,
Vampire,
Vindicator,
Visionary,
Warlock,
Wildling,
Witch,
YinYanger,
Zombie,
//Crewmates (Vanilla)
Engineer,
@@ -744,178 +740,169 @@ public enum CustomRoles
// Crewmate
Luckey,
Needy,
SuperStar,
CyberStar,
Demolitionist,
Ventguard,
Express,
NiceEraser,
TaskManager,
Shiftguard,
Mole,
Sentinel,
Electric,
Philantropist,
Tornado,
Insight,
Tunneler,
Detour,
Gaulois,
Druid,
Drainer,
CameraMan,
NiceHacker,
Spy,
Ricochet,
Doormaster,
Tether,
Admirer,
Addict,
Aid,
Benefactor,
GuessManager,
Escort,
DonutDelivery,
Alchemist,
Altruist,
Analyzer,
Mayor,
Jailor,
Paranoia,
Psychic,
SabotageMaster,
Sheriff,
Snitch,
Enigma,
Marshall,
SpeedBooster,
Lookout,
Autocrat,
Benefactor,
Bodyguard,
CameraMan,
CyberStar, // Celebrity
Chameleon,
Cleaner,
Cleanser,
CopyCat,
Bloodhound, // Coroner
Crusader,
Demolitionist,
Deputy,
Detective,
Detour,
Dictator,
Doctor,
Detective,
SwordsMan,
NiceGuesser,
Transporter,
NiceSwapper,
Altruist,
Transmitter,
Autocrat,
Nightmare,
TimeManager,
Veteran,
Bodyguard,
//Counterfeiter,
Witness,
Grenadier,
Lighter,
SecurityGuard,
Medic,
Divinator,
Glitch,
Judge,
Mortician,
Mediumshiper,
Observer,
DonutDelivery,
Doormaster,
DovesOfNeace,
Monarch,
CopyCat,
Drainer,
Druid,
Electric,
Enigma,
Escort,
Express,
Farseer,
Bloodhound,
Tracker,
Merchant,
//Retributionist,
Deputy,
Divinator, // Fortune Teller
Gaulois,
Glitch,
Grenadier,
GuessManager,
Guardian,
Addict,
Alchemist,
Tracefinder,
Ignitor,
Oracle,
Spiritualist,
Chameleon,
ParityCop,
Admirer,
TimeMaster,
Insight,
ParityCop, // Inspector
Jailor,
Judge,
Needy, // Lazy Guy
Lighter,
Lookout,
Luckey,
Marshall,
Mayor,
SabotageMaster, // Mechanic
Medic,
Mediumshiper,
Merchant,
Monitor,
Crusader,
Cleanser,
//Reverie,
Mole,
Monarch,
Mortician,
NiceEraser,
NiceGuesser,
NiceHacker,
NiceSwapper,
Nightmare,
Observer,
Oracle,
Paranoia,
Philantropist,
Psychic,
Ricochet,
Sentinel,
SecurityGuard,
Sheriff,
Shiftguard,
Snitch,
Spiritualist,
Speedrunner,
SpeedBooster,
Spy,
SuperStar,
TaskManager,
Tether,
TimeManager,
TimeMaster,
Tornado,
Tracker,
Transmitter,
Transporter,
Tracefinder,
Tunneler,
Ventguard,
Veteran,
SwordsMan, // Vigilante
Witness,
//Neutrals
Arsonist,
HexMaster,
Jester,
God,
Opportunist,
Mario,
Terrorist,
Executioner,
Bandit,
Lawyer,
Jackal,
Poisoner,
//NWitch,
Innocent,
Pelican,
Revolutionist,
NSerialKiller,
Enderman,
Mycologist,
Bubble,
Hookshot,
Sprayer,
PlagueDoctor,
Postman,
Reckless,
Magician,
WeaponMaster,
Eclipse,
Pyromaniac,
Vengeance,
HeadHunter,
Imitator,
Werewolf,
Juggernaut,
Infectious,
FFF,
Konan,
Gamer,
DarkHide,
Workaholic,
Speedrunner,
Collector,
Agitater,
Provocateur,
Sunnyboy,
BloodKnight,
Wraith,
Totocalcio,
Romantic,
VengefulRomantic,
RuthlessRomantic,
Succubus,
Virus,
Pursuer,
Phantom,
Jinx,
Maverick,
//CursedSoul,
//Pirate,
Ritualist,
Doppelganger,
Pickpocket,
Traitor,
Vulture,
PlagueBearer,
Pestilence,
Medusa,
Sidekick,
//Baker,
//Famine,
Spiritcaller,
Amnesiac,
Arsonist,
Bandit,
BloodKnight,
Bubble,
Collector,
Gamer, // Demon
Doppelganger,
Doomsayer,
//Masochist,
// Flux,
Eclipse,
Enderman,
Executioner,
Totocalcio, // Follower
God,
FFF, // Hater
HeadHunter,
HexMaster,
Hookshot,
Imitator,
Infectious,
Innocent,
Jackal,
Jester,
Jinx,
Juggernaut,
Konan,
Lawyer,
Magician,
Mario,
Maverick,
Medusa,
Mycologist,
Opportunist,
Pelican,
Pestilence,
Phantom,
Pickpocket,
PlagueBearer,
PlagueDoctor,
Poisoner,
Postman,
Provocateur,
Pursuer,
Pyromaniac,
Reckless,
Revolutionist,
Ritualist,
Romantic,
RuthlessRomantic,
NSerialKiller, // Serial Killer
Sidekick,
Spiritcaller,
Sprayer,
DarkHide, // Stalker
Succubus,
Sunnyboy,
Terrorist,
Traitor,
Vengeance,
VengefulRomantic,
Virus,
Vulture,
Wraith,
Werewolf,
WeaponMaster,
Workaholic,
//SoloKombat
KB_Normal,
@@ -926,66 +913,67 @@ public enum CustomRoles
//GM
GM,
// ????
Convict,
// Sub-role after 500
NotAssigned = 500,
LastImpostor,
Lovers,
Ntr,
Madmate,
Watcher,
Flashman,
Torch,
Seer,
Brakar,
Oblivious,
Bewilder,
Sunglasses,
Workhorse,
Fool,
Avanger,
Youtuber,
Egoist,
TicketsStealer,
DualPersonality,
Mimic,
Guesser,
Necroview,
Reach,
Charmed,
Bait,
Trapper,
Infected,
Onbound,
Knighted,
Contagious,
Cleansed,
Unreportable,
DeadlyQuota,
Damocles,
Stressed,
Rogue,
Lucky,
Unlucky,
DoubleShot,
// Reflective,
Rascal,
Soulless,
Gravestone,
Lazy,
Autopsy,
Loyal,
EvilSpirit,
Recruit,
Admired,
Glow,
Diseased,
Antidote,
Swift,
Autopsy,
Avanger,
Bait,
Trapper, // Beartrap
Bewilder,
Charmed,
Cleansed,
Contagious,
Damocles,
DeadlyQuota,
Diseased,
Unreportable, // Disregarded
DoubleShot,
Egoist,
EvilSpirit,
Flashman,
Fool,
Ghoul,
Glow,
Gravestone,
Guesser,
Infected,
Knighted,
LastImpostor,
Lazy,
Lovers,
Loyal,
Lucky,
Madmate,
Mare,
Mimic,
Necroview,
Ntr, // Neptune
Nimble,
Oblivious,
Onbound,
Physicist,
// QuickFix
Rascal,
Reach,
Recruit,
Rogue,
DualPersonality, // Schizophrenic
Seer,
Soulless,
TicketsStealer, // Stealer
Stressed,
Swift,
Sunglasses,
Brakar, // Tiebreaker
Torch,
Unlucky,
Watcher,
Workhorse,
Youtuber
}
//WinData
public enum CustomWinner