Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ An Among Us mod that adds a bunch of roles, modifiers and game settings
- [Teleporter](#teleporter)
- [Concealer](#concealer)
- [Grenadier](#grenadier)
- [Bomber](#bomber)

**Modifiers**
- [Torch](#torch)
Expand Down Expand Up @@ -898,7 +899,6 @@ These revelations can be about players who are living or dead.
| Prophet Cooldown | The cooldown of how long it takes for the Prophet to be given a revelation | Time | 40s |
| Prophet Initial Reveal | Whether the Prophet starts the game with a player already revealed to them | Toggle | False |


----------------------
## Covert
### **Team: Crewmates**
Expand All @@ -911,7 +911,6 @@ The Covert is a Crewmate that can temporarily turn invisible. Their vision is ha
| Covert Cooldown | The cooldown of the Covert's invisibility button | Time | 30s |
| Covert Duration | How long the Covert is invisible | Time | 15s |


----------------------
## Lighter
### **Team: Crewmates**
Expand All @@ -925,7 +924,6 @@ get normal crewmate vision is lights are off and normal impostor vision if light
| Lighter Cooldown | The cooldown of the Lighter's visibility | Time | 20s |
| Lighter Duration | How long the Lighter gets improved visibility invisible | Time | 5s |


----------------------
## Auspex
### **Team: Crewmates**
Expand All @@ -937,7 +935,6 @@ when another player is killed.
|----------|:-------------:|:------:|:------:|
| Auspex | The percentage probability of the Auspex appearing | Percentage | 0% |


-----------------------
# Neutral Roles
## Jester
Expand Down Expand Up @@ -1168,6 +1165,26 @@ However, a sabotage and a smoke grenade can not be active at the same time.
| Flash Grenade Cooldown | The cooldown of the Grenadier's Flash button | Time | 25s |
| Flash Grenade Duration | How long the Flash Grenade lasts for | Time | 10s |

-----------------------
## Bomber
### **Team: Impostors**

The Bomber is an Impostor that can make others murder for them.\
The Bomber can plant a bomb on a nearby player. After a certain amount of time, that player will be given a new kill
button and informed they have been set to explode. If the bombed player doesn't use that kill button to kill another
player within a certain amount of time, they will die.\
If the bombed player attempts to use this ability to kill the Bomber, they will kill themselves instead. They can
kill any other impostors though.\
The bombed player will lose all their emergency meetings, even if they successfull kill someone else with the bomb.

### Game Options
| Name | Description | Type | Default |
|----------|:-------------:|:------:|:------:|
| Bomber | The percentage probability of the Bomber appearing | Percentage | 0% |
| Bomb Cooldown | The cooldown of the Grenadier's Bomb Plant button | Time | 40s |
| Time Before Bomb is Armed | How long after the Bomber plants the bomb to inform the bombed player | Time | 5s |
| Time Before Bomb Explodes | How long after the Bomb is armed will the bombed player die | Time | 20s |

-----------------------

# Modifiers
Expand Down
5 changes: 5 additions & 0 deletions source/Patches/CustomGameOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public static class CustomGameOptions
public static int TeleporterOn => (int) Generate.TeleporterOn.Get();
public static int ConcealerOn => (int) Generate.ConcealerOn.Get();
public static int GrenadierOn => (int) Generate.GrenadierOn.Get();
public static int BomberOn => (int) Generate.BomberOn.Get();
public static int TorchOn => (int) Generate.TorchOn.Get();
public static int DiseasedOn => (int) Generate.DiseasedOn.Get();
public static int FlashOn => (int) Generate.FlashOn.Get();
Expand Down Expand Up @@ -142,6 +143,9 @@ public static class CustomGameOptions
public static float ConcealDuration => Generate.ConcealDuration.Get();
public static float GrenadeCooldown => Generate.GrenadeCooldown.Get();
public static float GrenadeDuration => Generate.GrenadeDuration.Get();
public static float BomberCooldown => Generate.BomberCooldown.Get();
public static float BombArmTime => Generate.BombArmTime.Get();
public static float BombFuseTime => Generate.BombFuseTime.Get();

public static List<RoleEnum> GetEnabledRoles(params Faction[] factions)
{
Expand Down Expand Up @@ -189,6 +193,7 @@ public static List<RoleEnum> GetEnabledRoles(params Faction[] factions)
if (On(TeleporterOn)) enabledRoles.Add(RoleEnum.Teleporter);
if (On(ConcealerOn)) enabledRoles.Add(RoleEnum.Concealer);
if (On(GrenadierOn)) enabledRoles.Add(RoleEnum.Grenadier);
if (On(BomberOn)) enabledRoles.Add(RoleEnum.Bomber);
}
}

Expand Down
13 changes: 13 additions & 0 deletions source/Patches/CustomOption/Generate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public static class Generate
public static CustomNumberOption TeleporterOn;
public static CustomNumberOption ConcealerOn;
public static CustomNumberOption GrenadierOn;
public static CustomNumberOption BomberOn;

private static CustomHeaderOption Modifiers;
public static CustomNumberOption TorchOn;
Expand Down Expand Up @@ -201,6 +202,11 @@ public static class Generate
public static CustomNumberOption GrenadeCooldown;
public static CustomNumberOption GrenadeDuration;

private static CustomHeaderOption Bomber;
public static CustomNumberOption BomberCooldown;
public static CustomNumberOption BombArmTime;
public static CustomNumberOption BombFuseTime;

private static Func<object, string> PercentFormat { get; } = value => $"{value:0}%";
private static Func<object, string> CooldownFormat { get; } = value => $"{value:0.0#}s";

Expand Down Expand Up @@ -286,6 +292,8 @@ public static void GenerateAll()
PercentFormat);
GrenadierOn = new CustomNumberOption(true, num++, $"{RoleDetailsAttribute.GetRoleDetails(RoleEnum.Grenadier).GetColoredName()}", 0f, 0f, 100f, 10f,
PercentFormat);
BomberOn = new CustomNumberOption(true, num++, $"{RoleDetailsAttribute.GetRoleDetails(RoleEnum.Bomber).GetColoredName()}", 0f, 0f, 100f, 10f,
PercentFormat);


Modifiers = new CustomHeaderOption(num++, "Modifiers");
Expand Down Expand Up @@ -529,6 +537,11 @@ public static void GenerateAll()
new CustomNumberOption(num++, "Flash Grenade Cooldown", 25, 10, 40, 2.5f, CooldownFormat);
GrenadeDuration =
new CustomNumberOption(num++, "Flash Grenade Duration", 10, 5, 15, 1f, CooldownFormat);

Bomber = new CustomHeaderOption(num++, $"{RoleDetailsAttribute.GetRoleDetails(RoleEnum.Bomber).GetColoredName()}");
BomberCooldown = new CustomNumberOption(num++, "Bomb Cooldown", 40, 35, 60, 2.5f, CooldownFormat);
BombArmTime = new CustomNumberOption(num++, "Time Before Bomb is Armed", 5, 2.5f, 15, 2.5f, CooldownFormat);
BombFuseTime = new CustomNumberOption(num++, "Time Before Bomb Explodes", 20, 10, 30, 2.5f, CooldownFormat);
#endregion
}
}
Expand Down
2 changes: 2 additions & 0 deletions source/Patches/CustomRPC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public enum CustomRPC
SetTeleporter,
SetConcealer,
SetGrenadier,
SetBomber,

SetTorch,
SetDiseased,
Expand Down Expand Up @@ -93,6 +94,7 @@ public enum CustomRPC
GoCovert,
LighterOn,
FlashGrenade,
PlantBomb,

SetGlitch,
BypassKill,
Expand Down
18 changes: 18 additions & 0 deletions source/Patches/ImpostorRoles/BomberMod/BombUpdate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Linq;
using HarmonyLib;
using TownOfUs.Roles;

namespace TownOfUs.Patches.ImpostorRoles.BomberMod
{
[HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))]
public class BombUpdate
{
public static void Postfix(HudManager __instance)
{
foreach (Bomber bomber in Role.GetRoles(RoleEnum.Bomber).Cast<Bomber>())
{
bomber.BombTick();
}
}
}
}
54 changes: 54 additions & 0 deletions source/Patches/ImpostorRoles/BomberMod/KillWithBomb.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System.Linq;
using HarmonyLib;
using TownOfUs.Roles;

namespace TownOfUs.Patches.ImpostorRoles.BomberMod
{
[HarmonyPatch(typeof(KillButton), nameof(KillButton.DoClick))]
public class KillWithBomb
{
public static bool Prefix(KillButton __instance)
{
if (
!PlayerControl.LocalPlayer.CanMove
|| PlayerControl.LocalPlayer.Data.IsDead
)
{
return false;
}

foreach (Bomber bomber in Role.GetRoles(RoleEnum.Bomber).ToList().Cast<Bomber>())
{
if (
__instance != bomber.KillWithBombButton
|| bomber.ShouldShowKillWithBombButton(PlayerControl.LocalPlayer)
)
{
continue;
}

if (
__instance.isCoolingDown
|| !__instance.isActiveAndEnabled
|| bomber.BombedPlayerTarget == null
)
{
return false;
}

if (bomber.BombedPlayerTarget.PlayerId == bomber.Player.PlayerId)
{
bomber.BombKill(bomber.BombedPlayer);
}
else
{
bomber.BombKill(bomber.BombedPlayerTarget);
}

return false;
}

return true;
}
}
}
48 changes: 48 additions & 0 deletions source/Patches/ImpostorRoles/BomberMod/ManageBombedPlayerButton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Linq;
using HarmonyLib;
using Rewired;
using TownOfUs.Roles;
using UnityEngine;

namespace TownOfUs.Patches.ImpostorRoles.BomberMod
{
[HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))]
public class ManageBombedPlayerButton
{
public static void Postfix(HudManager __instance)
{
if (
PlayerControl.AllPlayerControls.Count <= 1
|| PlayerControl.LocalPlayer == null
|| PlayerControl.LocalPlayer.Data == null
)
{
return;
}

foreach (var bomber in Role.GetRoles(RoleEnum.Bomber).ToList().Cast<Bomber>())
{
if (bomber.KillWithBombButton == null)
{
bomber.KillWithBombButton = Object.Instantiate(__instance.KillButton, __instance.KillButton.transform.parent);
bomber.KillWithBombButton.graphic.enabled = true;
// TODO
bomber.KillWithBombButton.GetComponent<AspectPosition>().DistanceFromEdge = new Vector3(
Camera.main.ScreenToWorldPoint(new Vector3(0, 0)).x + 0.75f,
__instance.UseButton.transform.position.y, __instance.UseButton.transform.position.z);
bomber.KillWithBombButton.gameObject.SetActive(false);
}
bomber.KillWithBombButton.GetComponent<AspectPosition>().Update();
bomber.KillWithBombButton.graphic.sprite = TranslationController.Instance.GetImage(ImageNames.KillButton);
bomber.KillWithBombButton.gameObject.SetActive(
!PlayerControl.LocalPlayer.Data.IsDead
&& !MeetingHud.Instance
&& bomber.ShouldShowKillWithBombButton(PlayerControl.LocalPlayer)
);

bomber.KillWithBombButton.SetCoolDown(0, 0); // TODO: Is this right?
Utils.SetTarget(ref bomber.BombedPlayerTarget, bomber.KillWithBombButton);
}
}
}
}
65 changes: 65 additions & 0 deletions source/Patches/ImpostorRoles/BomberMod/ManagePlantBombButton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using HarmonyLib;
using TownOfUs.Extensions;
using TownOfUs.Roles;
using UnityEngine;

namespace TownOfUs.Patches.ImpostorRoles.BomberMod
{
[HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))]
public class ManagePlantBombButton
{
// TODO
private static Sprite BombSprite => TownOfUs.ButtonSprite;

public static void Postfix(HudManager __instance)
{
if (
PlayerControl.AllPlayerControls.Count <= 1
|| PlayerControl.LocalPlayer == null
|| PlayerControl.LocalPlayer.Data == null
|| !PlayerControl.LocalPlayer.Is(RoleEnum.Bomber)
)
{
return;
}

Bomber role = Role.GetRole<Bomber>(PlayerControl.LocalPlayer);
if (role.PlantBombButton == null)
{
role.PlantBombButton = Object.Instantiate(__instance.KillButton, __instance.KillButton.transform.parent);
role.PlantBombButton.graphic.enabled = true;
role.PlantBombButton.GetComponent<AspectPosition>().DistanceFromEdge = TownOfUs.ButtonPosition;
role.PlantBombButton.gameObject.SetActive(false);
}

role.PlantBombButton.GetComponent<AspectPosition>().Update();
role.PlantBombButton.graphic.sprite = BombSprite;
role.PlantBombButton.gameObject.SetActive(!PlayerControl.LocalPlayer.Data.IsDead && !MeetingHud.Instance);

if (role.IsReadyToPlant())
{
Utils.SetTarget(ref role.Target, role.PlantBombButton);
role.PlantBombButton.SetCoolDown(role.CooldownTimer(), CustomGameOptions.BomberCooldown);
if (
role.Target != null
&& !role.Target.Data.IsImpostor()
)
{
role.PlantBombButton.graphic.color = Palette.DisabledClear;
role.PlantBombButton.graphic.material.SetFloat("_Desat", 1f);
}
else
{
role.PlantBombButton.graphic.color = Palette.EnabledColor;
role.PlantBombButton.graphic.material.SetFloat("_Desat", 0f);
}
}
else
{
role.PlantBombButton.SetCoolDown(role.TimeUntilBombArmed, CustomGameOptions.BombArmTime);
role.PlantBombButton.graphic.color = Palette.EnabledColor;
role.PlantBombButton.graphic.material.SetFloat("_Desat", 0f);
}
}
}
}
Loading