Skip to content

Commit 8dfc0ef

Browse files
committed
Unofficial ToU v2.3.0
An update to ToU with a few bug fixes, some new settings and 3 new roles. All changes can be found here: https://docs.google.com/document/d/1xcNvPul0IbNTVbHXd_mvupzpZya6pCixM_pRw5RiL-U/edit?usp=sharing.
1 parent 0e26637 commit 8dfc0ef

File tree

106 files changed

+2506
-1058
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+2506
-1058
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using System.Linq;
2+
using HarmonyLib;
3+
using Hazel;
4+
using TownOfUs.Roles;
5+
using Reactor;
6+
using UnityEngine;
7+
8+
namespace TownOfUs.CrewmateRoles.HaunterMod
9+
{
10+
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CompleteTask))]
11+
public class CompleteTask
12+
{
13+
public static Sprite Sprite => TownOfUs.Arrow;
14+
public static void Postfix(PlayerControl __instance)
15+
{
16+
if (!__instance.Is(RoleEnum.Haunter)) return;
17+
var role = Role.GetRole<Haunter>(__instance);
18+
19+
var taskinfos = __instance.Data.Tasks.ToArray();
20+
21+
var tasksLeft = taskinfos.Count(x => !x.Complete);
22+
23+
if (tasksLeft == CustomGameOptions.HaunterLessTasks+CustomGameOptions.HaunterTasksRemaining && !role.Caught)
24+
{
25+
if (PlayerControl.LocalPlayer.Is(RoleEnum.Haunter))
26+
{
27+
Coroutines.Start(Utils.FlashCoroutine(role.Color));
28+
}
29+
else if (PlayerControl.LocalPlayer.Data.IsImpostor || (PlayerControl.LocalPlayer.Is(RoleEnum.Glitch) && CustomGameOptions.HaunterRevealsNeutrals))
30+
{
31+
Coroutines.Start(Utils.FlashCoroutine(role.Color));
32+
var gameObj = new GameObject();
33+
var arrow = gameObj.AddComponent<ArrowBehaviour>();
34+
gameObj.transform.parent = PlayerControl.LocalPlayer.gameObject.transform;
35+
var renderer = gameObj.AddComponent<SpriteRenderer>();
36+
renderer.sprite = Sprite;
37+
arrow.image = renderer;
38+
gameObj.layer = 5;
39+
role.ImpArrows.Add(arrow);
40+
}
41+
}
42+
43+
if (tasksLeft == CustomGameOptions.HaunterLessTasks && !role.Caught)
44+
{
45+
role.CompletedTasks = true;
46+
if (PlayerControl.LocalPlayer.Is(RoleEnum.Haunter))
47+
{
48+
Coroutines.Start(Utils.FlashCoroutine(Color.white));
49+
}
50+
else if (PlayerControl.LocalPlayer.Data.IsImpostor || (PlayerControl.LocalPlayer.Is(RoleEnum.Glitch) && CustomGameOptions.HaunterRevealsNeutrals))
51+
{
52+
Coroutines.Start(Utils.FlashCoroutine(Color.white));
53+
}
54+
}
55+
}
56+
}
57+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using HarmonyLib;
2+
using TownOfUs.Roles;
3+
4+
namespace TownOfUs.CrewmateRoles.HaunterMod
5+
{
6+
[HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.HandleAnimation))]
7+
public class HandleAnimation
8+
{
9+
public static void Prefix(PlayerPhysics __instance, [HarmonyArgument(0)] ref bool amDead)
10+
{
11+
if (__instance.myPlayer.Is(RoleEnum.Haunter)) amDead = Role.GetRole<Haunter>(__instance.myPlayer).Caught;
12+
}
13+
}
14+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using HarmonyLib;
2+
using TownOfUs.Roles;
3+
using UnityEngine;
4+
5+
namespace TownOfUs.CrewmateRoles.HaunterMod
6+
{
7+
[HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))]
8+
[HarmonyPriority(Priority.Last)]
9+
public class Hide
10+
{
11+
public static void Postfix(HudManager __instance)
12+
{
13+
foreach (var role in Role.GetRoles(RoleEnum.Haunter))
14+
{
15+
var haunter = (Haunter) role;
16+
var caught = haunter.Caught;
17+
if (!caught)
18+
{
19+
haunter.Fade();
20+
}
21+
else if (haunter.Faded)
22+
{
23+
Utils.Unmorph(haunter.Player);
24+
haunter.Player.myRend.color = Color.white;
25+
haunter.Player.gameObject.layer = LayerMask.NameToLayer("Ghost");
26+
haunter.Faded = false;
27+
haunter.Player.MyPhysics.ResetMoveState();
28+
}
29+
}
30+
}
31+
}
32+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using HarmonyLib;
2+
using TownOfUs.Roles;
3+
using Hazel;
4+
5+
namespace TownOfUs.CrewmateRoles.HaunterMod
6+
{
7+
[HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))]
8+
public class HighlightImpostors
9+
{
10+
public static void UpdateMeeting(MeetingHud __instance)
11+
{
12+
foreach (var state in __instance.playerStates)
13+
{
14+
if (Utils.PlayerById(state.TargetPlayerId).Data.IsImpostor) state.NameText.color = Palette.ImpostorRed;
15+
16+
var role = Role.GetRole(state);
17+
if (role.Faction == Faction.Neutral && CustomGameOptions.HaunterRevealsNeutrals)
18+
state.NameText.color = role.Color;
19+
}
20+
}
21+
public static void Postfix(HudManager __instance)
22+
{
23+
if (!PlayerControl.LocalPlayer.Is(RoleEnum.Haunter)) return;
24+
var role = Role.GetRole<Haunter>(PlayerControl.LocalPlayer);
25+
if (!role.CompletedTasks || role.Caught) return;
26+
if (MeetingHud.Instance)
27+
{
28+
UpdateMeeting(MeetingHud.Instance);
29+
var writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId,
30+
(byte)CustomRPC.HaunterFinished, SendOption.Reliable, -1);
31+
writer.Write(role.Player.PlayerId);
32+
AmongUsClient.Instance.FinishRpcImmediately(writer);
33+
}
34+
}
35+
}
36+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using HarmonyLib;
2+
using TownOfUs.Roles;
3+
4+
namespace TownOfUs.CrewmateRoles.HaunterMod
5+
{
6+
[HarmonyPatch(typeof(SpawnInMinigame), nameof(SpawnInMinigame.Begin))]
7+
public class NoSpawn
8+
{
9+
public static bool Prefix(SpawnInMinigame __instance)
10+
{
11+
if (PlayerControl.LocalPlayer.Is(RoleEnum.Haunter))
12+
{
13+
var caught = Role.GetRole<Haunter>(PlayerControl.LocalPlayer).Caught;
14+
if (!caught)
15+
{
16+
__instance.Close();
17+
return false;
18+
}
19+
}
20+
21+
return true;
22+
}
23+
}
24+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using HarmonyLib;
2+
using TownOfUs.Roles;
3+
4+
namespace TownOfUs.CrewmateRoles.HaunterMod
5+
{
6+
[HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.ResetMoveState))]
7+
public class ResetMoveState
8+
{
9+
public static void Postfix(PlayerPhysics __instance)
10+
{
11+
if (!__instance.myPlayer.Is(RoleEnum.Haunter)) return;
12+
13+
var role = Role.GetRole<Haunter>(__instance.myPlayer);
14+
__instance.myPlayer.Collider.enabled = !role.Caught;
15+
}
16+
}
17+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
using System;
2+
using HarmonyLib;
3+
using Hazel;
4+
using TownOfUs.Roles;
5+
using UnityEngine;
6+
using UnityEngine.UI;
7+
using Object = UnityEngine.Object;
8+
using Random = UnityEngine.Random;
9+
using System.Linq;
10+
11+
namespace TownOfUs.CrewmateRoles.HaunterMod
12+
{
13+
public enum HaunterCanBeClickedBy
14+
{
15+
All,
16+
NonCrew,
17+
ImpsOnly
18+
}
19+
[HarmonyPatch(typeof(AirshipExileController), nameof(AirshipExileController.WrapUpAndSpawn))]
20+
public static class AirshipExileController_WrapUpAndSpawn
21+
{
22+
public static void Postfix(AirshipExileController __instance) => SetHaunter.ExileControllerPostfix(__instance);
23+
}
24+
25+
[HarmonyPatch(typeof(ExileController), nameof(ExileController.WrapUp))]
26+
public class SetHaunter
27+
{
28+
public static PlayerControl WillBeHaunter;
29+
public static Vector2 StartPosition;
30+
31+
public static void ExileControllerPostfix(ExileController __instance)
32+
{
33+
var exiled = __instance.exiled?.Object;
34+
if (!PlayerControl.LocalPlayer.Data.IsDead && exiled != PlayerControl.LocalPlayer) return;
35+
if (exiled == PlayerControl.LocalPlayer && PlayerControl.LocalPlayer.Is(RoleEnum.Jester)) return;
36+
if (PlayerControl.LocalPlayer != WillBeHaunter) return;
37+
38+
if (!PlayerControl.LocalPlayer.Is(RoleEnum.Haunter))
39+
{
40+
Role.RoleDictionary.Remove(PlayerControl.LocalPlayer.PlayerId);
41+
var role = new Haunter(PlayerControl.LocalPlayer);
42+
role.RegenTask();
43+
Lights.SetLights();
44+
45+
RemoveTasks(PlayerControl.LocalPlayer);
46+
PlayerControl.LocalPlayer.MyPhysics.ResetMoveState();
47+
48+
System.Console.WriteLine("Become Haunter - Haunter");
49+
50+
PlayerControl.LocalPlayer.gameObject.layer = LayerMask.NameToLayer("Players");
51+
52+
var writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId,
53+
(byte) CustomRPC.HaunterDied, SendOption.Reliable, -1);
54+
AmongUsClient.Instance.FinishRpcImmediately(writer);
55+
}
56+
57+
if (Role.GetRole<Haunter>(PlayerControl.LocalPlayer).Caught) return;
58+
var startingVent =
59+
ShipStatus.Instance.AllVents[Random.RandomRangeInt(0, ShipStatus.Instance.AllVents.Count)];
60+
if (PlayerControl.GameOptions.MapId == 2)
61+
{
62+
while (startingVent == ShipStatus.Instance.AllVents[5])
63+
{
64+
startingVent = ShipStatus.Instance.AllVents[Random.RandomRangeInt(0, ShipStatus.Instance.AllVents.Count)];
65+
}
66+
}
67+
PlayerControl.LocalPlayer.NetTransform.RpcSnapTo(startingVent.transform.position);
68+
PlayerControl.LocalPlayer.MyPhysics.RpcEnterVent(startingVent.Id);
69+
}
70+
71+
public static void Postfix(ExileController __instance) => ExileControllerPostfix(__instance);
72+
73+
public static void RemoveTasks(PlayerControl player)
74+
{
75+
var totalTasks = PlayerControl.GameOptions.NumCommonTasks + PlayerControl.GameOptions.NumLongTasks +
76+
PlayerControl.GameOptions.NumShortTasks;
77+
78+
79+
foreach (var task in player.myTasks)
80+
if (task.TryCast<NormalPlayerTask>() != null)
81+
{
82+
var normalPlayerTask = task.Cast<NormalPlayerTask>();
83+
84+
var updateArrow = normalPlayerTask.taskStep > 0;
85+
86+
normalPlayerTask.taskStep = 0;
87+
normalPlayerTask.Initialize();
88+
if (normalPlayerTask.TaskType == TaskTypes.PickUpTowels)
89+
foreach (var console in Object.FindObjectsOfType<TowelTaskConsole>())
90+
console.Image.color = Color.white;
91+
normalPlayerTask.taskStep = 0;
92+
if (normalPlayerTask.TaskType == TaskTypes.UploadData)
93+
normalPlayerTask.taskStep = 1;
94+
if (updateArrow)
95+
normalPlayerTask.UpdateArrow();
96+
97+
var taskInfo = player.Data.FindTaskById(task.Id);
98+
taskInfo.Complete = false;
99+
}
100+
}
101+
102+
/*public static void ResetTowels(NormalPlayerTask task)
103+
{
104+
var towelTask = task.Cast<TowelTask>();
105+
var data = new byte[8];
106+
var array = Enumerable.Range(0, 14).ToList();
107+
array.Shuffle();
108+
var b3 = 0;
109+
while (b3 < data.Length)
110+
{
111+
data[b3] = (byte)array[b3];
112+
b3++;
113+
}
114+
115+
towelTask.Data = data;
116+
return;
117+
}
118+
119+
public static void ResetRecords(NormalPlayerTask task)
120+
{
121+
task.Data = new
122+
}*/
123+
124+
public static void AddCollider(Haunter role)
125+
{
126+
var player = role.Player;
127+
var collider2d = player.gameObject.AddComponent<BoxCollider2D>();
128+
collider2d.isTrigger = true;
129+
var button = player.gameObject.AddComponent<PassiveButton>();
130+
button.OnClick = new Button.ButtonClickedEvent();
131+
button.OnMouseOut = new Button.ButtonClickedEvent();
132+
button.OnMouseOver = new Button.ButtonClickedEvent();
133+
134+
button.OnClick.AddListener((Action) (() =>
135+
{
136+
if (MeetingHud.Instance) return;
137+
if (PlayerControl.LocalPlayer.Data.IsDead) return;
138+
if (CustomGameOptions.HaunterCanBeClickedBy == HaunterCanBeClickedBy.ImpsOnly && !PlayerControl.LocalPlayer.Data.IsImpostor) return;
139+
if (CustomGameOptions.HaunterCanBeClickedBy == HaunterCanBeClickedBy.NonCrew && !(PlayerControl.LocalPlayer.Data.IsImpostor || PlayerControl.LocalPlayer.Is(RoleEnum.Jester) || PlayerControl.LocalPlayer.Is(RoleEnum.Shifter) || PlayerControl.LocalPlayer.Is(RoleEnum.Glitch) || PlayerControl.LocalPlayer.Is(RoleEnum.Executioner) || PlayerControl.LocalPlayer.Is(RoleEnum.Arsonist))) return;
140+
var taskinfos = player.Data.Tasks.ToArray();
141+
var tasksLeft = taskinfos.Count(x => !x.Complete);
142+
if ((tasksLeft > CustomGameOptions.HaunterLessTasks + CustomGameOptions.HaunterTasksRemaining && CustomGameOptions.HaunterCanBeClickedBefore) || (tasksLeft <= CustomGameOptions.HaunterLessTasks + CustomGameOptions.HaunterTasksRemaining && CustomGameOptions.HaunterCanBeClickedAfter))
143+
{
144+
role.Caught = true;
145+
var writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId,
146+
(byte)CustomRPC.CatchHaunter, SendOption.Reliable, -1);
147+
writer.Write(role.Player.PlayerId);
148+
AmongUsClient.Instance.FinishRpcImmediately(writer);
149+
}
150+
}));
151+
}
152+
}
153+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using HarmonyLib;
2+
using TownOfUs.Roles;
3+
4+
namespace TownOfUs.CrewmateRoles.HaunterMod
5+
{
6+
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.Visible), MethodType.Setter)]
7+
public static class VisibleOverride
8+
{
9+
public static void Prefix(PlayerControl __instance, [HarmonyArgument(0)] ref bool value)
10+
{
11+
if (!__instance.Is(RoleEnum.Haunter)) return;
12+
if (Role.GetRole<Haunter>(__instance).Caught) return;
13+
value = !__instance.inVent;
14+
}
15+
}
16+
}

0 commit comments

Comments
 (0)