Skip to content

Commit

Permalink
Version 2.6.7
Browse files Browse the repository at this point in the history
- New Role: Guesser
- Changed the colors of some roles
- Changed name of Child to Mini
- Changed Version check to allow to check for modified versions of the mod. (Forks don't need to use different versioning now)
- Changed Role Assignment to make Spy incompatible with Mini (former child)
- Fixed a bug where a Jester win was triggered, when the partner of a Jester Lover was voted out
- Fixed a bug where a Mini lose was triggered, when the partner of a Crew Mini Lover was voted out
  • Loading branch information
EoF-1141 committed May 30, 2021
1 parent ad6bf05 commit c3680a5
Show file tree
Hide file tree
Showing 16 changed files with 679 additions and 549 deletions.
105 changes: 70 additions & 35 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Source Code/Buttons.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public static void Postfix(HudManager __instance)
}
byte targetId = 0;
if ((Sheriff.currentTarget.Data.IsImpostor && (Sheriff.currentTarget != Child.child || Child.isGrownUp())) ||
if ((Sheriff.currentTarget.Data.IsImpostor && (Sheriff.currentTarget != Mini.mini || Mini.isGrownUp())) ||
(Sheriff.spyCanDieToSheriff && Spy.spy == Sheriff.currentTarget) ||
(Sheriff.canKillNeutrals && (Arsonist.arsonist == Sheriff.currentTarget || Jester.jester == Sheriff.currentTarget || Jackal.jackal == Sheriff.currentTarget || Sidekick.sidekick == Sheriff.currentTarget))) {
targetId = Sheriff.currentTarget.PlayerId;
Expand Down
22 changes: 15 additions & 7 deletions Source Code/CustomOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,18 @@ public class CustomOptionHolder {
public static CustomOption eraserCooldown;
public static CustomOption eraserCanEraseAnyone;

public static CustomOption childSpawnRate;
public static CustomOption childGrowingUpDuration;
public static CustomOption miniSpawnRate;
public static CustomOption miniGrowingUpDuration;

public static CustomOption loversSpawnRate;
public static CustomOption loversImpLoverRate;
public static CustomOption loversBothDie;
public static CustomOption loversCanHaveAnotherRole;

public static CustomOption guesserSpawnRate;
public static CustomOption guesserIsImpGuesserRate;
public static CustomOption guesserNumberOfShots;

public static CustomOption jesterSpawnRate;
public static CustomOption jesterCanCallEmergency;
public static CustomOption jesterCanSabotage;
Expand Down Expand Up @@ -207,14 +211,18 @@ public static void Load() {
warlockCooldown = CustomOption.Create(271, "Warlock Cooldown", 30f, 10f, 60f, 2.5f, warlockSpawnRate);
warlockRootTime = CustomOption.Create(272, "Warlock Root Time", 5f, 0f, 15f, 1f, warlockSpawnRate);

childSpawnRate = CustomOption.Create(180, cs(Child.color, "Child"), rates, null, true);
childGrowingUpDuration = CustomOption.Create(181, "Child Growing Up Duration", 400f, 100f, 1500f, 100f, childSpawnRate);
miniSpawnRate = CustomOption.Create(180, cs(Mini.color, "Mini"), rates, null, true);
miniGrowingUpDuration = CustomOption.Create(181, "Mini Growing Up Duration", 400f, 100f, 1500f, 100f, miniSpawnRate);

loversSpawnRate = CustomOption.Create(50, cs(Lovers.color, "Lovers"), rates, null, true);
loversImpLoverRate = CustomOption.Create(51, "Chance That One Lover Is Impostor", rates, loversSpawnRate);
loversBothDie = CustomOption.Create(52, "Both Lovers Die", true, loversSpawnRate);
loversCanHaveAnotherRole = CustomOption.Create(53, "Lovers Can Have Another Role", true, loversSpawnRate);

guesserSpawnRate = CustomOption.Create(310, cs(Guesser.color, "Guesser"), rates, null, true);
guesserIsImpGuesserRate = CustomOption.Create(311, "Chance That The Guesser Is An Impostor", rates, guesserSpawnRate);
guesserNumberOfShots = CustomOption.Create(312, "Guesser Number Of Shots", 2f, 1f, 15f, 1f, guesserSpawnRate);

jesterSpawnRate = CustomOption.Create(60, cs(Jester.color, "Jester"), rates, null, true);
jesterCanCallEmergency = CustomOption.Create(61, "Jester can call emergency meeting", true, jesterSpawnRate);
jesterCanSabotage = CustomOption.Create(62, "Jester can sabotage", true, jesterSpawnRate);
Expand Down Expand Up @@ -616,7 +624,7 @@ private static void Postfix(ref string __result)
var hudString = sb.ToString();

int defaultSettingsLines = 19;
int roleSettingsLines = defaultSettingsLines + 32;
int roleSettingsLines = defaultSettingsLines + 33;
int detailedSettingsP1 = roleSettingsLines + 34;
int detailedSettingsP2 = detailedSettingsP1 + 35;
int end1 = hudString.TakeWhile(c => (defaultSettingsLines -= (c == '\n' ? 1 : 0)) > 0).Count();
Expand All @@ -635,10 +643,10 @@ private static void Postfix(ref string __result)
gap = 5;
index = hudString.TakeWhile(c => (gap -= (c == '\n' ? 1 : 0)) > 0).Count();
hudString = hudString.Insert(index, "\n");
gap = 16;
gap = 17;
index = hudString.TakeWhile(c => (gap -= (c == '\n' ? 1 : 0)) > 0).Count();
hudString = hudString.Insert(index + 1, "\n");
gap = 20;
gap = 21;
index = hudString.TakeWhile(c => (gap -= (c == '\n' ? 1 : 0)) > 0).Count();
hudString = hudString.Insert(index + 1, "\n");
} else if (counter == 2) {
Expand Down
30 changes: 15 additions & 15 deletions Source Code/EndGamePatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace TheOtherRoles {
enum CustomGameOverReason {
LoversWin = 10,
TeamJackalWin = 11,
ChildLose = 12,
MiniLose = 12,
JesterWin = 13,
ArsonistWin = 14
}
Expand All @@ -26,7 +26,7 @@ enum WinCondition {
LoversSoloWin,
JesterWin,
JackalWin,
ChildLose,
MiniLose,
ArsonistWin
}

Expand Down Expand Up @@ -82,17 +82,17 @@ public static void Postfix(AmongUsClient __instance, [HarmonyArgument(0)]ref Gam

bool jesterWin = Jester.jester != null && gameOverReason == (GameOverReason)CustomGameOverReason.JesterWin;
bool arsonistWin = Arsonist.arsonist != null && gameOverReason == (GameOverReason)CustomGameOverReason.ArsonistWin;
bool childLose = Child.child != null && gameOverReason == (GameOverReason)CustomGameOverReason.ChildLose;
bool miniLose = Mini.mini != null && gameOverReason == (GameOverReason)CustomGameOverReason.MiniLose;
bool loversWin = Lovers.existingAndAlive() && (gameOverReason == (GameOverReason)CustomGameOverReason.LoversWin || (TempData.DidHumansWin(gameOverReason) && !Lovers.existingWithKiller())); // Either they win if they are among the last 3 players, or they win if they are both Crewmates and both alive and the Crew wins (Team Imp/Jackal Lovers can only win solo wins)
bool teamJackalWin = gameOverReason == (GameOverReason)CustomGameOverReason.TeamJackalWin && ((Jackal.jackal != null && !Jackal.jackal.Data.IsDead) || (Sidekick.sidekick != null && !Sidekick.sidekick.Data.IsDead));

// Child lose
if (childLose) {
// Mini lose
if (miniLose) {
TempData.winners = new Il2CppSystem.Collections.Generic.List<WinningPlayerData>();
WinningPlayerData wpd = new WinningPlayerData(Child.child.Data);
wpd.IsYou = false; // If "no one is the Child", it will display the Child, but also show defeat to everyone
WinningPlayerData wpd = new WinningPlayerData(Mini.mini.Data);
wpd.IsYou = false; // If "no one is the Mini", it will display the Mini, but also show defeat to everyone
TempData.winners.Add(wpd);
AdditionalTempData.winCondition = WinCondition.ChildLose;
AdditionalTempData.winCondition = WinCondition.MiniLose;
}

// Jester win
Expand Down Expand Up @@ -191,9 +191,9 @@ public static void Postfix(EndGameManager __instance) {
textRenderer.text = "Team Jackal Wins";
textRenderer.color = Jackal.color;
}
else if (AdditionalTempData.winCondition == WinCondition.ChildLose) {
textRenderer.text = "Child died";
textRenderer.color = Child.color;
else if (AdditionalTempData.winCondition == WinCondition.MiniLose) {
textRenderer.text = "Mini died";
textRenderer.color = Mini.color;
}

if(MapOptions.showRoleSummary) {
Expand Down Expand Up @@ -231,7 +231,7 @@ public static bool Prefix(ShipStatus __instance) {
if (DestroyableSingleton<TutorialManager>.InstanceExists) // InstanceExists | Don't check Custom Criteria when in Tutorial
return true;
var statistics = new PlayerStatistics(__instance);
if (CheckAndEndGameForChildLose(__instance)) return false;
if (CheckAndEndGameForMiniLose(__instance)) return false;
if (CheckAndEndGameForJesterWin(__instance)) return false;
if (CheckAndEndGameForArsonistWin(__instance)) return false;
if (CheckAndEndGameForSabotageWin(__instance)) return false;
Expand All @@ -243,10 +243,10 @@ public static bool Prefix(ShipStatus __instance) {
return false;
}

private static bool CheckAndEndGameForChildLose(ShipStatus __instance) {
if (Child.triggerChildLose) {
private static bool CheckAndEndGameForMiniLose(ShipStatus __instance) {
if (Mini.triggerMiniLose) {
__instance.enabled = false;
ShipStatus.RpcEndGame((GameOverReason)CustomGameOverReason.ChildLose, false);
ShipStatus.RpcEndGame((GameOverReason)CustomGameOverReason.MiniLose, false);
return true;
}
return false;
Expand Down
149 changes: 149 additions & 0 deletions Source Code/ExileControllerPatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
using HarmonyLib;
using Hazel;
using System.Collections.Generic;
using System.Linq;
using UnhollowerBaseLib;
using static TheOtherRoles.TheOtherRoles;
using static TheOtherRoles.MapOptions;
using System.Collections;
using System;
using System.Text;
using UnityEngine;
using System.Reflection;

namespace TheOtherRoles {
[HarmonyPatch(typeof(ExileController), "Begin")]
class ExileControllerBeginPatch {
public static void Prefix(ExileController __instance, [HarmonyArgument(0)]ref GameData.PlayerInfo exiled, [HarmonyArgument(1)]bool tie) {
// Shifter shift
if (Shifter.shifter != null && AmongUsClient.Instance.AmHost && Shifter.futureShift != null) { // We need to send the RPC from the host here, to make sure that the order of shifting and erasing is correct (for that reason the futureShifted and futureErased are being synced)
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.ShifterShift, Hazel.SendOption.Reliable, -1);
writer.Write(Shifter.futureShift.PlayerId);
AmongUsClient.Instance.FinishRpcImmediately(writer);
RPCProcedure.shifterShift(Shifter.futureShift.PlayerId);
}
Shifter.futureShift = null;

// Eraser erase
if (Eraser.eraser != null && AmongUsClient.Instance.AmHost && Eraser.futureErased != null) { // We need to send the RPC from the host here, to make sure that the order of shifting and erasing is correct (for that reason the futureShifted and futureErased are being synced)
foreach (PlayerControl target in Eraser.futureErased) {
if (target != null) {
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.ErasePlayerRoles, Hazel.SendOption.Reliable, -1);
writer.Write(target.PlayerId);
AmongUsClient.Instance.FinishRpcImmediately(writer);
RPCProcedure.erasePlayerRoles(target.PlayerId);
}
}
}
Eraser.futureErased = new List<PlayerControl>();

// Trickster boxes
if (Trickster.trickster != null && JackInTheBox.hasJackInTheBoxLimitReached()) {
JackInTheBox.convertToVents();
}

// SecurityGuard vents and cameras
var allCameras = ShipStatus.Instance.AllCameras.ToList();
MapOptions.camerasToAdd.ForEach(camera => {
camera.gameObject.SetActive(true);
camera.gameObject.GetComponent<SpriteRenderer>().color = Color.white;
allCameras.Add(camera);
});
ShipStatus.Instance.AllCameras = allCameras.ToArray();
MapOptions.camerasToAdd = new List<SurvCamera>();

foreach (Vent vent in MapOptions.ventsToSeal) {
PowerTools.SpriteAnim animator = vent.GetComponent<PowerTools.SpriteAnim>();
animator?.Stop();
vent.EnterVentAnim = vent.ExitVentAnim = null;
vent.myRend.sprite = animator == null ? SecurityGuard.getStaticVentSealedSprite() : SecurityGuard.getAnimatedVentSealedSprite();
vent.myRend.color = Color.white;
vent.name = "SealedVent_" + vent.name;
}
MapOptions.ventsToSeal = new List<Vent>();
}
}

[HarmonyPatch(typeof(UnityEngine.Object), nameof(UnityEngine.Object.Destroy), new Type[] { typeof(UnityEngine.Object) })]
class ExileControllerDestroyPatch {
static void Prefix(UnityEngine.Object obj) {
if (ExileController.Instance == null || obj != ExileController.Instance.gameObject) return;
var exiled = ExileController.Instance.exiled;

// Mini exile lose condition
if (exiled != null && Mini.mini != null && Mini.mini.PlayerId == exiled.PlayerId && !Mini.isGrownUp() && !Mini.mini.Data.IsImpostor) {
Mini.triggerMiniLose = true;
}
// Jester win condition
else if (exiled != null && Jester.jester != null && Jester.jester.PlayerId == exiled.PlayerId) {
Jester.triggerJesterWin = true;
}

// Reset custom button timers where necessary
CustomButton.MeetingEndedUpdate();

// Mini set adapted cooldown
if (Mini.mini != null && PlayerControl.LocalPlayer == Mini.mini && Mini.mini.Data.IsImpostor) {
var multiplier = Mini.isGrownUp() ? 0.66f : 2f;
Mini.mini.SetKillTimer(PlayerControl.GameOptions.KillCooldown * multiplier);
}

// Seer spawn souls
if (Seer.deadBodyPositions != null && Seer.seer != null && PlayerControl.LocalPlayer == Seer.seer && (Seer.mode == 0 || Seer.mode == 2)) {
foreach (Vector3 pos in Seer.deadBodyPositions) {
GameObject soul = new GameObject();
soul.transform.position = pos;
soul.layer = 5;
var rend = soul.AddComponent<SpriteRenderer>();
rend.sprite = Seer.getSoulSprite();

if(Seer.limitSoulDuration) {
HudManager.Instance.StartCoroutine(Effects.Lerp(Seer.soulDuration, new Action<float>((p) => {
if (rend != null) {
var tmp = rend.color;
tmp.a = Mathf.Clamp01(1 - p);
rend.color = tmp;
}
if (p == 1f && rend != null && rend.gameObject != null) UnityEngine.Object.Destroy(rend.gameObject);
})));
}
}
Seer.deadBodyPositions = new List<Vector3>();
}

// Arsonist deactivate dead poolable players
if (Arsonist.arsonist != null && Arsonist.arsonist == PlayerControl.LocalPlayer) {
int visibleCounter = 0;
Vector3 bottomLeft = new Vector3(-HudManager.Instance.UseButton.transform.localPosition.x, HudManager.Instance.UseButton.transform.localPosition.y, HudManager.Instance.UseButton.transform.localPosition.z);
bottomLeft += new Vector3(-0.25f, -0.25f, 0);
foreach (PlayerControl p in PlayerControl.AllPlayerControls) {
if (!Arsonist.dousedIcons.ContainsKey(p.PlayerId)) continue;
if (p.Data.IsDead || p.Data.Disconnected) {
Arsonist.dousedIcons[p.PlayerId].gameObject.SetActive(false);
} else {
Arsonist.dousedIcons[p.PlayerId].transform.localPosition = bottomLeft + Vector3.right * visibleCounter * 0.35f;
visibleCounter++;
}
}
}
}
}

[HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetString), new Type[] { typeof(StringNames), typeof(Il2CppReferenceArray<Il2CppSystem.Object>) })]
class ExileControllerMessagePatch {
static void Postfix(ref string __result, [HarmonyArgument(0)]StringNames id, [HarmonyArgument(1)]Il2CppReferenceArray<Il2CppSystem.Object> parts) {
if (ExileController.Instance != null && ExileController.Instance.exiled != null) {
PlayerControl player = Helpers.playerById(ExileController.Instance.exiled.Object.PlayerId);
if (player == null) return;
// Exile role text
if (id == StringNames.ExileTextPN || id == StringNames.ExileTextSN || id == StringNames.ExileTextPP || id == StringNames.ExileTextSP) {
__result = player.Data.PlayerName + " was The " + String.Join(" ", RoleInfo.getRoleInfoForPlayer(player).Select(x => x.name).ToArray());
}
// Hide number of remaining impostors on Jester win
if (id == StringNames.ImpostorsRemainP || id == StringNames.ImpostorsRemainS) {
if (Jester.jester != null && player.PlayerId == Jester.jester.PlayerId) __result = "";
}
}
}
}
}
Loading

0 comments on commit c3680a5

Please sign in to comment.