mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-19 15:51:48 +00:00
GameModifiers, and fixes
This commit is contained in:
1 parent
a9ff1c7f63
commit
a88646465b
13 files changed
+202
-50
No files matched your search
@@ -1,4 +1,5 @@
|
||||
using MiraAPI.Hud;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities;
|
||||
using UnityEngine;
|
||||
@@ -13,7 +14,7 @@ public class ExampleButton : CustomActionButton
|
||||
public override float EffectDuration => 0f;
|
||||
public override int MaxUses => 5;
|
||||
public override LoadableAsset<Sprite> Sprite { get; } = new LoadableResourceAsset("MiraAPI.Resources.ExampleButton.png");
|
||||
|
||||
|
||||
protected override void OnClick()
|
||||
{
|
||||
Logger<ExamplePlugin>.Info("Example button clicked!");
|
||||
@@ -21,6 +22,6 @@ public class ExampleButton : CustomActionButton
|
||||
|
||||
public override bool Enabled(RoleBehaviour role)
|
||||
{
|
||||
return true;
|
||||
return PlayerControl.LocalPlayer.HasModifier<ModifierExample>();
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,22 @@
|
||||
namespace MiraAPI.Example;
|
||||
|
||||
[RegisterModifier]
|
||||
public class ModifierExample : TimedModifier
|
||||
public class ModifierExample : GameModifier
|
||||
{
|
||||
public override string ModifierName => "Timed modifier example";
|
||||
public override float Duration => 1.5f;
|
||||
public override bool AutoStart => true;
|
||||
public override string ModifierName => "Example";
|
||||
|
||||
private System.Random _rand = new();
|
||||
|
||||
public override void OnTimerComplete()
|
||||
public override bool CanVent()
|
||||
{
|
||||
Player.SetColor((byte)_rand.Next(0, 18));
|
||||
StartTimer();
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetAmountPerGame()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public override int GetAssignmentChance()
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,7 @@ public abstract class CustomActionButton
|
||||
/// The button object in game. This is created by Mira API automatically.
|
||||
/// </summary>
|
||||
protected ActionButton Button { get; private set; }
|
||||
|
||||
|
||||
internal void CreateButton(Transform parent)
|
||||
{
|
||||
if (Button)
|
||||
@@ -99,10 +99,10 @@ public abstract class CustomActionButton
|
||||
{
|
||||
OnEffectEnd();
|
||||
}
|
||||
|
||||
|
||||
EffectActive = false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A utility function to override the sprite of the button.
|
||||
/// </summary>
|
||||
@@ -225,7 +225,7 @@ public abstract class CustomActionButton
|
||||
{
|
||||
Button.SetDisabled();
|
||||
}
|
||||
|
||||
|
||||
Button.SetCoolDown(Timer, EffectActive ? EffectDuration : Cooldown);
|
||||
|
||||
FixedUpdate(playerControl);
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
public abstract class BaseModifier
|
||||
{
|
||||
public abstract string ModifierName { get; }
|
||||
|
||||
public PlayerControl Player { get; internal set; }
|
||||
|
||||
public uint ModifierId { get; internal set; }
|
||||
public virtual void OnActivate() { }
|
||||
public virtual void OnDeactivate() { }
|
||||
public virtual void Update() { }
|
||||
public virtual void OnDeath() { }
|
||||
public virtual bool CanVent() => Player.Data.Role.CanVent;
|
||||
}
|
||||
@@ -13,13 +13,14 @@ namespace MiraAPI.Modifiers;
|
||||
[RegisterInIl2Cpp]
|
||||
public class ModifierComponent(IntPtr ptr) : MonoBehaviour(ptr)
|
||||
{
|
||||
public readonly List<BaseModifier> ActiveModifiers = [];
|
||||
public List<BaseModifier> ActiveModifiers { get; private set; }
|
||||
|
||||
public PlayerControl player;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
player = GetComponent<PlayerControl>();
|
||||
ActiveModifiers = new List<BaseModifier>();
|
||||
}
|
||||
|
||||
public void Update()
|
||||
@@ -50,6 +51,11 @@ public class ModifierComponent(IntPtr ptr) : MonoBehaviour(ptr)
|
||||
|
||||
modifier.OnDeactivate();
|
||||
modifierComponent.ActiveModifiers.Remove(modifier);
|
||||
|
||||
if (target.AmOwner)
|
||||
{
|
||||
HudManager.Instance.SetHudActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddModifier(PlayerControl target, uint modifierId)
|
||||
@@ -72,11 +78,17 @@ public class ModifierComponent(IntPtr ptr) : MonoBehaviour(ptr)
|
||||
|
||||
modifierComponent.ActiveModifiers.Add(modifier);
|
||||
modifier.Player = modifierComponent.player;
|
||||
modifier.ModifierId = modifierId;
|
||||
modifier.OnActivate();
|
||||
|
||||
if (modifier is TimedModifier { AutoStart: true } timer && target.AmOwner)
|
||||
if (target.AmOwner)
|
||||
{
|
||||
timer.StartTimer();
|
||||
if (modifier is TimedModifier { AutoStart: true } timer)
|
||||
{
|
||||
timer.StartTimer();
|
||||
}
|
||||
|
||||
HudManager.Instance.SetHudActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
using MiraAPI.Networking;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MiraAPI.Modifiers.Types;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Random = System.Random;
|
||||
|
||||
namespace MiraAPI.Modifiers;
|
||||
|
||||
@@ -30,10 +34,58 @@ public static class ModifierManager
|
||||
TypeToIdModifiers.Add(modifierType, _nextId);
|
||||
}
|
||||
|
||||
public static void AssignModifiers(List<PlayerControl> plrs)
|
||||
{
|
||||
Random rand = new Random();
|
||||
|
||||
List<uint> filteredModifiers = [];
|
||||
|
||||
foreach (var modifier in IdToTypeModifiers)
|
||||
{
|
||||
var mod = (GameModifier)Activator.CreateInstance(modifier.Value);
|
||||
var num = mod.GetAmountPerGame();
|
||||
var chance = mod.GetAssignmentChance();
|
||||
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
int randomNum = rand.Next(100);
|
||||
|
||||
if (randomNum < Math.Clamp(chance, 0, 100))
|
||||
{
|
||||
filteredModifiers.Add(TypeToIdModifiers[modifier.Value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var shuffledModifiers = filteredModifiers.Randomize();
|
||||
if (shuffledModifiers.Count > plrs.Count)
|
||||
{
|
||||
shuffledModifiers = shuffledModifiers.GetRange(0, plrs.Count);
|
||||
}
|
||||
|
||||
while (shuffledModifiers.Count > 0)
|
||||
{
|
||||
var id = shuffledModifiers[0];
|
||||
|
||||
var mod = (GameModifier)Activator.CreateInstance(IdToTypeModifiers[id]);
|
||||
var plr = plrs.Random();
|
||||
|
||||
if (plr.Data.Role is ICustomRole modRole)
|
||||
{
|
||||
if (!modRole.IsModifierApplicable(mod)) continue;
|
||||
}
|
||||
|
||||
if (plr.HasModifier(id) || mod.IsModifierValidOn(plr.Data.Role)) continue;
|
||||
|
||||
shuffledModifiers.RemoveAt(0);
|
||||
ModifierComponent.RpcAddModifier(plr, id);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SyncAllModifiers(int targetId = -1)
|
||||
{
|
||||
var data = new List<NetData>();
|
||||
|
||||
|
||||
if (targetId == -1)
|
||||
{
|
||||
foreach (var player in GameData.Instance.AllPlayers)
|
||||
@@ -44,24 +96,24 @@ public static class ModifierManager
|
||||
else
|
||||
{
|
||||
var player = GameData.Instance.GetPlayerById((byte)targetId).Object;
|
||||
|
||||
|
||||
data.Add(GetPlayerModifiers(player));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Rpc<SyncModifiersRpc>.Instance.Send(PlayerControl.LocalPlayer, data.ToArray(), true);
|
||||
}
|
||||
|
||||
|
||||
public static void HandleSyncModifiers(NetData[] data)
|
||||
{
|
||||
foreach (var netData in data)
|
||||
{
|
||||
var ids = new uint[netData.Data.Length / 4];
|
||||
Buffer.BlockCopy(netData.Data, 0, ids, 0, netData.Data.Length);
|
||||
|
||||
|
||||
var plr = GameData.Instance.GetPlayerById((byte)netData.Id).Object;
|
||||
var modifierComponent = plr.GetComponent<ModifierComponent>();
|
||||
|
||||
|
||||
if (!modifierComponent)
|
||||
{
|
||||
continue;
|
||||
@@ -72,7 +124,7 @@ public static class ModifierManager
|
||||
modifier.OnDeactivate();
|
||||
}
|
||||
modifierComponent.ActiveModifiers.Clear();
|
||||
|
||||
|
||||
foreach (var id in ids)
|
||||
{
|
||||
ModifierComponent.AddModifier(plr, id);
|
||||
@@ -88,12 +140,12 @@ public static class ModifierManager
|
||||
{
|
||||
return new NetData(player.PlayerId, []);
|
||||
}
|
||||
|
||||
|
||||
foreach (var modifier in modifierComponent.ActiveModifiers)
|
||||
{
|
||||
bytes.AddRange(BitConverter.GetBytes(TypeToIdModifiers[modifier.GetType()]));
|
||||
}
|
||||
|
||||
|
||||
return new NetData(player.PlayerId, bytes.ToArray());
|
||||
}
|
||||
}
|
||||
@@ -3,4 +3,5 @@ public abstract class GameModifier : BaseModifier
|
||||
{
|
||||
public abstract int GetAssignmentChance();
|
||||
public abstract int GetAmountPerGame();
|
||||
public virtual bool IsModifierValidOn(RoleBehaviour role) => true;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Utilities;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Patches.Modifiers;
|
||||
|
||||
[HarmonyPatch(typeof(Vent))]
|
||||
public static class VentPatches
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(Vent.CanUse))]
|
||||
public static void CanUseVentPatch(Vent __instance, ref float __result, [HarmonyArgument(0)] NetworkedPlayerInfo pc, [HarmonyArgument(1)] ref bool canUse, [HarmonyArgument(2)] ref bool couldUse)
|
||||
{
|
||||
var @object = pc.Object;
|
||||
var role = @object.Data.Role;
|
||||
|
||||
List<BaseModifier> modifiers = @object.GetModifierComponent().ActiveModifiers;
|
||||
if (modifiers.Count > 0)
|
||||
{
|
||||
if (role.CanVent && modifiers.Any(x => !x.CanVent()))
|
||||
{
|
||||
couldUse = canUse = false;
|
||||
return;
|
||||
}
|
||||
else if (!role.CanVent && modifiers.Any(x => x.CanVent()))
|
||||
{
|
||||
couldUse = true;
|
||||
}
|
||||
|
||||
var num = float.MaxValue;
|
||||
|
||||
canUse = couldUse;
|
||||
if (canUse)
|
||||
{
|
||||
var center = @object.Collider.bounds.center;
|
||||
var position = __instance.transform.position;
|
||||
num = Vector2.Distance(center, position);
|
||||
canUse &= num <= __instance.UsableDistance && !PhysicsHelpers.AnythingBetween(@object.Collider, center, position, Constants.ShipOnlyMask, false);
|
||||
}
|
||||
__result = num;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,19 @@
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Hud;
|
||||
using MiraAPI.Modifiers;
|
||||
using Reactor.Utilities.Extensions;
|
||||
|
||||
namespace MiraAPI.Patches;
|
||||
|
||||
[HarmonyPatch(typeof(PlayerControl))]
|
||||
public static class PlayerControlPatches
|
||||
{
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(PlayerControl.Start))]
|
||||
public static void PlayerControlStartPostfix(PlayerControl __instance)
|
||||
{
|
||||
if (__instance.gameObject.TryGetComponent<ModifierComponent>(out var comp)) comp.DestroyImmediate();
|
||||
|
||||
__instance.gameObject.AddComponent<ModifierComponent>();
|
||||
}
|
||||
|
||||
@@ -23,7 +25,7 @@ public static class PlayerControlPatches
|
||||
|
||||
foreach (var button in CustomButtonManager.CustomButtons)
|
||||
{
|
||||
if (!button.Enabled(__instance.Data.Role))
|
||||
if (!button.Enabled(__instance.Data?.Role))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using AmongUs.GameOptions;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Roles;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Patches.Roles;
|
||||
@@ -8,6 +10,15 @@ namespace MiraAPI.Patches.Roles;
|
||||
[HarmonyPatch(typeof(RoleManager))]
|
||||
public static class RoleManagerPatches
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(RoleManager.SelectRoles))]
|
||||
public static void ModifierSelectionPatches(RoleManager __instance)
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
|
||||
ModifierManager.AssignModifiers(PlayerControl.AllPlayerControls.ToArray().Where(plr => !plr.Data.IsDead && !plr.Data.Disconnected).ToList());
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(RoleManager.AssignRoleOnDeath))]
|
||||
public static bool AssignRoleOnDeath(RoleManager __instance, [HarmonyArgument(0)] PlayerControl plr)
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
using System;
|
||||
using AmongUs.GameOptions;
|
||||
using AmongUs.GameOptions;
|
||||
using BepInEx.Configuration;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using System.Text;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Networking;
|
||||
using Reactor.Utilities;
|
||||
using System;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Roles;
|
||||
@@ -22,7 +23,7 @@ public interface ICustomRole
|
||||
Color RoleColor { get; }
|
||||
|
||||
ModdedRoleTeams Team { get; }
|
||||
|
||||
|
||||
LoadableAsset<Sprite> OptionsScreenshot { get; }
|
||||
|
||||
LoadableAsset<Sprite> Icon => MiraAssets.Empty;
|
||||
@@ -69,12 +70,17 @@ public interface ICustomRole
|
||||
var taskStringBuilder = Helpers.CreateForRole(this);
|
||||
return taskStringBuilder;
|
||||
}
|
||||
|
||||
|
||||
bool IsModifierApplicable(BaseModifier modifier)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
NetData GetNetData(RoleBehaviour roleBehaviour)
|
||||
{
|
||||
PluginSingleton<MiraApiPlugin>.Instance.Config.TryGetEntry<int>(NumConfigDefinition, out var numEntry);
|
||||
PluginSingleton<MiraApiPlugin>.Instance.Config.TryGetEntry<int>(ChanceConfigDefinition, out var chanceEntry);
|
||||
|
||||
|
||||
return new NetData((uint)roleBehaviour.Role, BitConverter.GetBytes(numEntry.Value).AddRangeToArray(BitConverter.GetBytes(chanceEntry.Value)));
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Roles;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
@@ -19,12 +19,29 @@ public static class Extensions
|
||||
|
||||
public static ModifierComponent GetModifierComponent(this PlayerControl player)
|
||||
{
|
||||
return player.gameObject.GetComponent<ModifierComponent>();
|
||||
return player.GetComponent<ModifierComponent>();
|
||||
}
|
||||
|
||||
public static List<T> Randomize<T>(this List<T> list)
|
||||
{
|
||||
List<T> randomizedList = new List<T>();
|
||||
System.Random rnd = new();
|
||||
while (list.Count > 0)
|
||||
{
|
||||
int index = rnd.Next(0, list.Count);
|
||||
randomizedList.Add(list[index]);
|
||||
list.RemoveAt(index);
|
||||
}
|
||||
return randomizedList;
|
||||
}
|
||||
|
||||
public static bool HasModifier<T>(this PlayerControl player) where T : BaseModifier
|
||||
{
|
||||
return player.GetModifierComponent().ActiveModifiers.Exists(x => x is T);
|
||||
return player is not null && player.GetModifierComponent() is not null && player.GetModifierComponent().ActiveModifiers.Exists(x => x is T);
|
||||
}
|
||||
public static bool HasModifier(this PlayerControl player, uint id)
|
||||
{
|
||||
return player is not null && player.GetModifierComponent() is not null && player.GetModifierComponent().ActiveModifiers.Exists(x => x.ModifierId == id);
|
||||
}
|
||||
|
||||
public static void AddModifier<T>(this PlayerControl player) where T : BaseModifier
|
||||
|
||||
@@ -8,7 +8,6 @@ namespace MiraAPI.Utilities;
|
||||
public static class Helpers
|
||||
{
|
||||
public static readonly ContactFilter2D Filter = ContactFilter2D.CreateLegacyFilter(Constants.NotShipMask, float.MinValue, float.MaxValue);
|
||||
|
||||
public static PlainShipRoom GetRoom(Vector3 pos)
|
||||
{
|
||||
return ShipStatus.Instance.AllRooms.ToList().Find(room => room.roomArea.OverlapPoint(pos));
|
||||
@@ -18,7 +17,7 @@ public static class Helpers
|
||||
{
|
||||
return Object.FindObjectsOfType<DeadBody>().FirstOrDefault(body => body.ParentId == id);
|
||||
}
|
||||
|
||||
|
||||
public static string GetSuffix(NumberSuffixes suffix)
|
||||
{
|
||||
return suffix switch
|
||||
|
||||
Reference in new issue
Block a user