Skip to content
Merged
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
67 changes: 67 additions & 0 deletions NewMod/Components/Birthday/Toast.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using System.Collections;
using Reactor.Utilities;
using TMPro;
using UnityEngine;
using NewMod;
using NewMod.Utilities;
using Reactor.Utilities.Attributes;
using Il2CppInterop.Runtime.Attributes;

[RegisterInIl2Cpp]
public class Toast(IntPtr ptr) : MonoBehaviour(ptr)
{
public SpriteRenderer toastRend;
public TextMeshPro TimerText;
public bool isExpanded = false;
public void Awake()
{
toastRend = transform.Find("Background").GetComponent<SpriteRenderer>();
TimerText = transform.Find("Timer").GetComponent<TextMeshPro>();
}
public static Toast CreateToast()
{
var gameObject = Instantiate(NewModAsset.Toast.LoadAsset(), HudManager.Instance.transform);
var toast = gameObject.AddComponent<Toast>();
return toast;
}
[HideFromIl2Cpp]
public void SetText(string msg)
{
if (TimerText) TimerText.text = msg;
}

[HideFromIl2Cpp]
public void StartCountdown(TimeSpan duration)
{
Coroutines.Start(CoCountdown(duration));
}
[HideFromIl2Cpp]
public IEnumerator CoCountdown(TimeSpan span)
{
var end = DateTime.UtcNow + span;
while (true)
{
var left = end - DateTime.UtcNow;
if (left.TotalSeconds <= 0) break;

if (TimerText)
TimerText.text = Utils.FormatSpan(left);

yield return new WaitForSecondsRealtime(0.2f);
}
if (TimerText) TimerText.text = "00:00:00:00";

DisconnectAllPlayers();
}
[HideFromIl2Cpp]
public static void DisconnectAllPlayers()
{
var client = AmongUsClient.Instance;
if (client.GameState == InnerNet.InnerNetClient.GameStates.Started) return;

client.LastCustomDisconnect =
"The Birthday Update is now live! Please restart to see the new lobby and menu style.";
client.HandleDisconnect(DisconnectReasons.Custom);
}
}
37 changes: 2 additions & 35 deletions NewMod/DebugWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@
using NewMod.Roles.CrewmateRoles;
using NewMod.Roles.ImpostorRoles;
using NewMod.Roles.NeutralRoles;
using NewMod.Buttons.EnergyThief;
using NewMod.Buttons.SpecialAgent;
using NewMod.Buttons.Visionary;
using NewMod.Buttons.Prankster;
using NewMod.Buttons.Necromancer;
using Reactor.Utilities.Attributes;
using Reactor.Utilities.ImGui;
using UnityEngine;
Expand Down Expand Up @@ -42,16 +37,6 @@ public class DebugWindow(nint ptr) : MonoBehaviour(ptr)
if (!isFreeplay) return;
PlayerControl.LocalPlayer.RpcRemoveModifier<ExplosiveModifier>();
}
if (GUILayout.Button("Disable Collider"))
{
if (!isFreeplay) return;
PlayerControl.LocalPlayer.Collider.enabled = false;
}
if (GUILayout.Button("Enable Collider"))
{
if (!isFreeplay) return;
PlayerControl.LocalPlayer.Collider.enabled = true;
}
if (GUILayout.Button("Become Necromancer"))
{
if (!isFreeplay) return;
Expand Down Expand Up @@ -79,27 +64,9 @@ public class DebugWindow(nint ptr) : MonoBehaviour(ptr)
}
if (GUILayout.Button("Increases Uses by 3"))
{
var player = PlayerControl.LocalPlayer;
if (player.Data.Role is NecromancerRole)
{
CustomButtonSingleton<ReviveButton>.Instance.IncreaseUses(3);
}
else if (player.Data.Role is EnergyThief)
{
CustomButtonSingleton<DrainButton>.Instance.IncreaseUses(3);
}
else if (player.Data.Role is SpecialAgent)
{
CustomButtonSingleton<AssignButton>.Instance.IncreaseUses(3);
}
else if (player.Data.Role is Prankster)
{
CustomButtonSingleton<FakeBodyButton>.Instance.IncreaseUses(3);
}
else
foreach (var button in CustomButtonManager.Buttons)
{
CustomButtonSingleton<CaptureButton>.Instance.IncreaseUses(3);
CustomButtonSingleton<ShowScreenshotButton>.Instance.IncreaseUses(3);
button.SetUses(3);
}
}
if (GUILayout.Button("Randomly Cast a Vote"))
Expand Down
126 changes: 126 additions & 0 deletions NewMod/Features/CustomPlayerTag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using HarmonyLib;
using Hazel;
using MiraAPI.Events;
using MiraAPI.Events.Vanilla.Meeting;
using Reactor.Utilities;

namespace NewMod.Features
{
public static class CustomPlayerTag
{
public enum TagType : byte
{
Player,
Dev,
Creator,
Tester,
Staff,
Contributor,
Host,
AOUDev
}

public static readonly Dictionary<TagType, string> DefaultHex = new()
{
{ TagType.Player, "c0c0c0" },
{ TagType.Dev, "ff4d4d" },
{ TagType.Creator, "ffb000" },
{ TagType.Tester, "00e0ff" },
{ TagType.Staff, "9b59b6" },
{ TagType.Contributor, "7ee081" },
{ TagType.Host, "ff7f50" },
{ TagType.AOUDev, "00ffb3" }
};

public static string DisplayName(TagType t) => t switch
{
TagType.Player => "Player",
TagType.Dev => "Developer",
TagType.Creator => "Creator",
TagType.Tester => "Tester",
TagType.Staff => "Staff",
TagType.Contributor => "Contributor",
TagType.Host => "Host",
TagType.AOUDev => "AOU Dev",
_ => ""
};

public static string Format(TagType t, string hex)
{
string color = string.IsNullOrWhiteSpace(hex)
? (DefaultHex.TryGetValue(t, out var h) ? h : "ffffff")
: hex;
string label = DisplayName(t);
return $"\n<size=1.7><color=#{color}>{label}</color></size>";
}
public static TagType GetTag(string friendCode)
{
if (string.Equals(friendCode, "puncool#9009", StringComparison.OrdinalIgnoreCase)) return TagType.Creator;
if (string.Equals(friendCode, "peaktipple#8186", StringComparison.OrdinalIgnoreCase)) return TagType.Dev;
if (string.Equals(friendCode, "shinyrake#9382", StringComparison.OrdinalIgnoreCase)) return TagType.Dev;
if (string.Equals(friendCode, "dimpledue#6629", StringComparison.OrdinalIgnoreCase)) return TagType.AOUDev;
return TagType.Player;
}

[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.RpcSetName))]
public static class RpcSetNamePatch
{
public static bool Prefix(PlayerControl __instance, ref string name)
{
var friendCode = __instance.FriendCode;
TagType tag = GetTag(friendCode);

var host = GameData.Instance.GetHost();
bool isHost = host.PlayerId == __instance.PlayerId;

string baseName = name.Split('\n')[0];

string newName = baseName;
if (isHost)
newName += Format(TagType.Host, DefaultHex[TagType.Host]);
if (tag != TagType.Player)
newName += Format(tag, DefaultHex[tag]);
else
newName += Format(TagType.Player, DefaultHex[TagType.Player]);

Logger<NewMod>.Instance.LogInfo($"Player {__instance.PlayerId} '{baseName}' " + $"FriendCode={friendCode}, Host={isHost}, Tag={DisplayName(tag)} " + $"FinalName='{newName}'");

__instance.SetName(newName);

var writer = AmongUsClient.Instance.StartRpcImmediately(__instance.NetId, (byte)RpcCalls.SetName, SendOption.Reliable, -1);
writer.Write(__instance.Data.NetId);
writer.Write(newName);
AmongUsClient.Instance.FinishRpcImmediately(writer);

return false;
}
}

[RegisterEvent]
public static void OnMeetingStart(StartMeetingEvent evt)
{
var host = GameData.Instance.GetHost();

foreach (var ps in evt.MeetingHud.playerStates)
{
string baseName = ps.NameText.text.Split('\n')[0];
bool isHost = ps.TargetPlayerId == host.PlayerId;

TagType tag = GetTag(GameData.Instance.GetPlayerById(ps.TargetPlayerId).FriendCode);
string newName = baseName;

if (isHost)
newName += Format(TagType.Host, DefaultHex[TagType.Host]);

if (tag != TagType.Player)
newName += Format(tag, DefaultHex[tag]);
else
newName += Format(TagType.Player, DefaultHex[TagType.Player]);

ps.NameText.text = newName;
}
}
}
}
1 change: 0 additions & 1 deletion NewMod/NewMod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
using MiraAPI.Events.Vanilla.Gameplay;
using NewMod.Roles.NeutralRoles;
using MiraAPI.Roles;
using System;
using MiraAPI.Hud;
using UnityEngine.Events;
using NewMod.Options.Roles.OverloadOptions;
Expand Down
9 changes: 2 additions & 7 deletions NewMod/NewMod.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<VersionPrefix>1.2.1</VersionPrefix>
<VersionPrefix>1.2.4</VersionPrefix>
<VersionSuffix>dev</VersionSuffix>
<Description>NewMod is a mod for Among Us that introduces a variety of new roles, unique abilities</Description>
<Authors>CallofCreator</Authors>
Expand All @@ -21,6 +21,7 @@

<ItemGroup>
<PackageReference Include="Reactor" Version="2.3.1" />
<PackageReference Include="AllOfUs.MiraAPI" Version="0.2.1" />
<PackageReference Condition="'$(Configuration)' == 'Debug' Or '$(Configuration)' == 'Release' " Include="AmongUs.GameLibs.Steam" Version="2025.4.15" PrivateAssets="all" />
<PackageReference Condition="'$(Configuration)' == 'ANDROID' " Include="AmongUs.GameLibs.Android" Version="2025.6.10" PrivateAssets="all" />
<PackageReference Include="BepInEx.AutoPlugin" Version="1.1.0" PrivateAssets="all" />
Expand All @@ -31,10 +32,4 @@
<ItemGroup>
<EmbeddedResource Include="Resources\**\*.*" />
</ItemGroup>

<ItemGroup>
<Reference Include="MiraAPI">
<HintPath>..\libs\MiraAPI.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
8 changes: 8 additions & 0 deletions NewMod/NewModAsset.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
using Reactor.Utilities;
using MiraAPI.Utilities.Assets;
using UnityEngine;

namespace NewMod;

public static class NewModAsset
{
public static AssetBundle Bundle = AssetBundleManager.Load("newmod");
// Miscellaneous
public static LoadableResourceAsset Banner { get; } = new("NewMod.Resources.optionImage.png");
public static LoadableResourceAsset Arrow { get; } = new("NewMod.Resources.Arrow.png");
public static LoadableResourceAsset ModLogo { get; } = new("NewMod.Resources.Logo.png");
public static LoadableResourceAsset CustomCursor { get; } = new("NewMod.Resources.cursor.png");

// NewMod's First Birthday Assets
public static LoadableResourceAsset MainMenuBG { get; } = new("NewMod.Resources.Birthday.newmod-birthday-v1.png");
public static LoadableAsset<GameObject> CustomLobby { get; } = new LoadableBundleAsset<GameObject>("CustomLobby", Bundle);
public static LoadableAsset<GameObject> Toast { get; } = new LoadableBundleAsset<GameObject>("Toast", Bundle);
// Button icons
public static LoadableResourceAsset SpecialAgentButton { get; } = new("NewMod.Resources.givemission.png");
public static LoadableResourceAsset ShowScreenshotButton { get; } = new("NewMod.Resources.showscreenshot.png");
Expand Down
24 changes: 18 additions & 6 deletions NewMod/NewModDateTime.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
using System;

namespace NewMod;
public static class NewModDateTime
namespace NewMod
{
public static DateTime NewModBirthday
public static class NewModDateTime
{
get
public static DateTime NewModBirthday
{
var thisYear = new DateTime(DateTime.Now.Year, 8, 28);
return DateTime.Now <= thisYear ? thisYear : new DateTime(DateTime.Now.Year + 1, 8, 28);
get
{
var thisYear = new DateTime(DateTime.Now.Year, 8, 28, 16, 0, 0);
return DateTime.Now <= thisYear ? thisYear : new DateTime(DateTime.Now.Year + 1, 8, 28);
}
}
public static DateTime NewModBirthdayWeekEnd
{
get
{
return NewModBirthday.AddDays(7);
}
}

public static bool IsNewModBirthdayWeek =>
DateTime.Now >= NewModBirthday && DateTime.Now <= NewModBirthdayWeekEnd;
}
}
25 changes: 2 additions & 23 deletions NewMod/Options/CompatibilityOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,8 @@ public class CompatibilityOptions : AbstractOptionGroup
{
public override string GroupName => "Mod Compatibility";
public override Func<bool> GroupVisible => ModCompatibility.IsLaunchpadLoaded;
public ModdedToggleOption AllowRevenantHitmanCombo { get; } = new("Allow Revenant & Hitman in Same Match", false)
{
ChangedEvent = value =>
{
HudManager.Instance.ShowPopUp(value
? "You enabled the Revenant & Hitman combo. This may break game balance!"
: "Revenant & Hitman combo disabled. Only one will be allowed per match.");
}
};
public ModdedEnumOption<ModPriority> Compatibility { get; } = new("Mod Compatibility", ModPriority.PreferNewMod)
{
ChangedEvent = value =>
{
HudManager.Instance.ShowPopUp(
value switch
{
ModPriority.PreferNewMod => "You selected 'PreferNewMod'. Medic will be disabled.\n" +
"Switch to 'Prefer LaunchpadReloaded' to enable Medic and disable Necromancer.",
ModPriority.PreferLaunchpadReloaded => "You selected 'PreferLaunchpadReloaded'. Necromancer will be disabled.\n" +
"Switch to 'PreferNewMod' to enable Necromancer and disable Medic.",
});
}
};
public ModdedToggleOption AllowRevenantHitmanCombo { get; } = new("Allow Revenant & Hitman in Same Match", false);
public ModdedEnumOption<ModPriority> Compatibility { get; } = new("Mod Compatibility", ModPriority.PreferNewMod);
public enum ModPriority
{
PreferNewMod,
Expand Down
Loading
Loading