Skip to content

Commit

Permalink
Merge pull request #1294 from tukasa0001/develop-5.1.0
Browse files Browse the repository at this point in the history
Develop-5.1.0
  • Loading branch information
Hyz-sui committed Sep 4, 2023
2 parents 9e78c46 + 8ac1040 commit f137dd9
Show file tree
Hide file tree
Showing 69 changed files with 3,274 additions and 1,572 deletions.
22 changes: 22 additions & 0 deletions Helpers/ColorHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using UnityEngine;

namespace TownOfHost;

public static class ColorHelper
{
/// <summary>蛍光マーカーのような色合いの透過色に変換する</summary>
/// <param name="bright">最大明度にするかどうか.黒っぽい色を黒っぽいままにしたい場合はfalse</param>
public static Color ToMarkingColor(this Color color, bool bright = true)
{
Color.RGBToHSV(color, out var h, out _, out var v);
var markingColor = Color.HSVToRGB(h, MarkerSat, bright ? MarkerVal : v).SetAlpha(MarkerAlpha);
return markingColor;
}

/// <summary>マーカー色のS値 = 彩度</summary>
private const float MarkerSat = 1f;
/// <summary>マーカー色のV値 = 明度</summary>
private const float MarkerVal = 1f;
/// <summary>マーカー色のアルファ = 不透明度</summary>
private const float MarkerAlpha = 0.2f;
}
22 changes: 2 additions & 20 deletions Helpers/CustomRolesHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,15 @@ public static bool IsMadmate(this CustomRoles role)
var roleInfo = role.GetRoleInfo();
if (roleInfo != null)
return roleInfo.CustomRoleType == CustomRoleTypes.Madmate;
return
role is
CustomRoles.SKMadmate or
CustomRoles.MSchrodingerCat;
return role == CustomRoles.SKMadmate;
}
public static bool IsImpostorTeam(this CustomRoles role) => role.IsImpostor() || role.IsMadmate();
public static bool IsNeutral(this CustomRoles role)
{
var roleInfo = role.GetRoleInfo();
if (roleInfo != null)
return roleInfo.CustomRoleType == CustomRoleTypes.Neutral;
return
role is
CustomRoles.SchrodingerCat or
CustomRoles.EgoSchrodingerCat or
CustomRoles.JSchrodingerCat or
CustomRoles.HASTroll or
CustomRoles.HASFox;
return role is CustomRoles.HASTroll or CustomRoles.HASFox;
}
public static bool IsCrewmate(this CustomRoles role) => role.GetRoleInfo()?.CustomRoleType == CustomRoleTypes.Crewmate || (!role.IsImpostorTeam() && !role.IsNeutral());
public static bool IsVanilla(this CustomRoles role)
Expand All @@ -52,15 +43,6 @@ CustomRoles.GuardianAngel or
CustomRoles.Impostor or
CustomRoles.Shapeshifter;
}
public static bool IsKilledSchrodingerCat(this CustomRoles role)
{
return role is
CustomRoles.SchrodingerCat or
CustomRoles.MSchrodingerCat or
CustomRoles.CSchrodingerCat or
CustomRoles.EgoSchrodingerCat or
CustomRoles.JSchrodingerCat;
}

public static CustomRoleTypes GetCustomRoleTypes(this CustomRoles role)
{
Expand Down
25 changes: 25 additions & 0 deletions Helpers/StringHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Text;
using UnityEngine;

namespace TownOfHost;

public static class StringHelper
{
public static readonly Encoding shiftJIS = CodePagesEncodingProvider.Instance.GetEncoding("Shift_JIS");

/// <summary>蛍光マーカーのような装飾をする</summary>
/// <param name="self">文字列</param>
/// <param name="color">元の色 自動で半透明の蛍光色に変換される</param>
/// <param name="bright">最大明度にするかどうか.黒っぽい色を黒っぽいままにしたい場合はfalse</param>
/// <returns>マーキング済文字列</returns>
public static string Mark(this string self, Color color, bool bright = true)
{
var markingColor = color.ToMarkingColor(bright);
var markingColorCode = ColorUtility.ToHtmlStringRGBA(markingColor);
return $"<mark=#{markingColorCode}>{self}</mark>";
}
/// <summary>
/// SJISでのバイト数を計算する
/// </summary>
public static int GetByteCount(this string self) => shiftJIS.GetByteCount(self);
}
106 changes: 106 additions & 0 deletions Modules/AdminProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using System.Collections.Generic;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using TownOfHost.Roles.Core;
using UnityEngine;

namespace TownOfHost.Modules;

public static class AdminProvider
{
// ref: MapCountOverlay.Update
/// <summary>
/// 実行された時点でのアドミン情報を取得する
/// </summary>
/// <returns>Key: 部屋のSystemType, Value: <see cref="AdminEntry"/>で,Key順にソートされた辞書</returns>
public static SortedDictionary<SystemTypes, AdminEntry> CalculateAdmin()
{
SortedDictionary<SystemTypes, AdminEntry> allAdmins = new();
// 既にカウントされた人のPlayerIdを格納する
// これに追加しようとしたときにfalseが返ってきたらカウントしないようにすることで,各プレイヤーが1回しかカウントされないようになっている
HashSet<int> countedPlayers = new(15);
// 検出された当たり判定の格納用に使い回す配列 変換時の負荷を回避するためIl2CppReferenceArrayで扱う
Il2CppReferenceArray<Collider2D> colliders = new(45);
// ref: MapCountOverlay.Awake
ContactFilter2D filter = new()
{
useLayerMask = true,
layerMask = Constants.LivingPlayersOnlyMask,
useTriggers = true,
};

// 各部屋の人数カウント処理
foreach (var room in ShipStatus.Instance.AllRooms)
{
var roomId = room.RoomId;
// 通路か当たり判定がないなら何もしない
if (roomId == SystemTypes.Hallway || room.roomArea == null)
{
continue;
}
// 検出された当たり判定の数 検出された当たり判定はここでcollidersに格納される
var numColliders = room.roomArea.OverlapCollider(filter, colliders);
// 実際にアドミンで表示される,死体も含めた全部の数
var totalPlayers = 0;
// 死体の数
var numDeadBodies = 0;
// インポスターの数
var numImpostors = 0;

// 検出された各当たり判定への処理
for (var i = 0; i < numColliders; i++)
{
var collider = colliders[i];
// おにくの場合
if (collider.CompareTag("DeadBody"))
{
var deadBody = collider.GetComponent<DeadBody>();
if (deadBody != null && countedPlayers.Add(deadBody.ParentId))
{
totalPlayers++;
numDeadBodies++;
// インポスターの死体だった場合
if (Utils.GetPlayerById(deadBody.ParentId)?.Is(CustomRoleTypes.Impostor) == true)
{
numImpostors++;
}
}
}
// 生きてる場合
else if (!collider.isTrigger)
{
var playerControl = collider.GetComponent<PlayerControl>();
if (playerControl.IsAlive() && countedPlayers.Add(playerControl.PlayerId))
{
totalPlayers++;
// インポスターだった場合
if (playerControl.Is(CustomRoleTypes.Impostor))
{
numImpostors++;
}
}
}
}

allAdmins[roomId] = new()
{
Room = roomId,
TotalPlayers = totalPlayers,
NumDeadBodies = numDeadBodies,
NumImpostors = numImpostors,
};
}
return allAdmins;
}

public readonly record struct AdminEntry
{
/// <summary>対象の部屋</summary>
public SystemTypes Room { get; init; }
/// <summary>部屋の中にいるプレイヤーの合計
public int TotalPlayers { get; init; }
/// <summary>部屋の中にある死体の数</summary>
public int NumDeadBodies { get; init; }
/// <summary>部屋の中にインポスターがいるかどうか</summary>
public int NumImpostors { get; init; }
}
}
29 changes: 2 additions & 27 deletions Modules/AntiBlackout.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using AmongUs.GameOptions;
using Hazel;

using TownOfHost.Attributes;
Expand All @@ -15,32 +14,8 @@ public static class AntiBlackout
///<summary>
///追放処理を上書きするかどうか
///</summary>
public static bool OverrideExiledPlayer => IsRequired && (IsSingleImpostor || Diff_CrewImp == 1);
///<summary>
///インポスターが一人しか存在しない設定かどうか
///</summary>
public static bool IsSingleImpostor => Main.RealOptionsData != null ? Main.RealOptionsData.GetInt(Int32OptionNames.NumImpostors) == 1 : Main.NormalOptions.NumImpostors == 1;
///<summary>
///AntiBlackout内の処理が必要であるかどうか
///</summary>
public static bool IsRequired => Options.NoGameEnd.GetBool() || Jackal.RoleInfo.IsEnable;
///<summary>
///インポスター以外の人数とインポスターの人数の差
///</summary>
public static int Diff_CrewImp
{
get
{
int numImpostors = 0;
int numCrewmates = 0;
foreach (var pc in Main.AllPlayerControls)
{
if (pc.Data.Role.IsImpostor) numImpostors++;
else numCrewmates++;
}
return numCrewmates - numImpostors;
}
}
public static bool OverrideExiledPlayer => Options.NoGameEnd.GetBool() || Jackal.RoleInfo.IsEnable;

public static bool IsCached { get; private set; } = false;
private static Dictionary<byte, (bool isDead, bool Disconnected)> isDeadCache = new();
private readonly static LogHandler logger = Logger.Handler("AntiBlackout");
Expand Down
9 changes: 8 additions & 1 deletion Modules/DebugModeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,14 @@ public static void SetupCustomOption()
{
EnableDebugMode = BooleanOptionItem.Create(2, "EnableDebugMode", false, TabGroup.MainSettings, true)
.SetColor(Color.green)
.SetHidden(!AmDebugger);
.SetHidden(!AmDebugger)
.RegisterUpdateValueEvent((obj, args) =>
{
if (DestroyableSingleton<GameStartManager>.InstanceExists && Main.NormalOptions.NumImpostors == 0 && AmongUsClient.Instance.AmHost && !EnableDebugMode.GetBool())
{
Main.NormalOptions.NumImpostors = 1;
}
});
}
}
}
95 changes: 95 additions & 0 deletions Modules/DoorsReset.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using TownOfHost.Attributes;

namespace TownOfHost.Modules;

public static class DoorsReset
{
private static bool isEnabled = false;
private static ResetMode mode;
private static DoorsSystemType DoorsSystem => ShipStatus.Instance.Systems.TryGetValue(SystemTypes.Doors, out var system) ? system.TryCast<DoorsSystemType>() : null;
private static readonly LogHandler logger = Logger.Handler(nameof(DoorsReset));

[GameModuleInitializer]
public static void Initialize()
{
// AirshipとPolus以外は非対応
if ((MapNames)Main.NormalOptions.MapId is not (MapNames.Airship or MapNames.Polus))
{
isEnabled = false;
return;
}
isEnabled = Options.ResetDoorsEveryTurns.GetBool();
mode = (ResetMode)Options.DoorsResetMode.GetValue();
logger.Info($"初期化: [ {isEnabled}, {mode} ]");
}

/// <summary>設定に応じてドア状況をリセット</summary>
public static void ResetDoors()
{
if (!isEnabled || DoorsSystem == null)
{
return;
}
logger.Info("リセット");

switch (mode)
{
case ResetMode.AllOpen: OpenAllDoors(); break;
case ResetMode.AllClosed: CloseAllDoors(); break;
case ResetMode.RandomByDoor: OpenOrCloseAllDoorsRandomly(); break;
default: logger.Warn($"無効なモード: {mode}"); break;
}
}
/// <summary>マップ上の全ドアを開放</summary>
private static void OpenAllDoors()
{
foreach (var door in ShipStatus.Instance.AllDoors)
{
SetDoorOpenState(door, true);
}
DoorsSystem.IsDirty = true;
}
/// <summary>マップ上の全ドアを閉鎖</summary>
private static void CloseAllDoors()
{
foreach (var door in ShipStatus.Instance.AllDoors)
{
SetDoorOpenState(door, false);
}
DoorsSystem.IsDirty = true;
}
/// <summary>マップ上の全ドアをランダムに開閉</summary>
private static void OpenOrCloseAllDoorsRandomly()
{
foreach (var door in ShipStatus.Instance.AllDoors)
{
var isOpen = IRandom.Instance.Next(2) > 0;
SetDoorOpenState(door, isOpen);
}
DoorsSystem.IsDirty = true;
}

/// <summary>ドアの開閉状況を設定する.サボタージュで閉められないドアに対しては何もしない</summary>
/// <param name="door">対象のドア</param>
/// <param name="isOpen">開けるならtrue,閉めるならfalse</param>
private static void SetDoorOpenState(PlainDoor door, bool isOpen)
{
if (IsValidDoor(door))
{
door.SetDoorway(isOpen);
}
}
/// <summary>リセット対象のドアかどうか判定する</summary>
/// <returns>リセット対象ならtrue</returns>
private static bool IsValidDoor(PlainDoor door)
{
// エアシラウンジトイレとPolus除染室のドアは対象外
if (door.Room is SystemTypes.Lounge or SystemTypes.Decontamination)
{
return false;
}
return true;
}

public enum ResetMode { AllOpen, AllClosed, RandomByDoor, }
}
10 changes: 0 additions & 10 deletions Modules/GameOptionsSender/PlayerGameOptionsSender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using Mathf = UnityEngine.Mathf;

using TownOfHost.Roles.Core;
using TownOfHost.Roles.Neutral;

namespace TownOfHost.Modules
{
Expand Down Expand Up @@ -97,15 +96,6 @@ public override IGameOptions BuildGameOptions()

var roleClass = player.GetRoleClass();
roleClass?.ApplyGameOptions(opt);
switch (role)
{
case CustomRoles.EgoSchrodingerCat:
opt.SetVision(true);
break;
case CustomRoles.JSchrodingerCat:
((Jackal)roleClass).ApplyGameOptions(opt);
break;
}
foreach (var subRole in player.GetCustomSubRoles())
{
switch (subRole)
Expand Down
Loading

0 comments on commit f137dd9

Please sign in to comment.