# Releases
| Among Us - Version| Mod Version | Link |
|----------|-------------|-----------------|
+| 2022.3.29s| v3.4.5| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v3.4.5/TheOtherRoles.zip)
| 2022.2.23s| v3.4.4| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v3.4.4/TheOtherRoles.zip)
| 2021.12.15s| v3.4.3| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v3.4.3/TheOtherRoles.zip)
| 2021.12.15s| v3.4.2| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v3.4.2/TheOtherRoles.zip)
<details>
<summary>Click to show the Changelog</summary>
+**Version 3.4.5**
+- Update to Among Us version 2022.3.29s
+- Added horse-mode button in the main menu (bottom right)
+- Added TheOtherRoles-discord button in the main menu (bottom left, report your bugs and feature suggestions here)
+- Fixed a bug where the deputy was not assigned properly
+- Fixed a bug where a promoted deputy had wrong cooldown
+- Fixed a bug where the killer doesn't teleport to the body
+- Changed the light source to prevent vanilla bugs
+- Removed dlekS (for now) :c
+
**Version 3.4.4**
-- Fixed a bug where games were not finished properly on official servers (special thanks to miniduikboot & 6pak)
+- Fixed a bug where games were not finished properly on offical servers (special thanks to miniduikboot & 6pak)
**Version 3.4.3**
- Fixed a bug where "Guesser Is Impostor Chance" crashed the role system
public static CustomOption dynamicMapEnableSkeld;
public static CustomOption dynamicMapEnableMira;
public static CustomOption dynamicMapEnablePolus;
- public static CustomOption dynamicMapEnableDleks;
public static CustomOption dynamicMapEnableAirShip;
dynamicMapEnableMira = CustomOption.Create(502, "Enable Mira Rotation", true, dynamicMap, false);
dynamicMapEnablePolus = CustomOption.Create(503, "Enable Polus Rotation", true, dynamicMap, false);
dynamicMapEnableAirShip = CustomOption.Create(504, "Enable Airship Rotation", true, dynamicMap, false);
- dynamicMapEnableDleks = CustomOption.Create(505, "Enable dlekS Rotation", false, dynamicMap, false);
blockedRolePairings.Add((byte)RoleId.Vampire, new [] { (byte)RoleId.Warlock});
blockedRolePairings.Add((byte)RoleId.Warlock, new [] { (byte)RoleId.Vampire});
target.RawSetHat(hatId, colorId);
target.RawSetName(hidePlayerName(PlayerControl.LocalPlayer, target) ? "" : playerName);
- SkinData nextSkin = DestroyableSingleton<HatManager>.Instance.GetSkinById(skinId);
+ SkinViewData nextSkin = DestroyableSingleton<HatManager>.Instance.GetSkinById(skinId).viewData.viewData;
PlayerPhysics playerPhysics = target.MyPhysics;
AnimationClip clip = null;
var spriteAnim = playerPhysics.Skin.animator;
var currentPhysicsAnim = playerPhysics.Animator.GetCurrentAnimation();
- if (currentPhysicsAnim == playerPhysics.RunAnim) clip = nextSkin.RunAnim;
- else if (currentPhysicsAnim == playerPhysics.SpawnAnim) clip = nextSkin.SpawnAnim;
- else if (currentPhysicsAnim == playerPhysics.EnterVentAnim) clip = nextSkin.EnterVentAnim;
- else if (currentPhysicsAnim == playerPhysics.ExitVentAnim) clip = nextSkin.ExitVentAnim;
- else if (currentPhysicsAnim == playerPhysics.IdleAnim) clip = nextSkin.IdleAnim;
+ if (currentPhysicsAnim == playerPhysics.CurrentAnimationGroup.RunAnim) clip = nextSkin.RunAnim;
+ else if (currentPhysicsAnim == playerPhysics.CurrentAnimationGroup.SpawnAnim) clip = nextSkin.SpawnAnim;
+ else if (currentPhysicsAnim == playerPhysics.CurrentAnimationGroup.EnterVentAnim) clip = nextSkin.EnterVentAnim;
+ else if (currentPhysicsAnim == playerPhysics.CurrentAnimationGroup.ExitVentAnim) clip = nextSkin.ExitVentAnim;
+ else if (currentPhysicsAnim == playerPhysics.CurrentAnimationGroup.IdleAnim) clip = nextSkin.IdleAnim;
else clip = nextSkin.IdleAnim;
float progress = playerPhysics.Animator.m_animator.GetCurrentAnimatorStateInfo(0).normalizedTime;
playerPhysics.Skin.skin = nextSkin;
spriteAnim.m_animator.Update(0f);
if (target.CurrentPet) UnityEngine.Object.Destroy(target.CurrentPet.gameObject);
- target.CurrentPet = UnityEngine.Object.Instantiate<PetBehaviour>(DestroyableSingleton<HatManager>.Instance.GetPetById(petId).PetPrefab);
+ target.CurrentPet = UnityEngine.Object.Instantiate<PetBehaviour>(DestroyableSingleton<HatManager>.Instance.GetPetById(petId).viewData.viewData);
target.CurrentPet.transform.position = target.transform.position;
target.CurrentPet.Source = target;
target.CurrentPet.Visible = target.Visible;
PlayerControl.SetPlayerMaterialColors(colorId, target.CurrentPet.rend);
}
+ public static void showFlash(Color color, float duration=1f) {
+ if (HudManager.Instance == null || HudManager.Instance.FullScreen == null) return;
+ HudManager.Instance.FullScreen.gameObject.SetActive(true);
+ HudManager.Instance.FullScreen.enabled = true;
+ HudManager.Instance.StartCoroutine(Effects.Lerp(duration, new Action<float>((p) => {
+ var renderer = HudManager.Instance.FullScreen;
+
+ if (p < 0.5) {
+ if (renderer != null)
+ renderer.color = new Color(color.r, color.g, color.b, Mathf.Clamp01(p * 2 * 0.75f));
+ } else {
+ if (renderer != null)
+ renderer.color = new Color(color.r, color.g, color.b, Mathf.Clamp01((1 - p) * 2 * 0.75f));
+ }
+ if (p == 1f && renderer != null) renderer.enabled = false;
+ })));
+ }
+
public static bool roleCanUseVents(this PlayerControl player) {
bool roleCouldUse = false;
if (Engineer.engineer != null && Engineer.engineer == player)
public class TheOtherRolesPlugin : BasePlugin
{
public const string Id = "me.eisbison.theotherroles";
- public const string VersionString = "3.4.4";
+ public const string VersionString = "3.4.5";
public static System.Version Version = System.Version.Parse(VersionString);
internal static BepInEx.Logging.ManualLogSource Logger;
public static ConfigEntry<bool> GhostsSeeVotes{ get; set; }
public static ConfigEntry<bool> ShowRoleSummary { get; set; }
public static ConfigEntry<bool> ShowLighterDarker { get; set; }
+ public static ConfigEntry<bool> EnableHorseMode { get; set; }
public static ConfigEntry<string> StreamerModeReplacementText { get; set; }
public static ConfigEntry<string> StreamerModeReplacementColor { get; set; }
public static ConfigEntry<string> Ip { get; set; }
GhostsSeeVotes = Config.Bind("Custom", "Ghosts See Votes", true);
ShowRoleSummary = Config.Bind("Custom", "Show Role Summary", true);
ShowLighterDarker = Config.Bind("Custom", "Show Lighter / Darker", true);
+ EnableHorseMode = Config.Bind("Custom", "Enable Horse Mode", false);
ShowPopUpVersion = Config.Bind("Custom", "Show PopUp", "0");
StreamerModeReplacementText = Config.Bind("Custom", "Streamer Mode Replacement Text", "\n\nThe Other Roles");
StreamerModeReplacementColor = Config.Bind("Custom", "Streamer Mode Replacement Text Hex Color", "#87AAF5FF");
public static bool showRoleSummary = true;
public static bool allowParallelMedBayScans = false;
public static bool showLighterDarker = true;
+ public static bool enableHorseMode = false;
// Updating values
public static int meetingsCount = 0;
public static List<Vent> ventsToSeal = new List<Vent>();
public static Dictionary<byte, PoolablePlayer> playerIcons = new Dictionary<byte, PoolablePlayer>();
-public static void clearAndReloadMapOptions() {
+ public static void clearAndReloadMapOptions() {
meetingsCount = 0;
camerasToAdd = new List<SurvCamera>();
ventsToSeal = new List<Vent>();
noVoteIsSelfVote = CustomOptionHolder.noVoteIsSelfVote.getBool();
hidePlayerNames = CustomOptionHolder.hidePlayerNames.getBool();
allowParallelMedBayScans = CustomOptionHolder.allowParallelMedBayScans.getBool();
+ }
+
+ public static void reloadPluginOptions() {
ghostsSeeRoles = TheOtherRolesPlugin.GhostsSeeRoles.Value;
ghostsSeeTasks = TheOtherRolesPlugin.GhostsSeeTasks.Value;
ghostsSeeVotes = TheOtherRolesPlugin.GhostsSeeVotes.Value;
showRoleSummary = TheOtherRolesPlugin.ShowRoleSummary.Value;
showLighterDarker = TheOtherRolesPlugin.ShowLighterDarker.Value;
+ enableHorseMode = TheOtherRolesPlugin.EnableHorseMode.Value;
+ Patches.ShouldAlwaysHorseAround.isHorseMode = TheOtherRolesPlugin.EnableHorseMode.Value;
}
}
}
\ No newline at end of file
return sprite;
}
- private static HatBehaviour CreateHatBehaviour(CustomHat ch, bool fromDisk = false, bool testOnly = false) {
- if (hatShader == null && DestroyableSingleton<HatManager>.InstanceExists) {
- foreach (HatBehaviour h in DestroyableSingleton<HatManager>.Instance.AllHats) {
- if (h.AltShader != null) {
- hatShader = h.AltShader;
- break;
- }
- }
+ private static HatData CreateHatBehaviour(CustomHat ch, bool fromDisk = false, bool testOnly = false) {
+ if (hatShader == null) {
+ Material tmpShader = new Material("PlayerMaterial");
+ tmpShader.shader = Shader.Find("Unlit/PlayerShader");
+ hatShader = tmpShader;
}
- HatBehaviour hat = ScriptableObject.CreateInstance<HatBehaviour>();
- hat.MainImage = CreateHatSprite(ch.resource, fromDisk);
+ HatData hat = ScriptableObject.CreateInstance<HatData>();
+ hat.hatViewData.viewData = ScriptableObject.CreateInstance<HatViewData>();
+ hat.hatViewData.viewData.MainImage = CreateHatSprite(ch.resource, fromDisk);
if (ch.backresource != null) {
- hat.BackImage = CreateHatSprite(ch.backresource, fromDisk);
+ hat.hatViewData.viewData.BackImage = CreateHatSprite(ch.backresource, fromDisk);
ch.behind = true; // Required to view backresource
}
if (ch.climbresource != null)
- hat.ClimbImage = CreateHatSprite(ch.climbresource, fromDisk);
+ hat.hatViewData.viewData.ClimbImage = CreateHatSprite(ch.climbresource, fromDisk);
hat.name = ch.name;
- hat.Order = 99;
+ hat.displayOrder = 99;
hat.ProductId = "hat_" + ch.name.Replace(' ', '_');
hat.InFront = !ch.behind;
hat.NoBounce = !ch.bounce;
hat.Free = true;
if (ch.adaptive && hatShader != null)
- hat.AltShader = hatShader;
+ hat.hatViewData.viewData.AltShader = hatShader;
HatExtension extend = new HatExtension();
extend.author = ch.author != null ? ch.author : "Unknown";
return hat;
}
- private static HatBehaviour CreateHatBehaviour(CustomHatLoader.CustomHatOnline chd) {
+ private static HatData CreateHatBehaviour(CustomHatLoader.CustomHatOnline chd) {
string filePath = Path.GetDirectoryName(Application.dataPath) + @"\TheOtherHats\";
chd.resource = filePath + chd.resource;
if (chd.backresource != null)
RUNNING = true; // prevent simultanious execution
try {
while (CustomHatLoader.hatdetails.Count > 0) {
- __instance.AllHats.Add(CreateHatBehaviour(CustomHatLoader.hatdetails[0]));
+ __instance.allHats.Add(CreateHatBehaviour(CustomHatLoader.hatdetails[0]));
CustomHatLoader.hatdetails.RemoveAt(0);
}
} catch (System.Exception e) {
private static class PlayerPhysicsHandleAnimationPatch {
private static void Postfix(PlayerPhysics __instance) {
AnimationClip currentAnimation = __instance.Animator.GetCurrentAnimation();
- if (currentAnimation == __instance.ClimbAnim || currentAnimation == __instance.ClimbDownAnim) return;
+ if (currentAnimation == __instance.CurrentAnimationGroup.ClimbAnim || currentAnimation == __instance.CurrentAnimationGroup.ClimbDownAnim) return;
HatParent hp = __instance.myPlayer.HatRenderer;
if (hp.Hat == null) return;
HatExtension extend = hp.Hat.getHatExtension();
if (__instance.rend.flipX) {
hp.FrontLayer.sprite = extend.FlipImage;
} else {
- hp.FrontLayer.sprite = hp.Hat.MainImage;
+ hp.FrontLayer.sprite = hp.hatView.MainImage;
}
}
if (extend.BackFlipImage != null) {
if (__instance.rend.flipX) {
hp.BackLayer.sprite = extend.BackFlipImage;
} else {
- hp.BackLayer.sprite = hp.Hat.BackImage;
+ hp.BackLayer.sprite = hp.hatView.BackImage;
}
}
}
public static string innerslothPackageName = "Innersloth Hats";
private static TMPro.TMP_Text textTemplate;
- public static float createHatPackage(List<System.Tuple<HatBehaviour, HatExtension>> hats, string packageName, float YStart, HatsTab __instance) {
+ public static float createHatPackage(List<System.Tuple<HatData, HatExtension>> hats, string packageName, float YStart, HatsTab __instance) {
bool isDefaultPackage = innerslothPackageName == packageName;
if (!isDefaultPackage)
hats = hats.OrderBy(x => x.Item1.name).ToList();
offset -= 0.8f * __instance.YOffset;
}
for (int i = 0; i < hats.Count; i++) {
- HatBehaviour hat = hats[i].Item1;
+ HatData hat = hats[i].Item1;
HatExtension ext = hats[i].Item2;
float xpos = __instance.XRange.Lerp((i % __instance.NumPerRow) / (__instance.NumPerRow - 1f));
UnityEngine.Object.Destroy(__instance.scroller.Inner.GetChild(i).gameObject);
__instance.ColorChips = new Il2CppSystem.Collections.Generic.List<ColorChip>();
- HatBehaviour[] unlockedHats = DestroyableSingleton<HatManager>.Instance.GetUnlockedHats();
- Dictionary<string, List<System.Tuple<HatBehaviour, HatExtension>>> packages = new Dictionary<string, List<System.Tuple<HatBehaviour, HatExtension>>>();
+ HatData[] unlockedHats = DestroyableSingleton<HatManager>.Instance.GetUnlockedHats();
+ Dictionary<string, List<System.Tuple<HatData, HatExtension>>> packages = new Dictionary<string, List<System.Tuple<HatData, HatExtension>>>();
- foreach (HatBehaviour hatBehaviour in unlockedHats) {
+ foreach (HatData hatBehaviour in unlockedHats) {
HatExtension ext = hatBehaviour.getHatExtension();
if (ext != null) {
if (!packages.ContainsKey(ext.package))
- packages[ext.package] = new List<System.Tuple<HatBehaviour, HatExtension>>();
- packages[ext.package].Add(new System.Tuple<HatBehaviour, HatExtension>(hatBehaviour, ext));
+ packages[ext.package] = new List<System.Tuple<HatData, HatExtension>>();
+ packages[ext.package].Add(new System.Tuple<HatData, HatExtension>(hatBehaviour, ext));
} else {
if (!packages.ContainsKey(innerslothPackageName))
- packages[innerslothPackageName] = new List<System.Tuple<HatBehaviour, HatExtension>>();
- packages[innerslothPackageName].Add(new System.Tuple<HatBehaviour, HatExtension>(hatBehaviour, null));
+ packages[innerslothPackageName] = new List<System.Tuple<HatData, HatExtension>>();
+ packages[innerslothPackageName].Add(new System.Tuple<HatData, HatExtension>(hatBehaviour, null));
}
}
return 500;
});
foreach (string key in orderedKeys) {
- List<System.Tuple<HatBehaviour, HatExtension>> value = packages[key];
+ List<System.Tuple<HatData, HatExtension>> value = packages[key];
YOffset = createHatPackage(value, key, YOffset, __instance);
}
}
}
public static class CustomHatExtensions {
- public static CustomHats.HatExtension getHatExtension(this HatBehaviour hat) {
+ public static CustomHats.HatExtension getHatExtension(this HatData hat) {
CustomHats.HatExtension ret = null;
if (CustomHats.TestExt != null && CustomHats.TestExt.condition.Equals(hat.name)) {
return CustomHats.TestExt;
public static void Postfix(GameSettingMenu __instance) {
// Setup mapNameTransform
- var mapNameTransform = __instance.AllItems.FirstOrDefault(x => x.gameObject.activeSelf && x.name.Equals("MapName", StringComparison.OrdinalIgnoreCase));
+ var mapNameTransform = __instance.AllItems.FirstOrDefault(x => x.name.Equals("MapName", StringComparison.OrdinalIgnoreCase));
if (mapNameTransform == null) return;
-
var options = new Il2CppSystem.Collections.Generic.List<Il2CppSystem.Collections.Generic.KeyValuePair<string, int>>();
for (int i = 0; i < Constants.MapNames.Length; i++) {
+ if (i == 3) continue; // Ignore dlekS
var kvp = new Il2CppSystem.Collections.Generic.KeyValuePair<string, int>();
kvp.key = Constants.MapNames[i];
kvp.value = i;
options.Add(kvp);
}
mapNameTransform.GetComponent<KeyValueOption>().Values = options;
- }
- }
+ mapNameTransform.gameObject.active = true;
- [HarmonyPatch(typeof(Constants), nameof(Constants.ShouldFlipSkeld))]
- class ConstantsShouldFlipSkeldPatch {
- public static bool Prefix(ref bool __result) {
- if (PlayerControl.GameOptions == null) return true;
- __result = PlayerControl.GameOptions.MapId == 3;
- return false;
+ foreach (Transform i in __instance.AllItems.ToList()) {
+ float num = -0.5f;
+ if (i.name.Equals("MapName", StringComparison.OrdinalIgnoreCase)) num = -0.25f;
+ if (i.name.Equals("NumImpostors", StringComparison.OrdinalIgnoreCase) || i.name.Equals("ResetToDefault", StringComparison.OrdinalIgnoreCase)) num = 0f;
+ i.position += new Vector3(0, num, 0);
+ }
+ __instance.Scroller.ContentYBounds.max += 0.5F;
}
}
if (template == null) return;
var button = UnityEngine.Object.Instantiate(template, null);
- button.transform.localPosition = new Vector3(button.transform.localPosition.x, button.transform.localPosition.y + 0.6f, button.transform.localPosition.z);
+ button.transform.localPosition = new Vector3(button.transform.localPosition.x, button.transform.localPosition.y + 1.2f, button.transform.localPosition.z);
PassiveButton passiveButton = button.GetComponent<PassiveButton>();
+ SpriteRenderer buttonSprite = button.GetComponent<SpriteRenderer>();
passiveButton.OnClick = new Button.ButtonClickedEvent();
passiveButton.OnClick.AddListener((UnityEngine.Events.UnityAction)onClick);
-
+
var text = button.transform.GetChild(0).GetComponent<TMPro.TMP_Text>();
__instance.StartCoroutine(Effects.Lerp(0.1f, new System.Action<float>((p) => {
- text.SetText("Update\nThe Other Roles");
+ text.SetText("Update");
})));
+ buttonSprite.color = text.color = Color.red;
+ passiveButton.OnMouseOut.AddListener((UnityEngine.Events.UnityAction)delegate {
+ buttonSprite.color = text.color = Color.red;
+ });
+
TwitchManager man = DestroyableSingleton<TwitchManager>.Instance;
ModUpdater.InfoPopup = UnityEngine.Object.Instantiate<GenericPopup>(man.TwitchPopup);
ModUpdater.InfoPopup.TextAreaTMP.fontSize *= 0.7f;
DestroyableSingleton<MainMenuManager>.Instance.Announcement.gameObject.SetActive(true);
TheOtherRolesPlugin.ShowPopUpVersion.Value = TheOtherRolesPlugin.VersionString;
}
+ MapOptions.reloadPluginOptions();
}
public static void ExecuteUpdate() {
{
var moreOptions = Object.Instantiate(buttonPrefab, __instance.CensorChatButton.transform.parent);
var transform = __instance.CensorChatButton.transform;
+ __instance.CensorChatButton.Text.transform.localScale = new Vector3(1 / 0.66f, 1, 1);
_origin ??= transform.localPosition;
-
- transform.localPosition = _origin.Value + Vector3.left * 1.3f;
- moreOptions.transform.localPosition = _origin.Value + Vector3.right * 1.3f;
-
+
+ transform.localPosition = _origin.Value + Vector3.left * 0.45f;
+ transform.localScale = new Vector3(0.66f, 1, 1);
+ __instance.EnableFriendInvitesButton.transform.localScale = new Vector3(0.66f, 1, 1);
+ __instance.EnableFriendInvitesButton.transform.localPosition += Vector3.right * 0.5f;
+ __instance.EnableFriendInvitesButton.Text.transform.localScale = new Vector3(1.2f, 1, 1);
+
+ moreOptions.transform.localPosition = _origin.Value + Vector3.right * 4f / 3f;
+ moreOptions.transform.localScale = new Vector3(0.66f, 1, 1);
+
moreOptions.gameObject.SetActive(true);
moreOptions.Text.text = "Mod Options...";
+ moreOptions.Text.transform.localScale = new Vector3(1 / 0.66f, 1, 1);
var moreOptionsButton = moreOptions.GetComponent<PassiveButton>();
moreOptionsButton.OnClick = new ButtonClickedEvent();
moreOptionsButton.OnClick.AddListener((Action) (() =>
}
}
- private class SelectionBehaviour
+ public class SelectionBehaviour
{
public string Title;
public Func<bool> OnClick;
}
[HarmonyPatch(typeof(MainMenuManager), nameof(MainMenuManager.Start))]
- private static class LogoPatch
+ public static class LogoPatch
{
+ public static SpriteRenderer renderer;
+ public static Sprite bannerSprite;
+ public static Sprite horseBannerSprite;
+ private static PingTracker instance;
static void Postfix(PingTracker __instance) {
var amongUsLogo = GameObject.Find("bannerLogo_AmongUs");
if (amongUsLogo != null) {
var torLogo = new GameObject("bannerLogo_TOR");
torLogo.transform.position = Vector3.up;
- var renderer = torLogo.AddComponent<SpriteRenderer>();
+ renderer = torLogo.AddComponent<SpriteRenderer>();
+ loadSprites();
renderer.sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Banner.png", 300f);
+
+ instance = __instance;
+ loadSprites();
+ renderer.sprite = MapOptions.enableHorseMode ? horseBannerSprite : bannerSprite;
+ }
+
+ public static void loadSprites() {
+ if (bannerSprite == null) bannerSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Banner.png", 300f);
+ if (horseBannerSprite == null) horseBannerSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.bannerTheHorseRoles.png", 300f);
+ }
+
+ public static void updateSprite() {
+ loadSprites();
+ if (renderer != null) {
+ float fadeDuration = 1f;
+ instance.StartCoroutine(Effects.Lerp(fadeDuration, new Action<float>((p) => {
+ renderer.color = new Color(1, 1, 1, 1 - p);
+ if (p == 1) {
+ renderer.sprite = MapOptions.enableHorseMode ? horseBannerSprite : bannerSprite;
+ instance.StartCoroutine(Effects.Lerp(fadeDuration, new Action<float>((p) => {
+ renderer.color = new Color(1, 1, 1, p);
+ })));
+ }
+ })));
+ }
}
}
}
poolablePlayer.transform.localScale = vector;
poolablePlayer.UpdateFromPlayerOutfit(winningPlayerData2, winningPlayerData2.IsDead);
if (winningPlayerData2.IsDead) {
- poolablePlayer.Body.sprite = __instance.GhostSprite;
+ poolablePlayer.CurrentBodySprite.BodySprite.sprite = poolablePlayer.CurrentBodySprite.GhostSprite;
poolablePlayer.SetDeadFlipX(i % 2 == 0);
} else {
poolablePlayer.SetFlipX(i % 2 == 0);
possibleMaps.Add(1);
if (CustomOptionHolder.dynamicMapEnablePolus.getBool())
possibleMaps.Add(2);
- if (CustomOptionHolder.dynamicMapEnableDleks.getBool())
- possibleMaps.Add(3);
if (CustomOptionHolder.dynamicMapEnableAirShip.getBool())
possibleMaps.Add(4);
byte chosenMapId = possibleMaps[TheOtherRoles.rnd.Next(possibleMaps.Count)];
foreach (PlayerControl p in PlayerControl.AllPlayerControls) {
GameData.PlayerInfo data = p.Data;
PoolablePlayer player = UnityEngine.Object.Instantiate<PoolablePlayer>(__instance.PlayerPrefab, HudManager.Instance.transform);
- PlayerControl.SetPlayerMaterialColors(data.DefaultOutfit.ColorId, player.Body);
- DestroyableSingleton<HatManager>.Instance.SetSkin(player.Skin.layer, data.DefaultOutfit.SkinId);
+ PlayerControl.SetPlayerMaterialColors(data.DefaultOutfit.ColorId, player.CurrentBodySprite.BodySprite);
+ player.SetSkin(data.DefaultOutfit.SkinId, data.DefaultOutfit.ColorId);
player.HatSlot.SetHat(data.DefaultOutfit.HatId, data.DefaultOutfit.ColorId);
PlayerControl.SetPetImage(data.DefaultOutfit.PetId, data.DefaultOutfit.ColorId, player.PetSlot);
player.NameText.text = data.PlayerName;
}
}
- [HarmonyPatch(typeof(IntroCutscene), nameof(IntroCutscene.SetUpRoleText))]
- class SetUpRoleTextPatch {
- public static void Postfix(IntroCutscene __instance) {
- if (!CustomOptionHolder.activateRoles.getBool()) return; // Don't override the intro of the vanilla roles
+ public static IEnumerator<WaitForSeconds> EndShowRole(IntroCutscene __instance) {
+ yield return new WaitForSeconds(5f);
+
+ __instance.YouAreText.gameObject.SetActive(false);
+ __instance.RoleText.gameObject.SetActive(false);
+ __instance.RoleBlurbText.gameObject.SetActive(false);
+ __instance.ourCrewmate.gameObject.SetActive(false);
+
+ }
+ [HarmonyPatch(typeof(IntroCutscene), nameof(IntroCutscene.ShowRole))]
+ class SetUpRoleTextPatch {
+ static public void SetRoleTexts(IntroCutscene __instance) {
+ // Don't override the intro of the vanilla roles
List<RoleInfo> infos = RoleInfo.getRoleInfoForPlayer(PlayerControl.LocalPlayer);
RoleInfo roleInfo = infos.Where(info => info.roleId != RoleId.Lover).FirstOrDefault();
-
if (roleInfo != null) {
__instance.RoleText.text = roleInfo.name;
__instance.RoleText.color = roleInfo.color;
__instance.RoleBlurbText.text = roleInfo.introDescription;
__instance.RoleBlurbText.color = roleInfo.color;
}
-
if (infos.Any(info => info.roleId == RoleId.Lover)) {
PlayerControl otherLover = PlayerControl.LocalPlayer == Lovers.lover1 ? Lovers.lover2 : Lovers.lover1;
__instance.RoleBlurbText.text += Helpers.cs(Lovers.color, $"\n♥ You are in love with {otherLover?.Data?.PlayerName ?? ""} ♥");
}
if (Deputy.knowsSheriff && Deputy.deputy != null && Sheriff.sheriff != null) {
- if (infos.Any(info => info.roleId == RoleId.Sheriff))
+ if (infos.Any(info => info.roleId == RoleId.Sheriff))
__instance.RoleBlurbText.text += Helpers.cs(Sheriff.color, $"\nYour Deputy is {Deputy.deputy?.Data?.PlayerName ?? ""}");
else if (infos.Any(info => info.roleId == RoleId.Deputy))
__instance.RoleBlurbText.text += Helpers.cs(Sheriff.color, $"\nYour Sheriff is {Sheriff.sheriff?.Data?.PlayerName ?? ""}");
}
-
+ }
+ public static bool Prefix(IntroCutscene __instance) {
+ if (!CustomOptionHolder.activateRoles.getBool()) return true;
+ HudManager.Instance.StartCoroutine(Effects.Lerp(1f, new Action<float>((p) => {
+ SetRoleTexts(__instance);
+ })));
+ return true;
}
}
[HarmonyPatch(typeof(IntroCutscene), nameof(IntroCutscene.BeginCrewmate))]
class BeginCrewmatePatch {
- public static void Prefix(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List<PlayerControl> yourTeam) {
- setupIntroTeamIcons(__instance, ref yourTeam);
+ public static void Prefix(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List<PlayerControl> teamToDisplay) {
+ setupIntroTeamIcons(__instance, ref teamToDisplay);
}
- public static void Postfix(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List<PlayerControl> yourTeam) {
- setupIntroTeam(__instance, ref yourTeam);
+ public static void Postfix(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List<PlayerControl> teamToDisplay) {
+ setupIntroTeam(__instance, ref teamToDisplay);
}
}
}
}
}
+
+ [HarmonyPatch(typeof(Constants), nameof(Constants.ShouldHorseAround))]
+ public static class ShouldAlwaysHorseAround {
+ public static bool isHorseMode;
+ public static bool Prefix(ref bool __result) {
+ if (isHorseMode != MapOptions.enableHorseMode && LobbyBehaviour.Instance != null) __result = isHorseMode;
+ else {
+ __result = MapOptions.enableHorseMode;
+ isHorseMode = MapOptions.enableHorseMode;
+ }
+ return false;
+ }
+ }
}
--- /dev/null
+using HarmonyLib;
+using System;
+using Hazel;
+using UnityEngine;
+using UnityEngine.Rendering;
+
+
+namespace TheOtherRoles.Patches {
+
+ [HarmonyPatch(typeof(LightSource), nameof(LightSource.DrawOcclusion))]
+
+ class LightSourceUpdatePatch {
+ static bool Prefix(LightSource __instance, float effectiveRadius) {
+ if (__instance.cb == null) {
+ __instance.cb = new CommandBuffer();
+ __instance.cb.name = "Draw occlusion";
+ }
+ if (__instance.shadowTexture && __instance.shadowCasterMaterial) {
+ float num = (float)__instance.shadowTexture.width;
+ __instance.shadowCasterMaterial.SetFloat("_DepthCompressionValue", effectiveRadius);
+ __instance.cb.Clear();
+ __instance.cb.SetRenderTarget(__instance.shadowTexture);
+ __instance.cb.ClearRenderTarget(true, true, new Color(1f, 1f, 1f, 1f));
+ __instance.cb.SetGlobalTexture("_ShmapTexture", __instance.shadowTexture);
+ __instance.cb.SetGlobalFloat("_Radius", __instance.LightRadius);
+ __instance.cb.SetGlobalFloat("_Column", 0f);
+ __instance.cb.SetGlobalVector("_lightPosition", __instance.transform.position + Vector3.down * 0.095f); ;
+ __instance.cb.SetGlobalVector("_TexelSize", new Vector4(1f / num, 1f / num, num, num));
+ __instance.cb.SetGlobalFloat("_DepthCompressionValue", effectiveRadius);
+ __instance.cb.DrawMesh(__instance.occluderMesh, Matrix4x4.identity, __instance.shadowCasterMaterial);
+ Graphics.ExecuteCommandBuffer(__instance.cb);
+ }
+ return false;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using HarmonyLib;
+using UnityEngine;
+using UnityEngine.UI;
+using static UnityEngine.UI.Button;
+using Object = UnityEngine.Object;
+using TheOtherRoles.Patches;
+
+namespace TheOtherRoles.Modules {
+ [HarmonyPatch(typeof(MainMenuManager), nameof(MainMenuManager.Start))]
+ public class MainMenuPatch {
+ private static bool horseButtonState = MapOptions.enableHorseMode;
+ private static Sprite horseModeOffSprite = null;
+ private static Sprite horseModeOnSprite = null;
+
+ private static void Prefix(MainMenuManager __instance) {
+ CustomHatLoader.LaunchHatFetcher();
+ var template = GameObject.Find("ExitGameButton");
+ if (template == null) return;
+
+ var buttonDiscord = UnityEngine.Object.Instantiate(template, null);
+ buttonDiscord.transform.localPosition = new Vector3(buttonDiscord.transform.localPosition.x, buttonDiscord.transform.localPosition.y + 0.6f, buttonDiscord.transform.localPosition.z);
+
+ var textDiscord = buttonDiscord.transform.GetChild(0).GetComponent<TMPro.TMP_Text>();
+ __instance.StartCoroutine(Effects.Lerp(0.1f, new System.Action<float>((p) => {
+ textDiscord.SetText("Discord");
+ })));
+
+ PassiveButton passiveButtonDiscord = buttonDiscord.GetComponent<PassiveButton>();
+ SpriteRenderer buttonSpriteDiscord = buttonDiscord.GetComponent<SpriteRenderer>();
+
+ passiveButtonDiscord.OnClick = new Button.ButtonClickedEvent();
+ passiveButtonDiscord.OnClick.AddListener((UnityEngine.Events.UnityAction)delegate {
+ Application.OpenURL("https://discord.gg/77RkMJHWsM");
+ });
+
+ Color discordColor = new Color32(88, 101, 242, byte.MaxValue);
+ buttonSpriteDiscord.color = textDiscord.color = discordColor;
+ passiveButtonDiscord.OnMouseOut.AddListener((UnityEngine.Events.UnityAction)delegate {
+ buttonSpriteDiscord.color = textDiscord.color = discordColor;
+ });
+
+
+ // Horse mode stuff
+ var horseModeSelectionBehavior = new ClientOptionsPatch.SelectionBehaviour("Enable Horse Mode", () => MapOptions.enableHorseMode = TheOtherRolesPlugin.EnableHorseMode.Value = !TheOtherRolesPlugin.EnableHorseMode.Value, TheOtherRolesPlugin.EnableHorseMode.Value);
+
+ var bottomTemplate = GameObject.Find("InventoryButton");
+ if (bottomTemplate == null) return;
+ var horseButton = Object.Instantiate(bottomTemplate, bottomTemplate.transform.parent);
+ var passiveHorseButton = horseButton.GetComponent<PassiveButton>();
+ var spriteHorseButton = horseButton.GetComponent<SpriteRenderer>();
+
+ horseModeOffSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.HorseModeButtonOff.png", 75f);
+ horseModeOnSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.HorseModeButtonOn.png", 75f);
+
+ spriteHorseButton.sprite = horseButtonState ? horseModeOnSprite : horseModeOffSprite;
+
+ passiveHorseButton.OnClick = new ButtonClickedEvent();
+
+ passiveHorseButton.OnClick.AddListener((UnityEngine.Events.UnityAction)delegate {
+ horseButtonState = horseModeSelectionBehavior.OnClick();
+ if (horseButtonState) {
+ if (horseModeOnSprite == null) horseModeOnSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.HorseModeButtonOn.png", 75f);
+ spriteHorseButton.sprite = horseModeOnSprite;
+ }
+ else {
+ if (horseModeOffSprite == null) horseModeOffSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.HorseModeButtonOff.png", 75f);
+ spriteHorseButton.sprite = horseModeOffSprite;
+ }
+ CredentialsPatch.LogoPatch.updateSprite();
+ // Avoid wrong Player Particles floating around in the background
+ var particles = GameObject.FindObjectOfType<PlayerParticles>();
+ if (particles != null) {
+ particles.pool.ReclaimAll();
+ particles.Start();
+ }
+ });
+ }
+ }
+}
\ No newline at end of file
Transform button = UnityEngine.Object.Instantiate(buttonTemplate, buttonParent);
Transform buttonMask = UnityEngine.Object.Instantiate(maskTemplate, buttonParent);
TMPro.TextMeshPro label = UnityEngine.Object.Instantiate(textTemplate, button);
- button.GetComponent<SpriteRenderer>().sprite = DestroyableSingleton<HatManager>.Instance.AllNamePlates[0].Image;
+ button.GetComponent<SpriteRenderer>().sprite = DestroyableSingleton<HatManager>.Instance.GetNamePlateById("nameplate_NoPlate")?.viewData?.viewData?.Image;
buttons.Add(button);
int row = i/5, col = i%5;
buttonParent.localPosition = new Vector3(-3.47f + 1.75f * col, 1.5f - 0.45f * row, -5);
}
static void setPlayerOutline(PlayerControl target, Color color) {
- if (target == null || target.myRend == null) return;
+ if (target == null || target.MyRend == null) return;
- target.myRend.material.SetFloat("_Outline", 1f);
- target.myRend.material.SetColor("_OutlineColor", color);
+ target.MyRend.material.SetFloat("_Outline", 1f);
+ target.MyRend.material.SetColor("_OutlineColor", color);
}
// Update functions
static void setBasePlayerOutlines() {
foreach (PlayerControl target in PlayerControl.AllPlayerControls) {
- if (target == null || target.myRend == null) continue;
+ if (target == null || target.MyRend == null) continue;
bool isMorphedMorphling = target == Morphling.morphling && Morphling.morphTarget != null && Morphling.morphTimer > 0f;
bool hasVisibleShield = false;
}
if (hasVisibleShield) {
- target.myRend.material.SetFloat("_Outline", 1f);
- target.myRend.material.SetColor("_OutlineColor", Medic.shieldedColor);
+ target.MyRend.material.SetFloat("_Outline", 1f);
+ target.MyRend.material.SetColor("_OutlineColor", Medic.shieldedColor);
}
else {
- target.myRend.material.SetFloat("_Outline", 0f);
+ target.MyRend.material.SetFloat("_Outline", 0f);
}
}
}
// Warlock Button Sync
if (Warlock.warlock != null && PlayerControl.LocalPlayer == Warlock.warlock && __instance == Warlock.warlock && HudManagerStartPatch.warlockCurseButton != null) {
- if(Warlock.warlock.killTimer > HudManagerStartPatch.warlockCurseButton.Timer) {
+ if (Warlock.warlock.killTimer > HudManagerStartPatch.warlockCurseButton.Timer) {
HudManagerStartPatch.warlockCurseButton.Timer = Warlock.warlock.killTimer;
}
}
// Seer show flash and add dead player position
if (Seer.seer != null && PlayerControl.LocalPlayer == Seer.seer && !Seer.seer.Data.IsDead && Seer.seer != target && Seer.mode <= 1) {
- HudManager.Instance.FullScreen.enabled = true;
- HudManager.Instance.StartCoroutine(Effects.Lerp(1f, new Action<float>((p) => {
- var renderer = HudManager.Instance.FullScreen;
- if (p < 0.5) {
- if (renderer != null)
- renderer.color = new Color(42f / 255f, 187f / 255f, 245f / 255f, Mathf.Clamp01(p * 2 * 0.75f));
- } else {
- if (renderer != null)
- renderer.color = new Color(42f / 255f, 187f / 255f, 245f / 255f, Mathf.Clamp01((1-p) * 2 * 0.75f));
- }
- if (p == 1f && renderer != null) renderer.enabled = false;
- })));
+ Helpers.showFlash(new Color(42f / 255f, 187f / 255f, 245f / 255f));
}
if (Seer.deadBodyPositions != null) Seer.deadBodyPositions.Add(target.transform.position);
// Show flash on bait kill to the killer if enabled
if (Bait.bait != null && target == Bait.bait && Bait.showKillFlash && __instance == PlayerControl.LocalPlayer) {
- HudManager.Instance.FullScreen.enabled = true;
- HudManager.Instance.StartCoroutine(Effects.Lerp(1f, new Action<float>((p) => {
- var renderer = HudManager.Instance.FullScreen;
- if (p < 0.5) {
- if (renderer != null)
- renderer.color = new Color(204f / 255f, 102f / 255f, 0f / 255f, Mathf.Clamp01(p * 2 * 0.75f));
- }
- else {
- if (renderer != null)
- renderer.color = new Color(204f / 255f, 102f / 255f, 0f / 255f, Mathf.Clamp01((1 - p) * 2 * 0.75f));
- }
- if (p == 1f && renderer != null) renderer.enabled = false;
- })));
+ Helpers.showFlash(new Color(204f / 255f, 102f / 255f, 0f / 255f));
}
}
}
[HarmonyPatch(typeof(KillAnimation), nameof(KillAnimation.CoPerformKill))]
class KillAnimationCoPerformKillPatch {
- public static bool hideNextAnimation = true;
+ public static bool hideNextAnimation = false;
public static void Prefix(KillAnimation __instance, [HarmonyArgument(0)]ref PlayerControl source, [HarmonyArgument(1)]ref PlayerControl target) {
if (hideNextAnimation)
source = target;
class KillAnimationSetMovementPatch {
private static int? colorId = null;
public static void Prefix(PlayerControl source, bool canMove) {
- Color color = source.myRend.material.GetColor("_BodyColor");
+ Color color = source.MyRend.material.GetColor("_BodyColor");
if (color != null && Morphling.morphling != null && source.Data.PlayerId == Morphling.morphling.PlayerId) {
var index = Palette.PlayerColors.IndexOf(color);
if (index != -1) colorId = index;
public static void Postfix(RegionMenu __instance) {
var template = DestroyableSingleton<JoinGameButton>.Instance;
+ var joinGameButtons = GameObject.FindObjectsOfType<JoinGameButton>();
+ foreach (var t in joinGameButtons) { // The correct button has a background, the other 2 dont
+ if (t.GameIdText != null && t.GameIdText.Background != null) {
+ template = t;
+ break;
+ }
+ }
if (template == null || template.GameIdText == null) return;
if (ipField == null || ipField.gameObject == null) {
if (arrow == null || arrow.gameObject == null) return;
UnityEngine.Object.DestroyImmediate(arrow.gameObject);
- ipField.transform.localPosition = new Vector3(0, -1f, -100f);
+ ipField.transform.localPosition = new Vector3(0.225f, -1f, -100f);
ipField.characterLimit = 30;
ipField.AllowSymbols = true;
ipField.ForceUppercase = false;
if (arrow == null || arrow.gameObject == null) return;
UnityEngine.Object.DestroyImmediate(arrow.gameObject);
- portField.transform.localPosition = new Vector3(0, -1.75f, -100f);
+ portField.transform.localPosition = new Vector3(0.225f, -1.75f, -100f);
portField.characterLimit = 5;
portField.SetText(TheOtherRolesPlugin.Port.Value.ToString());
__instance.StartCoroutine(Effects.Lerp(0.1f, new Action<float>((p) => {
bool guesserFlag = CustomOptionHolder.guesserSpawnBothRate.getSelection() > 0
&& CustomOptionHolder.guesserSpawnRate.getSelection() > 0;
bool sheriffFlag = CustomOptionHolder.deputySpawnRate.getSelection() > 0
- && CustomOptionHolder.sheriffSpawnRate.getSelection() > 0
- && Sheriff.sheriff == null;
+ && CustomOptionHolder.sheriffSpawnRate.getSelection() > 0;
if (!guesserFlag && !sheriffFlag) return; // assignDependentRoles is not needed
int crew = data.crewmates.Count < data.maxCrewmateRoles ? data.crewmates.Count : data.maxCrewmateRoles; // Max number of crew loops
int imp = data.impostors.Count < data.maxImpostorRoles ? data.impostors.Count : data.maxImpostorRoles; // Max number of imp loops
- int crewSteps = crew / data.crewSettings.Keys.Count(); // Avarage crewvalues deducted after each loop
+ int crewSteps = crew / data.crewSettings.Keys.Count(); // Avarage crewvalues deducted after each loop
int impSteps = imp / data.impSettings.Keys.Count(); // Avarage impvalues deducted after each loop
// set to false if needed, otherwise we can skip the loop
if (!component || component.Data == null || component.Data.Disconnected || component.Data.IsDead)
{
num2--;
- } else if (component?.myRend?.material != null) {
- Color color = component.myRend.material.GetColor("_BodyColor");
+ } else if (component?.MyRend?.material != null) {
+ Color color = component.MyRend.material.GetColor("_BodyColor");
if (Hacker.onlyColorType) {
var id = Mathf.Max(0, Palette.PlayerColors.IndexOf(color));
color = Helpers.isLighterColor((byte)id) ? Palette.PlayerColors[7] : Palette.PlayerColors[6];
}
HudManager.Instance.FullScreen.color = new Color(0f, 0.5f, 0.8f, 0.3f);
HudManager.Instance.FullScreen.enabled = true;
+ HudManager.Instance.FullScreen.gameObject.SetActive(true);
HudManager.Instance.StartCoroutine(Effects.Lerp(TimeMaster.rewindTime / 2, new Action<float>((p) => {
if (p == 1f) HudManager.Instance.FullScreen.enabled = false;
})));
bool isShieldedAndShow = Medic.shielded == PlayerControl.LocalPlayer && Medic.showAttemptToShielded;
bool isMedicAndShow = Medic.medic == PlayerControl.LocalPlayer && Medic.showAttemptToMedic;
- if ((isShieldedAndShow || isMedicAndShow) && HudManager.Instance?.FullScreen != null) {
- HudManager.Instance.FullScreen.enabled = true;
- HudManager.Instance.StartCoroutine(Effects.Lerp(0.5f, new Action<float>((p) => {
- var renderer = HudManager.Instance.FullScreen;
- Color c = Palette.ImpostorRed;
- if (p < 0.5) {
- if (renderer != null)
- renderer.color = new Color(c.r, c.g, c.b, Mathf.Clamp01(p * 2 * 0.75f));
- } else {
- if (renderer != null)
- renderer.color = new Color(c.r, c.g, c.b, Mathf.Clamp01((1-p) * 2 * 0.75f));
- }
- if (p == 1f && renderer != null) renderer.enabled = false;
- })));
- }
+ if (isShieldedAndShow || isMedicAndShow) Helpers.showFlash(Palette.ImpostorRed, duration: 0.5f);
}
public static void shifterShift(byte targetId) {
if (!formerSheriff) formerSheriff = sheriff;
sheriff = deputy;
currentTarget = null;
- cooldown = CustomOptionHolder.jackalKillCooldown.getFloat();
+ cooldown = CustomOptionHolder.sheriffCooldown.getFloat();
}
public static void clearAndReload() {
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
- <Version>3.4.4</Version>
+ <Version>3.4.5</Version>
<Description>TheOtherRoles</Description>
<Authors>Eisbison</Authors>
</PropertyGroup>